Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-05-03 03:11:15 +00:00
parent a0754ad291
commit 8d94a37915
34 changed files with 565 additions and 58 deletions

View File

@ -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

View File

@ -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]

View File

@ -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"},

View File

@ -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)

View File

@ -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"

View File

@ -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
>

View File

@ -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

View File

@ -19,6 +19,7 @@ query getDependencyProxyDetails(
nodes {
id
createdAt
digest
imageName
status
}

View File

@ -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

View File

@ -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

View File

@ -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

11
db/docs/pm_advisories.yml Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
cb1766c3c3b6604353dfcb774b8b4f3fe65dac10d15312785855153769ac6fe0

View File

@ -0,0 +1 @@
e13f88c8de95d10e1150b07e6d112aaa9221e0a866fce3f92883cec9ee026acd

View File

@ -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;

View File

@ -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:

View File

@ -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
```

View File

@ -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

View File

@ -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

View File

@ -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).

View File

@ -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.

View File

@ -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 groups 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}."

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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")

View File

@ -165,6 +165,7 @@ describe('DependencyProxyApp', () => {
it('shows list', () => {
expect(findManifestList().props()).toMatchObject({
dependencyProxyImagePrefix: proxyData().dependencyProxyImagePrefix,
manifests: proxyManifests(),
pagination: pagination(),
});

View File

@ -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', () => {

View File

@ -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',
);
});
});
});

View File

@ -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',
},
];

View File

@ -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)