Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a0754ad291
commit
8d94a37915
|
|
@ -128,6 +128,8 @@ e2e:test-on-gdk:
|
|||
# In MRs we assume the last scheduled master pipeline built the image already.
|
||||
- job: build-qa-on-gdk-master-image
|
||||
optional: true
|
||||
variables:
|
||||
QA_RUN_TYPE: e2e-test-on-gdk # Setting it here so that all the child pipeline reporting jobs inherit this variable
|
||||
allow_failure: true
|
||||
trigger:
|
||||
strategy: depend
|
||||
|
|
|
|||
|
|
@ -3,6 +3,27 @@ default:
|
|||
|
||||
include:
|
||||
- local: .gitlab/ci/package-and-test/rules.gitlab-ci.yml
|
||||
- local: .gitlab/ci/package-and-test/variables.gitlab-ci.yml
|
||||
- project: 'gitlab-org/quality/pipeline-common'
|
||||
ref: 3.1.3
|
||||
file:
|
||||
- /ci/base.gitlab-ci.yml
|
||||
- /ci/allure-report.yml
|
||||
- /ci/knapsack-report.yml
|
||||
|
||||
stages:
|
||||
- test
|
||||
- report
|
||||
- notify
|
||||
|
||||
.qa-install:
|
||||
variables:
|
||||
BUNDLE_SUPPRESS_INSTALL_USING_MESSAGES: "true"
|
||||
BUNDLE_SILENCE_ROOT_WARNING: "true"
|
||||
RUN_WITH_BUNDLE: "true" # instructs pipeline to install and run gitlab-qa gem via bundler
|
||||
QA_PATH: qa # sets the optional path for bundler to run from
|
||||
extends:
|
||||
- .gitlab-qa-install
|
||||
|
||||
dont-interrupt-me:
|
||||
extends: .rules:dont-interrupt
|
||||
|
|
@ -11,6 +32,25 @@ dont-interrupt-me:
|
|||
script:
|
||||
- echo "This jobs makes sure this pipeline won't be interrupted! See https://docs.gitlab.com/ee/ci/yaml/#interruptible."
|
||||
|
||||
download-knapsack-report:
|
||||
extends:
|
||||
- .gitlab-qa-image
|
||||
- .rules:download-knapsack
|
||||
stage: .pre
|
||||
variables:
|
||||
KNAPSACK_DIR: ${CI_PROJECT_DIR}/qa/knapsack
|
||||
GIT_STRATEGY: none
|
||||
script:
|
||||
# when using qa-image, code runs in /home/gitlab/qa folder
|
||||
- bundle exec rake "knapsack:download[test]"
|
||||
- mkdir -p "$KNAPSACK_DIR" && cp knapsack/*.json "${KNAPSACK_DIR}/"
|
||||
- echo "$PROCESS_TEST_RESULTS"
|
||||
allow_failure: true
|
||||
artifacts:
|
||||
paths:
|
||||
- qa/knapsack/*.json
|
||||
expire_in: 1 day
|
||||
|
||||
.run-tests:
|
||||
stage: test
|
||||
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-ruby-${RUBY_VERSION}:bundler-2.3-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}
|
||||
|
|
@ -25,15 +65,15 @@ dont-interrupt-me:
|
|||
DOCKER_DRIVER: overlay2
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
QA_GDK_IMAGE: "${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-qa-gdk:master"
|
||||
QA_GENERATE_ALLURE_REPORT: "false"
|
||||
QA_GENERATE_ALLURE_REPORT: "true"
|
||||
QA_CAN_TEST_PRAEFECT: "false"
|
||||
QA_INTERCEPT_REQUESTS: "false"
|
||||
QA_RUN_TYPE: e2e-test-on-gdk
|
||||
TEST_LICENSE_MODE: $QA_TEST_LICENSE_MODE
|
||||
EE_LICENSE: $QA_EE_LICENSE
|
||||
GITHUB_ACCESS_TOKEN: $QA_GITHUB_ACCESS_TOKEN
|
||||
GITLAB_QA_ADMIN_ACCESS_TOKEN: $QA_ADMIN_ACCESS_TOKEN
|
||||
QA_KNAPSACK_REPORTS: qa-smoke,ee-instance-parallel
|
||||
RSPEC_REPORT_OPTS: "--format QA::Support::JsonFormatter --out tmp/rspec-${CI_JOB_ID}.json --format RspecJunitFormatter --out tmp/rspec-${CI_JOB_ID}.xml --format html --out tmp/rspec-${CI_JOB_ID}.htm --color --format documentation"
|
||||
timeout: 2 hours
|
||||
artifacts:
|
||||
when: always
|
||||
|
|
@ -41,6 +81,8 @@ dont-interrupt-me:
|
|||
- test_output
|
||||
- logs
|
||||
expire_in: 7 days
|
||||
reports:
|
||||
junit: test_output/**/rspec-*.xml
|
||||
script:
|
||||
- echo -e "\e[0Ksection_start:`date +%s`:pull_image\r\e[0KPull GDK QA image"
|
||||
- docker pull ${QA_GDK_IMAGE}
|
||||
|
|
@ -57,8 +99,8 @@ dont-interrupt-me:
|
|||
--volume $CI_PROJECT_DIR/test_output:/home/gdk/gdk/gitlab/qa/tmp:z \
|
||||
--volume $CI_PROJECT_DIR/logs/gdk:/home/gdk/gdk/log \
|
||||
--volume $CI_PROJECT_DIR/logs/gitlab:/home/gdk/gdk/gitlab/log \
|
||||
${QA_GDK_IMAGE} "${CI_COMMIT_SHA}" "$TEST_GDK_TAGS --tag ~requires_praefect" || true
|
||||
- echo -e "\e[0Ksection_end:`date +%s`:launch_gdk_and_tests\r\e[0K"
|
||||
${QA_GDK_IMAGE} "${CI_COMMIT_SHA}" "$RSPEC_REPORT_OPTS $TEST_GDK_TAGS --tag ~requires_praefect"
|
||||
# The above image's launch script takes two arguments only - first one is the commit sha and the second one Rspec Args
|
||||
allow_failure: true
|
||||
|
||||
test-on-gdk-smoke:
|
||||
|
|
@ -79,3 +121,98 @@ test-on-gdk-full:
|
|||
QA_KNAPSACK_REPORT_NAME: ee-instance-parallel
|
||||
rules:
|
||||
- when: manual
|
||||
|
||||
# ==========================================
|
||||
# Post test stage
|
||||
# ==========================================
|
||||
e2e-test-report:
|
||||
extends:
|
||||
- .generate-allure-report-base
|
||||
- .rules:report:allure-report
|
||||
stage: report
|
||||
variables:
|
||||
ALLURE_JOB_NAME: e2e-test-on-gdk
|
||||
ALLURE_RESULTS_GLOB: test_output/allure-results
|
||||
GITLAB_AUTH_TOKEN: $PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE
|
||||
ALLURE_PROJECT_PATH: $CI_PROJECT_PATH
|
||||
ALLURE_MERGE_REQUEST_IID: $CI_MERGE_REQUEST_IID
|
||||
|
||||
upload-knapsack-report:
|
||||
extends:
|
||||
- .generate-knapsack-report-base
|
||||
- .qa-install
|
||||
- .ruby-qa-image
|
||||
- .rules:report:process-results
|
||||
variables:
|
||||
QA_KNAPSACK_REPORT_FILE_PATTERN: $CI_PROJECT_DIR/test_output/knapsack/*/*.json
|
||||
stage: report
|
||||
when: always
|
||||
|
||||
export-test-metrics:
|
||||
extends:
|
||||
- .qa-install
|
||||
- .ruby-qa-image
|
||||
- .rules:report:process-results
|
||||
stage: report
|
||||
when: always
|
||||
script:
|
||||
- pwd
|
||||
- bundle exec rake "ci:export_test_metrics[$CI_PROJECT_DIR/test_output/test-metrics-*.json]"
|
||||
|
||||
relate-test-failures:
|
||||
extends:
|
||||
- .qa-install
|
||||
- .ruby-qa-image
|
||||
- .rules:report:process-results
|
||||
stage: report
|
||||
variables:
|
||||
QA_FAILURES_REPORTING_PROJECT: gitlab-org/gitlab
|
||||
QA_FAILURES_MAX_DIFF_RATIO: "0.15"
|
||||
GITLAB_QA_ACCESS_TOKEN: $QA_GITLAB_CI_TOKEN
|
||||
when: on_failure
|
||||
script:
|
||||
- |
|
||||
bundle exec gitlab-qa-report \
|
||||
--relate-failure-issue "$CI_PROJECT_DIR/test_output/rspec-*.json" \
|
||||
--project "$QA_FAILURES_REPORTING_PROJECT" \
|
||||
--max-diff-ratio "$QA_FAILURES_MAX_DIFF_RATIO"
|
||||
|
||||
generate-test-session:
|
||||
extends:
|
||||
- .qa-install
|
||||
- .ruby-qa-image
|
||||
- .rules:report:process-results
|
||||
stage: report
|
||||
variables:
|
||||
QA_TESTCASE_SESSIONS_PROJECT: gitlab-org/quality/testcase-sessions
|
||||
GITLAB_QA_ACCESS_TOKEN: $QA_TEST_SESSION_TOKEN
|
||||
GITLAB_CI_API_TOKEN: $QA_GITLAB_CI_TOKEN
|
||||
when: always
|
||||
script:
|
||||
- |
|
||||
bundle exec gitlab-qa-report \
|
||||
--generate-test-session "$CI_PROJECT_DIR/test_output/rspec-*.json" \
|
||||
--project "$QA_TESTCASE_SESSIONS_PROJECT"
|
||||
artifacts:
|
||||
when: always
|
||||
expire_in: 1d
|
||||
paths:
|
||||
- qa/REPORT_ISSUE_URL
|
||||
|
||||
notify-slack:
|
||||
extends:
|
||||
- .notify-slack-qa
|
||||
- .qa-install
|
||||
- .ruby-qa-image
|
||||
- .rules:report:process-results
|
||||
stage: notify
|
||||
variables:
|
||||
ALLURE_JOB_NAME: e2e-test-on-gdk
|
||||
SLACK_ICON_EMOJI: ci_failing
|
||||
STATUS_SYM: ☠️
|
||||
STATUS: failed
|
||||
TYPE: "(e2e-test-on-gdk) "
|
||||
when: on_failure
|
||||
script:
|
||||
- bundle exec gitlab-qa-report --prepare-stage-reports "$CI_PROJECT_DIR/test_output/rspec-*.xml" # generate summary
|
||||
- !reference [.notify-slack-qa, script]
|
||||
|
|
|
|||
|
|
@ -450,11 +450,11 @@
|
|||
{"name":"premailer","version":"1.16.0","platform":"ruby","checksum":"03e4402c448e6bae13fb5f6301a8bde4f3508e1bff90ae7c0972c7be94694786"},
|
||||
{"name":"premailer-rails","version":"1.10.3","platform":"ruby","checksum":"7cdcb97027866f7a81c490c6d15ada7f39666b5f6375f0821b7e97e0483b112f"},
|
||||
{"name":"proc_to_ast","version":"0.1.0","platform":"ruby","checksum":"92a73fa66e2250a83f8589f818b0751bcf227c68f85916202df7af85082f8691"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.0","platform":"aarch64-linux","checksum":"1f17600960e3d779ccf40da9e0603d8d754eceff6addb2f5b8482b10e93c980a"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.0","platform":"arm64-darwin","checksum":"8b1872583814e9d8bbf81032c67412fcec7a8130a2d1e7e4a5784cd3c7300a89"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.0","platform":"ruby","checksum":"e90b353fc583e0a317a3aeae02439a96e86d2193d4a3a31b733cafc6e4d6280b"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.0","platform":"x86_64-darwin","checksum":"d73d3a2b1f1d0f3e1f4b9b8b06c4471f1cf951a7e6b38b83f2f3eb4816500cac"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.0","platform":"x86_64-linux","checksum":"35dc742f4b3a718bda62c80cd618c0ec42accabf58f8330d92e39f67be58a0bf"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.1","platform":"aarch64-linux","checksum":"4091121090d1d44747b3d09f2dbd5fdd61e274d557b8ed98b06c65cdd006d174"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.1","platform":"arm64-darwin","checksum":"fa54f230631852392b38cba1ad396c0472cb9f088eef563d0c381b19b1333855"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.1","platform":"ruby","checksum":"48545f23217a5e85ca79fa8c2563711e319debdae46ddbd6348ff37f48029c40"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.1","platform":"x86_64-darwin","checksum":"99b56f4017f0a1a062914da253c613b9957bfabf5b38af5012e3d8515ed49555"},
|
||||
{"name":"prometheus-client-mmap","version":"0.23.1","platform":"x86_64-linux","checksum":"624da747dbb97e0d88be1f2ba5ae5253941fc85dea875845f5b4c7a2c95ee032"},
|
||||
{"name":"pry","version":"0.14.2","platform":"java","checksum":"fd780670977ba04ff7ee32dabd4d02fe4bf02e977afe8809832d5dca1412862e"},
|
||||
{"name":"pry","version":"0.14.2","platform":"ruby","checksum":"c4fe54efedaca1d351280b45b8849af363184696fcac1c72e0415f9bdac4334d"},
|
||||
{"name":"pry-byebug","version":"3.10.1","platform":"ruby","checksum":"c8f975c32255bfdb29e151f5532130be64ff3d0042dc858d0907e849125581f8"},
|
||||
|
|
|
|||
|
|
@ -1154,7 +1154,7 @@ GEM
|
|||
coderay
|
||||
parser
|
||||
unparser
|
||||
prometheus-client-mmap (0.23.0)
|
||||
prometheus-client-mmap (0.23.1)
|
||||
rb_sys (~> 0.9)
|
||||
pry (0.14.2)
|
||||
coderay (~> 1.1)
|
||||
|
|
|
|||
|
|
@ -114,8 +114,11 @@ export default {
|
|||
showDeleteDropdown() {
|
||||
return this.group.dependencyProxyManifests?.nodes.length > 0 && this.canClearCache;
|
||||
},
|
||||
dependencyProxyImagePrefix() {
|
||||
return this.group.dependencyProxyImagePrefix;
|
||||
},
|
||||
showDependencyProxyImagePrefix() {
|
||||
return this.group.dependencyProxyImagePrefix?.length > 0;
|
||||
return this.dependencyProxyImagePrefix?.length > 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -208,6 +211,7 @@ export default {
|
|||
|
||||
<manifests-list
|
||||
v-if="manifests && manifests.length"
|
||||
:dependency-proxy-image-prefix="dependencyProxyImagePrefix"
|
||||
:loading="$apollo.queries.group.loading"
|
||||
:manifests="manifests"
|
||||
:pagination="pageInfo"
|
||||
|
|
|
|||
|
|
@ -3,11 +3,16 @@ import { GlIcon, GlSprintf } from '@gitlab/ui';
|
|||
import { MANIFEST_PENDING_DESTRUCTION_STATUS } from '~/packages_and_registries/dependency_proxy/constants';
|
||||
import ListItem from '~/vue_shared/components/registry/list_item.vue';
|
||||
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import { s__ } from '~/locale';
|
||||
|
||||
const SHORT_DIGEST_START_INDEX = 7;
|
||||
const SHORT_DIGEST_END_INDEX = 14;
|
||||
|
||||
export default {
|
||||
name: 'ManifestRow',
|
||||
components: {
|
||||
ClipboardButton,
|
||||
GlIcon,
|
||||
GlSprintf,
|
||||
ListItem,
|
||||
|
|
@ -18,13 +23,25 @@ export default {
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
dependencyProxyImagePrefix: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
name() {
|
||||
return this.manifest?.imageName.split(':')[0];
|
||||
if (this.containsDigestInImageName) {
|
||||
return this.manifest?.imageName.split(':')[0];
|
||||
}
|
||||
return this.manifest?.imageName;
|
||||
},
|
||||
version() {
|
||||
return this.manifest?.imageName.split(':')[1];
|
||||
imageCopyText() {
|
||||
const name = this.manifest?.imageName.replace(':sha256:', '@sha256:') ?? '';
|
||||
return `${this.dependencyProxyImagePrefix}/${name}`;
|
||||
},
|
||||
containsDigestInImageName() {
|
||||
return this.manifest?.imageName.includes(':sha256:');
|
||||
},
|
||||
isErrorStatus() {
|
||||
return this.manifest?.status === MANIFEST_PENDING_DESTRUCTION_STATUS;
|
||||
|
|
@ -32,9 +49,16 @@ export default {
|
|||
disabledRowStyle() {
|
||||
return this.isErrorStatus ? 'gl-font-weight-normal gl-text-gray-500' : '';
|
||||
},
|
||||
shortDigest() {
|
||||
// digest is in the format `sha256:995efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089`
|
||||
// for short digest, remove sha256: from the string, and show only the first 7 char
|
||||
return this.manifest.digest?.substring(SHORT_DIGEST_START_INDEX, SHORT_DIGEST_END_INDEX);
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
cachedAgoMessage: s__('DependencyProxy|Cached %{time}'),
|
||||
copyImagePathTitle: s__('DependencyProxy|Copy image path'),
|
||||
digestLabel: s__('DependencyProxy|Digest: %{shortDigest}'),
|
||||
scheduledForDeletion: s__('DependencyProxy|Scheduled for deletion'),
|
||||
},
|
||||
};
|
||||
|
|
@ -44,9 +68,21 @@ export default {
|
|||
<list-item :disabled="isErrorStatus">
|
||||
<template #left-primary>
|
||||
<span :class="disabledRowStyle">{{ name }}</span>
|
||||
<clipboard-button
|
||||
class="gl-ml-2"
|
||||
:text="imageCopyText"
|
||||
:title="$options.i18n.copyImagePathTitle"
|
||||
category="tertiary"
|
||||
/>
|
||||
</template>
|
||||
<template #left-secondary>
|
||||
{{ version }}
|
||||
<span data-testid="manifest-row-short-digest">
|
||||
<gl-sprintf :message="$options.i18n.digestLabel">
|
||||
<template #shortDigest>
|
||||
{{ shortDigest }}
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</span>
|
||||
<span v-if="isErrorStatus" class="gl-ml-4" data-testid="status"
|
||||
><gl-icon name="clock" /> {{ $options.i18n.scheduledForDeletion }}</span
|
||||
>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ export default {
|
|||
required: false,
|
||||
default: () => false,
|
||||
},
|
||||
dependencyProxyImagePrefix: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
listTitle: s__('DependencyProxy|Image list'),
|
||||
|
|
@ -45,7 +50,12 @@ export default {
|
|||
<div
|
||||
class="gl-border-t-1 gl-border-gray-100 gl-border-t-solid gl-display-flex gl-flex-direction-column"
|
||||
>
|
||||
<manifest-row v-for="(manifest, index) in manifests" :key="index" :manifest="manifest" />
|
||||
<manifest-row
|
||||
v-for="(manifest, index) in manifests"
|
||||
:key="index"
|
||||
:dependency-proxy-image-prefix="dependencyProxyImagePrefix"
|
||||
:manifest="manifest"
|
||||
/>
|
||||
</div>
|
||||
<div class="gl-display-flex gl-justify-content-center">
|
||||
<gl-keyset-pagination
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ query getDependencyProxyDetails(
|
|||
nodes {
|
||||
id
|
||||
createdAt
|
||||
digest
|
||||
imageName
|
||||
status
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ export default {
|
|||
</div>
|
||||
<slot name="actions"></slot>
|
||||
<span v-if="hasPill || isPinnable" class="gl-flex-grow-1 gl-text-right gl-mr-3">
|
||||
<gl-badge v-if="hasPill" size="sm" variant="info">
|
||||
<gl-badge v-if="hasPill" size="sm" variant="neutral">
|
||||
{{ pillData }}
|
||||
</gl-badge>
|
||||
<gl-button
|
||||
|
|
|
|||
|
|
@ -449,6 +449,9 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord
|
|||
validates :silent_mode_enabled,
|
||||
inclusion: { in: [true, false], message: N_('must be a boolean value') }
|
||||
|
||||
validates :remember_me_enabled,
|
||||
inclusion: { in: [true, false], message: N_('must be a boolean value') }
|
||||
|
||||
Gitlab::SSHPublicKey.supported_types.each do |type|
|
||||
validates :"#{type}_key_restriction", presence: true, key_restriction: { type: type }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@ module Enums
|
|||
cbl_mariner: 12
|
||||
}.with_indifferent_access.freeze
|
||||
|
||||
ADVISORY_SOURCES = {
|
||||
glad: 1, # gitlab advisory db
|
||||
trivy: 2
|
||||
}.with_indifferent_access.freeze
|
||||
|
||||
def self.purl_types
|
||||
PURL_TYPES
|
||||
end
|
||||
|
|
@ -24,5 +29,9 @@ module Enums
|
|||
def self.purl_types_numerical
|
||||
purl_types.invert
|
||||
end
|
||||
|
||||
def self.advisory_sources
|
||||
ADVISORY_SOURCES
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
table_name: pm_advisories
|
||||
classes:
|
||||
- PackageMetadata::Advisory
|
||||
feature_categories:
|
||||
- software_composition_analysis
|
||||
- container_scanning
|
||||
description: Stores security advisories.
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117326
|
||||
milestone: '16.0'
|
||||
gitlab_schema: gitlab_pm
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
table_name: pm_affected_packages
|
||||
classes:
|
||||
- PackageMetadata::AffectedPackage
|
||||
feature_categories:
|
||||
- software_composition_analysis
|
||||
- container_scanning
|
||||
description: Stores info for packages affected by an advisory.
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117326
|
||||
milestone: '16.0'
|
||||
gitlab_schema: gitlab_pm
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreatePackageMetadataAdvisoryInfo < Gitlab::Database::Migration[2.1]
|
||||
def change
|
||||
create_table :pm_advisories do |t|
|
||||
t.text :advisory_xid, limit: 36, null: false
|
||||
t.date :published_date, null: false
|
||||
t.timestamps_with_timezone null: false
|
||||
t.integer :source_xid, limit: 2, null: false
|
||||
|
||||
t.text :title, limit: 256
|
||||
t.text :description, limit: 8192
|
||||
t.text :cvss_v2, limit: 128
|
||||
t.text :cvss_v3, limit: 128
|
||||
t.text :urls, array: true, default: []
|
||||
t.jsonb :identifiers, null: false
|
||||
|
||||
t.index [:advisory_xid, :source_xid], unique: true
|
||||
t.check_constraint 'CARDINALITY(urls) <= 10'
|
||||
end
|
||||
|
||||
create_table :pm_affected_packages do |t|
|
||||
t.references :pm_advisory, index: true, foreign_key: { on_delete: :cascade }, null: false
|
||||
t.timestamps_with_timezone null: false
|
||||
t.integer :purl_type, limit: 2, null: false
|
||||
|
||||
t.text :package_name, limit: 256, null: false
|
||||
t.text :distro_version, limit: 256, null: true
|
||||
t.text :solution, limit: 2048, null: true
|
||||
t.text :affected_range, limit: 512, null: false
|
||||
t.text :fixed_versions, array: true, default: []
|
||||
t.jsonb :overridden_advisory_fields, null: false, default: {}
|
||||
|
||||
t.index [:pm_advisory_id, :purl_type, :package_name, :distro_version], unique: true,
|
||||
name: 'i_affected_packages_unique_for_upsert'
|
||||
t.check_constraint 'CARDINALITY(fixed_versions) <= 10'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddRememberMeEnabledToApplicationSettings < Gitlab::Database::Migration[2.1]
|
||||
def change
|
||||
add_column :application_settings, :remember_me_enabled, :boolean, default: true, null: false
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
cb1766c3c3b6604353dfcb774b8b4f3fe65dac10d15312785855153769ac6fe0
|
||||
|
|
@ -0,0 +1 @@
|
|||
e13f88c8de95d10e1150b07e6d112aaa9221e0a866fce3f92883cec9ee026acd
|
||||
|
|
@ -11844,6 +11844,7 @@ CREATE TABLE application_settings (
|
|||
encrypted_tofa_client_library_fetch_access_token_method_iv bytea,
|
||||
encrypted_tofa_access_token_expires_in bytea,
|
||||
encrypted_tofa_access_token_expires_in_iv bytea,
|
||||
remember_me_enabled boolean DEFAULT true NOT NULL,
|
||||
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
|
||||
CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)),
|
||||
CONSTRAINT app_settings_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)),
|
||||
|
|
@ -20224,6 +20225,64 @@ CREATE SEQUENCE plans_id_seq
|
|||
|
||||
ALTER SEQUENCE plans_id_seq OWNED BY plans.id;
|
||||
|
||||
CREATE TABLE pm_advisories (
|
||||
id bigint NOT NULL,
|
||||
advisory_xid text NOT NULL,
|
||||
published_date date NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
source_xid smallint NOT NULL,
|
||||
title text,
|
||||
description text,
|
||||
cvss_v2 text,
|
||||
cvss_v3 text,
|
||||
urls text[] DEFAULT '{}'::text[],
|
||||
identifiers jsonb NOT NULL,
|
||||
CONSTRAINT check_152def3868 CHECK ((char_length(cvss_v2) <= 128)),
|
||||
CONSTRAINT check_19cbd06439 CHECK ((char_length(advisory_xid) <= 36)),
|
||||
CONSTRAINT check_bed97fa77a CHECK ((char_length(cvss_v3) <= 128)),
|
||||
CONSTRAINT check_e4bfd3ffbf CHECK ((char_length(title) <= 256)),
|
||||
CONSTRAINT check_fee880f7aa CHECK ((char_length(description) <= 8192)),
|
||||
CONSTRAINT chk_rails_e73af9de76 CHECK ((cardinality(urls) <= 10))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE pm_advisories_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE pm_advisories_id_seq OWNED BY pm_advisories.id;
|
||||
|
||||
CREATE TABLE pm_affected_packages (
|
||||
id bigint NOT NULL,
|
||||
pm_advisory_id bigint NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
purl_type smallint NOT NULL,
|
||||
package_name text NOT NULL,
|
||||
distro_version text,
|
||||
solution text,
|
||||
affected_range text NOT NULL,
|
||||
fixed_versions text[] DEFAULT '{}'::text[],
|
||||
overridden_advisory_fields jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
CONSTRAINT check_5dd528a2be CHECK ((char_length(package_name) <= 256)),
|
||||
CONSTRAINT check_80dea16c7b CHECK ((char_length(affected_range) <= 512)),
|
||||
CONSTRAINT check_d1d4646298 CHECK ((char_length(solution) <= 2048)),
|
||||
CONSTRAINT check_ec4c8efb5e CHECK ((char_length(distro_version) <= 256)),
|
||||
CONSTRAINT chk_rails_a0f80d74e0 CHECK ((cardinality(fixed_versions) <= 10))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE pm_affected_packages_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE pm_affected_packages_id_seq OWNED BY pm_affected_packages.id;
|
||||
|
||||
CREATE TABLE pm_checkpoints (
|
||||
sequence integer NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
|
|
@ -25483,6 +25542,10 @@ ALTER TABLE ONLY plan_limits ALTER COLUMN id SET DEFAULT nextval('plan_limits_id
|
|||
|
||||
ALTER TABLE ONLY plans ALTER COLUMN id SET DEFAULT nextval('plans_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY pm_advisories ALTER COLUMN id SET DEFAULT nextval('pm_advisories_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY pm_affected_packages ALTER COLUMN id SET DEFAULT nextval('pm_affected_packages_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY pm_licenses ALTER COLUMN id SET DEFAULT nextval('pm_licenses_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY pm_package_version_licenses ALTER COLUMN id SET DEFAULT nextval('pm_package_version_licenses_id_seq'::regclass);
|
||||
|
|
@ -27777,6 +27840,12 @@ ALTER TABLE ONLY plan_limits
|
|||
ALTER TABLE ONLY plans
|
||||
ADD CONSTRAINT plans_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY pm_advisories
|
||||
ADD CONSTRAINT pm_advisories_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY pm_affected_packages
|
||||
ADD CONSTRAINT pm_affected_packages_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY pm_checkpoints
|
||||
ADD CONSTRAINT pm_checkpoints_pkey PRIMARY KEY (purl_type);
|
||||
|
||||
|
|
@ -29387,6 +29456,8 @@ CREATE UNIQUE INDEX finding_link_url_idx ON vulnerability_finding_links USING bt
|
|||
|
||||
CREATE INDEX finding_links_on_vulnerability_occurrence_id ON vulnerability_finding_links USING btree (vulnerability_occurrence_id);
|
||||
|
||||
CREATE UNIQUE INDEX i_affected_packages_unique_for_upsert ON pm_affected_packages USING btree (pm_advisory_id, purl_type, package_name, distro_version);
|
||||
|
||||
CREATE INDEX i_batched_background_migration_job_transition_logs_on_job_id ON ONLY batched_background_migration_job_transition_logs USING btree (batched_background_migration_job_id);
|
||||
|
||||
CREATE UNIQUE INDEX i_bulk_import_export_batches_id_batch_number ON bulk_import_export_batches USING btree (export_id, batch_number);
|
||||
|
|
@ -31863,6 +31934,10 @@ CREATE UNIQUE INDEX index_plan_limits_on_plan_id ON plan_limits USING btree (pla
|
|||
|
||||
CREATE UNIQUE INDEX index_plans_on_name ON plans USING btree (name);
|
||||
|
||||
CREATE UNIQUE INDEX index_pm_advisories_on_advisory_xid_and_source_xid ON pm_advisories USING btree (advisory_xid, source_xid);
|
||||
|
||||
CREATE INDEX index_pm_affected_packages_on_pm_advisory_id ON pm_affected_packages USING btree (pm_advisory_id);
|
||||
|
||||
CREATE INDEX index_pm_package_version_licenses_on_pm_license_id ON pm_package_version_licenses USING btree (pm_license_id);
|
||||
|
||||
CREATE INDEX index_pm_package_version_licenses_on_pm_package_version_id ON pm_package_version_licenses USING btree (pm_package_version_id);
|
||||
|
|
@ -35735,6 +35810,9 @@ ALTER TABLE ONLY gpg_signatures
|
|||
ALTER TABLE ONLY project_authorizations
|
||||
ADD CONSTRAINT fk_rails_11e7aa3ed9 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY pm_affected_packages
|
||||
ADD CONSTRAINT fk_rails_1279c1b9a1 FOREIGN KEY (pm_advisory_id) REFERENCES pm_advisories(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY description_versions
|
||||
ADD CONSTRAINT fk_rails_12b144011c FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ by default:
|
|||
| Consul | No | Port | X | 8300, 8301(UDP), 8500, 8600[^Consul-notes] |
|
||||
| Patroni | No | Port | X | 8008 |
|
||||
| GitLab KAS | Yes | Port | X | 8150 |
|
||||
| Gitaly | No | Port | X | 8075 |
|
||||
| Gitaly | No | Port | X | 8075 or 9999 (TLS) |
|
||||
| Praefect | No | Port | X | 2305 or 3305 (TLS) |
|
||||
|
||||
Legend:
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ Matches use:
|
|||
|
||||
- Regex for environments.
|
||||
- String matching for pipelines.
|
||||
- Regex or string matching for jobs.
|
||||
- Regex or string matching for jobs
|
||||
- Lambda or truthy/falsey value for generic condition
|
||||
|
||||
| Test execution context | Key | Matches |
|
||||
| ---------------- | --- | --------------- |
|
||||
|
|
@ -47,6 +48,7 @@ Matches use:
|
|||
| The `nightly` and `canary` pipelines | `only: { pipeline: [:nightly, :canary] }` | ["nightly"](https://gitlab.com/gitlab-org/quality/nightly) and ["canary"](https://gitlab.com/gitlab-org/quality/canary) |
|
||||
| The `ee:instance` job | `only: { job: 'ee:instance' }` | The `ee:instance` job in any pipeline |
|
||||
| Any `quarantine` job | `only: { job: '.*quarantine' }` | Any job ending in `quarantine` in any pipeline |
|
||||
| Any run where condition evaluates to a truthy value | `only: { condition: -> { ENV['TEST_ENV'] == 'true' } }` | Any run where `TEST_ENV` is set to true
|
||||
|
||||
```ruby
|
||||
RSpec.describe 'Area' do
|
||||
|
|
@ -62,6 +64,8 @@ RSpec.describe 'Area' do
|
|||
it 'runs only in nightly pipeline', only: { pipeline: :nightly } do; end
|
||||
|
||||
it 'runs in nightly and canary pipelines', only: { pipeline: [:nightly, :canary] } do; end
|
||||
|
||||
it 'runs in specific environment matching condition', only: { condition: -> { ENV['TEST_ENV'] == 'true' } } do; end
|
||||
end
|
||||
```
|
||||
|
||||
|
|
@ -73,7 +77,8 @@ Matches use:
|
|||
|
||||
- Regex for environments.
|
||||
- String matching for pipelines.
|
||||
- Regex or string matching for jobs.
|
||||
- Regex or string matching for jobs
|
||||
- Lambda or truthy/falsey value for generic condition
|
||||
|
||||
| Test execution context | Key | Matches |
|
||||
| ---------------- | --- | --------------- |
|
||||
|
|
@ -86,6 +91,7 @@ Matches use:
|
|||
| The `nightly` and `canary` pipelines | `except: { pipeline: [:nightly, :canary] }` | ["nightly"](https://gitlab.com/gitlab-org/quality/nightly) and ["canary"](https://gitlab.com/gitlab-org/quality/canary) |
|
||||
| The `ee:instance` job | `except: { job: 'ee:instance' }` | The `ee:instance` job in any pipeline |
|
||||
| Any `quarantine` job | `except: { job: '.*quarantine' }` | Any job ending in `quarantine` in any pipeline |
|
||||
| Any run except where condition evaluates to a truthy value | `except: { condition: -> { ENV['TEST_ENV'] == 'true' } }` | Any run where `TEST_ENV` is not set to true
|
||||
|
||||
```ruby
|
||||
RSpec.describe 'Area' do
|
||||
|
|
@ -96,6 +102,8 @@ RSpec.describe 'Area' do
|
|||
it 'runs in any execution context except the nightly pipeline', except: { pipeline: :nightly } do; end
|
||||
|
||||
it 'runs in any execution context except the ee:instance job', except: { job: 'ee:instance' } do; end
|
||||
|
||||
it 'runs in specific environment not matching condition', except: { condition: -> { ENV['TEST_ENV'] == 'true' } } do; end
|
||||
end
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -615,6 +615,7 @@ flags are added to the scanner's CLI options.
|
|||
| Analyzer | CLI option | Description |
|
||||
|------------------------------------------------------------------------------|--------------------|------------------------------------------------------------------------------|
|
||||
| [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) | `--max-memory` | Sets the maximum system memory to use when running a rule on a single file. Measured in MB. |
|
||||
| [Flawfinder](https://gitlab.com/gitlab-org/security-products/analyzers/flawfinder) | `--neverignore` | Never ignore security issues, even if they have an “ignore” directive in a comment. Adding this option is likely to result in the analyzer detecting additional vulnerability findings which cannot be automatically resolved. |
|
||||
|
||||
#### Custom CI/CD variables
|
||||
|
||||
|
|
|
|||
|
|
@ -460,6 +460,41 @@ For more information on the syntax of passthroughs, see the
|
|||
[passthroughs section on the SAST customize rulesets](../sast/customize_rulesets.md#the-analyzerpassthrough-section)
|
||||
page.
|
||||
|
||||
#### Extending the default configuration
|
||||
|
||||
You can extend the default configuration with additional changes by using [Gitleaks `extend` support](https://github.com/gitleaks/gitleaks#configuration).
|
||||
|
||||
In the following `file` passthrough example, the string `glpat-1234567890abcdefghij` is ignored by Secret Detection. That GitLab personal access token (PAT) is used in test cases. Detection of it would be a false positive.
|
||||
|
||||
The `secret-detection-ruleset.toml` file defines that the configuration in `extended-gitleaks-config.toml` file is to be included. The `extended-gitleaks-config.toml` file defines the custom Gitleaks configuration. The `allowlist` stanza defines a regular expression that matches the secret that is to be ignored ("allowed").
|
||||
|
||||
```toml
|
||||
# .gitlab/secret-detection-ruleset.toml
|
||||
[secrets]
|
||||
description = 'secrets custom rules configuration'
|
||||
|
||||
[[secrets.passthrough]]
|
||||
type = "file"
|
||||
target = "gitleaks.toml"
|
||||
value = "extended-gitleaks-config.toml"
|
||||
```
|
||||
|
||||
```toml
|
||||
# extended-gitleaks-config.toml
|
||||
title = "extension of gitlab's default gitleaks config"
|
||||
|
||||
[extend]
|
||||
# Extends default packaged path
|
||||
path = "/gitleaks.toml"
|
||||
|
||||
[allowlist]
|
||||
description = "allow list of test tokens to ignore in detection"
|
||||
regexTarget = "match"
|
||||
regexes = [
|
||||
'''glpat-1234567890abcdefghij''',
|
||||
]
|
||||
```
|
||||
|
||||
## Running Secret Detection in an offline environment **(PREMIUM SELF)**
|
||||
|
||||
An offline environment has limited, restricted, or intermittent access to external resources through
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
# Compliance **(ULTIMATE)**
|
||||
|
||||
The compliance tools provided by GitLab help you keep an eye on various aspects of your project. For more information
|
||||
on GitLab compliance features for projects, groups, and instances, see
|
||||
The compliance tools provided by GitLab help you keep an eye on various aspects of your project, including:
|
||||
|
||||
- [Compliance report](compliance_report/index.md).
|
||||
- [License approval policies](license_approval_policies.md).
|
||||
- [License list](license_list.md).
|
||||
- [License scanning of CycloneDX files](license_scanning_of_cyclonedx_files/index.md).
|
||||
|
||||
For more information on other GitLab compliance features for projects, groups, and instances, see
|
||||
[Compliance features](../../administration/compliance.md).
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@ group: Security Policies
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# License Approval Policies **(ULTIMATE)**
|
||||
# License approval policies **(ULTIMATE)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8092) in GitLab 15.9 [with a flag](../../administration/feature_flags.md) named `license_scanning_policies`.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/397644) in GitLab 15.11. Feature flag `license_scanning_policies` removed.
|
||||
|
||||
License Approval Policies allow you to specify multiple types of criteria that define when approval is required before a merge request can be merged in.
|
||||
License approval policies allow you to specify multiple types of criteria that define when approval is required before a merge request can be merged in.
|
||||
|
||||
NOTE:
|
||||
License Approval Policies are applicable only to [protected](../project/protected_branches.md) target branches.
|
||||
License approval policies are applicable only to [protected](../project/protected_branches.md) target branches.
|
||||
|
||||
The following video provides an overview of these policies.
|
||||
|
||||
|
|
|
|||
|
|
@ -14574,6 +14574,9 @@ msgstr ""
|
|||
msgid "DependencyProxy|Contains %{count} blobs of images (%{size})"
|
||||
msgstr ""
|
||||
|
||||
msgid "DependencyProxy|Copy image path"
|
||||
msgstr ""
|
||||
|
||||
msgid "DependencyProxy|Copy prefix"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -14583,6 +14586,9 @@ msgstr ""
|
|||
msgid "DependencyProxy|Dependency Proxy image prefix"
|
||||
msgstr ""
|
||||
|
||||
msgid "DependencyProxy|Digest: %{shortDigest}"
|
||||
msgstr ""
|
||||
|
||||
msgid "DependencyProxy|Enable Dependency Proxy"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21044,7 +21050,7 @@ msgstr ""
|
|||
msgid "GroupSAML|SHA1 fingerprint of the SAML token signing certificate. Get this from your identity provider, where it can also be called \"Thumbprint\"."
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSAML|Some todos may be hidden because your SAML session has expired. Click to reauthenticate with the following groups to view hidden todos:"
|
||||
msgid "GroupSAML|Some to-do items may be hidden because your SAML session has expired. Select the group’s path to reauthenticate and view the hidden to-do items."
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSAML|The SCIM token is now hidden. To see the value of the token again, you need to %{linkStart}reset it%{linkEnd}."
|
||||
|
|
|
|||
|
|
@ -37,4 +37,4 @@ bundle install --jobs=$(nproc) --retry=3 --quiet
|
|||
|
||||
# Run the tests
|
||||
bundle exec rake "knapsack:download[test]"
|
||||
bundle exec bin/qa Test::Instance::All http://gdk.test:3000 -- $RSPEC_ARGS || true
|
||||
bundle exec bin/qa Test::Instance::All http://gdk.test:3000 -- $RSPEC_ARGS
|
||||
|
|
|
|||
|
|
@ -43,7 +43,12 @@ module QA
|
|||
|
||||
it(
|
||||
'allows enforcing 2FA via UI and logging in with 2FA',
|
||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347931'
|
||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347931',
|
||||
quarantine: {
|
||||
type: :bug,
|
||||
only: { condition: -> { QA::Runtime::Env.super_sidebar_enabled? } },
|
||||
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/409336'
|
||||
}
|
||||
) do
|
||||
enforce_two_factor_authentication_on_group(group)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,11 @@ module QA
|
|||
|
||||
def except?(*options)
|
||||
return false if Runtime::Env.ci_job_name.blank? && options.any? { |o| o.is_a?(Hash) && o[:job].present? }
|
||||
return false if Runtime::Env.ci_project_name.blank? && options.any? { |o| o.is_a?(Hash) && o[:pipeline].present? }
|
||||
|
||||
return false if Runtime::Env.ci_project_name.blank? && options.any? do |o|
|
||||
o.is_a?(Hash) && o[:pipeline].present?
|
||||
end
|
||||
|
||||
return false if Runtime::Scenario.attributes[:gitlab_address].blank?
|
||||
|
||||
context_matches?(*options)
|
||||
|
|
@ -34,24 +38,13 @@ module QA
|
|||
opts.merge!(option)
|
||||
|
||||
if option[:pipeline].present?
|
||||
return true if Runtime::Env.ci_project_name.blank?
|
||||
|
||||
return pipeline_matches?(option[:pipeline])
|
||||
|
||||
return evaluate_pipeline_context(option[:pipeline])
|
||||
elsif option[:job].present?
|
||||
return true if Runtime::Env.ci_job_name.blank?
|
||||
|
||||
return job_matches?(option[:job])
|
||||
|
||||
return evaluate_job_context(option[:job])
|
||||
elsif !option[:condition].nil?
|
||||
return evaluate_generic_condition(option[:condition])
|
||||
elsif option[:subdomain].present?
|
||||
opts[:subdomain] = case option[:subdomain]
|
||||
when Array
|
||||
"(#{option[:subdomain].join("|")})\\."
|
||||
when Regexp
|
||||
option[:subdomain]
|
||||
else
|
||||
"(#{option[:subdomain]})\\."
|
||||
end
|
||||
opts[:subdomain] = evaluate_subdomain_context(option[:subdomain])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -60,6 +53,43 @@ module QA
|
|||
|
||||
alias_method :dot_com?, :context_matches?
|
||||
|
||||
private
|
||||
|
||||
def evaluate_pipeline_context(pipeline)
|
||||
return true if Runtime::Env.ci_project_name.blank?
|
||||
|
||||
pipeline_matches?(pipeline)
|
||||
end
|
||||
|
||||
def evaluate_job_context(job)
|
||||
return true if Runtime::Env.ci_job_name.blank?
|
||||
|
||||
job_matches?(job)
|
||||
end
|
||||
|
||||
def evaluate_generic_condition(condition)
|
||||
return condition.call if condition.respond_to?(:call)
|
||||
|
||||
condition
|
||||
end
|
||||
|
||||
def evaluate_subdomain_context(option)
|
||||
case option
|
||||
when Array
|
||||
"(#{option.join('|')})\\."
|
||||
when Regexp
|
||||
option
|
||||
else
|
||||
"(#{option})\\."
|
||||
end
|
||||
end
|
||||
|
||||
def pipeline_matches?(pipeline_to_run_in)
|
||||
Array(pipeline_to_run_in).any? do |pipeline|
|
||||
pipeline.to_s.casecmp?(pipeline_from_project_name(Runtime::Env.ci_project_name))
|
||||
end
|
||||
end
|
||||
|
||||
def job_matches?(job_patterns)
|
||||
Array(job_patterns).any? do |job|
|
||||
pattern = job.is_a?(Regexp) ? job : Regexp.new(job)
|
||||
|
|
@ -68,10 +98,6 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
def pipeline_matches?(pipeline_to_run_in)
|
||||
Array(pipeline_to_run_in).any? { |pipeline| pipeline.to_s.casecmp?(pipeline_from_project_name(Runtime::Env.ci_project_name)) }
|
||||
end
|
||||
|
||||
def pipeline_from_project_name(project_name)
|
||||
project_name.to_s.start_with?('gitlab-qa') ? Runtime::Env.default_branch : project_name
|
||||
end
|
||||
|
|
|
|||
|
|
@ -132,6 +132,20 @@ RSpec.describe QA::Specs::Helpers::ContextSelector do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with generic condition context matcher' do
|
||||
it 'matches truthy lambda condition result' do
|
||||
expect(described_class.context_matches?(condition: -> { true })).to be_truthy
|
||||
end
|
||||
|
||||
it 'matches truthy condition result' do
|
||||
expect(described_class.context_matches?(condition: true)).to be_truthy
|
||||
end
|
||||
|
||||
it 'skips falsey condition result' do
|
||||
expect(described_class.context_matches?(condition: false)).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns false for mismatching' do
|
||||
QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
|
||||
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@ describe('DependencyProxyApp', () => {
|
|||
|
||||
it('shows list', () => {
|
||||
expect(findManifestList().props()).toMatchObject({
|
||||
dependencyProxyImagePrefix: proxyData().dependencyProxyImagePrefix,
|
||||
manifests: proxyManifests(),
|
||||
pagination: pagination(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
|||
import ManifestRow from '~/packages_and_registries/dependency_proxy/components/manifest_row.vue';
|
||||
import Component from '~/packages_and_registries/dependency_proxy/components/manifests_list.vue';
|
||||
import {
|
||||
proxyData,
|
||||
proxyManifests,
|
||||
pagination,
|
||||
} from 'jest/packages_and_registries/dependency_proxy/mock_data';
|
||||
|
|
@ -11,6 +12,7 @@ describe('Manifests List', () => {
|
|||
let wrapper;
|
||||
|
||||
const defaultProps = {
|
||||
dependencyProxyImagePrefix: proxyData().dependencyProxyImagePrefix,
|
||||
manifests: proxyManifests(),
|
||||
pagination: pagination(),
|
||||
loading: false,
|
||||
|
|
@ -42,9 +44,15 @@ describe('Manifests List', () => {
|
|||
it('binds a manifest to each row', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findRows().at(0).props()).toMatchObject({
|
||||
manifest: defaultProps.manifests[0],
|
||||
});
|
||||
expect(findRows().at(0).props('manifest')).toBe(defaultProps.manifests[0]);
|
||||
});
|
||||
|
||||
it('binds a dependencyProxyImagePrefix to each row', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findRows().at(0).props('dependencyProxyImagePrefix')).toBe(
|
||||
proxyData().dependencyProxyImagePrefix,
|
||||
);
|
||||
});
|
||||
|
||||
describe('loading', () => {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
import { GlSprintf } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
||||
import ListItem from '~/vue_shared/components/registry/list_item.vue';
|
||||
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
import Component from '~/packages_and_registries/dependency_proxy/components/manifest_row.vue';
|
||||
import { MANIFEST_PENDING_DESTRUCTION_STATUS } from '~/packages_and_registries/dependency_proxy/constants';
|
||||
import { proxyManifests } from 'jest/packages_and_registries/dependency_proxy/mock_data';
|
||||
import { proxyData, proxyManifests } from 'jest/packages_and_registries/dependency_proxy/mock_data';
|
||||
|
||||
describe('Manifest Row', () => {
|
||||
let wrapper;
|
||||
|
||||
const defaultProps = {
|
||||
dependencyProxyImagePrefix: proxyData().dependencyProxyImagePrefix,
|
||||
manifest: proxyManifests()[0],
|
||||
};
|
||||
|
||||
|
|
@ -24,8 +26,10 @@ describe('Manifest Row', () => {
|
|||
});
|
||||
};
|
||||
|
||||
const findClipboardButton = () => wrapper.findComponent(ClipboardButton);
|
||||
const findListItem = () => wrapper.findComponent(ListItem);
|
||||
const findCachedMessages = () => wrapper.findByTestId('cached-message');
|
||||
const findDigest = () => wrapper.findByTestId('manifest-row-short-digest');
|
||||
const findTimeAgoTooltip = () => wrapper.findComponent(TimeagoTooltip);
|
||||
const findStatus = () => wrapper.findByTestId('status');
|
||||
|
||||
|
|
@ -38,12 +42,18 @@ describe('Manifest Row', () => {
|
|||
expect(findListItem().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('displays the name', () => {
|
||||
expect(wrapper.text()).toContain('alpine');
|
||||
it('displays the name with tag & digest', () => {
|
||||
expect(wrapper.text()).toContain('alpine:latest');
|
||||
expect(findDigest().text()).toMatchInterpolatedText('Digest: 995efde');
|
||||
});
|
||||
|
||||
it('displays the version', () => {
|
||||
expect(wrapper.text()).toContain('latest');
|
||||
it('displays the name & digest for manifests that contain digest in image name', () => {
|
||||
createComponent({
|
||||
...defaultProps,
|
||||
manifest: proxyManifests()[1],
|
||||
});
|
||||
expect(wrapper.text()).toContain('alpine');
|
||||
expect(findDigest().text()).toMatchInterpolatedText('Digest: e95efde');
|
||||
});
|
||||
|
||||
it('displays the cached time', () => {
|
||||
|
|
@ -82,4 +92,35 @@ describe('Manifest Row', () => {
|
|||
expect(findStatus().text()).toBe('Scheduled for deletion');
|
||||
});
|
||||
});
|
||||
|
||||
describe('clipboard button', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('exists', () => {
|
||||
expect(findClipboardButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('passes the correct title prop', () => {
|
||||
expect(findClipboardButton().attributes('title')).toBe(Component.i18n.copyImagePathTitle);
|
||||
});
|
||||
|
||||
it('has the correct copy text when image name contains tag name', () => {
|
||||
expect(findClipboardButton().attributes('text')).toBe(
|
||||
'gdk.test:3000/private-group/dependency_proxy/containers/alpine:latest',
|
||||
);
|
||||
});
|
||||
|
||||
it('has the correct copy text when image name contains digest', () => {
|
||||
createComponent({
|
||||
...defaultProps,
|
||||
manifest: proxyManifests()[1],
|
||||
});
|
||||
|
||||
expect(findClipboardButton().attributes('text')).toBe(
|
||||
'gdk.test:3000/private-group/dependency_proxy/containers/alpine@sha256:e95efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,13 +11,15 @@ export const proxyManifests = () => [
|
|||
{
|
||||
id: 'proxy-1',
|
||||
createdAt: '2021-09-22T09:45:28Z',
|
||||
digest: 'sha256:995efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089',
|
||||
imageName: 'alpine:latest',
|
||||
status: 'DEFAULT',
|
||||
},
|
||||
{
|
||||
id: 'proxy-2',
|
||||
createdAt: '2021-09-21T09:45:28Z',
|
||||
imageName: 'alpine:stable',
|
||||
digest: 'sha256:e95efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089',
|
||||
imageName: 'alpine:sha256:e95efde2e81b21d1ea7066aa77a59298a62a9e9fbb4b77f36c189774ec9b1089',
|
||||
status: 'DEFAULT',
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -284,6 +284,9 @@ RSpec.describe ApplicationSetting, feature_category: :shared, type: :model do
|
|||
it { is_expected.not_to allow_value(10.5).for(:ci_max_includes) }
|
||||
it { is_expected.not_to allow_value(-1).for(:ci_max_includes) }
|
||||
|
||||
it { is_expected.to allow_value([true, false]).for(:remember_me_enabled) }
|
||||
it { is_expected.not_to allow_value(nil).for(:remember_me_enabled) }
|
||||
|
||||
context 'when deactivate_dormant_users is enabled' do
|
||||
before do
|
||||
stub_application_setting(deactivate_dormant_users: true)
|
||||
|
|
|
|||
Loading…
Reference in New Issue