diff --git a/.gitlab/ci/qa-common/main.gitlab-ci.yml b/.gitlab/ci/qa-common/main.gitlab-ci.yml
index 1d952ffffdb..c7a463bfb2a 100644
--- a/.gitlab/ci/qa-common/main.gitlab-ci.yml
+++ b/.gitlab/ci/qa-common/main.gitlab-ci.yml
@@ -6,7 +6,7 @@ workflow:
include:
- local: .gitlab/ci/version.yml
- - component: "gitlab.com/gitlab-org/quality/pipeline-common/allure-report@8.21.0"
+ - component: "gitlab.com/gitlab-org/quality/pipeline-common/allure-report@8.22.0"
inputs:
job_name: "e2e-test-report"
job_stage: "report"
@@ -16,7 +16,7 @@ include:
gitlab_auth_token_variable_name: "PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE"
allure_job_name: "${QA_RUN_TYPE}"
- project: gitlab-org/quality/pipeline-common
- ref: 8.21.0
+ ref: 8.22.0
file:
- /ci/base.gitlab-ci.yml
- /ci/knapsack-report.yml
diff --git a/.gitlab/ci/qa-common/variables.gitlab-ci.yml b/.gitlab/ci/qa-common/variables.gitlab-ci.yml
index f04b878e55e..bc9817e8ae8 100644
--- a/.gitlab/ci/qa-common/variables.gitlab-ci.yml
+++ b/.gitlab/ci/qa-common/variables.gitlab-ci.yml
@@ -18,4 +18,4 @@ variables:
# Retry failed specs in separate process
QA_RETRY_FAILED_SPECS: "true"
# helm chart ref used by test-on-cng pipeline
- GITLAB_HELM_CHART_REF: "e7f459ab671d8fdaecddd34c739e3d53c498bae2"
+ GITLAB_HELM_CHART_REF: "3466c297acf5efa6de6bdfaa3c12b696041faa02"
diff --git a/app/assets/javascripts/merge_requests/components/reviewers/reviewer_drawer.vue b/app/assets/javascripts/merge_requests/components/reviewers/reviewer_drawer.vue
index df4f7af2176..c1b12e8dcda 100644
--- a/app/assets/javascripts/merge_requests/components/reviewers/reviewer_drawer.vue
+++ b/app/assets/javascripts/merge_requests/components/reviewers/reviewer_drawer.vue
@@ -71,6 +71,7 @@ export default {
:reviewers="reviewers"
:loading-reviewers="loadingReviewers"
@request-review="(params) => $emit('request-review', params)"
+ @remove-reviewer="(params) => $emit('remove-reviewer', params)"
/>
diff --git a/app/assets/javascripts/merge_requests/components/reviewers/reviewers_container.vue b/app/assets/javascripts/merge_requests/components/reviewers/reviewers_container.vue
index 9e475d0ee68..94679a11be1 100644
--- a/app/assets/javascripts/merge_requests/components/reviewers/reviewers_container.vue
+++ b/app/assets/javascripts/merge_requests/components/reviewers/reviewers_container.vue
@@ -83,10 +83,12 @@ export default {
$emit('request-review', params)"
+ @remove-reviewer="(params) => $emit('remove-reviewer', params)"
/>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue
index 820e88ffd76..e5b6167f0a3 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue
@@ -83,6 +83,7 @@ export default {
$emit('request-review', params)"
+ @remove-reviewer="(data) => $emit('remove-reviewer', data)"
@close="toggleDrawerOpen(false)"
/>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue
index 1766da4605f..385fcdd3f8e 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue
@@ -51,6 +51,9 @@ export default {
requestReview(data) {
this.$emit('request-review', data);
},
+ removeReviewer(data) {
+ this.$emit('remove-reviewer', data);
+ },
},
};
@@ -84,6 +87,7 @@ export default {
:root-path="rootPath"
:issuable-type="issuableType"
@request-review="requestReview"
+ @remove-reviewer="removeReviewer"
/>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
index e4b47785b7d..ae93f43d9c6 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
@@ -5,7 +5,7 @@ import Vue from 'vue';
import { createAlert } from '~/alert';
import { TYPE_ISSUE } from '~/issues/constants';
import { __ } from '~/locale';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { fetchUserCounts } from '~/super_sidebar/user_counts_fetch';
import eventHub from '../../event_hub';
import getMergeRequestReviewersQuery from '../../queries/get_merge_request_reviewers.query.graphql';
@@ -166,6 +166,17 @@ export default {
requestReview(data) {
this.mediator.requestReview(data);
},
+ async removeReviewerById(event) {
+ const userId = isGid(event.userId) ? getIdFromGraphQLId(event.userId) : event.userId;
+ this.store.reviewers = this.store.reviewers.filter((user) => user.id !== userId);
+ try {
+ await this.saveReviewers();
+ } catch (error) {
+ createAlert(__('Unable to remove a reviewer at the moment, try again later'), { error });
+ } finally {
+ event.done();
+ }
+ },
},
};
@@ -177,6 +188,7 @@ export default {
:loading="isLoading"
:editable="canUpdate"
@request-review="requestReview"
+ @remove-reviewer="removeReviewerById"
/>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue
index 9601293a86d..c987b97fcdc 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue
@@ -38,6 +38,7 @@ const REVIEW_STATE_ICONS = {
export default {
i18n: {
reRequestReview: __('Re-request review'),
+ removeReviewer: s__('MergeRequest|Remove reviewer'),
},
components: {
GlButton,
@@ -61,6 +62,11 @@ export default {
required: false,
default: TYPE_ISSUE,
},
+ isEditable: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -112,7 +118,13 @@ export default {
this.loadingStates[userId] = LOADING_STATE;
this.$emit('request-review', { userId, callback: this.requestReviewComplete });
},
-
+ removeReviewer(userId) {
+ this.loadingStates[userId] = LOADING_STATE;
+ this.$emit('remove-reviewer', {
+ userId,
+ callback: () => this.requestRemovalComplete(userId),
+ });
+ },
requestReviewComplete(userId, success) {
if (success) {
this.loadingStates[userId] = SUCCESS_STATE;
@@ -124,6 +136,9 @@ export default {
this.loadingStates[userId] = null;
}
},
+ requestRemovalComplete(userId) {
+ delete this.loadingStates[userId];
+ },
reviewStateIcon(user) {
if (user.mergeRequestInteraction.approved) {
return {
@@ -201,6 +216,20 @@ export default {
data-testid="reviewer-state-icon"
/>
+
+
+
diff --git a/app/assets/javascripts/work_items/components/create_work_item.vue b/app/assets/javascripts/work_items/components/create_work_item.vue
index f84833b1ca9..2bfa0541b94 100644
--- a/app/assets/javascripts/work_items/components/create_work_item.vue
+++ b/app/assets/javascripts/work_items/components/create_work_item.vue
@@ -510,6 +510,7 @@ export default {
class="js-assignee gl-mb-5"
:can-update="canUpdate"
:full-path="fullPath"
+ :is-group="isGroup"
:work-item-id="workItemId"
:assignees="workItemAssignees.assignees.nodes"
:participants="workItemParticipantNodes"
@@ -525,6 +526,7 @@ export default {
class="js-labels gl-mb-5"
:can-update="canUpdate"
:full-path="fullPath"
+ :is-group="isGroup"
:work-item-id="workItemId"
:work-item-iid="workItemIid"
:work-item-type="selectedWorkItemTypeName"
diff --git a/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue b/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue
index 5e3195a2ef9..50f7835f69e 100644
--- a/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue
+++ b/app/assets/javascripts/work_items/components/shared/work_item_token_input.vue
@@ -27,7 +27,6 @@ export default {
GlAlert,
},
directives: { SafeHtml },
- inject: ['isGroup'],
props: {
value: {
type: Array,
@@ -38,6 +37,11 @@ export default {
type: String,
required: true,
},
+ isGroup: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
childrenType: {
type: String,
required: false,
diff --git a/app/assets/javascripts/work_items/components/work_item_assignees.vue b/app/assets/javascripts/work_items/components/work_item_assignees.vue
index a0f6971bc65..84bee6035fc 100644
--- a/app/assets/javascripts/work_items/components/work_item_assignees.vue
+++ b/app/assets/javascripts/work_items/components/work_item_assignees.vue
@@ -23,7 +23,6 @@ export default {
UncollapsedAssigneeList,
},
mixins: [Tracking.mixin()],
- inject: ['isGroup'],
props: {
fullPath: {
type: String,
@@ -55,6 +54,11 @@ export default {
required: false,
default: false,
},
+ isGroup: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
participants: {
type: Array,
required: false,
diff --git a/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue b/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
index 1ee214513fd..9ed1976dae5 100644
--- a/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
+++ b/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
@@ -60,6 +60,11 @@ export default {
type: String,
required: true,
},
+ isGroup: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
workItem: {
type: Object,
required: true,
@@ -185,6 +190,7 @@ export default {
class="js-assignee gl-mb-5"
:can-update="canUpdate"
:full-path="fullPath"
+ :is-group="isGroup"
:work-item-id="workItem.id"
:assignees="workItemAssignees.assignees.nodes"
:participants="workItemParticipants"
@@ -203,6 +209,7 @@ export default {
class="js-labels gl-mb-5"
:can-update="canUpdate"
:full-path="fullPath"
+ :is-group="isGroup"
:work-item-id="workItem.id"
:work-item-iid="workItem.iid"
:work-item-type="workItemType"
@@ -314,6 +321,7 @@ export default {
:parent="workItemParent"
:has-parent="hasParent"
:group-path="groupPath"
+ :is-group="isGroup"
@error="$emit('error', $event)"
/>
diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue
index a294b65352a..40e9e0604bb 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -7,7 +7,7 @@ import { s__ } from '~/locale';
import { getParameterByName, updateHistory, setUrlParams } from '~/lib/utils/url_utility';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { TYPENAME_WORK_ITEM } from '~/graphql_shared/constants';
+import { TYPENAME_GROUP, TYPENAME_WORK_ITEM } from '~/graphql_shared/constants';
import { isLoggedIn } from '~/lib/utils/common_utils';
import { WORKSPACE_PROJECT } from '~/issues/constants';
import {
@@ -252,6 +252,9 @@ export default {
isDiscussionLocked() {
return this.workItemNotes?.discussionLocked;
},
+ isGroupWorkItem() {
+ return this.workItem.namespace?.id.includes(TYPENAME_GROUP);
+ },
workItemsAlphaEnabled() {
return this.glFeatures.workItemsAlpha;
},
@@ -701,6 +704,7 @@ export default {
diff --git a/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationships.vue b/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationships.vue
index d8f914bbff0..c8d149d65e3 100644
--- a/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationships.vue
+++ b/app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationships.vue
@@ -27,6 +27,11 @@ export default {
WorkItemMoreActions,
},
props: {
+ isGroup: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
workItemId: {
type: String,
required: false,
@@ -227,6 +232,7 @@ export default {
{ generic? && Feature.disabled?(:generic_extract_generic_package_model, Feature.current_request) }
# package_files must be destroyed by ruby code in order to properly remove carrierwave uploads and update project statistics
has_many :package_files, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -71,7 +73,10 @@ class Packages::Package < ApplicationRecord
validate :npm_package_already_taken, if: :npm?
+ # TODO: Remove with the rollout of the FF generic_extract_generic_package_model
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/479933
validates :name, format: { with: Gitlab::Regex.generic_package_name_regex }, if: :generic?
+
validates :name, format: { with: Gitlab::Regex.npm_package_name_regex, message: Gitlab::Regex.npm_package_name_regex_message }, if: :npm?
validates :name, format: { with: Gitlab::Regex.nuget_package_name_regex }, if: :nuget?
validates :name, format: { with: Gitlab::Regex.terraform_module_package_name_regex }, if: :terraform_module?
@@ -81,6 +86,8 @@ class Packages::Package < ApplicationRecord
validates :version, format: { with: Gitlab::Regex.semver_regex, message: Gitlab::Regex.semver_regex_message },
if: -> { npm? || terraform_module? }
+ # TODO: Remove with the rollout of the FF generic_extract_generic_package_model
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/479933
validates :version,
presence: true,
format: { with: Gitlab::Regex.generic_package_version_regex },
@@ -183,16 +190,24 @@ class Packages::Package < ApplicationRecord
def self.inheritance_column = 'package_type'
- def self.inheritance_column_to_class_map = {
- ml_model: 'Packages::MlModel::Package',
- golang: 'Packages::Go::Package',
- rubygems: 'Packages::Rubygems::Package',
- conan: 'Packages::Conan::Package',
- rpm: 'Packages::Rpm::Package',
- debian: 'Packages::Debian::Package',
- composer: 'Packages::Composer::Package',
- helm: 'Packages::Helm::Package'
- }.freeze
+ def self.inheritance_column_to_class_map
+ hash = {
+ ml_model: 'Packages::MlModel::Package',
+ golang: 'Packages::Go::Package',
+ rubygems: 'Packages::Rubygems::Package',
+ conan: 'Packages::Conan::Package',
+ rpm: 'Packages::Rpm::Package',
+ debian: 'Packages::Debian::Package',
+ composer: 'Packages::Composer::Package',
+ helm: 'Packages::Helm::Package'
+ }
+
+ if Feature.enabled?(:generic_extract_generic_package_model, Feature.current_request)
+ hash[:generic] = 'Packages::Generic::Package'
+ end
+
+ hash
+ end
def self.only_maven_packages_with_path(path, use_cte: false)
if use_cte
diff --git a/app/models/project_setting.rb b/app/models/project_setting.rb
index f15923ce672..ac25c3f3c2f 100644
--- a/app/models/project_setting.rb
+++ b/app/models/project_setting.rb
@@ -54,6 +54,11 @@ class ProjectSetting < ApplicationRecord
Feature.enabled?(:legacy_open_source_license_available, type: :ops)
end
+ # Checks if a given domain is already assigned to any existing project
+ def self.unique_domain_exists?(domain)
+ where(pages_unique_domain: domain).exists?
+ end
+
def squash_enabled_by_default?
%w[always default_on].include?(squash_option)
end
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index b599cb65612..1180416e5ee 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -39,10 +39,10 @@ module Projects
else
update_failed!
end
- rescue ValidationError => e
- error(e.message)
rescue ApiError => e
error(e.message, status: :api_error)
+ rescue ValidationError, Gitlab::Pages::UniqueDomainGenerationFailure => e
+ error(e.message)
end
def run_auto_devops_pipeline?
diff --git a/config/feature_flags/experiment/prompt_migration_explain_vulnerability.yml b/config/feature_flags/experiment/prompt_migration_explain_vulnerability.yml
new file mode 100644
index 00000000000..4ac92a2ab69
--- /dev/null
+++ b/config/feature_flags/experiment/prompt_migration_explain_vulnerability.yml
@@ -0,0 +1,9 @@
+---
+name: prompt_migration_explain_vulnerability
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/475046
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/164210
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/480824
+milestone: '17.4'
+group: group::custom models
+type: experiment
+default_enabled: false
diff --git a/config/feature_flags/gitlab_com_derisk/generic_extract_generic_package_model.yml b/config/feature_flags/gitlab_com_derisk/generic_extract_generic_package_model.yml
new file mode 100644
index 00000000000..27377e38e18
--- /dev/null
+++ b/config/feature_flags/gitlab_com_derisk/generic_extract_generic_package_model.yml
@@ -0,0 +1,9 @@
+---
+name: generic_extract_generic_package_model
+feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/435829
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/163477
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/479933
+milestone: '17.4'
+group: group::package registry
+type: gitlab_com_derisk
+default_enabled: false
diff --git a/db/docs/packages_packages.yml b/db/docs/packages_packages.yml
index 4db4888927d..87b6b370fb0 100644
--- a/db/docs/packages_packages.yml
+++ b/db/docs/packages_packages.yml
@@ -4,6 +4,7 @@ classes:
- Packages::Composer::Package
- Packages::Conan::Package
- Packages::Debian::Package
+- Packages::Generic::Package
- Packages::Go::Package
- Packages::Helm::Package
- Packages::MlModel::Package
diff --git a/db/docs/security_policy_requirements.yml b/db/docs/security_policy_requirements.yml
new file mode 100644
index 00000000000..bec02ea9805
--- /dev/null
+++ b/db/docs/security_policy_requirements.yml
@@ -0,0 +1,12 @@
+---
+table_name: security_policy_requirements
+classes:
+ - ComplianceManagement::ComplianceFramework::SecurityPolicyRequirement
+feature_categories:
+ - compliance_management
+description: Stores the mapping of compliance framework security policies and compliance requirements
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/163535
+milestone: '17.4'
+gitlab_schema: gitlab_main_cell
+sharding_key:
+ namespace_id: namespaces
diff --git a/db/migrate/20240821171027_create_security_policy_requirements.rb b/db/migrate/20240821171027_create_security_policy_requirements.rb
new file mode 100644
index 00000000000..a83b06c429f
--- /dev/null
+++ b/db/migrate/20240821171027_create_security_policy_requirements.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class CreateSecurityPolicyRequirements < Gitlab::Database::Migration[2.2]
+ milestone '17.4'
+
+ def change
+ create_table :security_policy_requirements do |t| # rubocop:disable Migration/EnsureFactoryForTable -- https://gitlab.com/gitlab-org/gitlab/-/issues/468630
+ t.bigint :compliance_framework_security_policy_id, null: false
+ t.bigint :compliance_requirement_id, null: false
+ t.bigint :namespace_id, null: false
+ t.index :namespace_id
+ t.index :compliance_requirement_id
+ t.index [:compliance_framework_security_policy_id, :compliance_requirement_id], unique: true,
+ name: :uniq_idx_security_policy_requirements_on_requirement_and_policy
+ end
+ end
+end
diff --git a/db/migrate/20240821183748_add_fk_to_security_policy_requirements_on_namespace_id.rb b/db/migrate/20240821183748_add_fk_to_security_policy_requirements_on_namespace_id.rb
new file mode 100644
index 00000000000..101402ab4d7
--- /dev/null
+++ b/db/migrate/20240821183748_add_fk_to_security_policy_requirements_on_namespace_id.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddFkToSecurityPolicyRequirementsOnNamespaceId < Gitlab::Database::Migration[2.2]
+ milestone '17.4'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :security_policy_requirements, :namespaces, column: :namespace_id, on_delete: :cascade,
+ reverse_lock_order: true
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key_if_exists :security_policy_requirements, column: :namespace_id, reverse_lock_order: true
+ end
+ end
+end
diff --git a/db/migrate/20240821183842_add_fk_to_security_policy_requirements_on_policy_id.rb b/db/migrate/20240821183842_add_fk_to_security_policy_requirements_on_policy_id.rb
new file mode 100644
index 00000000000..0a68727e4ff
--- /dev/null
+++ b/db/migrate/20240821183842_add_fk_to_security_policy_requirements_on_policy_id.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddFkToSecurityPolicyRequirementsOnPolicyId < Gitlab::Database::Migration[2.2]
+ milestone '17.4'
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :security_policy_requirements, :compliance_framework_security_policies,
+ column: :compliance_framework_security_policy_id, on_delete: :cascade, reverse_lock_order: true
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key_if_exists :security_policy_requirements, column: :compliance_framework_security_policy_id,
+ reverse_lock_order: true
+ end
+ end
+end
diff --git a/db/migrate/20240821183928_add_fk_to_security_policy_requirements_on_requirement_id.rb b/db/migrate/20240821183928_add_fk_to_security_policy_requirements_on_requirement_id.rb
new file mode 100644
index 00000000000..101a5162f88
--- /dev/null
+++ b/db/migrate/20240821183928_add_fk_to_security_policy_requirements_on_requirement_id.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddFkToSecurityPolicyRequirementsOnRequirementId < Gitlab::Database::Migration[2.2]
+ milestone '17.4'
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :security_policy_requirements, :compliance_requirements,
+ column: :compliance_requirement_id, on_delete: :cascade, reverse_lock_order: true
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key_if_exists :security_policy_requirements, column: :compliance_requirement_id,
+ reverse_lock_order: true
+ end
+ end
+end
diff --git a/db/schema_migrations/20240821171027 b/db/schema_migrations/20240821171027
new file mode 100644
index 00000000000..e2a898208ec
--- /dev/null
+++ b/db/schema_migrations/20240821171027
@@ -0,0 +1 @@
+d4eb4ba8c8e1aff092c54710456eefc6aef515eada1241577c3ff9dbfe2ecc44
\ No newline at end of file
diff --git a/db/schema_migrations/20240821183748 b/db/schema_migrations/20240821183748
new file mode 100644
index 00000000000..5935b177f08
--- /dev/null
+++ b/db/schema_migrations/20240821183748
@@ -0,0 +1 @@
+e829816829772abaf14b6a66ebeebd1abd1420da3e56da80152f288e0d4eb160
\ No newline at end of file
diff --git a/db/schema_migrations/20240821183842 b/db/schema_migrations/20240821183842
new file mode 100644
index 00000000000..cf4c85e9c3a
--- /dev/null
+++ b/db/schema_migrations/20240821183842
@@ -0,0 +1 @@
+9963ffaf6bb629a07340bc4ebf09af6f034be4e408b904dfe889dab340ac9f86
\ No newline at end of file
diff --git a/db/schema_migrations/20240821183928 b/db/schema_migrations/20240821183928
new file mode 100644
index 00000000000..a02965974c8
--- /dev/null
+++ b/db/schema_migrations/20240821183928
@@ -0,0 +1 @@
+7e0c29fe5575e2dcc5e24bff41657ea3243f958566187a46d7c51207a1a8265d
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index fda9e3ba239..b1794194905 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -17952,6 +17952,22 @@ CREATE SEQUENCE security_policy_project_links_id_seq
ALTER SEQUENCE security_policy_project_links_id_seq OWNED BY security_policy_project_links.id;
+CREATE TABLE security_policy_requirements (
+ id bigint NOT NULL,
+ compliance_framework_security_policy_id bigint NOT NULL,
+ compliance_requirement_id bigint NOT NULL,
+ namespace_id bigint NOT NULL
+);
+
+CREATE SEQUENCE security_policy_requirements_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE security_policy_requirements_id_seq OWNED BY security_policy_requirements.id;
+
CREATE TABLE security_scans (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -22158,6 +22174,8 @@ ALTER TABLE ONLY security_policies ALTER COLUMN id SET DEFAULT nextval('security
ALTER TABLE ONLY security_policy_project_links ALTER COLUMN id SET DEFAULT nextval('security_policy_project_links_id_seq'::regclass);
+ALTER TABLE ONLY security_policy_requirements ALTER COLUMN id SET DEFAULT nextval('security_policy_requirements_id_seq'::regclass);
+
ALTER TABLE ONLY security_scans ALTER COLUMN id SET DEFAULT nextval('security_scans_id_seq'::regclass);
ALTER TABLE ONLY security_training_providers ALTER COLUMN id SET DEFAULT nextval('security_training_providers_id_seq'::regclass);
@@ -24801,6 +24819,9 @@ ALTER TABLE ONLY security_policies
ALTER TABLE ONLY security_policy_project_links
ADD CONSTRAINT security_policy_project_links_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY security_policy_requirements
+ ADD CONSTRAINT security_policy_requirements_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY security_scans
ADD CONSTRAINT security_scans_pkey PRIMARY KEY (id);
@@ -30023,6 +30044,10 @@ CREATE UNIQUE INDEX index_security_policy_project_links_on_project_and_policy ON
CREATE INDEX index_security_policy_project_links_on_project_id ON security_policy_project_links USING btree (project_id);
+CREATE INDEX index_security_policy_requirements_on_compliance_requirement_id ON security_policy_requirements USING btree (compliance_requirement_id);
+
+CREATE INDEX index_security_policy_requirements_on_namespace_id ON security_policy_requirements USING btree (namespace_id);
+
CREATE INDEX index_security_scans_for_non_purged_records ON security_scans USING btree (created_at, id) WHERE (status <> 6);
CREATE INDEX index_security_scans_on_created_at ON security_scans USING btree (created_at);
@@ -30945,6 +30970,8 @@ CREATE UNIQUE INDEX uniq_idx_packages_packages_on_project_id_name_version_ml_mod
CREATE UNIQUE INDEX uniq_idx_project_compliance_framework_on_project_framework ON project_compliance_framework_settings USING btree (project_id, framework_id);
+CREATE UNIQUE INDEX uniq_idx_security_policy_requirements_on_requirement_and_policy ON security_policy_requirements USING btree (compliance_framework_security_policy_id, compliance_requirement_id);
+
CREATE UNIQUE INDEX uniq_idx_streaming_destination_id_and_namespace_id ON audit_events_streaming_instance_namespace_filters USING btree (external_streaming_destination_id, namespace_id);
CREATE UNIQUE INDEX uniq_idx_streaming_group_destination_id_and_namespace_id ON audit_events_streaming_group_namespace_filters USING btree (external_streaming_destination_id, namespace_id);
@@ -33357,6 +33384,9 @@ ALTER TABLE ONLY incident_management_timeline_events
ALTER TABLE ONLY todos
ADD CONSTRAINT fk_45054f9c45 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY security_policy_requirements
+ ADD CONSTRAINT fk_458f7f5ad5 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY releases
ADD CONSTRAINT fk_47fe2a0596 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -33453,6 +33483,9 @@ ALTER TABLE ONLY project_export_jobs
ALTER TABLE ONLY dependency_list_exports
ADD CONSTRAINT fk_5b3d11e1ef FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;
+ALTER TABLE ONLY security_policy_requirements
+ ADD CONSTRAINT fk_5b4fae9635 FOREIGN KEY (compliance_requirement_id) REFERENCES compliance_requirements(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY user_broadcast_message_dismissals
ADD CONSTRAINT fk_5c0cfb74ce FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
@@ -33990,6 +34023,9 @@ ALTER TABLE ONLY catalog_resource_versions
ALTER TABLE ONLY bulk_import_entities
ADD CONSTRAINT fk_b69fa2b2df FOREIGN KEY (bulk_import_id) REFERENCES bulk_imports(id) ON DELETE CASCADE;
+ALTER TABLE ONLY security_policy_requirements
+ ADD CONSTRAINT fk_b6e48e3428 FOREIGN KEY (compliance_framework_security_policy_id) REFERENCES compliance_framework_security_policies(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY compliance_management_frameworks
ADD CONSTRAINT fk_b74c45b71f FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
diff --git a/doc/administration/auth/ldap/ldap_synchronization.md b/doc/administration/auth/ldap/ldap_synchronization.md
index 8f6dad1b007..d5b30b3591e 100644
--- a/doc/administration/auth/ldap/ldap_synchronization.md
+++ b/doc/administration/auth/ldap/ldap_synchronization.md
@@ -17,6 +17,24 @@ LDAP synchronization updates user and group information for existing GitLab user
You can change when synchronization occurs.
+## LDAP servers with rate limits
+
+Some LDAP servers have rate limits configured.
+
+GitLab queries the LDAP server once for every:
+
+- User during the scheduled [user sync](#user-sync) process.
+- Group during the scheduled [group sync](#group-sync) process.
+
+In some cases, more queries to the LDAP server may be triggered. For example, when a [group sync query returns a `memberuid` attribute](#queries).
+
+If the LDAP server has a rate limit configured and that limit is reached during the:
+
+- User sync process, the LDAP server responds with an error code and GitLab blocks that user.
+- Group sync process, the LDAP server responds with an error code and GitLab removes that user's group memberships.
+
+You must consider your LDAP server's rate limits when configuring LDAP synchronization to prevent unwanted user blocks and group membership removals.
+
## User sync
> - Preventing LDAP user's profile name synchronization [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11336) in GitLab 15.11.
@@ -49,6 +67,9 @@ The process also updates the following user information:
- SSH public keys if `sync_ssh_keys` is set.
- Kerberos identity if Kerberos is enabled.
+NOTE:
+If your LDAP server has a rate limit, that limit might be reached during the user sync process. Check the [rate limit documentation](#ldap-servers-with-rate-limits) for more information.
+
### Synchronize LDAP user's profile name
By default, GitLab synchronizes the LDAP user's profile name field.
@@ -184,6 +205,9 @@ be available to GitLab. For example, `group_base` could be
`ou=groups,dc=example,dc=com`. In the configuration file, it looks like the
following.
+NOTE:
+If your LDAP server has a rate limit, that limit might be reached during the group sync process. Check the [rate limit documentation](#ldap-servers-with-rate-limits) for more information.
+
::Tabs
:::TabTitle Linux package (Omnibus)
diff --git a/doc/ci/runners/runner_fleet_dashboard.md b/doc/ci/runners/runner_fleet_dashboard.md
index 2eba6a52295..8b8253b2fc7 100644
--- a/doc/ci/runners/runner_fleet_dashboard.md
+++ b/doc/ci/runners/runner_fleet_dashboard.md
@@ -65,7 +65,7 @@ DETAILS:
**Status:** Beta
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/11180) as an [experiment](../../policy/experiment-beta-support.md#experiment) in GitLab 16.7 with [flags](../../administration/feature_flags.md) named `ci_data_ingestion_to_click_house` and `clickhouse_ci_analytics`. Disabled by default.
-> - [Enabled on GitLab.com, self-managed, and GitLab Dedicated](https://gitlab.com/gitlab-org/gitlab/-/issues/424866) in GitLab 16.10. Feature flags `ci_data_ingestion_to_click_house` and `clickhouse_ci_analytics` removed.
+> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/424866) in GitLab 16.10. Feature flags `ci_data_ingestion_to_click_house` and `clickhouse_ci_analytics` removed.
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/424789) to [beta](../../policy/experiment-beta-support.md#beta) in GitLab 17.1.
WARNING:
diff --git a/doc/ci/testing/test_coverage_visualization/jacoco.md b/doc/ci/testing/test_coverage_visualization/jacoco.md
index a5c40dff455..b5e6014b304 100644
--- a/doc/ci/testing/test_coverage_visualization/jacoco.md
+++ b/doc/ci/testing/test_coverage_visualization/jacoco.md
@@ -11,8 +11,7 @@ DETAILS:
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Status:** Beta
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227345) in
-> GitLab 17.3 [with a flag](../../../administration/feature_flags.md) named `jacoco_coverage_reports`. Disabled by default.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227345) in GitLab 17.3 [with a flag](../../../administration/feature_flags.md) named `jacoco_coverage_reports`. Disabled by default.
For JaCoCo coverage reports to work, you must generate a properly formatted [JaCoCo XML file](https://www.jacoco.org/jacoco/trunk/coverage/jacoco.xml)
that provides [line coverage](https://www.eclemma.org/jacoco/trunk/doc/counters.html).
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index b8177ac6abc..f0afc4560de 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -155,6 +155,13 @@ Instead of **agnostic**, use **platform-independent** or **vendor-neutral**.
Use **AI**. Do not spell out **artificial intelligence**.
+## AI Impact Dashboard
+
+Use title case for **AI Impact Dashboard**.
+
+On first mention on a page, use **GitLab Duo AI Impact Dashboard**.
+Thereafter, use **AI Impact Dashboard** by itself.
+
## AI-powered DevSecOps platform
If preceded by GitLab, capitalize **Platform**. For example, the GitLab AI-powered DevSecOps Platform.
@@ -428,12 +435,12 @@ Example:
- Use code completion to populate the file.
-## Code explanation
+## Code Explanation
-Use sentence case for **Code explanation**.
+Use title case for **Code Explanation**.
-On first mention on a page, use **GitLab Duo Code explanation**.
-Thereafter, use **Code explanation** by itself.
+On first mention on a page, use **GitLab Duo Code Explanation**.
+Thereafter, use **Code Explanation** by itself.
## code generation
@@ -452,12 +459,12 @@ Examples:
- Use code generation to create code based on your comments.
- Adjust your code generation results by adding code comments to your file.
-## Code review summary
+## Code Review Summary
-Use sentence case for **Code review summary**.
+Use title case for **Code Review Summary**.
-On first mention on a page, use **GitLab Duo Code review summary**.
-Thereafter, use **Code review summary** by itself.
+On first mention on a page, use **GitLab Duo Code Review Summary**.
+Thereafter, use **Code Review Summary** by itself.
## Code Suggestions
@@ -672,12 +679,12 @@ Use **inactive** or **off** instead.
Use **prevent** instead of **disallow**. ([Vale](../testing/vale.md) rule: [`Substitutions.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab_base/Substitutions.yml))
-## Discussion summary
+## Discussion Summary
-Use sentence case for **Discussion summary**.
+Use title case for **Discussion Summary**.
-On first mention on a page, use **GitLab Duo Discussion summary**.
-Thereafter, use **Discussion summary** by itself.
+On first mention on a page, use **GitLab Duo Discussion Summary**.
+Thereafter, use **Discussion Summary** by itself.
## Docker-in-Docker, `dind`
@@ -967,25 +974,34 @@ Do not use **Dedicated** by itself. Always use **GitLab Dedicated**.
Do not use **Duo** by itself. Always use **GitLab Duo**.
-On first use on a page, use **GitLab Duo ``**. As of Dec, 2023,
+On first use on a page, use **GitLab Duo ``**. As of Aug, 2024,
the following are the names of GitLab Duo features:
+- GitLab Duo AI Impact Dashboard
- GitLab Duo Chat
+- GitLab Duo Code Explanation
+- GitLab Duo Code Review Summary
- GitLab Duo Code Suggestions
-- GitLab Duo Value stream forecasting
-- GitLab Duo Discussion summary
-- GitLab Duo Merge request summary
-- GitLab Duo Code review summary
-- GitLab Duo Code explanation
-- GitLab Duo Vulnerability explanation
-- GitLab Duo Vulnerability resolution
-- GitLab Duo Test generation
- GitLab Duo for the CLI
-- GitLab Duo Root cause analysis
-- GitLab Duo Issue description generation
+- GitLab Duo Issue Description Generation
+- GitLab Duo Issue Discussion Summary
+- GitLab Duo Merge Commit Message Generation
+- GitLab Duo Merge Request Summary
+- GitLab Duo Product Analytics
+- GitLab Duo Root Cause Analysis
+- GitLab Duo Test Generation
+- GitLab Duo Vulnerability Explanation
+- GitLab Duo Vulnerability Resolution
After the first use, use the feature name without **GitLab Duo**.
+## GitLab Duo Enterprise
+
+Always use **GitLab Duo Enterprise** for the add-on. Do not use **Duo Enterprise** unless approved by legal.
+
+You can use **the GitLab Duo Enterprise add-on** (with this capitalization) but you do not need to use **add-on**
+and should leave it off when you can.
+
## GitLab Duo Pro
Always use **GitLab Duo Pro** for the add-on. Do not use **Duo Pro** unless approved by legal.
@@ -1171,12 +1187,19 @@ Use lowercase for **issue**.
Use lowercase for **issue board**.
-## Issue description generation
+## Issue Description Generation
-Use sentence case for **Issue description generation**.
+Use title case for **Issue Description Generation**.
-On first mention on a page, use **GitLab Duo Issue description generation**.
-Thereafter, use **Issue description generation** by itself.
+On first mention on a page, use **GitLab Duo Issue Description Generation**.
+Thereafter, use **Issue Description Generation** by itself.
+
+## Issue Discussion Summary
+
+Use title case for **Issue Discussion Summary**.
+
+On first mention on a page, use **GitLab Duo Issue Discussion Summary**.
+Thereafter, use **Issue Discussion Summary** by itself.
## issue weights
@@ -1387,6 +1410,13 @@ For **MB** and **GB**, follow the [Microsoft guidance](https://learn.microsoft.c
When you add a [user account](#user-account) to a group or project,
the user account becomes a **member**.
+## Merge Commit Message Generation
+
+Use title case for **Merge Commit Message Generation**.
+
+On first mention on a page, use **GitLab Duo Merge Commit Message Generation**.
+Thereafter, use **Merge Commit Message Generation** by itself.
+
## merge request branch
Do not use **merge request branch**. See [branch](#branch).
@@ -1395,12 +1425,12 @@ Do not use **merge request branch**. See [branch](#branch).
Use lowercase for **merge requests**. If you use **MR** as the acronym, spell it out on first use.
-## Merge request summary
+## Merge Request Summary
-Use sentence case for **Merge request summary**.
+Use title case for **Merge Request Summary**.
-On first mention on a page, use **GitLab Duo Merge request summary**.
-Thereafter, use **Merge request summary** by itself.
+On first mention on a page, use **GitLab Duo Merge Request Summary**.
+Thereafter, use **Merge Request Summary** by itself.
## milestones
@@ -1829,12 +1859,12 @@ There are two types of roles: [custom](#custom-role) and [default](#default-role
Roles are not the same as [**access levels**](#access-level).
-## Root cause analysis
+## Root Cause Analysis
-Use sentence case for **Root cause analysis**.
+Use title case for **Root Cause Analysis**.
-On first mention on a page, use **GitLab Duo Root cause analysis**.
-Thereafter, use **Root cause analysis** by itself.
+On first mention on a page, use **GitLab Duo Root Cause Analysis**.
+Thereafter, use **Root Cause Analysis** by itself.
## roll back
@@ -2110,12 +2140,12 @@ talking about non-specific modules. For example:
- You can publish a Terraform module to your project's Terraform Module Registry.
-## Test generation
+## Test Generation
-Use sentence case for **Test generation**.
+Use title case for **Test Generation**.
-On first mention on a page, use **GitLab Duo Test generation**.
-Thereafter, use **Test generation** by itself.
+On first mention on a page, use **GitLab Duo Test Generation**.
+Thereafter, use **Test Generation** by itself.
## text box
@@ -2272,12 +2302,6 @@ For example:
Do not use **utilize**. Use **use** instead. It's more succinct and easier for non-native English speakers to understand.
([Vale](../testing/vale.md) rule: [`SubstitutionWarning.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab_base/SubstitutionWarning.yml))
-## Value stream forecasting
-
-Use sentence case for **Value stream forecasting**. On first mention on a page, use **GitLab Duo Value stream forecasting**.
-
-Thereafter, use **Value stream forecasting** by itself.
-
## version, v
To describe versions of GitLab, use **GitLab ``**. For example:
@@ -2297,19 +2321,19 @@ Pay attention to spacing by the letter **v**. In semantic versioning, no space e
Do not use Latin abbreviations. Use **with**, **through**, or **by using** instead. ([Vale](../testing/vale.md) rule: [`LatinTerms.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab_base/LatinTerms.yml))
-## Vulnerability resolution
+## Vulnerability Explanation
-Use sentence case for **Vulnerability resolution**.
+Use title case for **Vulnerability Explanation**.
-On first mention on a page, use **GitLab Duo Vulnerability resolution**.
-Thereafter, use **Vulnerability resolution** by itself.
+On first mention on a page, use **GitLab Duo Vulnerability Explanation**.
+Thereafter, use **Vulnerability Explanation** by itself.
-## Vulnerability explanation
+## Vulnerability Resolution
-Use sentence case for **Vulnerability explanation**.
+Use title case for **Vulnerability Resolution**.
-On first mention on a page, use **GitLab Duo Vulnerability explanation**.
-Thereafter, use **Vulnerability explanation** by itself.
+On first mention on a page, use **GitLab Duo Vulnerability Resolution**.
+Thereafter, use **Vulnerability Resolution** by itself.
## we
diff --git a/doc/editor_extensions/visual_studio_code/index.md b/doc/editor_extensions/visual_studio_code/index.md
index 00fad377717..b5db4acbb5e 100644
--- a/doc/editor_extensions/visual_studio_code/index.md
+++ b/doc/editor_extensions/visual_studio_code/index.md
@@ -92,7 +92,7 @@ To add more languages to Code Suggestions:
1. On the top bar, go to **Code > Settings > Extensions**.
1. Search for **GitLab Workflow** in the list, then select **Manage** (**{settings}**) **> Extension Settings**.
1. In your **User** settings, find
- **GitLab › Ai Assisted Code Suggestions: Additional Languages** and select **Add Item**.
+ **GitLab › Duo Code Suggestions: Additional Languages** and select **Add Item**.
1. In **Item**, add the language identifier, and select **OK**.
## Integrate with GitLab
diff --git a/doc/operations/tracing.md b/doc/operations/tracing.md
index 3446a536f6d..41323fbd559 100644
--- a/doc/operations/tracing.md
+++ b/doc/operations/tracing.md
@@ -85,3 +85,23 @@ To request a limit increase to 1,048,576 bytes per minute, contact GitLab suppor
## Data retention
GitLab has a retention limit of 30 days for all traces.
+
+## Create an issue for a trace
+
+You can create an issue to track any action taken to resolve or investigate a trace. To create an issue for a trace:
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Monitor > Traces**.
+1. From the list of traces, select a trace.
+1. Select **Create issue**.
+
+The issue is created in the selected project and pre-filled with information from the trace.
+You can edit the issue title and description.
+
+## View issues related to a trace
+
+1. On the left sidebar, select **Search or go to** and find your project.
+1. Select **Monitor > Traces**.
+1. From the list of traces, select a trace.
+1. Scroll to **Related issues**.
+1. Optional. To view the issue details, select an issue.
diff --git a/doc/subscriptions/quarterly_reconciliation.md b/doc/subscriptions/quarterly_reconciliation.md
index 684e4168f57..fc0667e6b14 100644
--- a/doc/subscriptions/quarterly_reconciliation.md
+++ b/doc/subscriptions/quarterly_reconciliation.md
@@ -78,7 +78,7 @@ You are automatically enrolled in quarterly reconciliation if:
You are excluded from quarterly reconciliation if you:
- Purchased your subscription from a reseller or another channel partner.
-- Purchased a multi-year subscription.
+- Purchased a subscription that is not a 12-month term (includes multi-year and non-standard length subscriptions).
- Purchased your subscription with a purchasing order.
- Are a public sector customer.
- Have an offline environment and used a license file to activate your subscription.
@@ -91,12 +91,9 @@ If you are excluded from quarterly reconciliation and not on a free tier, your t
### Failed payment
-If your credit card is declined during the reconciliation process, you receive an email with the subject `Your GitLab subscription failed to reconcile`.
-To resolve this issue, you must [update your payment information](customers_portal.md#set-a-default-payment-method).
+If your credit card is declined during the reconciliation process, you receive an email with the subject `Action required: Your GitLab subscription failed to reconcile`. To resolve this issue, you must:
-1. Sign in to your account at `https://customers.gitlab.com`.
-1. On the left sidebar, select **Billing account settings**.
-1. Under **Payment methods**, select **Add new payment method**.
-1. To mark the new payment method as default, select **Edit** > **Default**.
+1. [Update your payment information](customers_portal.md#change-your-payment-method).
+1. [Set your chosen payment method as default](customers_portal.md#set-a-default-payment-method).
When the payment method is updated, reconciliation is retried automatically.
diff --git a/doc/subscriptions/self_managed/index.md b/doc/subscriptions/self_managed/index.md
index 9b11c4a209c..d1fe0c3237b 100644
--- a/doc/subscriptions/self_managed/index.md
+++ b/doc/subscriptions/self_managed/index.md
@@ -574,28 +574,28 @@ To add another contact for your subscription, see [Add a secondary contact](../c
## Subscription expiry
-When your license expires, GitLab locks down features, like Git pushes
-and issue creation. Then, your instance becomes read-only and
-an expiration message is displayed to all administrators.
-
Licenses expire at the start of the expiration date, 00:00 server time.
-For GitLab self-managed instances, you have a 14-day grace period
-before this occurs.
+When your license expires, after a 14 day grace period:
-For example, if a license has a start date of January 1, 2024 and an end date of January 1, 2025:
+- Your instance becomes read-only.
+- GitLab locks features, such as Git pushes and issue creation.
+- An expiration message is displayed to all administrators.
+
+For example, if a license has an expiry date of January 1, 2025:
- It expires at 11:59:59 PM server time December 31, 2024.
- It is considered expired from 12:00:00 AM server time January 1, 2025.
-- The grace period of 14 days starts at 12:00:00 AM server time January 1, 2025 and ends at 11:59:59 PM server time January 14, 2025.
+- The grace period of 14 days starts at 12:00:00 AM server time January 1, 2025
+ and ends at 11:59:59 PM server time January 14, 2025.
- Your instance becomes read-only at 12:00:00 AM server time January 15, 2025.
-- To resume functionality, activate a new license.
-- To fall back to Free features, delete the expired license.
+After your license has expired:
-## Activate a license file or key
-
-If you have a license file or key, you can activate it [in the **Admin** area](../../administration/license_file.md#activate-gitlab-ee-with-a-license-file-or-key).
+- To resume functionality,
+ [activate a new license](../../administration/license_file.md#activate-gitlab-ee-with-a-license-file-or-key).
+- To keep using Free tier features only,
+ [delete the expired license](../../administration/license_file.md#remove-a-license).
## Storage
diff --git a/doc/user/application_security/secret_detection/pipeline/index.md b/doc/user/application_security/secret_detection/pipeline/index.md
index 738624c1e34..0dc015405e2 100644
--- a/doc/user/application_security/secret_detection/pipeline/index.md
+++ b/doc/user/application_security/secret_detection/pipeline/index.md
@@ -297,9 +297,8 @@ DETAILS:
**Tier:** Ultimate
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211387) in GitLab 13.5.
-> Expanded to include additional passthrough types of `file` and `raw` in GitLab 14.6.
-> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/235359) support for overriding rules in
-> GitLab 14.8.
+> - Expanded to include additional passthrough types of `file` and `raw` in GitLab 14.6.
+> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/235359) support for overriding rules in GitLab 14.8.
> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/336395) support for passthrough chains and included additional passthrough types of `git` and `url` in GitLab 17.2.
You can customize the behavior of pipeline secret detection by [creating a ruleset configuration file](#create-a-ruleset-configuration-file),
diff --git a/doc/user/project/integrations/google_artifact_management.md b/doc/user/project/integrations/google_artifact_management.md
index 7bbf5665cc6..37484e137f5 100644
--- a/doc/user/project/integrations/google_artifact_management.md
+++ b/doc/user/project/integrations/google_artifact_management.md
@@ -11,8 +11,7 @@ DETAILS:
**Offering:** GitLab.com
**Status:** Beta
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141127) in GitLab 16.10 [with a flag](../../../administration/feature_flags.md) named
-`google_cloud_support_feature_flag`. This feature is in [beta](../../../policy/experiment-beta-support.md).
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/141127) in GitLab 16.10 [with a flag](../../../administration/feature_flags.md) named `google_cloud_support_feature_flag`. This feature is in [beta](../../../policy/experiment-beta-support.md).
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/150472) in GitLab 17.1. Feature flag `google_cloud_support_feature_flag` removed.
This feature is in [beta](../../../policy/experiment-beta-support.md).
@@ -127,7 +126,7 @@ list-images:
```yaml
list-images:
- image:
+ image:
name: gcr.io/go-containerregistry/crane:debug
entrypoint: [""]
identity: google_cloud
@@ -209,7 +208,7 @@ copy-image:
```yaml
copy-image:
- image:
+ image:
name: gcr.io/go-containerregistry/crane:debug
entrypoint: [""]
identity: google_cloud
diff --git a/doc/user/project/repository/code_suggestions/supported_extensions.md b/doc/user/project/repository/code_suggestions/supported_extensions.md
index 3382941356f..88dd4064815 100644
--- a/doc/user/project/repository/code_suggestions/supported_extensions.md
+++ b/doc/user/project/repository/code_suggestions/supported_extensions.md
@@ -182,7 +182,7 @@ Prerequisites:
from the Visual Studio Marketplace.
1. Configure the extension following the
[setup instructions](https://gitlab.com/gitlab-org/gitlab-vscode-extension#extension-settings).
-1. Enable the feature by toggling the `gitlab.aiAssistedCodeSuggestions.enabledSupportedLanguages` setting.
+1. Enable the feature by toggling the `gitlab.duoCodeSuggestions.enabledSupportedLanguages` setting.
:::TabTitle JetBrains IDEs
diff --git a/doc/user/project/repository/code_suggestions/troubleshooting.md b/doc/user/project/repository/code_suggestions/troubleshooting.md
index b022e7fd288..07e1c956123 100644
--- a/doc/user/project/repository/code_suggestions/troubleshooting.md
+++ b/doc/user/project/repository/code_suggestions/troubleshooting.md
@@ -41,7 +41,7 @@ If you are a self-managed user, ensure that Code Suggestions for the [GitLab Web
1. On the left sidebar, select **Extensions > GitLab Workflow**.
1. Select **Settings** (**{settings}**), and then select **Extension Settings**.
-1. In **GitLab > AI Assisted Code Suggestions**, select the **GitLab Duo Code Suggestions**
+1. In **GitLab > Duo Code Suggestions**, select the **GitLab Duo Code Suggestions**
checkbox.
### View Code Suggestions logs
diff --git a/lib/gitlab/ci/config/interpolation/inputs/string_input.rb b/lib/gitlab/ci/config/interpolation/inputs/string_input.rb
index 3c4868b299c..caba4d2d68a 100644
--- a/lib/gitlab/ci/config/interpolation/inputs/string_input.rb
+++ b/lib/gitlab/ci/config/interpolation/inputs/string_input.rb
@@ -43,7 +43,7 @@ module Gitlab
override :validate_regex
def validate_regex(value, default)
- return unless spec.key?(:regex)
+ return unless spec.key?(:regex) && value.is_a?(String)
safe_regex = ::Gitlab::UntrustedRegexp.new(spec[:regex])
diff --git a/lib/gitlab/ci/parsers/security/validators/schema_validator.rb b/lib/gitlab/ci/parsers/security/validators/schema_validator.rb
index c44b5c9bbf4..4375c51eb39 100644
--- a/lib/gitlab/ci/parsers/security/validators/schema_validator.rb
+++ b/lib/gitlab/ci/parsers/security/validators/schema_validator.rb
@@ -7,14 +7,14 @@ module Gitlab
module Validators
class SchemaValidator
SUPPORTED_VERSIONS = {
- cluster_image_scanning: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0],
- container_scanning: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0],
- coverage_fuzzing: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0],
- dast: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0],
- api_fuzzing: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0],
- dependency_scanning: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0],
- sast: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0],
- secret_detection: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0]
+ cluster_image_scanning: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0 15.2.1],
+ container_scanning: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0 15.2.1],
+ coverage_fuzzing: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0 15.2.1],
+ dast: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0 15.2.1],
+ api_fuzzing: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0 15.2.1],
+ dependency_scanning: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0 15.2.1],
+ sast: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0 15.2.1],
+ secret_detection: %w[15.0.0 15.0.1 15.0.2 15.0.4 15.0.5 15.0.6 15.0.7 15.1.0 15.1.1 15.1.2 15.1.3 15.1.4 15.2.0 15.2.1]
}.freeze
VERSIONS_TO_REMOVE_IN_18_0 = %w[].freeze
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/cluster-image-scanning-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/cluster-image-scanning-report-format.json
new file mode 100644
index 00000000000..5d62971c4e6
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/cluster-image-scanning-report-format.json
@@ -0,0 +1,1243 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/cluster-image-scanning-report-format.json",
+ "title": "Report format for GitLab Cluster Image Scanning",
+ "description": "This schema provides the the report format for Cluster Image Scanning (https://docs.gitlab.com/ee/user/application_security/cluster_image_scanning/).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ },
+ {
+ "$ref": "#/definitions/code_flows"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "line_end": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_end": {
+ "type": "integer",
+ "minimum": 1
+ }
+ },
+ "dependencies": {
+ "column_end": [
+ "column_start"
+ ],
+ "column_start": [
+ "column_end"
+ ]
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ },
+ "code_flow_node": {
+ "type": "object",
+ "description": "A code flow node representing a part of a vulnerability flow from source to sink",
+ "required": [
+ "file_location",
+ "node_type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flow-node"
+ },
+ "file_location": {
+ "$ref": "#/definitions/file_location"
+ },
+ "node_type": {
+ "type": "string",
+ "description": "Describes a code flow node type",
+ "enum": [
+ "source",
+ "sink",
+ "propagation"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ },
+ "code_flows": {
+ "type": "object",
+ "description": "A code flow representing a vulnerability flow from source to sink",
+ "required": [
+ "items",
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flows"
+ },
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "#/definitions/code_flow_node"
+ }
+ }
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flows",
+ "items": [
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 1,
+ "line_end": 2
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 3
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ],
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "different_flow.py",
+ "line_start": 100,
+ "line_end": 102
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ },
+ "self": {
+ "version": "15.2.1"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "options": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "A configuration option used for this scan.",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The configuration option name.",
+ "maxLength": 255,
+ "minLength": 1,
+ "examples": [
+ "DAST_FF_ENABLE_BAS",
+ "DOCKER_TLS_CERTDIR",
+ "DS_MAX_DEPTH",
+ "SECURE_LOG_LEVEL"
+ ]
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of this option.",
+ "enum": [
+ "argument",
+ "file",
+ "env_variable",
+ "other"
+ ]
+ },
+ "value": {
+ "type": [
+ "boolean",
+ "integer",
+ "null",
+ "string"
+ ],
+ "description": "The value used for this scan.",
+ "examples": [
+ true,
+ 2,
+ null,
+ "fatal",
+ ""
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "cluster_image_scanning"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "observability": {
+ "type": "object",
+ "description": "Internal GitLab use only. Observability data such as metrics collected by the analyzers.",
+ "properties": {
+ "events": {
+ "type": "array",
+ "description": "Internal GitLab use only. Array of events containing metrics logged via the GitLab internal event tracking system. Recommend working with the analytics instrumentation team to define events.",
+ "items": {
+ "type": "object",
+ "description": "Internal GitLab use only. An event with zero or more values. Additional properties can be used to collect various metrics associated with event. Recommend working with the analytics instrumentation team to define events.",
+ "required": [
+ "event"
+ ],
+ "properties": {
+ "event": {
+ "type": "string",
+ "description": "Name of the event. Events must be defined and added to the security reports observability events allow list."
+ },
+ "property": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "label": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "value": {
+ "type": "number",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "cvss_vectors": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "description": "An ordered array of CVSS vectors, each issued by a vendor to rate the vulnerability. The first item in the array is used as the primary CVSS vector, and is used to filter and sort the vulnerability.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 16,
+ "maxLength": 128,
+ "pattern": "^((AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))/)*(AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 32,
+ "maxLength": 128,
+ "pattern": "^CVSS:3[.][01]/((AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])/)*(AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ }
+ ]
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^(https?|ftp)://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "required": [
+ "dependency",
+ "image",
+ "kubernetes_resource"
+ ],
+ "properties": {
+ "dependency": {
+ "type": "object",
+ "description": "Describes the dependency of a project where the vulnerability is located.",
+ "required": [
+ "package",
+ "version"
+ ],
+ "properties": {
+ "package": {
+ "type": "object",
+ "description": "Provides information on the package where the vulnerability is located.",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the package where the vulnerability is located."
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "Version of the vulnerable package."
+ },
+ "direct": {
+ "type": "boolean",
+ "description": "Tells whether this is a direct, top-level dependency of the scanned project."
+ }
+ }
+ },
+ "operating_system": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The operating system that contains the vulnerable package."
+ },
+ "image": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The analyzed Docker image.",
+ "examples": [
+ "index.docker.io/library/nginx:1.21"
+ ]
+ },
+ "kubernetes_resource": {
+ "type": "object",
+ "description": "The specific Kubernetes resource that was scanned.",
+ "required": [
+ "namespace",
+ "kind",
+ "name",
+ "container_name"
+ ],
+ "properties": {
+ "namespace": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The Kubernetes namespace the resource that had its image scanned.",
+ "examples": [
+ "default",
+ "staging",
+ "production"
+ ]
+ },
+ "kind": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The Kubernetes kind the resource that had its image scanned.",
+ "examples": [
+ "Deployment",
+ "DaemonSet"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The name of the resource that had its image scanned.",
+ "examples": [
+ "nginx-ingress"
+ ]
+ },
+ "container_name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The name of the container that had its image scanned.",
+ "examples": [
+ "nginx"
+ ]
+ },
+ "agent_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The GitLab ID of the Kubernetes Agent which performed the scan.",
+ "examples": [
+ "1234"
+ ]
+ },
+ "cluster_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The GitLab ID of the Kubernetes cluster when using cluster integration.",
+ "examples": [
+ "1234"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/container-scanning-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/container-scanning-report-format.json
new file mode 100644
index 00000000000..494156a613f
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/container-scanning-report-format.json
@@ -0,0 +1,1176 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/container-scanning-report-format.json",
+ "title": "Report format for GitLab Container Scanning",
+ "description": "This schema provides the the report format for Container Scanning (https://docs.gitlab.com/ee/user/application_security/container_scanning).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ },
+ {
+ "$ref": "#/definitions/code_flows"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "line_end": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_end": {
+ "type": "integer",
+ "minimum": 1
+ }
+ },
+ "dependencies": {
+ "column_end": [
+ "column_start"
+ ],
+ "column_start": [
+ "column_end"
+ ]
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ },
+ "code_flow_node": {
+ "type": "object",
+ "description": "A code flow node representing a part of a vulnerability flow from source to sink",
+ "required": [
+ "file_location",
+ "node_type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flow-node"
+ },
+ "file_location": {
+ "$ref": "#/definitions/file_location"
+ },
+ "node_type": {
+ "type": "string",
+ "description": "Describes a code flow node type",
+ "enum": [
+ "source",
+ "sink",
+ "propagation"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ },
+ "code_flows": {
+ "type": "object",
+ "description": "A code flow representing a vulnerability flow from source to sink",
+ "required": [
+ "items",
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flows"
+ },
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "#/definitions/code_flow_node"
+ }
+ }
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flows",
+ "items": [
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 1,
+ "line_end": 2
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 3
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ],
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "different_flow.py",
+ "line_start": 100,
+ "line_end": 102
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ },
+ "self": {
+ "version": "15.2.1"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "options": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "A configuration option used for this scan.",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The configuration option name.",
+ "maxLength": 255,
+ "minLength": 1,
+ "examples": [
+ "DAST_FF_ENABLE_BAS",
+ "DOCKER_TLS_CERTDIR",
+ "DS_MAX_DEPTH",
+ "SECURE_LOG_LEVEL"
+ ]
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of this option.",
+ "enum": [
+ "argument",
+ "file",
+ "env_variable",
+ "other"
+ ]
+ },
+ "value": {
+ "type": [
+ "boolean",
+ "integer",
+ "null",
+ "string"
+ ],
+ "description": "The value used for this scan.",
+ "examples": [
+ true,
+ 2,
+ null,
+ "fatal",
+ ""
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "container_scanning",
+ "container_scanning_for_registry"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "observability": {
+ "type": "object",
+ "description": "Internal GitLab use only. Observability data such as metrics collected by the analyzers.",
+ "properties": {
+ "events": {
+ "type": "array",
+ "description": "Internal GitLab use only. Array of events containing metrics logged via the GitLab internal event tracking system. Recommend working with the analytics instrumentation team to define events.",
+ "items": {
+ "type": "object",
+ "description": "Internal GitLab use only. An event with zero or more values. Additional properties can be used to collect various metrics associated with event. Recommend working with the analytics instrumentation team to define events.",
+ "required": [
+ "event"
+ ],
+ "properties": {
+ "event": {
+ "type": "string",
+ "description": "Name of the event. Events must be defined and added to the security reports observability events allow list."
+ },
+ "property": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "label": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "value": {
+ "type": "number",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "cvss_vectors": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "description": "An ordered array of CVSS vectors, each issued by a vendor to rate the vulnerability. The first item in the array is used as the primary CVSS vector, and is used to filter and sort the vulnerability.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 16,
+ "maxLength": 128,
+ "pattern": "^((AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))/)*(AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 32,
+ "maxLength": 128,
+ "pattern": "^CVSS:3[.][01]/((AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])/)*(AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ }
+ ]
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^(https?|ftp)://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "required": [
+ "dependency",
+ "operating_system",
+ "image"
+ ],
+ "properties": {
+ "dependency": {
+ "type": "object",
+ "description": "Describes the dependency of a project where the vulnerability is located.",
+ "required": [
+ "package",
+ "version"
+ ],
+ "properties": {
+ "package": {
+ "type": "object",
+ "description": "Provides information on the package where the vulnerability is located.",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the package where the vulnerability is located."
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "Version of the vulnerable package."
+ },
+ "direct": {
+ "type": "boolean",
+ "description": "Tells whether this is a direct, top-level dependency of the scanned project."
+ }
+ }
+ },
+ "operating_system": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The operating system that contains the vulnerable package."
+ },
+ "image": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The analyzed Docker image."
+ },
+ "default_branch_image": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the image on the default branch."
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/coverage-fuzzing-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/coverage-fuzzing-report-format.json
new file mode 100644
index 00000000000..d974e443196
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/coverage-fuzzing-report-format.json
@@ -0,0 +1,1153 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/coverage-fuzzing-report-format.json",
+ "title": "Report format for GitLab Fuzz Testing",
+ "description": "This schema provides the report format for Coverage Guided Fuzz Testing (https://docs.gitlab.com/ee/user/application_security/coverage_fuzzing).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ },
+ {
+ "$ref": "#/definitions/code_flows"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "line_end": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_end": {
+ "type": "integer",
+ "minimum": 1
+ }
+ },
+ "dependencies": {
+ "column_end": [
+ "column_start"
+ ],
+ "column_start": [
+ "column_end"
+ ]
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ },
+ "code_flow_node": {
+ "type": "object",
+ "description": "A code flow node representing a part of a vulnerability flow from source to sink",
+ "required": [
+ "file_location",
+ "node_type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flow-node"
+ },
+ "file_location": {
+ "$ref": "#/definitions/file_location"
+ },
+ "node_type": {
+ "type": "string",
+ "description": "Describes a code flow node type",
+ "enum": [
+ "source",
+ "sink",
+ "propagation"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ },
+ "code_flows": {
+ "type": "object",
+ "description": "A code flow representing a vulnerability flow from source to sink",
+ "required": [
+ "items",
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flows"
+ },
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "#/definitions/code_flow_node"
+ }
+ }
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flows",
+ "items": [
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 1,
+ "line_end": 2
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 3
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ],
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "different_flow.py",
+ "line_start": 100,
+ "line_end": 102
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ },
+ "self": {
+ "version": "15.2.1"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "options": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "A configuration option used for this scan.",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The configuration option name.",
+ "maxLength": 255,
+ "minLength": 1,
+ "examples": [
+ "DAST_FF_ENABLE_BAS",
+ "DOCKER_TLS_CERTDIR",
+ "DS_MAX_DEPTH",
+ "SECURE_LOG_LEVEL"
+ ]
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of this option.",
+ "enum": [
+ "argument",
+ "file",
+ "env_variable",
+ "other"
+ ]
+ },
+ "value": {
+ "type": [
+ "boolean",
+ "integer",
+ "null",
+ "string"
+ ],
+ "description": "The value used for this scan.",
+ "examples": [
+ true,
+ 2,
+ null,
+ "fatal",
+ ""
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "coverage_fuzzing"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "observability": {
+ "type": "object",
+ "description": "Internal GitLab use only. Observability data such as metrics collected by the analyzers.",
+ "properties": {
+ "events": {
+ "type": "array",
+ "description": "Internal GitLab use only. Array of events containing metrics logged via the GitLab internal event tracking system. Recommend working with the analytics instrumentation team to define events.",
+ "items": {
+ "type": "object",
+ "description": "Internal GitLab use only. An event with zero or more values. Additional properties can be used to collect various metrics associated with event. Recommend working with the analytics instrumentation team to define events.",
+ "required": [
+ "event"
+ ],
+ "properties": {
+ "event": {
+ "type": "string",
+ "description": "Name of the event. Events must be defined and added to the security reports observability events allow list."
+ },
+ "property": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "label": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "value": {
+ "type": "number",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "cvss_vectors": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "description": "An ordered array of CVSS vectors, each issued by a vendor to rate the vulnerability. The first item in the array is used as the primary CVSS vector, and is used to filter and sort the vulnerability.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 16,
+ "maxLength": 128,
+ "pattern": "^((AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))/)*(AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 32,
+ "maxLength": 128,
+ "pattern": "^CVSS:3[.][01]/((AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])/)*(AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ }
+ ]
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^(https?|ftp)://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "description": "The location of the error",
+ "type": "object",
+ "properties": {
+ "crash_address": {
+ "type": "string",
+ "description": "The relative address in memory were the crash occurred.",
+ "examples": [
+ "0xabababab"
+ ]
+ },
+ "stacktrace_snippet": {
+ "type": "string",
+ "description": "The stack trace recorded during fuzzing resulting the crash.",
+ "examples": [
+ "func_a+0xabcd\nfunc_b+0xabcc"
+ ]
+ },
+ "crash_state": {
+ "type": "string",
+ "description": "Minimised and normalized crash stack-trace (called crash_state).",
+ "examples": [
+ "func_a+0xa\nfunc_b+0xb\nfunc_c+0xc"
+ ]
+ },
+ "crash_type": {
+ "type": "string",
+ "description": "Type of the crash.",
+ "examples": [
+ "Heap-Buffer-overflow",
+ "Division-by-zero"
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/dast-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/dast-report-format.json
new file mode 100644
index 00000000000..a40602007d7
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/dast-report-format.json
@@ -0,0 +1,1558 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/dast-report-format.json",
+ "title": "Report format for GitLab DAST",
+ "description": "This schema provides the the report format for Dynamic Application Security Testing (https://docs.gitlab.com/ee/user/application_security/dast).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ },
+ {
+ "$ref": "#/definitions/code_flows"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "line_end": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_end": {
+ "type": "integer",
+ "minimum": 1
+ }
+ },
+ "dependencies": {
+ "column_end": [
+ "column_start"
+ ],
+ "column_start": [
+ "column_end"
+ ]
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ },
+ "code_flow_node": {
+ "type": "object",
+ "description": "A code flow node representing a part of a vulnerability flow from source to sink",
+ "required": [
+ "file_location",
+ "node_type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flow-node"
+ },
+ "file_location": {
+ "$ref": "#/definitions/file_location"
+ },
+ "node_type": {
+ "type": "string",
+ "description": "Describes a code flow node type",
+ "enum": [
+ "source",
+ "sink",
+ "propagation"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ },
+ "code_flows": {
+ "type": "object",
+ "description": "A code flow representing a vulnerability flow from source to sink",
+ "required": [
+ "items",
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flows"
+ },
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "#/definitions/code_flow_node"
+ }
+ }
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flows",
+ "items": [
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 1,
+ "line_end": 2
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 3
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ],
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "different_flow.py",
+ "line_start": 100,
+ "line_end": 102
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ },
+ "self": {
+ "version": "15.2.1"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanned_resources",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "options": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "A configuration option used for this scan.",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The configuration option name.",
+ "maxLength": 255,
+ "minLength": 1,
+ "examples": [
+ "DAST_FF_ENABLE_BAS",
+ "DOCKER_TLS_CERTDIR",
+ "DS_MAX_DEPTH",
+ "SECURE_LOG_LEVEL"
+ ]
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of this option.",
+ "enum": [
+ "argument",
+ "file",
+ "env_variable",
+ "other"
+ ]
+ },
+ "value": {
+ "type": [
+ "boolean",
+ "integer",
+ "null",
+ "string"
+ ],
+ "description": "The value used for this scan.",
+ "examples": [
+ true,
+ 2,
+ null,
+ "fatal",
+ ""
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "dast",
+ "api_fuzzing"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "observability": {
+ "type": "object",
+ "description": "Internal GitLab use only. Observability data such as metrics collected by the analyzers.",
+ "properties": {
+ "events": {
+ "type": "array",
+ "description": "Internal GitLab use only. Array of events containing metrics logged via the GitLab internal event tracking system. Recommend working with the analytics instrumentation team to define events.",
+ "items": {
+ "type": "object",
+ "description": "Internal GitLab use only. An event with zero or more values. Additional properties can be used to collect various metrics associated with event. Recommend working with the analytics instrumentation team to define events.",
+ "required": [
+ "event"
+ ],
+ "properties": {
+ "event": {
+ "type": "string",
+ "description": "Name of the event. Events must be defined and added to the security reports observability events allow list."
+ },
+ "property": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "label": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "value": {
+ "type": "number",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ }
+ }
+ }
+ }
+ }
+ },
+ "scanned_resources": {
+ "type": "array",
+ "description": "The attack surface scanned by DAST.",
+ "items": {
+ "type": "object",
+ "required": [
+ "method",
+ "url",
+ "type"
+ ],
+ "properties": {
+ "method": {
+ "type": "string",
+ "minLength": 1,
+ "description": "HTTP method of the scanned resource.",
+ "examples": [
+ "GET",
+ "POST",
+ "HEAD"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "description": "URL of the scanned resource.",
+ "examples": [
+ "http://my.site.com/a-page"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Type of the scanned resource, for DAST, this must be 'url'.",
+ "examples": [
+ "url"
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "cvss_vectors": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "description": "An ordered array of CVSS vectors, each issued by a vendor to rate the vulnerability. The first item in the array is used as the primary CVSS vector, and is used to filter and sort the vulnerability.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 16,
+ "maxLength": 128,
+ "pattern": "^((AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))/)*(AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 32,
+ "maxLength": 128,
+ "pattern": "^CVSS:3[.][01]/((AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])/)*(AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ }
+ ]
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^(https?|ftp)://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "evidence": {
+ "type": "object",
+ "properties": {
+ "source": {
+ "type": "object",
+ "description": "Source of evidence",
+ "required": [
+ "id",
+ "name"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique source identifier",
+ "examples": [
+ "assert:LogAnalysis",
+ "assert:StatusCode"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Source display name",
+ "examples": [
+ "Log Analysis",
+ "Status Code"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "Link to additional information",
+ "examples": [
+ "https://docs.gitlab.com/ee/development/integrations/secure.html"
+ ]
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "description": "Human readable string containing evidence of the vulnerability.",
+ "examples": [
+ "Credit card 4111111111111111 found",
+ "Server leaked information nginx/1.17.6"
+ ]
+ },
+ "request": {
+ "type": "object",
+ "description": "An HTTP request.",
+ "required": [
+ "headers",
+ "method",
+ "url"
+ ],
+ "properties": {
+ "headers": {
+ "type": "array",
+ "description": "HTTP headers present on the request.",
+ "items": {
+ "type": "object",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Name of the HTTP header.",
+ "examples": [
+ "Accept",
+ "Content-Length",
+ "Content-Type"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the HTTP header.",
+ "examples": [
+ "*/*",
+ "560",
+ "application/json; charset=utf-8"
+ ]
+ }
+ }
+ }
+ },
+ "method": {
+ "type": "string",
+ "minLength": 1,
+ "description": "HTTP method used in the request.",
+ "examples": [
+ "GET",
+ "POST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "description": "URL of the request.",
+ "examples": [
+ "http://my.site.com/vulnerable-endpoint?show-credit-card"
+ ]
+ },
+ "body": {
+ "type": "string",
+ "description": "Body of the request for display purposes. Body must be suitable for display (not binary), and truncated to a reasonable size.",
+ "examples": [
+ "user=jsmith&first=%27&last=smith"
+ ]
+ }
+ }
+ },
+ "response": {
+ "type": "object",
+ "description": "An HTTP response.",
+ "required": [
+ "headers",
+ "reason_phrase",
+ "status_code"
+ ],
+ "properties": {
+ "headers": {
+ "type": "array",
+ "description": "HTTP headers present on the request.",
+ "items": {
+ "type": "object",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Name of the HTTP header.",
+ "examples": [
+ "Accept",
+ "Content-Length",
+ "Content-Type"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the HTTP header.",
+ "examples": [
+ "*/*",
+ "560",
+ "application/json; charset=utf-8"
+ ]
+ }
+ }
+ }
+ },
+ "reason_phrase": {
+ "type": "string",
+ "description": "HTTP reason phrase of the response.",
+ "examples": [
+ "OK",
+ "Internal Server Error"
+ ]
+ },
+ "status_code": {
+ "type": "integer",
+ "description": "HTTP status code of the response.",
+ "examples": [
+ 200,
+ 500
+ ]
+ },
+ "body": {
+ "type": "string",
+ "description": "Body of the response for display purposes. Body must be suitable for display (not binary), and truncated to a reasonable size.",
+ "examples": [
+ "{\"user_id\": 2}"
+ ]
+ }
+ }
+ },
+ "supporting_messages": {
+ "type": "array",
+ "description": "Array of supporting http messages.",
+ "items": {
+ "type": "object",
+ "description": "A supporting http message.",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Message display name.",
+ "examples": [
+ "Unmodified",
+ "Recorded"
+ ]
+ },
+ "request": {
+ "type": "object",
+ "description": "An HTTP request.",
+ "required": [
+ "headers",
+ "method",
+ "url"
+ ],
+ "properties": {
+ "headers": {
+ "type": "array",
+ "description": "HTTP headers present on the request.",
+ "items": {
+ "type": "object",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Name of the HTTP header.",
+ "examples": [
+ "Accept",
+ "Content-Length",
+ "Content-Type"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the HTTP header.",
+ "examples": [
+ "*/*",
+ "560",
+ "application/json; charset=utf-8"
+ ]
+ }
+ }
+ }
+ },
+ "method": {
+ "type": "string",
+ "minLength": 1,
+ "description": "HTTP method used in the request.",
+ "examples": [
+ "GET",
+ "POST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "description": "URL of the request.",
+ "examples": [
+ "http://my.site.com/vulnerable-endpoint?show-credit-card"
+ ]
+ },
+ "body": {
+ "type": "string",
+ "description": "Body of the request for display purposes. Body must be suitable for display (not binary), and truncated to a reasonable size.",
+ "examples": [
+ "user=jsmith&first=%27&last=smith"
+ ]
+ }
+ }
+ },
+ "response": {
+ "type": "object",
+ "description": "An HTTP response.",
+ "required": [
+ "headers",
+ "reason_phrase",
+ "status_code"
+ ],
+ "properties": {
+ "headers": {
+ "type": "array",
+ "description": "HTTP headers present on the request.",
+ "items": {
+ "type": "object",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Name of the HTTP header.",
+ "examples": [
+ "Accept",
+ "Content-Length",
+ "Content-Type"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the HTTP header.",
+ "examples": [
+ "*/*",
+ "560",
+ "application/json; charset=utf-8"
+ ]
+ }
+ }
+ }
+ },
+ "reason_phrase": {
+ "type": "string",
+ "description": "HTTP reason phrase of the response.",
+ "examples": [
+ "OK",
+ "Internal Server Error"
+ ]
+ },
+ "status_code": {
+ "type": "integer",
+ "description": "HTTP status code of the response.",
+ "examples": [
+ 200,
+ 500
+ ]
+ },
+ "body": {
+ "type": "string",
+ "description": "Body of the response for display purposes. Body must be suitable for display (not binary), and truncated to a reasonable size.",
+ "examples": [
+ "{\"user_id\": 2}"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "properties": {
+ "hostname": {
+ "type": "string",
+ "description": "The protocol, domain, and port of the application where the vulnerability was found."
+ },
+ "method": {
+ "type": "string",
+ "description": "The HTTP method that was used to request the URL where the vulnerability was found."
+ },
+ "param": {
+ "type": "string",
+ "description": "A value provided by a vulnerability rule related to the found vulnerability. Examples include a header value, or a parameter used in a HTTP POST."
+ },
+ "path": {
+ "type": "string",
+ "description": "The path of the URL where the vulnerability was found. Typically, this would start with a forward slash."
+ }
+ }
+ },
+ "assets": {
+ "type": "array",
+ "description": "Array of build assets associated with vulnerability.",
+ "items": {
+ "type": "object",
+ "description": "Describes an asset associated with vulnerability.",
+ "required": [
+ "type",
+ "name",
+ "url"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of asset",
+ "enum": [
+ "http_session",
+ "postman"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Display name for asset",
+ "examples": [
+ "HTTP Messages",
+ "Postman Collection"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Link to asset in build artifacts",
+ "examples": [
+ "https://gitlab.com/gitlab-org/security-products/dast/-/jobs/626397001/artifacts/file//output/zap_session.data"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/dependency-scanning-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/dependency-scanning-report-format.json
new file mode 100644
index 00000000000..5d91db80736
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/dependency-scanning-report-format.json
@@ -0,0 +1,1164 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/dependency-scanning-report-format.json",
+ "title": "Report format for GitLab Dependency Scanning",
+ "description": "This schema provides the the report format for Dependency Scanning analyzers (https://docs.gitlab.com/ee/user/application_security/dependency_scanning).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ },
+ {
+ "$ref": "#/definitions/code_flows"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "line_end": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_end": {
+ "type": "integer",
+ "minimum": 1
+ }
+ },
+ "dependencies": {
+ "column_end": [
+ "column_start"
+ ],
+ "column_start": [
+ "column_end"
+ ]
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ },
+ "code_flow_node": {
+ "type": "object",
+ "description": "A code flow node representing a part of a vulnerability flow from source to sink",
+ "required": [
+ "file_location",
+ "node_type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flow-node"
+ },
+ "file_location": {
+ "$ref": "#/definitions/file_location"
+ },
+ "node_type": {
+ "type": "string",
+ "description": "Describes a code flow node type",
+ "enum": [
+ "source",
+ "sink",
+ "propagation"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ },
+ "code_flows": {
+ "type": "object",
+ "description": "A code flow representing a vulnerability flow from source to sink",
+ "required": [
+ "items",
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flows"
+ },
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "#/definitions/code_flow_node"
+ }
+ }
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flows",
+ "items": [
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 1,
+ "line_end": 2
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 3
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ],
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "different_flow.py",
+ "line_start": 100,
+ "line_end": 102
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ },
+ "self": {
+ "version": "15.2.1"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "options": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "A configuration option used for this scan.",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The configuration option name.",
+ "maxLength": 255,
+ "minLength": 1,
+ "examples": [
+ "DAST_FF_ENABLE_BAS",
+ "DOCKER_TLS_CERTDIR",
+ "DS_MAX_DEPTH",
+ "SECURE_LOG_LEVEL"
+ ]
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of this option.",
+ "enum": [
+ "argument",
+ "file",
+ "env_variable",
+ "other"
+ ]
+ },
+ "value": {
+ "type": [
+ "boolean",
+ "integer",
+ "null",
+ "string"
+ ],
+ "description": "The value used for this scan.",
+ "examples": [
+ true,
+ 2,
+ null,
+ "fatal",
+ ""
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "dependency_scanning"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "observability": {
+ "type": "object",
+ "description": "Internal GitLab use only. Observability data such as metrics collected by the analyzers.",
+ "properties": {
+ "events": {
+ "type": "array",
+ "description": "Internal GitLab use only. Array of events containing metrics logged via the GitLab internal event tracking system. Recommend working with the analytics instrumentation team to define events.",
+ "items": {
+ "type": "object",
+ "description": "Internal GitLab use only. An event with zero or more values. Additional properties can be used to collect various metrics associated with event. Recommend working with the analytics instrumentation team to define events.",
+ "required": [
+ "event"
+ ],
+ "properties": {
+ "event": {
+ "type": "string",
+ "description": "Name of the event. Events must be defined and added to the security reports observability events allow list."
+ },
+ "property": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "label": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "value": {
+ "type": "number",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "cvss_vectors": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "description": "An ordered array of CVSS vectors, each issued by a vendor to rate the vulnerability. The first item in the array is used as the primary CVSS vector, and is used to filter and sort the vulnerability.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 16,
+ "maxLength": 128,
+ "pattern": "^((AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))/)*(AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 32,
+ "maxLength": 128,
+ "pattern": "^CVSS:3[.][01]/((AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])/)*(AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ }
+ ]
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^(https?|ftp)://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "required": [
+ "file",
+ "dependency"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Path to the manifest or lock file where the dependency is declared (such as yarn.lock)."
+ },
+ "dependency": {
+ "type": "object",
+ "description": "Describes the dependency of a project where the vulnerability is located.",
+ "required": [
+ "package",
+ "version"
+ ],
+ "properties": {
+ "package": {
+ "type": "object",
+ "description": "Provides information on the package where the vulnerability is located.",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the package where the vulnerability is located."
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "Version of the vulnerable package."
+ },
+ "direct": {
+ "type": "boolean",
+ "description": "Tells whether this is a direct, top-level dependency of the scanned project."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/sast-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/sast-report-format.json
new file mode 100644
index 00000000000..55f3bc6391f
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/sast-report-format.json
@@ -0,0 +1,1148 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/sast-report-format.json",
+ "title": "Report format for GitLab SAST",
+ "description": "This schema provides the report format for Static Application Security Testing analyzers (https://docs.gitlab.com/ee/user/application_security/sast).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ },
+ {
+ "$ref": "#/definitions/code_flows"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "line_end": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_end": {
+ "type": "integer",
+ "minimum": 1
+ }
+ },
+ "dependencies": {
+ "column_end": [
+ "column_start"
+ ],
+ "column_start": [
+ "column_end"
+ ]
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ },
+ "code_flow_node": {
+ "type": "object",
+ "description": "A code flow node representing a part of a vulnerability flow from source to sink",
+ "required": [
+ "file_location",
+ "node_type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flow-node"
+ },
+ "file_location": {
+ "$ref": "#/definitions/file_location"
+ },
+ "node_type": {
+ "type": "string",
+ "description": "Describes a code flow node type",
+ "enum": [
+ "source",
+ "sink",
+ "propagation"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ },
+ "code_flows": {
+ "type": "object",
+ "description": "A code flow representing a vulnerability flow from source to sink",
+ "required": [
+ "items",
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flows"
+ },
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "#/definitions/code_flow_node"
+ }
+ }
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flows",
+ "items": [
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 1,
+ "line_end": 2
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 3
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ],
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "different_flow.py",
+ "line_start": 100,
+ "line_end": 102
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ },
+ "self": {
+ "version": "15.2.1"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "options": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "A configuration option used for this scan.",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The configuration option name.",
+ "maxLength": 255,
+ "minLength": 1,
+ "examples": [
+ "DAST_FF_ENABLE_BAS",
+ "DOCKER_TLS_CERTDIR",
+ "DS_MAX_DEPTH",
+ "SECURE_LOG_LEVEL"
+ ]
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of this option.",
+ "enum": [
+ "argument",
+ "file",
+ "env_variable",
+ "other"
+ ]
+ },
+ "value": {
+ "type": [
+ "boolean",
+ "integer",
+ "null",
+ "string"
+ ],
+ "description": "The value used for this scan.",
+ "examples": [
+ true,
+ 2,
+ null,
+ "fatal",
+ ""
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "sast"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "observability": {
+ "type": "object",
+ "description": "Internal GitLab use only. Observability data such as metrics collected by the analyzers.",
+ "properties": {
+ "events": {
+ "type": "array",
+ "description": "Internal GitLab use only. Array of events containing metrics logged via the GitLab internal event tracking system. Recommend working with the analytics instrumentation team to define events.",
+ "items": {
+ "type": "object",
+ "description": "Internal GitLab use only. An event with zero or more values. Additional properties can be used to collect various metrics associated with event. Recommend working with the analytics instrumentation team to define events.",
+ "required": [
+ "event"
+ ],
+ "properties": {
+ "event": {
+ "type": "string",
+ "description": "Name of the event. Events must be defined and added to the security reports observability events allow list."
+ },
+ "property": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "label": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "value": {
+ "type": "number",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "cvss_vectors": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "description": "An ordered array of CVSS vectors, each issued by a vendor to rate the vulnerability. The first item in the array is used as the primary CVSS vector, and is used to filter and sort the vulnerability.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 16,
+ "maxLength": 128,
+ "pattern": "^((AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))/)*(AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 32,
+ "maxLength": 128,
+ "pattern": "^CVSS:3[.][01]/((AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])/)*(AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ }
+ ]
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^(https?|ftp)://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the code affected by the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the code affected by the vulnerability."
+ },
+ "class": {
+ "type": "string",
+ "description": "Provides the name of the class where the vulnerability is located."
+ },
+ "method": {
+ "type": "string",
+ "description": "Provides the name of the method where the vulnerability is located."
+ }
+ }
+ },
+ "raw_source_code_extract": {
+ "type": "string",
+ "description": "Provides an unsanitized excerpt of the affected source code."
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/secret-detection-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/secret-detection-report-format.json
new file mode 100644
index 00000000000..9ee724c0ccc
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.2.1/secret-detection-report-format.json
@@ -0,0 +1,1172 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/secret-detection-report-format.json",
+ "title": "Report format for GitLab Secret Detection",
+ "description": "This schema provides the the report format for the Secret Detection analyzer (https://docs.gitlab.com/ee/user/application_security/secret_detection)",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ },
+ {
+ "$ref": "#/definitions/code_flows"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "line_end": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_start": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "column_end": {
+ "type": "integer",
+ "minimum": 1
+ }
+ },
+ "dependencies": {
+ "column_end": [
+ "column_start"
+ ],
+ "column_start": [
+ "column_end"
+ ]
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ },
+ "code_flow_node": {
+ "type": "object",
+ "description": "A code flow node representing a part of a vulnerability flow from source to sink",
+ "required": [
+ "file_location",
+ "node_type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flow-node"
+ },
+ "file_location": {
+ "$ref": "#/definitions/file_location"
+ },
+ "node_type": {
+ "type": "string",
+ "description": "Describes a code flow node type",
+ "enum": [
+ "source",
+ "sink",
+ "propagation"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ },
+ "code_flows": {
+ "type": "object",
+ "description": "A code flow representing a vulnerability flow from source to sink",
+ "required": [
+ "items",
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "const": "code-flows"
+ },
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "items": {
+ "type": "array",
+ "minItems": 1,
+ "items": {
+ "$ref": "#/definitions/code_flow_node"
+ }
+ }
+ }
+ },
+ "examples": [
+ {
+ "type": "code-flows",
+ "items": [
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 1,
+ "line_end": 2
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "propagation",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 3
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ],
+ [
+ {
+ "type": "code-flow-node",
+ "node_type": "source",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "different_flow.py",
+ "line_start": 100,
+ "line_end": 102
+ }
+ },
+ {
+ "type": "code-flow-node",
+ "node_type": "sink",
+ "file_location": {
+ "type": "file-location",
+ "file_name": "file_name.py",
+ "line_start": 4,
+ "line_end": 6
+ }
+ }
+ ]
+ ]
+ }
+ ]
+ }
+ },
+ "self": {
+ "version": "15.2.1"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "options": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "A configuration option used for this scan.",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The configuration option name.",
+ "maxLength": 255,
+ "minLength": 1,
+ "examples": [
+ "DAST_FF_ENABLE_BAS",
+ "DOCKER_TLS_CERTDIR",
+ "DS_MAX_DEPTH",
+ "SECURE_LOG_LEVEL"
+ ]
+ },
+ "source": {
+ "type": "string",
+ "description": "The source of this option.",
+ "enum": [
+ "argument",
+ "file",
+ "env_variable",
+ "other"
+ ]
+ },
+ "value": {
+ "type": [
+ "boolean",
+ "integer",
+ "null",
+ "string"
+ ],
+ "description": "The value used for this scan.",
+ "examples": [
+ true,
+ 2,
+ null,
+ "fatal",
+ ""
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "secret_detection"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "observability": {
+ "type": "object",
+ "description": "Internal GitLab use only. Observability data such as metrics collected by the analyzers.",
+ "properties": {
+ "events": {
+ "type": "array",
+ "description": "Internal GitLab use only. Array of events containing metrics logged via the GitLab internal event tracking system. Recommend working with the analytics instrumentation team to define events.",
+ "items": {
+ "type": "object",
+ "description": "Internal GitLab use only. An event with zero or more values. Additional properties can be used to collect various metrics associated with event. Recommend working with the analytics instrumentation team to define events.",
+ "required": [
+ "event"
+ ],
+ "properties": {
+ "event": {
+ "type": "string",
+ "description": "Name of the event. Events must be defined and added to the security reports observability events allow list."
+ },
+ "property": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "label": {
+ "type": "string",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ },
+ "value": {
+ "type": "number",
+ "description": "Data related to given event. Column in the data warehouse, fast to filter on in queries."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^(https?|ftp)://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "cvss_vectors": {
+ "type": "array",
+ "minItems": 1,
+ "maxItems": 10,
+ "description": "An ordered array of CVSS vectors, each issued by a vendor to rate the vulnerability. The first item in the array is used as the primary CVSS vector, and is used to filter and sort the vulnerability.",
+ "items": {
+ "oneOf": [
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 16,
+ "maxLength": 128,
+ "pattern": "^((AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))/)*(AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "vendor": {
+ "type": "string",
+ "minLength": 1,
+ "default": "unknown"
+ },
+ "vector": {
+ "type": "string",
+ "minLength": 32,
+ "maxLength": 128,
+ "pattern": "^CVSS:3[.][01]/((AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])/)*(AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$"
+ }
+ },
+ "required": [
+ "vendor",
+ "vector"
+ ]
+ }
+ ]
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^(https?|ftp)://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "required": [
+ "commit"
+ ],
+ "type": "object",
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located"
+ },
+ "commit": {
+ "type": "object",
+ "description": "Represents the commit in which the vulnerability was detected",
+ "required": [
+ "sha"
+ ],
+ "properties": {
+ "author": {
+ "type": "string"
+ },
+ "date": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ },
+ "sha": {
+ "type": "string",
+ "minLength": 1
+ }
+ }
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the code affected by the vulnerability"
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the code affected by the vulnerability"
+ },
+ "class": {
+ "type": "string",
+ "description": "Provides the name of the class where the vulnerability is located"
+ },
+ "method": {
+ "type": "string",
+ "description": "Provides the name of the method where the vulnerability is located"
+ }
+ }
+ },
+ "raw_source_code_extract": {
+ "type": "string",
+ "description": "Provides an unsanitized excerpt of the affected source code."
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/pages.rb b/lib/gitlab/pages.rb
index defe054d631..928248c1235 100644
--- a/lib/gitlab/pages.rb
+++ b/lib/gitlab/pages.rb
@@ -9,6 +9,12 @@ module Gitlab
include JwtAuthenticatable
+ class UniqueDomainGenerationFailure < StandardError
+ def initialize(msg = "Can't generate unique domain for GitLab Pages")
+ super(msg)
+ end
+ end
+
class << self
def verify_api_request(request_headers)
decode_jwt(request_headers[INTERNAL_API_REQUEST_HEADER], issuer: 'gitlab-pages')
@@ -35,9 +41,7 @@ module Gitlab
return if project.project_setting.pages_unique_domain_in_database.present?
project.project_setting.pages_unique_domain_enabled = true
- project.project_setting.pages_unique_domain = Gitlab::Pages::RandomDomain.generate(
- project_path: project.path,
- namespace_path: project.parent.full_path)
+ project.project_setting.pages_unique_domain = generate_unique_domain(project)
end
def multiple_versions_enabled_for?(project)
@@ -47,6 +51,17 @@ module Gitlab
project.licensed_feature_available?(:pages_multiple_versions) &&
project.project_setting.pages_multiple_versions_enabled
end
+
+ private
+
+ def generate_unique_domain(project)
+ 10.times do
+ pages_unique_domain = Gitlab::Pages::RandomDomain.generate(project_path: project.path)
+ return pages_unique_domain unless ProjectSetting.unique_domain_exists?(pages_unique_domain)
+ end
+
+ raise UniqueDomainGenerationFailure
+ end
end
end
end
diff --git a/lib/gitlab/pages/random_domain.rb b/lib/gitlab/pages/random_domain.rb
index 8aa7611c910..6d71639d3af 100644
--- a/lib/gitlab/pages/random_domain.rb
+++ b/lib/gitlab/pages/random_domain.rb
@@ -3,41 +3,27 @@
module Gitlab
module Pages
class RandomDomain
- PROJECT_PATH_LIMIT = 48
- SUBDOMAIN_LABEL_LIMIT = 63
+ PROJECT_PATH_LIMIT = 56
- def self.generate(project_path:, namespace_path:)
- new(project_path: project_path, namespace_path: namespace_path).generate
+ def self.generate(project_path:)
+ new(project_path: project_path).generate
end
- def initialize(project_path:, namespace_path:)
+ def initialize(project_path:)
@project_path = project_path
- @namespace_path = namespace_path
end
# Subdomains have a limit of 63 bytes (https://www.freesoft.org/CIE/RFC/1035/9.htm)
# For this reason we're limiting each part of the unique subdomain
#
- # The domain is made up of 3 parts, like: projectpath-namespacepath-randomstring
- # - project path: between 1 and 48 chars
- # - namespace path: when the project path has less than 48 chars,
- # the namespace full path will be used to fill the value up to 48 chars
- # - random hexadecimal: to ensure a random value, the domain is then filled
- # with a random hexadecimal value to complete 63 chars
+ # The domain is made up of 2 parts, like: projectpath-randomstring
+ # - project path: between 1 and 56 chars
+ # - random hexadecimal: to ensure a random value of length 6
def generate
domain = project_path.byteslice(0, PROJECT_PATH_LIMIT)
- # if the project_path has less than PROJECT_PATH_LIMIT chars,
- # fill the domain with the parent full_path up to 48 chars like:
- # projectpath-namespacepath
- if domain.length < PROJECT_PATH_LIMIT
- namespace_size = PROJECT_PATH_LIMIT - domain.length - 1
- domain.concat('-', namespace_path.byteslice(0, namespace_size))
- end
-
- # Complete the domain with random hexadecimal values util it is 63 chars long
# PS.: SecureRandom.hex return an string twice the size passed as argument.
- domain.concat('-', SecureRandom.hex(SUBDOMAIN_LABEL_LIMIT - domain.length - 1))
+ domain.concat('-', SecureRandom.hex(3))
# Slugify ensures the format and size (63 chars) of the given string
Gitlab::Utils.slugify(domain)
@@ -45,7 +31,7 @@ module Gitlab
private
- attr_reader :project_path, :namespace_path
+ attr_reader :project_path
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 2416b37fd62..5439eadfc78 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -33730,6 +33730,9 @@ msgstr ""
msgid "MergeRequest|No files found"
msgstr ""
+msgid "MergeRequest|Remove reviewer"
+msgstr ""
+
msgid "MergeRequest|Reviewed by @%{username} but not yet approved"
msgstr ""
@@ -56711,7 +56714,10 @@ msgstr ""
msgid "Tracing|Tracing"
msgstr ""
-msgid "Tracing|View Logs"
+msgid "Tracing|View logs"
+msgstr ""
+
+msgid "Tracing|View metrics"
msgstr ""
msgid "Tracing|You must select a Service and Operation first."
@@ -57334,6 +57340,9 @@ msgstr ""
msgid "Unable to parse the vulnerability report's options."
msgstr ""
+msgid "Unable to remove a reviewer at the moment, try again later"
+msgstr ""
+
msgid "Unable to save iteration. Please try again"
msgstr ""
diff --git a/qa/Gemfile b/qa/Gemfile
index c4ba47f4529..eafa669a8c8 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -3,7 +3,7 @@
source 'https://rubygems.org'
gem 'gitlab-qa', '~> 14', '>= 14.13.0', require: 'gitlab/qa'
-gem 'gitlab_quality-test_tooling', '~> 1.34.0', require: false
+gem 'gitlab_quality-test_tooling', '~> 1.35.0', require: false
gem 'gitlab-utils', path: '../gems/gitlab-utils'
gem 'activesupport', '~> 7.0.8.4' # This should stay in sync with the root's Gemfile
gem 'allure-rspec', '~> 2.25.0'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 8dfbcb173f0..4dedfb3f453 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -131,7 +131,7 @@ GEM
rainbow (>= 3, < 4)
table_print (= 1.5.7)
zeitwerk (>= 2, < 3)
- gitlab_quality-test_tooling (1.34.0)
+ gitlab_quality-test_tooling (1.35.0)
activesupport (>= 7.0, < 7.2)
amatch (~> 0.4.1)
gitlab (~> 4.19)
@@ -377,7 +377,7 @@ DEPENDENCIES
gitlab-cng!
gitlab-qa (~> 14, >= 14.13.0)
gitlab-utils!
- gitlab_quality-test_tooling (~> 1.34.0)
+ gitlab_quality-test_tooling (~> 1.35.0)
googleauth (~> 1.9.0)
influxdb-client (~> 3.1)
junit_merge (~> 0.1.2)
diff --git a/spec/factories/packages/generic/packages.rb b/spec/factories/packages/generic/packages.rb
new file mode 100644
index 00000000000..55f79b588cc
--- /dev/null
+++ b/spec/factories/packages/generic/packages.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :generic_package, class: 'Packages::Generic::Package', parent: :package do
+ sequence(:name) { |n| "generic-package-#{n}" }
+ version { '1.0.0' }
+ package_type { :generic }
+
+ trait(:with_zip_file) do
+ package_files do
+ [association(:package_file, :generic_zip, package: instance)]
+ end
+ end
+ end
+end
diff --git a/spec/factories/packages/packages.rb b/spec/factories/packages/packages.rb
index 69e90dec6b3..518ec990dcd 100644
--- a/spec/factories/packages/packages.rb
+++ b/spec/factories/packages/packages.rb
@@ -139,7 +139,9 @@ FactoryBot.define do
end
end
- factory :generic_package do
+ # TODO: Remove with the rollout of the FF generic_extract_generic_package_model
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/479933
+ factory :generic_package_legacy do
sequence(:name) { |n| "generic-package-#{n}" }
version { '1.0.0' }
package_type { :generic }
diff --git a/spec/finders/packages/generic/package_finder_spec.rb b/spec/finders/packages/generic/package_finder_spec.rb
index 707f943b285..14ff5acd4e7 100644
--- a/spec/finders/packages/generic/package_finder_spec.rb
+++ b/spec/finders/packages/generic/package_finder_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Packages::Generic::PackageFinder do
+RSpec.describe ::Packages::Generic::PackageFinder, feature_category: :package_registry do
let_it_be(:project) { create(:project) }
let_it_be(:package) { create(:generic_package, project: project) }
@@ -34,5 +34,27 @@ RSpec.describe ::Packages::Generic::PackageFinder do
expect { finder.execute!(package.name, '3.1.4') }
.to raise_error(ActiveRecord::RecordNotFound)
end
+
+ context 'when generic_extract_generic_package_model is disabled' do
+ let_it_be(:package) { create(:generic_package_legacy, project: project, name: FFaker::Lorem.word) }
+
+ before do
+ stub_feature_flags(generic_extract_generic_package_model: false)
+ end
+
+ it 'finds package by name and version' do
+ found_package = finder.execute!(package.name, package.version)
+
+ expect(found_package).to eq(package)
+ end
+
+ it 'ignores packages with same name but different version' do
+ create(:generic_package_legacy, project: project, name: package.name, version: '3.1.4')
+
+ found_package = finder.execute!(package.name, package.version)
+
+ expect(found_package).to eq(package)
+ end
+ end
end
end
diff --git a/spec/frontend/work_items/components/create_work_item_spec.js b/spec/frontend/work_items/components/create_work_item_spec.js
index 3e40481ecdf..e8d88968013 100644
--- a/spec/frontend/work_items/components/create_work_item_spec.js
+++ b/spec/frontend/work_items/components/create_work_item_spec.js
@@ -65,7 +65,6 @@ describe('Create work item component', () => {
const createComponent = ({
props = {},
- isGroup = false,
mutationHandler = createWorkItemSuccessHandler,
singleWorkItemType = false,
workItemTypeName = WORK_ITEM_TYPE_ENUM_EPIC,
@@ -97,7 +96,6 @@ describe('Create work item component', () => {
},
provide: {
fullPath: 'full-path',
- isGroup,
hasIssuableHealthStatusFeature: false,
},
});
diff --git a/spec/frontend/work_items/components/shared/work_item_token_input_spec.js b/spec/frontend/work_items/components/shared/work_item_token_input_spec.js
index 3f34b446a0b..f8b58b10528 100644
--- a/spec/frontend/work_items/components/shared/work_item_token_input_spec.js
+++ b/spec/frontend/work_items/components/shared/work_item_token_input_spec.js
@@ -80,14 +80,12 @@ describe('WorkItemTokenInput', () => {
[groupWorkItemsQuery, groupSearchedWorkItemResolver],
[workItemsByReferencesQuery, workItemReferencesQueryResolver],
]),
- provide: {
- isGroup,
- },
propsData: {
value: workItemsToAdd,
childrenType,
childrenIds: [],
fullPath: 'test-project-path',
+ isGroup,
parentWorkItemId: 'gid://gitlab/WorkItem/1',
parentConfidential,
areWorkItemsToAddValid,
diff --git a/spec/frontend/work_items/components/work_item_assignees_spec.js b/spec/frontend/work_items/components/work_item_assignees_spec.js
index ef5458e0024..35728105457 100644
--- a/spec/frontend/work_items/components/work_item_assignees_spec.js
+++ b/spec/frontend/work_items/components/work_item_assignees_spec.js
@@ -78,9 +78,6 @@ describe('WorkItemAssignees component', () => {
]);
wrapper = mountFn(WorkItemAssignees, {
- provide: {
- isGroup: false,
- },
propsData: {
assignees,
fullPath: 'test-project-path',
diff --git a/spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js b/spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js
index 2cad1fa0b38..5638a3ed7c8 100644
--- a/spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js
+++ b/spec/frontend/work_items/components/work_item_attributes_wrapper_spec.js
@@ -70,11 +70,6 @@ describe('WorkItemAttributesWrapper component', () => {
groupPath,
},
provide: {
- hasIssueWeightsFeature: true,
- hasIterationsFeature: true,
- hasOkrsFeature: true,
- hasIssuableHealthStatusFeature: true,
- projectNamespace: 'namespace',
hasSubepicsFeature: true,
glFeatures: {
workItemsBeta,
diff --git a/spec/frontend/work_items/components/work_item_detail_spec.js b/spec/frontend/work_items/components/work_item_detail_spec.js
index 91d8d7392eb..48def37b970 100644
--- a/spec/frontend/work_items/components/work_item_detail_spec.js
+++ b/spec/frontend/work_items/components/work_item_detail_spec.js
@@ -99,7 +99,6 @@ describe('WorkItemDetail component', () => {
const findDetailWrapper = () => wrapper.findByTestId('detail-wrapper');
const createComponent = ({
- isGroup = false,
isModal = false,
isDrawer = false,
updateInProgress = false,
@@ -142,15 +141,9 @@ describe('WorkItemDetail component', () => {
workItemsBeta,
namespaceLevelWorkItems,
},
- hasIssueWeightsFeature: true,
- hasIterationsFeature: true,
- hasOkrsFeature: true,
hasSubepicsFeature,
- hasIssuableHealthStatusFeature: true,
- projectNamespace: 'namespace',
fullPath: 'group/project',
groupPath: 'group',
- isGroup,
reportAbusePath: '/report/abuse/path',
},
stubs: {
diff --git a/spec/frontend/work_items/components/work_item_labels_spec.js b/spec/frontend/work_items/components/work_item_labels_spec.js
index 80630783979..aa81eb66e1f 100644
--- a/spec/frontend/work_items/components/work_item_labels_spec.js
+++ b/spec/frontend/work_items/components/work_item_labels_spec.js
@@ -82,7 +82,6 @@ describe('WorkItemLabels component', () => {
]),
provide: {
canAdminLabel: true,
- isGroup,
issuesListPath: 'test-project-path/issues',
labelsManagePath: 'test-project-path/labels',
},
@@ -91,6 +90,7 @@ describe('WorkItemLabels component', () => {
workItemIid,
canUpdate,
fullPath: 'test-project-path',
+ isGroup,
workItemType: 'Task',
},
});
diff --git a/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js b/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js
index 949a3cc3125..b02be5ffd61 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js
@@ -93,6 +93,7 @@ describe('WorkItemLinksForm', () => {
]),
propsData: {
fullPath: 'group-a',
+ isGroup,
issuableGid: 'gid://gitlab/WorkItem/1',
parentConfidential,
parentIteration,
@@ -105,7 +106,6 @@ describe('WorkItemLinksForm', () => {
},
provide: {
hasIterationsFeature,
- isGroup,
},
stubs: {
GlFormGroup: stubComponent(GlFormGroup, {
diff --git a/spec/frontend/work_items/components/work_item_parent_spec.js b/spec/frontend/work_items/components/work_item_parent_spec.js
index 50584f7947a..be5f4cfedc5 100644
--- a/spec/frontend/work_items/components/work_item_parent_spec.js
+++ b/spec/frontend/work_items/components/work_item_parent_spec.js
@@ -62,7 +62,6 @@ describe('WorkItemParent component', () => {
parent = null,
searchQueryHandler = availableWorkItemsSuccessHandler,
mutationHandler = successUpdateWorkItemMutationHandler,
- isGroup = false,
hasParent = true,
} = {}) => {
wrapper = mountExtended(WorkItemParent, {
@@ -74,7 +73,6 @@ describe('WorkItemParent component', () => {
]),
provide: {
fullPath: mockFullPath,
- isGroup,
},
propsData: {
canUpdate,
diff --git a/spec/frontend/work_items/components/work_item_relationships/work_item_add_relationship_form_spec.js b/spec/frontend/work_items/components/work_item_relationships/work_item_add_relationship_form_spec.js
index b58831a5a27..62c3dde6bf5 100644
--- a/spec/frontend/work_items/components/work_item_relationships/work_item_add_relationship_form_spec.js
+++ b/spec/frontend/work_items/components/work_item_relationships/work_item_add_relationship_form_spec.js
@@ -34,9 +34,6 @@ describe('WorkItemAddRelationshipForm', () => {
wrapper = shallowMountExtended(WorkItemAddRelationshipForm, {
apolloProvider: mockApolloProvider,
- provide: {
- isGroup: false,
- },
propsData: {
workItemId,
workItemIid,
diff --git a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb
index 00b12431560..2c786d4fb2d 100644
--- a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb
+++ b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb
@@ -421,6 +421,18 @@ RSpec.describe Gitlab::Ci::Config::Interpolation::Inputs, feature_category: :pip
end
end
+ context 'when given a value that is not a string' do
+ let(:specs) { { test_input: { regex: '^input_value$' } } }
+ let(:args) { { test_input: 999 } }
+
+ it 'is invalid' do
+ expect(inputs).not_to be_valid
+ expect(inputs.errors).to contain_exactly(
+ '`test_input` input: provided value is not a string'
+ )
+ end
+ end
+
context 'when the pattern is unsafe' do
let(:specs) { { test_input: { regex: 'a++' } } }
let(:args) { { test_input: 'aaaaaaaaaaaaaaaaaaaaa' } }
diff --git a/spec/lib/gitlab/pages/random_domain_spec.rb b/spec/lib/gitlab/pages/random_domain_spec.rb
index 978412bb72c..697f3360a42 100644
--- a/spec/lib/gitlab/pages/random_domain_spec.rb
+++ b/spec/lib/gitlab/pages/random_domain_spec.rb
@@ -3,10 +3,8 @@
require 'spec_helper'
RSpec.describe Gitlab::Pages::RandomDomain, feature_category: :pages do
- let(:namespace_path) { 'namespace' }
-
subject(:generator) do
- described_class.new(project_path: project_path, namespace_path: namespace_path)
+ described_class.new(project_path: project_path)
end
RSpec.shared_examples 'random domain' do |domain|
@@ -14,31 +12,30 @@ RSpec.describe Gitlab::Pages::RandomDomain, feature_category: :pages do
expect(SecureRandom)
.to receive(:hex)
.and_wrap_original do |_, size, _|
- ('h' * size)
+ ('h' * size * 2)
end
generated = generator.generate
expect(generated).to eq(domain)
- expect(generated.length).to eq(63)
end
end
context 'when project path is less than 48 chars' do
let(:project_path) { 'p' }
- it_behaves_like 'random domain', 'p-namespace-hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh'
+ it_behaves_like 'random domain', 'p-hhhhhh'
end
context 'when project path is close to 48 chars' do
- let(:project_path) { 'p' * 45 }
+ let(:project_path) { 'p' * 56 }
- it_behaves_like 'random domain', 'ppppppppppppppppppppppppppppppppppppppppppppp-na-hhhhhhhhhhhhhh'
+ it_behaves_like 'random domain', 'pppppppppppppppppppppppppppppppppppppppppppppppppppppppp-hhhhhh'
end
context 'when project path is larger than 48 chars' do
- let(:project_path) { 'p' * 49 }
+ let(:project_path) { 'p' * 57 }
- it_behaves_like 'random domain', 'pppppppppppppppppppppppppppppppppppppppppppppppp-hhhhhhhhhhhhhh'
+ it_behaves_like 'random domain', 'pppppppppppppppppppppppppppppppppppppppppppppppppppppppp-hhhhhh'
end
end
diff --git a/spec/lib/gitlab/pages_spec.rb b/spec/lib/gitlab/pages_spec.rb
index c20956788ac..928e5a6c461 100644
--- a/spec/lib/gitlab/pages_spec.rb
+++ b/spec/lib/gitlab/pages_spec.rb
@@ -131,6 +131,36 @@ RSpec.describe Gitlab::Pages, feature_category: :pages do
expect(project.project_setting.pages_unique_domain).to eq('unique-domain')
end
end
+
+ context 'when a unique domain is already in use and needs to generate a new one' do
+ it 'generates a different unique domain if the original is already taken' do
+ allow(Gitlab::Pages::RandomDomain).to receive(:generate).and_return('existing-domain', 'new-unique-domain')
+
+ # Simulate the existing domain being in use
+ create(:project_setting, pages_unique_domain: 'existing-domain')
+
+ described_class.add_unique_domain_to(project)
+
+ expect(project.project_setting.pages_unique_domain_enabled).to eq(true)
+ expect(project.project_setting.pages_unique_domain).to eq('new-unique-domain')
+ end
+ end
+
+ context 'when generated 10 unique domains are already in use' do
+ it 'raises an error' do
+ allow(Gitlab::Pages::RandomDomain).to receive(:generate).and_return('existing-domain')
+
+ # Simulate the existing domain being in use
+ create(:project_setting, pages_unique_domain: 'existing-domain')
+
+ expect { described_class.add_unique_domain_to(project) }.to raise_error(
+ described_class::UniqueDomainGenerationFailure,
+ "Can't generate unique domain for GitLab Pages"
+ )
+
+ expect(project.project_setting.pages_unique_domain).to be_nil
+ end
+ end
end
end
end
diff --git a/spec/models/packages/generic/package_spec.rb b/spec/models/packages/generic/package_spec.rb
new file mode 100644
index 00000000000..a6818572d5e
--- /dev/null
+++ b/spec/models/packages/generic/package_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Generic::Package, type: :model, feature_category: :package_registry do
+ describe 'validations' do
+ describe '#name' do
+ it { is_expected.to allow_value('123').for(:name) }
+ it { is_expected.to allow_value('foo').for(:name) }
+ it { is_expected.to allow_value('foo.bar.baz-2.0-20190901.47283-1').for(:name) }
+ it { is_expected.not_to allow_value('../../foo').for(:name) }
+ it { is_expected.not_to allow_value('..\..\foo').for(:name) }
+ it { is_expected.not_to allow_value('%2f%2e%2e%2f%2essh%2fauthorized_keys').for(:name) }
+ it { is_expected.not_to allow_value('$foo/bar').for(:name) }
+ it { is_expected.not_to allow_value('my file name').for(:name) }
+ it { is_expected.not_to allow_value('!!().for(:name)().for(:name)').for(:name) }
+ end
+
+ describe '#version' do
+ it { is_expected.to validate_presence_of(:version) }
+ it { is_expected.to allow_value('1.2.3').for(:version) }
+ it { is_expected.to allow_value('1.3.350').for(:version) }
+ it { is_expected.to allow_value('1.3.350-20201230123456').for(:version) }
+ it { is_expected.to allow_value('1.2.3-rc1').for(:version) }
+ it { is_expected.to allow_value('1.2.3g').for(:version) }
+ it { is_expected.to allow_value('1.2').for(:version) }
+ it { is_expected.to allow_value('1.2.bananas').for(:version) }
+ it { is_expected.to allow_value('v1.2.4-build').for(:version) }
+ it { is_expected.to allow_value('d50d836eb3de6177ce6c7a5482f27f9c2c84b672').for(:version) }
+ it { is_expected.to allow_value('this_is_a_string_only').for(:version) }
+ it { is_expected.not_to allow_value('..1.2.3').for(:version) }
+ it { is_expected.not_to allow_value(' 1.2.3').for(:version) }
+ it { is_expected.not_to allow_value("1.2.3 \r\t").for(:version) }
+ it { is_expected.not_to allow_value("\r\t 1.2.3").for(:version) }
+ it { is_expected.not_to allow_value('1.2.3-4/../../').for(:version) }
+ it { is_expected.not_to allow_value('1.2.3-4%2e%2e%').for(:version) }
+ it { is_expected.not_to allow_value('../../../../../1.2.3').for(:version) }
+ it { is_expected.not_to allow_value('%2e%2e%2f1.2.3').for(:version) }
+ it { is_expected.not_to allow_value('').for(:version) }
+ it { is_expected.not_to allow_value(nil).for(:version) }
+ end
+ end
+
+ describe '#publish_creation_event' do
+ let_it_be(:project) { create(:project) }
+
+ let(:version) { '-' }
+
+ subject(:create_package) { described_class.create!(project: project, name: 'incoming', version: version) }
+
+ it 'publishes an event' do
+ expect { create_package }
+ .to publish_event(::Packages::PackageCreatedEvent)
+ .with({
+ project_id: project.id,
+ id: kind_of(Numeric),
+ name: 'incoming',
+ version: '-',
+ package_type: 'generic'
+ })
+ end
+ end
+end
diff --git a/spec/models/packages/package_spec.rb b/spec/models/packages/package_spec.rb
index 2ab1e03d3f4..b6ef96d7f4f 100644
--- a/spec/models/packages/package_spec.rb
+++ b/spec/models/packages/package_spec.rb
@@ -111,6 +111,8 @@ RSpec.describe Packages::Package, type: :model, feature_category: :package_regis
it { is_expected.to allow_value("my.app-11.07.2018").for(:name) }
it { is_expected.not_to allow_value("my(dom$$$ain)com.my-app").for(:name) }
+ # TODO: Remove with the rollout of the FF generic_extract_generic_package_model
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/479933
context 'generic package' do
subject { build_stubbed(:generic_package) }
@@ -262,6 +264,8 @@ RSpec.describe Packages::Package, type: :model, feature_category: :package_regis
it { is_expected.not_to allow_value('%2e%2e%2f1.2.3').for(:version) }
end
+ # TODO: Remove with the rollout of the FF generic_extract_generic_package_model
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/479933
context 'generic package' do
subject { build_stubbed(:generic_package) }
@@ -1173,34 +1177,65 @@ RSpec.describe Packages::Package, type: :model, feature_category: :package_regis
it { is_expected.to eq(normalized_version) }
end
- describe "#publish_creation_event" do
+ describe '#publish_creation_event' do
let_it_be(:project) { create(:project) }
- let(:version) { '-' }
- let(:package_type) { :generic }
+ let(:package) { build_stubbed(:generic_package) }
- subject { described_class.create!(project: project, name: 'incoming', version: version, package_type: package_type) }
-
- context 'when package is generic' do
- it 'publishes an event' do
- expect { subject }
- .to publish_event(::Packages::PackageCreatedEvent)
- .with({
- project_id: project.id,
- id: kind_of(Numeric),
- name: "incoming",
- version: "-",
- package_type: 'generic'
- })
- end
+ it 'publishes an event' do
+ expect { package.publish_creation_event }
+ .to publish_event(::Packages::PackageCreatedEvent)
+ .with({
+ project_id: package.project_id,
+ id: package.id,
+ name: package.name,
+ version: package.version,
+ package_type: package.package_type
+ })
end
- context 'when package is not generic' do
- let(:package_type) { :debian }
- let(:version) { 1 }
+ # TODO: Remove with the rollout of the FF generic_extract_generic_package_model
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/479933
+ context 'with after_create_commit callback' do
+ let(:name) { FFaker::Lorem.word }
+ let(:version) { '1.0.0' }
- it 'does not create event' do
- expect { subject }.not_to publish_event(::Packages::PackageCreatedEvent)
+ subject(:create_package) do
+ described_class.create!(project: project, name: name, version: version, package_type: package_type)
+ end
+
+ context 'when package is generic' do
+ let(:package_type) { 'generic' }
+
+ it 'does not create event' do
+ expect { create_package }.not_to publish_event(::Packages::PackageCreatedEvent)
+ end
+
+ context 'when generic_extract_generic_package_model is disabled' do
+ before do
+ stub_feature_flags(generic_extract_generic_package_model: false)
+ end
+
+ it 'publishes an event' do
+ expect { create_package }
+ .to publish_event(::Packages::PackageCreatedEvent)
+ .with({
+ project_id: project.id,
+ id: kind_of(Numeric),
+ name: name,
+ version: version,
+ package_type: package_type
+ })
+ end
+ end
+ end
+
+ context 'when package is not generic' do
+ let(:package_type) { 'debian' }
+
+ it 'does not create event' do
+ expect { create_package }.not_to publish_event(::Packages::PackageCreatedEvent)
+ end
end
end
end
@@ -1237,5 +1272,19 @@ RSpec.describe Packages::Package, type: :model, feature_category: :package_regis
end
end
end
+
+ context 'when generic_extract_generic_package_model is disabled' do
+ before do
+ stub_feature_flags(generic_extract_generic_package_model: false)
+ end
+
+ context 'for package format generic' do
+ let(:format) { :generic }
+
+ it 'maps to Packages::Package' do
+ is_expected.to eq(described_class)
+ end
+ end
+ end
end
end