diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-22 13:39:34 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-09-22 13:39:34 +0000 |
commit | e23c409e66b47a970a3cb83ac15d2ff906e75ce0 (patch) | |
tree | b1d580cd64c5d67a81a9445da42e82ceeefa96c5 | |
parent | 2fa173410ad24b37aba6450ae4530ec231844d86 (diff) | |
download | gitlab-ce-e23c409e66b47a970a3cb83ac15d2ff906e75ce0.tar.gz |
Add latest changes from gitlab-org/gitlab@master
112 files changed, 7733 insertions, 555 deletions
diff --git a/.gitlab/issue_templates/Actionable Insight - Exploration needed.md b/.gitlab/issue_templates/Actionable Insight - Exploration needed.md index 76316fc626d..e410715909c 100644 --- a/.gitlab/issue_templates/Actionable Insight - Exploration needed.md +++ b/.gitlab/issue_templates/Actionable Insight - Exploration needed.md @@ -1,4 +1,4 @@ -<!-- Actionable insights must recommend an action that needs to take place. An actionable insight both defines the insight and clearly calls out action or next step required to improve based on the result of the research observation or data. Actionable insights are tracked over time and will include follow-up. Please follow the tasks outlined in this issue for best results. Learn more in the handbook here: https://about.gitlab.com/handbook/engineering/ux/ux-research-training/research-insights/#actionable-insights +<!-- Actionable insights must recommend an action that needs to take place. An actionable insight both defines the insight and clearly calls out action or next step required to improve based on the result of the research observation or data. Actionable insights are tracked over time and will include follow-up. Please follow the tasks outlined in this issue for best results. Learn more in the handbook here: https://about.gitlab.com/handbook/product/ux/ux-research-training/research-insights/#actionable-insights This issue template is for an actionable insight that requires further exploration.--> diff --git a/.gitlab/issue_templates/Actionable Insight - Product change.md b/.gitlab/issue_templates/Actionable Insight - Product change.md index 6c030220636..fba467afd0e 100644 --- a/.gitlab/issue_templates/Actionable Insight - Product change.md +++ b/.gitlab/issue_templates/Actionable Insight - Product change.md @@ -1,4 +1,4 @@ -<!-- Actionable insights must recommend an action that needs to take place. An actionable insight both defines the insight and clearly calls out action or next step required to improve based on the result of the research observation or data. Actionable insights are tracked over time and will include follow-up. Please follow the tasks outlined in this issue for best results. Learn more in the handbook here: https://about.gitlab.com/handbook/engineering/ux/ux-research-training/research-insights/#actionable-insights +<!-- Actionable insights must recommend an action that needs to take place. An actionable insight both defines the insight and clearly calls out action or next step required to improve based on the result of the research observation or data. Actionable insights are tracked over time and will include follow-up. Please follow the tasks outlined in this issue for best results. Learn more in the handbook here: https://about.gitlab.com/handbook/product/ux/ux-research-training/research-insights/#actionable-insights This issue template is for an actionable insight that requires a change in the product.--> diff --git a/.gitlab/issue_templates/Feature proposal - detailed.md b/.gitlab/issue_templates/Feature proposal - detailed.md index 48052ed49ea..9eac2ca27c5 100644 --- a/.gitlab/issue_templates/Feature proposal - detailed.md +++ b/.gitlab/issue_templates/Feature proposal - detailed.md @@ -37,7 +37,7 @@ Personas are described at https://about.gitlab.com/handbook/marketing/product-ma <!-- What is the single user experience workflow this problem addresses? For example, "The user should be able to use the UI/API/.gitlab-ci.yml with GitLab to <perform a specific task>" -https://about.gitlab.com/handbook/engineering/ux/ux-research-training/user-story-mapping/ --> +https://about.gitlab.com/handbook/product/ux/ux-research-training/user-story-mapping/ --> ### Proposal diff --git a/.gitlab/issue_templates/Solution Validation.md b/.gitlab/issue_templates/Solution Validation.md index 27f97d8dd12..e7ab7fe820f 100644 --- a/.gitlab/issue_templates/Solution Validation.md +++ b/.gitlab/issue_templates/Solution Validation.md @@ -26,7 +26,7 @@ <!-- #### TODO Checklist Consider adding a checklist in order to keep track of what stage the research is up to. Some possible checklist templates are here: - https://about.gitlab.com/handbook/engineering/ux/ux-research-training/templates-resources-for-research-studies/#checklists + https://about.gitlab.com/handbook/product/ux/ux-research-training/templates-resources-for-research-studies/#checklists --> /label ~"workflow::solution validation"
\ No newline at end of file diff --git a/.gitlab/issue_templates/UX Theme.md b/.gitlab/issue_templates/UX Theme.md index 043cb705352..2ba60523e20 100644 --- a/.gitlab/issue_templates/UX Theme.md +++ b/.gitlab/issue_templates/UX Theme.md @@ -1,6 +1,6 @@ <!-- A majority of the work designers do will be on themes in the (Now) Next 1-3 milestone column. These themes are comprised of high-confidence outcomes and validated needs. The UX theme issue is where collaboration should occur, including plans and discussion on subthemes, research, and design feedback. Related issues for design exploration and solution validation should stem from the theme issue. -One of the advantages of working with UX themes is that it allows us to think and design holistically by designing the theme as a whole as opposed to a single issue at a time trying to piece them together as you go. For more details please refer to this section of the handbook when creating UX Themes: https://about.gitlab.com/handbook/engineering/ux/product-design/ux-roadmaps/#theme-structure --> +One of the advantages of working with UX themes is that it allows us to think and design holistically by designing the theme as a whole as opposed to a single issue at a time trying to piece them together as you go. For more details please refer to this section of the handbook when creating UX Themes: https://about.gitlab.com/handbook/product/ux/product-design/ux-roadmaps/#theme-structure --> ### UX Theme <!-- A theme is written as a statement that combines the beneficiary, their need, and the expected outcome when the work is delivered. Well-defined statements are concise without sacrificing the substance of the theme so that anyone can understand it at a glance. (For instance; Reduce the effort for security teams to identify and escalate business-critical risks) @@ -37,7 +37,7 @@ One of the advantages of working with UX themes is that it allows us to think an #### Confidence -<!-- How well do we understand the user's problem and their need? Refer to https://about.gitlab.com/handbook/engineering/ux/product-design/ux-roadmaps/#confidence to assess confidence --> +<!-- How well do we understand the user's problem and their need? Refer to https://about.gitlab.com/handbook/product/ux/product-design/ux-roadmaps/#confidence to assess confidence --> | Confidence | Research | @@ -55,7 +55,7 @@ Note: This is not a backlog. If the subthemes can not be delivered in the theme Note: if feature issues already exist then you can add them to this table. Keep in mind that subthemes require validation if they are assumptive -Refer to https://about.gitlab.com/handbook/engineering/ux/product-designer/#ux-issue-weights for calculating UX weights. +Refer to https://about.gitlab.com/handbook/product/ux/product-designer/#ux-issue-weights for calculating UX weights. --> | Issue | UX Weight | diff --git a/.rubocop.yml b/.rubocop.yml index a7fe623aa9e..ee54d03d6af 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -26,7 +26,8 @@ inherit_mode: - Exclude AllCops: - TargetRubyVersion: 2.7 + # Target the current Ruby version. For example, "2.7" or "3.0". + TargetRubyVersion: <%= RUBY_VERSION[/^\d+\.\d+/, 0] %> TargetRailsVersion: 6.0 Exclude: - 'vendor/**/*' @@ -203,7 +203,7 @@ gem 'acts-as-taggable-on', '~> 9.0' # Background jobs gem 'sidekiq', '~> 6.4.0' gem 'sidekiq-cron', '~> 1.4.0' -gem 'redis-namespace', '~> 1.8.1' +gem 'redis-namespace', '~> 1.9.0' gem 'gitlab-sidekiq-fetcher', '0.8.0', require: 'sidekiq-reliable-fetch' # Cron Parser diff --git a/Gemfile.lock b/Gemfile.lock index 784734c11e0..33331a956f7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1132,8 +1132,8 @@ GEM actionpack (>= 5, < 8) redis-rack (>= 2.1.0, < 3) redis-store (>= 1.1.0, < 2) - redis-namespace (1.8.1) - redis (>= 3.0.4) + redis-namespace (1.9.0) + redis (>= 4) redis-rack (2.1.4) rack (>= 2.0.8, < 3) redis-store (>= 1.2, < 2) @@ -1736,7 +1736,7 @@ DEPENDENCIES recaptcha (~> 4.11) redis (~> 4.7.0) redis-actionpack (~> 5.3.0) - redis-namespace (~> 1.8.1) + redis-namespace (~> 1.9.0) request_store (~> 1.5) responders (~> 3.0) retriable (~> 3.1.2) diff --git a/app/assets/javascripts/blob/blob_line_permalink_updater.js b/app/assets/javascripts/blob/blob_line_permalink_updater.js index 0a5bcf326a1..df38c5400e2 100644 --- a/app/assets/javascripts/blob/blob_line_permalink_updater.js +++ b/app/assets/javascripts/blob/blob_line_permalink_updater.js @@ -22,6 +22,7 @@ const updateLineNumbersOnBlobPermalinks = (linksToUpdate) => { }; function BlobLinePermalinkUpdater(blobContentHolder, lineNumberSelector, elementsToUpdate) { + if (!blobContentHolder) return; const updateBlameAndBlobPermalinkCb = () => { // Wait for the hash to update from the LineHighlighter callback setTimeout(() => { diff --git a/app/assets/javascripts/listbox/index.js b/app/assets/javascripts/listbox/index.js index f63171e2785..2eeb0a77032 100644 --- a/app/assets/javascripts/listbox/index.js +++ b/app/assets/javascripts/listbox/index.js @@ -1,4 +1,4 @@ -import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { GlDropdown, GlDropdownItem, GlListbox } from '@gitlab/ui'; import Vue from 'vue'; import { parseBoolean } from '~/lib/utils/common_utils'; @@ -31,6 +31,28 @@ export function initListbox(el, { onChange } = {}) { }, }, render(h) { + if (gon.features?.glListboxForSortDropdowns) { + return h(GlListbox, { + props: { + items, + right, + selected: this.selected, + toggleText: this.text, + }, + class: className, + on: { + select: (selectedValue) => { + this.selected = selectedValue; + const selectedItem = items.find(({ value }) => value === selectedValue); + + if (typeof onChange === 'function') { + onChange(selectedItem); + } + }, + }, + }); + } + return h( GlDropdown, { diff --git a/app/assets/javascripts/repository/components/blob_controls.vue b/app/assets/javascripts/repository/components/blob_controls.vue index fb1227f0df9..8fd17695d4f 100644 --- a/app/assets/javascripts/repository/components/blob_controls.vue +++ b/app/assets/javascripts/repository/components/blob_controls.vue @@ -4,6 +4,8 @@ import { __ } from '~/locale'; import createFlash from '~/flash'; import getRefMixin from '~/repository/mixins/get_ref'; import initSourcegraph from '~/sourcegraph'; +import ShortcutsBlob from '~/behaviors/shortcuts/shortcuts_blob'; +import BlobLinePermalinkUpdater from '~/blob/blob_line_permalink_updater'; import { updateElementsVisibility } from '../utils/dom'; import blobControlsQuery from '../queries/blob_controls.query.graphql'; @@ -84,6 +86,33 @@ export default { }, blobInfo() { initSourcegraph(); + this.$nextTick(() => { + this.initShortcuts(); + this.initLinksUpdate(); + }); + }, + }, + methods: { + initShortcuts() { + const fileBlobPermalinkUrlElement = document.querySelector( + '.js-data-file-blob-permalink-url', + ); + const fileBlobPermalinkUrl = + fileBlobPermalinkUrlElement && fileBlobPermalinkUrlElement.getAttribute('href'); + // eslint-disable-next-line no-new + new ShortcutsBlob({ + skipResetBindings: true, + fileBlobPermalinkUrl, + fileBlobPermalinkUrlElement, + }); + }, + initLinksUpdate() { + // eslint-disable-next-line no-new + new BlobLinePermalinkUpdater( + document.querySelector('.tree-holder'), + '.file-line-num[data-line-number], .file-line-num[data-line-number] *', + document.querySelectorAll('.js-data-file-blob-permalink-url, .js-blob-blame-link'), + ); }, }, }; @@ -99,6 +128,7 @@ export default { data-testid="blame" :href="blobInfo.blamePath" :class="$options.buttonClassList" + class="js-blob-blame-link" > {{ $options.i18n.blame }} </gl-button> diff --git a/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue b/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue index 72148a0aa7c..c91c85d4e33 100644 --- a/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue +++ b/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue @@ -3,6 +3,7 @@ import { GlBadge } from '@gitlab/ui'; import { s__ } from '~/locale'; import axios from '~/lib/utils/axios_utils'; import { joinPaths } from '~/lib/utils/url_utility'; +import { helpPagePath } from '~/helpers/help_page_helper'; const STATUS_TYPES = { SUCCESS: 'success', @@ -10,6 +11,8 @@ const STATUS_TYPES = { DANGER: 'danger', }; +const UPGRADE_DOCS_URL = helpPagePath('update/index'); + export default { name: 'GitlabVersionCheck', components: { @@ -58,11 +61,17 @@ export default { }); }, }, + UPGRADE_DOCS_URL, }; </script> <template> - <gl-badge v-if="status" class="version-check-badge" :variant="status" :size="size">{{ - title - }}</gl-badge> + <gl-badge + v-if="status" + :href="$options.UPGRADE_DOCS_URL" + class="version-check-badge" + :variant="status" + :size="size" + >{{ title }}</gl-badge + > </template> 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 3d25df9fcb8..29d37cd8c99 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -25,6 +25,7 @@ import { import workItemQuery from '../graphql/work_item.query.graphql'; import workItemDatesSubscription from '../graphql/work_item_dates.subscription.graphql'; import workItemTitleSubscription from '../graphql/work_item_title.subscription.graphql'; +import workItemAssigneesSubscription from '../graphql/work_item_assignees.subscription.graphql'; import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql'; import updateWorkItemTaskMutation from '../graphql/update_work_item_task.mutation.graphql'; @@ -130,6 +131,17 @@ export default { return !this.workItemDueDate; }, }, + { + document: workItemAssigneesSubscription, + variables() { + return { + issuableId: this.workItemId, + }; + }, + skip() { + return !this.workItemAssignees; + }, + }, ], }, }, diff --git a/app/assets/javascripts/work_items/graphql/work_item_assignees.subscription.graphql b/app/assets/javascripts/work_items/graphql/work_item_assignees.subscription.graphql new file mode 100644 index 00000000000..95d25121ae4 --- /dev/null +++ b/app/assets/javascripts/work_items/graphql/work_item_assignees.subscription.graphql @@ -0,0 +1,20 @@ +subscription issuableAssignees($issuableId: IssuableID!) { + issuableAssigneesUpdated(issuableId: $issuableId) { + ... on WorkItem { + id + widgets { + ... on WorkItemWidgetAssignees { + assignees { + nodes { + avatarUrl + id + name + username + webUrl + } + } + } + } + } + } +} diff --git a/app/controllers/registrations/welcome_controller.rb b/app/controllers/registrations/welcome_controller.rb index 4e18e6a3b20..829905db955 100644 --- a/app/controllers/registrations/welcome_controller.rb +++ b/app/controllers/registrations/welcome_controller.rb @@ -25,7 +25,7 @@ module Registrations members = current_user.members - if members.count == 1 && members.last.source.present? + if registering_from_invite?(members) redirect_to members_activity_path(members), notice: helpers.invite_accepted_notice(members.last) else redirect_to path_for_signed_in_user(current_user) @@ -37,6 +37,10 @@ module Registrations private + def registering_from_invite?(members) + members.count == 1 && members.last.source.present? + end + def require_current_user return redirect_to new_user_registration_path unless current_user end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index 0bd266bb490..f931a4b3018 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -183,7 +183,7 @@ class RegistrationsController < Devise::RegistrationsController def resource @resource ||= Users::RegistrationsBuildService - .new(current_user, sign_up_params.merge({ skip_confirmation: skip_email_confirmation? })) + .new(current_user, sign_up_params.merge({ skip_confirmation: registered_with_invite_email? })) .execute end @@ -191,7 +191,7 @@ class RegistrationsController < Devise::RegistrationsController @devise_mapping ||= Devise.mappings[:user] end - def skip_email_confirmation? + def registered_with_invite_email? invite_email = session.delete(:invite_email) sign_up_params[:email] == invite_email diff --git a/app/graphql/mutations/work_items/update_widgets.rb b/app/graphql/mutations/work_items/update_widgets.rb deleted file mode 100644 index 7037b7e5a2a..00000000000 --- a/app/graphql/mutations/work_items/update_widgets.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -module Mutations - module WorkItems - # TODO: Deprecate in favor of using WorkItemUpdate. See https://gitlab.com/gitlab-org/gitlab/-/issues/366300 - class UpdateWidgets < BaseMutation - graphql_name 'WorkItemUpdateWidgets' - description "Updates the attributes of a work item's widgets by global ID." \ - " Available only when feature flag `work_items` is enabled." - - include Mutations::SpamProtection - - authorize :update_work_item - - argument :id, ::Types::GlobalIDType[::WorkItem], - required: true, - description: 'Global ID of the work item.' - - argument :description_widget, ::Types::WorkItems::Widgets::DescriptionInputType, - required: false, - description: 'Input for description widget.' - - field :work_item, Types::WorkItemType, - null: true, - description: 'Updated work item.' - - def resolve(id:, **widget_attributes) - work_item = authorized_find!(id: id) - - unless work_item.project.work_items_feature_flag_enabled? - return { errors: ['`work_items` feature flag disabled for this project'] } - end - - spam_params = ::Spam::SpamParams.new_from_request(request: context[:request]) - - ::WorkItems::UpdateService.new( - project: work_item.project, - current_user: current_user, - # Cannot use prepare to use `.to_h` on each input due to - # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87472#note_945199865 - widget_params: widget_attributes.transform_values { |values| values.to_h }, - spam_params: spam_params - ).execute(work_item) - - check_spam_action_response!(work_item) - - { - work_item: work_item.valid? ? work_item : nil, - errors: errors_on_object(work_item) - } - end - - private - - def find_object(id:) - GitlabSchema.find_by_gid(id) - end - end - end -end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index ea833b35085..304bb278afb 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -146,7 +146,6 @@ module Types mount_mutation Mutations::WorkItems::Delete, alpha: { milestone: '15.1' } mount_mutation Mutations::WorkItems::DeleteTask, alpha: { milestone: '15.1' } mount_mutation Mutations::WorkItems::Update, alpha: { milestone: '15.1' } - mount_mutation Mutations::WorkItems::UpdateWidgets, alpha: { milestone: '15.1' } mount_mutation Mutations::WorkItems::UpdateTask, alpha: { milestone: '15.1' } mount_mutation Mutations::SavedReplies::Create mount_mutation Mutations::SavedReplies::Update diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index f77bd6621f9..267371c6b35 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -126,8 +126,8 @@ module GroupsHelper group.root? && current_user.can?(:admin_setting_to_allow_project_access_token_creation, group) end - def show_thanks_for_purchase_alert? - params.key?(:purchased_quantity) && params[:purchased_quantity].to_i > 0 + def show_thanks_for_purchase_alert?(quantity) + quantity.to_i > 0 end def project_list_sort_by diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb index ddb20a835e1..0fa1bb96b13 100644 --- a/app/services/users/build_service.rb +++ b/app/services/users/build_service.rb @@ -106,6 +106,8 @@ module Users def build_user_params_for_non_admin @user_params = params.slice(*signup_params) + # if skip_confirmation is set to `true`, devise will set confirmed_at + # see: https://github.com/heartcombo/devise/blob/8593801130f2df94a50863b5db535c272b00efe1/lib/devise/models/confirmable.rb#L156 @user_params[:skip_confirmation] = skip_user_confirmation_email_from_setting if assign_skip_confirmation_from_settings? @user_params[:name] = fallback_name if use_fallback_name? end diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index f474f8fbd3b..012a31c1ecf 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -3,9 +3,6 @@ - @skip_current_level_breadcrumb = true - add_page_specific_style 'page_bundles/group' -- if show_thanks_for_purchase_alert? - = render_if_exists 'shared/thanks_for_purchase_alert', plan_title: plan_title, quantity: params[:purchased_quantity].to_i - = render_if_exists 'shared/qrtly_reconciliation_alert', group: @group = render_if_exists 'shared/free_user_cap_alert', source: @group diff --git a/app/views/layouts/header/_gitlab_version.html.haml b/app/views/layouts/header/_gitlab_version.html.haml index 125fbaa084c..fae6926a687 100644 --- a/app/views/layouts/header/_gitlab_version.html.haml +++ b/app/views/layouts/header/_gitlab_version.html.haml @@ -1,6 +1,6 @@ - return unless show_version_check? -.gl-display-flex.gl-flex-direction-column.gl-px-4.gl-py-3 +%a{ class: 'gl-display-flex! gl-flex-direction-column gl-px-4! gl-py-3! gl-line-height-24!', href: help_page_path('update/index'), 'data-testid': 'gitlab-version-container' } %span = s_("VersionCheck|Your GitLab Version") = emoji_icon('rocket') diff --git a/app/views/layouts/header/_help_dropdown.html.haml b/app/views/layouts/header/_help_dropdown.html.haml index 3a8f9c1ae8d..bdd1ae291fd 100644 --- a/app/views/layouts/header/_help_dropdown.html.haml +++ b/app/views/layouts/header/_help_dropdown.html.haml @@ -1,6 +1,7 @@ %ul - if current_user_menu?(:help) - = render 'layouts/header/gitlab_version' + %li + = render 'layouts/header/gitlab_version' = render_if_exists 'layouts/header/help_dropdown/cross_stage_fdm' = render 'layouts/header/whats_new_dropdown_item' %li diff --git a/app/workers/concerns/application_worker.rb b/app/workers/concerns/application_worker.rb index c1fec4f0196..f33ab80ece8 100644 --- a/app/workers/concerns/application_worker.rb +++ b/app/workers/concerns/application_worker.rb @@ -134,10 +134,6 @@ module ApplicationWorker @log_bulk_perform_async = true end - def queue_size - Sidekiq::Queue.new(queue).size - end - def bulk_perform_async(args_list) if log_bulk_perform_async? Sidekiq.logger.info('class' => self.name, 'args_list' => args_list, 'args_list_count' => args_list.length, 'message' => 'Inserting multiple jobs') diff --git a/config/application.rb b/config/application.rb index 9c3caee38fc..8464ac97a27 100644 --- a/config/application.rb +++ b/config/application.rb @@ -276,6 +276,7 @@ module Gitlab config.assets.precompile << "page_bundles/ide.css" config.assets.precompile << "page_bundles/import.css" config.assets.precompile << "page_bundles/incident_management_list.css" + config.assets.precompile << "page_bundles/issues_analytics.css" config.assets.precompile << "page_bundles/issues_list.css" config.assets.precompile << "page_bundles/issues_show.css" config.assets.precompile << "page_bundles/jira_connect.css" diff --git a/config/feature_flags/development/gl_listbox_for_sort_dropdowns.yml b/config/feature_flags/development/gl_listbox_for_sort_dropdowns.yml new file mode 100644 index 00000000000..03d930012ab --- /dev/null +++ b/config/feature_flags/development/gl_listbox_for_sort_dropdowns.yml @@ -0,0 +1,8 @@ +--- +name: gl_listbox_for_sort_dropdowns +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98363 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364715 +milestone: '15.5' +type: development +group: group::foundations +default_enabled: false diff --git a/config/feature_flags/development/hash_oauth_tokens.yml b/config/feature_flags/development/hash_oauth_tokens.yml index 43cd5672fc4..96bd4a3702e 100644 --- a/config/feature_flags/development/hash_oauth_tokens.yml +++ b/config/feature_flags/development/hash_oauth_tokens.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367570 milestone: '15.3' type: development group: group::authentication and authorization -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/development/present_groups_select_all.yml b/config/feature_flags/development/present_groups_select_all.yml new file mode 100644 index 00000000000..4d8ac160fa0 --- /dev/null +++ b/config/feature_flags/development/present_groups_select_all.yml @@ -0,0 +1,8 @@ +--- +name: present_groups_select_all +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93633 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/370306 +milestone: '15.5' +type: development +group: group::workspace +default_enabled: false diff --git a/danger/documentation/Dangerfile b/danger/documentation/Dangerfile index 41c75a9f176..eaa1839c8e5 100644 --- a/danger/documentation/Dangerfile +++ b/danger/documentation/Dangerfile @@ -5,7 +5,7 @@ def feature_mr? end DOCUMENTATION_UPDATE_MISSING = <<~MSG -~"feature::addition" and ~"feature::enhancement" merge requests normally have a documentation change. Consider adding a documentation update or confirming the documentation plan with the [Technical Writer counterpart](https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments). +~"feature::addition" and ~"feature::enhancement" merge requests normally have a documentation change. Consider adding a documentation update or confirming the documentation plan with the [Technical Writer counterpart](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments). For more information, see: diff --git a/data/deprecations/templates/_deprecation_template.md.erb b/data/deprecations/templates/_deprecation_template.md.erb index 0725ce2891e..4fd2ca29bc8 100644 --- a/data/deprecations/templates/_deprecation_template.md.erb +++ b/data/deprecations/templates/_deprecation_template.md.erb @@ -1,7 +1,7 @@ --- stage: none group: none -info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" +info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines" --- # Deprecations by version diff --git a/data/removals/templates/_removal_template.md.erb b/data/removals/templates/_removal_template.md.erb index dc779323096..ad0298a6596 100644 --- a/data/removals/templates/_removal_template.md.erb +++ b/data/removals/templates/_removal_template.md.erb @@ -1,7 +1,7 @@ --- stage: none group: none -info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" +info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines" --- # Removals by version diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md index 6fc2282cfe9..a4172703718 100644 --- a/doc/administration/reference_architectures/10k_users.md +++ b/doc/administration/reference_architectures/10k_users.md @@ -38,9 +38,15 @@ full list of reference architectures, see <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> @@ -2319,9 +2325,15 @@ services where applicable): <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md index 0f360ee6ab2..22adce85398 100644 --- a/doc/administration/reference_architectures/25k_users.md +++ b/doc/administration/reference_architectures/25k_users.md @@ -38,9 +38,15 @@ full list of reference architectures, see <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> @@ -2322,9 +2328,15 @@ services where applicable): <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> diff --git a/doc/administration/reference_architectures/2k_users.md b/doc/administration/reference_architectures/2k_users.md index 04f105273ff..09432e8f6d0 100644 --- a/doc/administration/reference_architectures/2k_users.md +++ b/doc/administration/reference_architectures/2k_users.md @@ -31,9 +31,15 @@ For a full list of reference architectures, see | NFS server (non-Gitaly) | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` | `F4s v2` | <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run as reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run as reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. <!-- markdownlint-enable MD029 --> @@ -1026,8 +1032,13 @@ services where applicable): <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. 3. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. <!-- markdownlint-enable MD029 --> diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md index cf3fdb403ea..7cadaff1691 100644 --- a/doc/administration/reference_architectures/3k_users.md +++ b/doc/administration/reference_architectures/3k_users.md @@ -47,9 +47,15 @@ For a full list of reference architectures, see <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> @@ -2283,9 +2289,15 @@ services where applicable): <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md index 58db8836fd1..9d5e1f4b6fc 100644 --- a/doc/administration/reference_architectures/50k_users.md +++ b/doc/administration/reference_architectures/50k_users.md @@ -38,9 +38,15 @@ full list of reference architectures, see <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> @@ -2339,9 +2345,15 @@ services where applicable): <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md index e694173f760..10d3553d88c 100644 --- a/doc/administration/reference_architectures/5k_users.md +++ b/doc/administration/reference_architectures/5k_users.md @@ -44,9 +44,15 @@ costly-to-operate environment by using the <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> @@ -2257,9 +2263,15 @@ services where applicable): <!-- Disable ordered list rule https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md029---ordered-list-item-prefix --> <!-- markdownlint-disable MD029 --> -1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. However, Amazon Aurora is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and Azure Database for PostgreSQL is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). Consul is primarily used for PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. -2. Can be optionally run on reputable third-party external PaaS Redis solutions. Google Memorystore and AWS ElastiCache are known to work. -3. Can be optionally run on reputable third-party load balancing services (LB PaaS). AWS ELB is known to work. +1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work. + - [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. + - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61). + - Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery. +2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work. +3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information. + - [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work. 4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section. 5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`. <!-- markdownlint-enable MD029 --> diff --git a/doc/administration/reference_architectures/index.md b/doc/administration/reference_architectures/index.md index c2ccc237727..d9863b2c16b 100644 --- a/doc/administration/reference_architectures/index.md +++ b/doc/administration/reference_architectures/index.md @@ -366,6 +366,7 @@ Additionally, the following cloud provider services are validated and supported The following specific cloud provider services have been found to have issues in terms of either functionality or performance. As such, they either have caveats that should be considered or are not recommended: +- [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo. - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is incompatible. See [14.4.0](../../update/index.md#1440) for more details. - [Azure Blob Storage](https://azure.microsoft.com/en-gb/services/storage/blobs/) has been found to have performance limits that can impact production use at certain times. For larger Reference Architectures the service may not be sufficient for production use and an alternative is recommended for use instead. - [Azure Database for PostgreSQL Server](https://azure.microsoft.com/en-gb/services/postgresql/#overview) (Single / Flexible) is not recommended for use due to notable performance issues or missing functionality. diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md index f837726be0b..b6651558b55 100644 --- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md +++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md @@ -972,37 +972,7 @@ License.select(&TYPE).each(&:destroy!) ### Registry Disk Space Usage by Project -As a GitLab administrator, you may want to reduce disk space consumption. -A common culprit is Docker Registry images that are no longer in use. To find -the storage broken down by each project, run the following in the -[GitLab Rails console](../operations/rails_console.md): - -```ruby -projects_and_size = [["project_id", "creator_id", "registry_size_bytes", "project path"]] -# You need to specify the projects that you want to look through. You can get these in any manner. -projects = Project.last(100) - -projects.each do |p| - project_total_size = 0 - container_repositories = p.container_repositories - - container_repositories.each do |c| - c.tags.each do |t| - project_total_size = project_total_size + t.total_size unless t.total_size.nil? - end - end - - if project_total_size > 0 - projects_and_size << [p.project_id, p.creator.id, project_total_size, p.full_path] - end -end - -# projects_and_size is filled out now -# maybe print it as comma separated output? -projects_and_size.each do |ps| - puts "%s,%s,%s,%s" % ps -end -``` +Find this content in the [Container Registry troubleshooting documentation](../packages/container_registry.md#registry-disk-space-usage-by-project). ### Run the Cleanup policy now diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md index eab48d65742..b7b7eb15c3e 100644 --- a/doc/api/graphql/index.md +++ b/doc/api/graphql/index.md @@ -1,7 +1,7 @@ --- stage: Ecosystem group: Integrations -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments --- # GraphQL API **(FREE)** diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 7270d884102..f26ed7cebba 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -5859,32 +5859,6 @@ Input type: `WorkItemUpdateTaskInput` | <a id="mutationworkitemupdatetasktask"></a>`task` | [`WorkItem`](#workitem) | Updated task. | | <a id="mutationworkitemupdatetaskworkitem"></a>`workItem` | [`WorkItem`](#workitem) | Updated work item. | -### `Mutation.workItemUpdateWidgets` - -Updates the attributes of a work item's widgets by global ID. Available only when feature flag `work_items` is enabled. - -WARNING: -**Introduced** in 15.1. -This feature is in Alpha. It can be changed or removed at any time. - -Input type: `WorkItemUpdateWidgetsInput` - -#### Arguments - -| Name | Type | Description | -| ---- | ---- | ----------- | -| <a id="mutationworkitemupdatewidgetsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | -| <a id="mutationworkitemupdatewidgetsdescriptionwidget"></a>`descriptionWidget` | [`WorkItemWidgetDescriptionInput`](#workitemwidgetdescriptioninput) | Input for description widget. | -| <a id="mutationworkitemupdatewidgetsid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. | - -#### Fields - -| Name | Type | Description | -| ---- | ---- | ----------- | -| <a id="mutationworkitemupdatewidgetsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | -| <a id="mutationworkitemupdatewidgetserrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | -| <a id="mutationworkitemupdatewidgetsworkitem"></a>`workItem` | [`WorkItem`](#workitem) | Updated work item. | - ## Connections Some types in our schema are `Connection` types - they represent a paginated diff --git a/doc/development/contributing/design.md b/doc/development/contributing/design.md index 28def7422bf..37be11d00cc 100644 --- a/doc/development/contributing/design.md +++ b/doc/development/contributing/design.md @@ -100,7 +100,7 @@ When the design is ready, _before_ starting its implementation: - Share design specifications in the related issue, preferably through a [Figma link](https://help.figma.com/hc/en-us/articles/360040531773-Share-Files-with-anyone-using-Link-Sharing#copy-link) link or [GitLab Designs feature](../../user/project/issues/design_management.md). - See [when you should use each tool](https://about.gitlab.com/handbook/engineering/ux/product-designer/#deliver). + See [when you should use each tool](https://about.gitlab.com/handbook/product/ux/product-designer/#deliver). - Document user flow and states (for example, using [Mermaid flowcharts in Markdown](../../user/markdown.md#mermaid)). - Document animations and transitions. - Document responsive behaviors. diff --git a/doc/development/development_processes.md b/doc/development/development_processes.md index 5035790f713..53b129f7d6e 100644 --- a/doc/development/development_processes.md +++ b/doc/development/development_processes.md @@ -79,7 +79,7 @@ In these cases, use the following workflow: - [Frontend](https://about.gitlab.com/handbook/engineering/frontend/) - [Backend](https://about.gitlab.com/handbook/engineering/) - [Database](https://about.gitlab.com/handbook/engineering/development/database/) - - [User Experience (UX)](https://about.gitlab.com/handbook/engineering/ux/) + - [User Experience (UX)](https://about.gitlab.com/handbook/product/ux/) - [Security](https://about.gitlab.com/handbook/engineering/security/) - [Quality](https://about.gitlab.com/handbook/engineering/quality/) - [Engineering Productivity](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/) diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index 6dcc57b0ff5..642d94fafab 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -2,7 +2,7 @@ type: reference, dev stage: none group: Development -info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" +info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines" --- # GraphQL diff --git a/doc/development/merge_request_concepts/index.md b/doc/development/merge_request_concepts/index.md index d463f6ba290..14d9582ad84 100644 --- a/doc/development/merge_request_concepts/index.md +++ b/doc/development/merge_request_concepts/index.md @@ -2,7 +2,7 @@ type: reference, dev stage: Create group: Code Review -info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" +info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines" --- # Merge request concepts diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md index 222a670f110..05e952fb31a 100644 --- a/doc/development/pipelines.md +++ b/doc/development/pipelines.md @@ -62,6 +62,8 @@ The test mappings contain a map of each source files to a list of test files whi In the `detect-tests` job, we use this mapping to identify the minimal tests needed for the current merge request. +Later on in [the `rspec fail-fast` job](#fail-fast-job-in-merge-request-pipelines), we run the minimal tests needed for the current merge request. + #### Exceptional cases In addition, there are a few circumstances where we would always run the full RSpec tests: @@ -97,18 +99,6 @@ label is set on the MR. The goal is to reduce the CI/CD minutes consumed by fork See the [experiment issue](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1170). -## Faster feedback when reverting merge requests - -When you need to revert a merge request, to get accelerated feedback, you can add the `~pipeline:revert` label to your merge request. - -When this label is assigned, the following steps of the CI/CD pipeline are skipped: - -- The `e2e:package-and-test` job. -- The `rspec:undercoverage` job. -- The entire [Review Apps process](testing_guide/review_apps.md). - -Apply the label to the merge request, and run a new pipeline for the MR. - ## Fail-fast job in merge request pipelines To provide faster feedback when a merge request breaks existing tests, we are experimenting with a @@ -155,6 +145,18 @@ merge request. This prevents `rspec fail-fast` duration from exceeding the avera This number can be overridden by setting a CI/CD variable named `RSPEC_FAIL_FAST_TEST_FILE_COUNT_THRESHOLD`. +## Faster feedback when reverting merge requests + +When you need to revert a merge request, to get accelerated feedback, you can add the `~pipeline:revert` label to your merge request. + +When this label is assigned, the following steps of the CI/CD pipeline are skipped: + +- The `e2e:package-and-test` job. +- The `rspec:undercoverage` job. +- The entire [Review Apps process](testing_guide/review_apps.md). + +Apply the label to the merge request, and run a new pipeline for the MR. + ## Test jobs We have dedicated jobs for each [testing level](testing_guide/testing_levels.md) and each job runs depending on the diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md index 221d6b89b20..f1a23f06699 100644 --- a/doc/development/testing_guide/best_practices.md +++ b/doc/development/testing_guide/best_practices.md @@ -2,7 +2,7 @@ type: reference, dev stage: none group: Development -info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" +info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines" description: "GitLab development guidelines - testing best practices." --- diff --git a/doc/development/work_items.md b/doc/development/work_items.md index a6a2b7da5e4..5f0ef88f200 100644 --- a/doc/development/work_items.md +++ b/doc/development/work_items.md @@ -150,8 +150,27 @@ of widgets. In order to customize each WIT with corresponding active widgets we will need a data structure to map each WIT to specific widgets. +The intent is for work item types to be highly configurable, both by GitLab for +implementing various work item schemes for customers (an opinionated GitLab +workflow, or SAFe 5, etc), and eventually for customers to customize their own +workflows. + +In this case, a work item scheme would be defined as a set of types with +certain characteristics (some widgets enabled, others not), such as an Epic, +Story, Bug, and Task, etc. + +As we're building a new work item architecture, we want to build the ability to +define these various types in a very flexible manner. Having GitLab use +this system first (without introducing customer customization) allows us to +better build out the initial system. + NOTE: -The exact structure of the WITs widgets metadata is still to be defined. +Currently work item's `base_type` is used to define static mapping of what +widgets are available for each type (current status), this definition should be +rather stored in database table. The exact structure of the WIT widgets +metadata is still to be defined. `base_type` was added to help converting other +types of resources (requirements and incidents) into work items. Eventually (when +these resources become regular work items), `base_type` will be removed. ### Custom work item types diff --git a/doc/development/workspace/index.md b/doc/development/workspace/index.md index b01a7826b3d..f4738e3fc31 100644 --- a/doc/development/workspace/index.md +++ b/doc/development/workspace/index.md @@ -3,7 +3,7 @@ comments: false type: index, dev stage: none group: Development -info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" +info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines" description: "Development Guidelines: learn about workspace when developing GitLab." --- diff --git a/doc/drawers/advanced_search_syntax.md b/doc/drawers/advanced_search_syntax.md index c48efbc120a..3c2ce212b99 100644 --- a/doc/drawers/advanced_search_syntax.md +++ b/doc/drawers/advanced_search_syntax.md @@ -1,7 +1,7 @@ --- stage: Data Stores group: Global Search -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: drawer source: /doc/user/search/global_search/advanced_search_syntax.md --- diff --git a/doc/gitlab-basics/add-file.md b/doc/gitlab-basics/add-file.md index af736c11d59..64384372a44 100644 --- a/doc/gitlab-basics/add-file.md +++ b/doc/gitlab-basics/add-file.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: howto --- diff --git a/doc/gitlab-basics/feature_branch_workflow.md b/doc/gitlab-basics/feature_branch_workflow.md index 989a1557ef2..de051c67bc2 100644 --- a/doc/gitlab-basics/feature_branch_workflow.md +++ b/doc/gitlab-basics/feature_branch_workflow.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" disqus_identifier: 'https://docs.gitlab.com/ee/workflow/workflow.html' --- diff --git a/doc/integration/gitpod.md b/doc/integration/gitpod.md index c2b27e79d6e..26d0da4b49d 100644 --- a/doc/integration/gitpod.md +++ b/doc/integration/gitpod.md @@ -2,7 +2,7 @@ type: reference, how-to stage: Create group: Editor -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" --- # Gitpod integration **(FREE)** diff --git a/doc/integration/kerberos.md b/doc/integration/kerberos.md index 5c9af96ebe8..bcdacc3a0a6 100644 --- a/doc/integration/kerberos.md +++ b/doc/integration/kerberos.md @@ -1,7 +1,7 @@ --- stage: Manage group: Authentication and Authorization -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" --- # Kerberos integration **(PREMIUM SELF)** diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md index 99f8f9ff783..19f9592c7ca 100644 --- a/doc/integration/oauth_provider.md +++ b/doc/integration/oauth_provider.md @@ -137,3 +137,17 @@ On self-managed GitLab, by default, this feature is not available. To make it av On GitLab.com, this feature is not available. By default, OAuth application secrets are stored as plain text in the database. When enabled, OAuth application secrets are stored in the database in hashed format and are only available to users immediately after creating OAuth applications. + +## Hashed OAuth tokens + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/364110) in GitLab 15.3 [with a flag](../administration/feature_flags.md) named `hash_oauth_tokens`. Enabled on GitLab.com. Disabled by default for self-managed. +> - [Enabled by default on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/337507) in GitLab 15.5. + +FLAG: +On self-managed GitLab, by default, this feature is enabled. If you detect a problem, ask an administrator to +[disable the feature flag](../administration/feature_flags.md) named `hash_oauth_tokens`. If the feature flag is disabled, any tokens that were stored +in encrypted format are inaccessible. Users must reauthorize applications. +On GitLab.com, this feature is enabled. + +By default, OAuth access tokens are stored in the database in PBKDF2+SHA512 format. GitLab administrators can disable this and OAuth access tokens are +then stored in plaintext in the database. diff --git a/doc/integration/sourcegraph.md b/doc/integration/sourcegraph.md index 731c21c17fa..39efccb7c50 100644 --- a/doc/integration/sourcegraph.md +++ b/doc/integration/sourcegraph.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: reference, how-to --- diff --git a/doc/security/index.md b/doc/security/index.md index fbd9a94fc9b..ff0769e0d93 100644 --- a/doc/security/index.md +++ b/doc/security/index.md @@ -8,7 +8,7 @@ type: index # Security **(FREE)** -- [Password storage](password_storage.md) +- [Passwords and OAuth tokens storage](password_storage.md) - [Password length limits](password_length_limits.md) - [Generated passwords for users created through integrated authentication](passwords_for_integrated_authentication_methods.md) - [Restrict SSH key technologies and minimum length](ssh_keys_restrictions.md) diff --git a/doc/security/password_storage.md b/doc/security/password_storage.md index 076d20c427a..518b1d9ac88 100644 --- a/doc/security/password_storage.md +++ b/doc/security/password_storage.md @@ -5,7 +5,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w type: reference --- -# Password storage **(FREE)** +# Password and OAuth token storage **(FREE)** + +GitLab administrators can configure how passwords and OAuth tokens are stored. + +## Password storage **(FREE)** > PBKDF2 and SHA512 [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/360658) in GitLab 15.2 [with flags](../administration/feature_flags.md) named `pbkdf2_password_encryption` and `pbkdf2_password_encryption_write`. Disabled by default. @@ -37,3 +41,13 @@ library to hash user passwords. Created password hashes have these attributes: is added to each password to harden against pre-computed hash and dictionary attacks. To increase security, each salt is randomly generated for each password, with no two passwords sharing a salt. + +## OAuth access token storage + +> - PBKDF2+SHA512 [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/364110) in GitLab 15.3 [with flag](../administration/feature_flags.md) named `hash_oauth_tokens`. +> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98242) in GitLab 15.5. + +Depending on your version of GitLab and configuration, OAuth access tokens are stored in the database in PBKDF2+SHA512 format. For version information, see +the relevant [OAuth provider documentation](../integration/oauth_provider.md#hashed-oauth-tokens). + +As with PBKDF2+SHA512 password storage, access token values are [stretched](https://en.wikipedia.org/wiki/Key_stretching) 20,000 times to harden against brute-force attacks. diff --git a/doc/topics/git/feature_branch_development.md b/doc/topics/git/feature_branch_development.md index b205cedbdaa..de9f9980811 100644 --- a/doc/topics/git/feature_branch_development.md +++ b/doc/topics/git/feature_branch_development.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: how-tos --- diff --git a/doc/topics/git/git_rebase.md b/doc/topics/git/git_rebase.md index 1e118f98ca5..2f12201fb45 100644 --- a/doc/topics/git/git_rebase.md +++ b/doc/topics/git/git_rebase.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: concepts, howto description: "Introduction to Git rebase and force-push, methods to resolve merge conflicts through the command line." --- diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md index 3e78e366e00..f5dd458f625 100644 --- a/doc/topics/git/index.md +++ b/doc/topics/git/index.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: index --- diff --git a/doc/topics/git/lfs/index.md b/doc/topics/git/lfs/index.md index 6fd7f4a5207..1ab4a8a8acc 100644 --- a/doc/topics/git/lfs/index.md +++ b/doc/topics/git/lfs/index.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: reference, howto disqus_identifier: 'https://docs.gitlab.com/ee/workflow/lfs/lfs/index.html' --- diff --git a/doc/topics/git/partial_clone.md b/doc/topics/git/partial_clone.md index eeae0d78638..ed80ab71c53 100644 --- a/doc/topics/git/partial_clone.md +++ b/doc/topics/git/partial_clone.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: reference, howto --- diff --git a/doc/topics/git/troubleshooting_git.md b/doc/topics/git/troubleshooting_git.md index 484f3a100bf..e585b860b16 100644 --- a/doc/topics/git/troubleshooting_git.md +++ b/doc/topics/git/troubleshooting_git.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: howto --- diff --git a/doc/topics/git/useful_git_commands.md b/doc/topics/git/useful_git_commands.md index 13a40dd58ca..26ad155054b 100644 --- a/doc/topics/git/useful_git_commands.md +++ b/doc/topics/git/useful_git_commands.md @@ -1,7 +1,7 @@ --- stage: Create group: Source Code -info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments" +info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments" type: reference --- diff --git a/doc/tutorials/index.md b/doc/tutorials/index.md index 8b2ad1173fc..428b90ab17d 100644 --- a/doc/tutorials/index.md +++ b/doc/tutorials/index.md @@ -1,7 +1,7 @@ --- stage: none group: unassigned -info: For assistance with this tutorials page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-other-projects-and-subjects. +info: For assistance with this tutorials page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects. --- # Learn GitLab with tutorials diff --git a/doc/tutorials/make_your_first_git_commit.md b/doc/tutorials/make_your_first_git_commit.md index 879257fc3b8..cb6f41bff6c 100644 --- a/doc/tutorials/make_your_first_git_commit.md +++ b/doc/tutorials/make_your_first_git_commit.md @@ -1,7 +1,7 @@ --- stage: none group: unassigned -info: For assistance with this tutorial, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-other-projects-and-subjects. +info: For assistance with this tutorial, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects. --- # Make your first Git commit diff --git a/doc/tutorials/move_personal_project_to_a_group.md b/doc/tutorials/move_personal_project_to_a_group.md index 49ce09a2ed4..2106f6ec1c9 100644 --- a/doc/tutorials/move_personal_project_to_a_group.md +++ b/doc/tutorials/move_personal_project_to_a_group.md @@ -1,7 +1,7 @@ --- stage: none group: unassigned -info: For assistance with this tutorial, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-other-projects-and-subjects. +info: For assistance with this tutorial, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects. --- # Move your personal project to a group **(FREE SAAS)** diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md index 44a7137f698..5a9ba616d8f 100644 --- a/doc/update/deprecations.md +++ b/doc/update/deprecations.md @@ -1,7 +1,7 @@ --- stage: none group: none -info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" +info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines" --- # Deprecations by version diff --git a/doc/update/removals.md b/doc/update/removals.md index 9b5596d67f2..392259176bb 100644 --- a/doc/update/removals.md +++ b/doc/update/removals.md @@ -1,7 +1,7 @@ --- stage: none group: none -info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines" +info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-development-guidelines" --- # Removals by version diff --git a/doc/user/admin_area/analytics/index.md b/doc/user/admin_area/analytics/index.md index 9bde3a57970..836b0e2ae3e 100644 --- a/doc/user/admin_area/analytics/index.md +++ b/doc/user/admin_area/analytics/index.md @@ -8,12 +8,18 @@ info: To determine the technical writer assigned to the Stage/Group associated w > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41416) in GitLab 11.2. -Administrators have access to instance-wide analytics: +Instance-level analytics provide insights into the feature and data usage of your entire instance. -1. On the top bar, select **Main menu > Admin**. -1. On the left sidebar, select **Analytics**. +## View instance-level analytics + +Prerequisite: + +- You must have administrator access for your instance. -There are several kinds of statistics: +To view instance-level analytics: + +1. On the top bar, select **Main menu > Admin**. +1. On the left sidebar, select **Analytics**, then one of the available analytics: -- [DevOps Reports](dev_ops_reports.md): Provides an overview of your entire instance's feature usage. -- [Usage Trends](usage_trends.md): Shows how much data your instance contains, and how that is changing. + - [DevOps Reports](dev_ops_reports.md): Provides an overview of your entire instance's feature usage. + - [Usage Trends](usage_trends.md): Shows how much data your instance contains, and how the data is changing. diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md index 723f544f02b..403a2564da3 100644 --- a/doc/user/admin_area/settings/continuous_integration.md +++ b/doc/user/admin_area/settings/continuous_integration.md @@ -70,7 +70,9 @@ runner settings: To view the rendered details: -1. On the top bar, select **Main menu > Projects** or **Main menu > Groups** and find your project or group. +1. On the top bar, select **Main menu**, and: + - For a project, select ***Projects** and find your project. + - For a group, select **Groups** and find your group. 1. On the left sidebar, select **Settings > CI/CD**. 1. Expand **Runners**. diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md index 1e2876a3741..ed9bf8e3f45 100644 --- a/doc/user/gitlab_com/index.md +++ b/doc/user/gitlab_com/index.md @@ -146,22 +146,22 @@ Below are the current settings regarding [GitLab CI/CD](../../ci/index.md). Any settings or feature limits not listed here are using the defaults listed in the related documentation. -| Setting | GitLab.com | Default (self-managed) | -|:-------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Artifacts maximum size (compressed) | 1 GB | See [Maximum artifacts size](../../user/admin_area/settings/continuous_integration.md#maximum-artifacts-size) | -| Artifacts [expiry time](../../ci/yaml/index.md#artifactsexpire_in) | From June 22, 2020, deleted after 30 days unless otherwise specified (artifacts created before that date have no expiry). | See [Default artifacts expiration](../admin_area/settings/continuous_integration.md#default-artifacts-expiration) | -| Scheduled Pipeline Cron | `*/5 * * * *` | See [Pipeline schedules advanced configuration](../../administration/cicd.md#change-maximum-scheduled-pipeline-frequency) | -| Maximum jobs in active pipelines | `500` for Free tier, `1000` for all trial tiers, and unlimited otherwise. | See [Number of jobs in active pipelines](../../administration/instance_limits.md#number-of-jobs-in-active-pipelines) | -| Maximum CI/CD subscriptions to a project | `2` | See [Number of CI/CD subscriptions to a project](../../administration/instance_limits.md#number-of-cicd-subscriptions-to-a-project) | -| Maximum number of pipeline triggers in a project | `25000` for Free tier, Unlimited for all paid tiers | See [Limit the number of pipeline triggers](../../administration/instance_limits.md#limit-the-number-of-pipeline-triggers) | -| Maximum pipeline schedules in projects | `10` for Free tier, `50` for all paid tiers | See [Number of pipeline schedules](../../administration/instance_limits.md#number-of-pipeline-schedules) | -| Maximum pipelines per schedule | `24` for Free tier, `288` for all paid tiers | See [Limit the number of pipelines created by a pipeline schedule per day](../../administration/instance_limits.md#limit-the-number-of-pipelines-created-by-a-pipeline-schedule-per-day) | -| Maximum number of schedule rules defined for each security policy project | Unlimited for all paid tiers | See [Number of schedule rules defined for each security policy project](../../administration/instance_limits.md#limit-the-number-of-schedule-rules-defined-for-security-policy-project) | -| Scheduled job archiving | 3 months (from June 22, 2020). Jobs created before that date were archived after September 22, 2020. | Never | -| Maximum test cases per [unit test report](../../ci/testing/unit_test_reports.md) | `500000` | Unlimited | -| Maximum registered runners | Free tier: `50` per-group / `50` per-project<br/>All paid tiers: `1000` per-group / `1000` per-project | See [Number of registered runners per scope](../../administration/instance_limits.md#number-of-registered-runners-per-scope) | -| Limit of dotenv variables | Free tier: `50` / Premium tier: `100` / Ultimate tier: `150` | See [Limit dotenv variables](../../administration/instance_limits.md#limit-dotenv-variables) | -| Authorization token duration (minutes) | `15` | To set a custom value, in the Rails console, run `ApplicationSetting.last.update(container_registry_token_expire_delay: <integer>)`, where `<integer>` is the desired number of minutes. | +| Setting | GitLab.com | Default (self-managed) | +|----------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------|------------------------| +| Artifacts maximum size (compressed) | 1 GB | See [Maximum artifacts size](../../user/admin_area/settings/continuous_integration.md#maximum-artifacts-size). | +| Artifacts [expiry time](../../ci/yaml/index.md#artifactsexpire_in) | From June 22, 2020, deleted after 30 days unless otherwise specified (artifacts created before that date have no expiry). | See [Default artifacts expiration](../admin_area/settings/continuous_integration.md#default-artifacts-expiration). | +| Scheduled Pipeline Cron | `*/5 * * * *` | See [Pipeline schedules advanced configuration](../../administration/cicd.md#change-maximum-scheduled-pipeline-frequency). | +| Maximum jobs in active pipelines | `500` for Free tier, `1000` for all trial tiers, and unlimited otherwise. | See [Number of jobs in active pipelines](../../administration/instance_limits.md#number-of-jobs-in-active-pipelines). | +| Maximum CI/CD subscriptions to a project | `2` | See [Number of CI/CD subscriptions to a project](../../administration/instance_limits.md#number-of-cicd-subscriptions-to-a-project). | +| Maximum number of pipeline triggers in a project | `25000` for Free tier, Unlimited for all paid tiers | See [Limit the number of pipeline triggers](../../administration/instance_limits.md#limit-the-number-of-pipeline-triggers). | +| Maximum pipeline schedules in projects | `10` for Free tier, `50` for all paid tiers | See [Number of pipeline schedules](../../administration/instance_limits.md#number-of-pipeline-schedules). | +| Maximum pipelines per schedule | `24` for Free tier, `288` for all paid tiers | See [Limit the number of pipelines created by a pipeline schedule per day](../../administration/instance_limits.md#limit-the-number-of-pipelines-created-by-a-pipeline-schedule-per-day). | +| Maximum number of schedule rules defined for each security policy project | Unlimited for all paid tiers | See [Number of schedule rules defined for each security policy project](../../administration/instance_limits.md#limit-the-number-of-schedule-rules-defined-for-security-policy-project). | +| Scheduled job archiving | 3 months (from June 22, 2020). Jobs created before that date were archived after September 22, 2020. | Never. | +| Maximum test cases per [unit test report](../../ci/testing/unit_test_reports.md) | `500000` | Unlimited. | +| Maximum registered runners | Free tier: `50` per-group / `50` per-project<br/>All paid tiers: `1000` per-group / `1000` per-project | See [Number of registered runners per scope](../../administration/instance_limits.md#number-of-registered-runners-per-scope). | +| Limit of dotenv variables | Free tier: `50` / Premium tier: `100` / Ultimate tier: `150` | See [Limit dotenv variables](../../administration/instance_limits.md#limit-dotenv-variables). | +| Authorization token duration (minutes) | `15` | To set a custom value, in the Rails console, run `ApplicationSetting.last.update(container_registry_token_expire_delay: <integer>)`, where `<integer>` is the desired number of minutes. | ## Package registry limits diff --git a/doc/user/project/deploy_tokens/index.md b/doc/user/project/deploy_tokens/index.md index a6dadb5ae6f..1ee0b8fbe73 100644 --- a/doc/user/project/deploy_tokens/index.md +++ b/doc/user/project/deploy_tokens/index.md @@ -31,7 +31,9 @@ You can create as many deploy tokens as you need from the settings of your project. Alternatively, you can also create [group-scoped deploy tokens](#group-deploy-token). 1. Sign in to your GitLab account. -1. On the top bar, select **Main menu > Projects** or **Main menu > Groups** to find your project or group. +1. On the top bar, select **Main menu**, and: + - For a project, select ***Projects** and find your project. + - For a group, select **Groups** and find your group. 1. On the left sidebar, select **Settings > Repository**. 1. Expand **Deploy tokens**. 1. Choose a name, and optionally, an expiration date and username for the token. @@ -51,7 +53,9 @@ Deploy tokens expire at midnight UTC on the date you define. To revoke a deploy token: -1. On the top bar, select **Main menu > Projects** or **Main menu > Groups** to find your project or group. +1. On the top bar, select **Main menu**, and: + - For a project, select ***Projects** and find your project. + - For a group, select **Groups** and find your group. 1. On the left sidebar, select **Settings > Repository**. 1. Expand **Deploy tokens**. 1. In the **Active Deploy Tokens** section, by the token you want to revoke, select **Revoke**. diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 6b1fc0d4279..ca99e30fbf7 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -123,6 +123,12 @@ module API end def present_groups_with_pagination_strategies(params, groups) + # Prevent Rails from optimizing the count query and inadvertadly creating a poor performing databse query. + # https://gitlab.com/gitlab-org/gitlab/-/issues/368969 + if Feature.enabled?(:present_groups_select_all) + groups = groups.select(groups.arel_table[Arel.star]) + end + return present_groups(params, groups) if current_user.present? options = { diff --git a/lib/gitlab/ci/parsers/security/validators/schema_validator.rb b/lib/gitlab/ci/parsers/security/validators/schema_validator.rb index 4626cc892dd..627a1f58715 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[14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1], - container_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1], - coverage_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1], - dast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1], - api_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1], - dependency_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1], - sast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1], - secret_detection: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1] + cluster_image_scanning: %w[14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2], + container_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2], + coverage_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2], + dast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2], + api_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2], + dependency_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2], + sast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2], + secret_detection: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2] }.freeze VERSIONS_TO_REMOVE_IN_16_0 = [].freeze diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/cluster-image-scanning-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/cluster-image-scanning-report-format.json new file mode 100644 index 00000000000..b753a44a3d4 --- /dev/null +++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/cluster-image-scanning-report-format.json @@ -0,0 +1,980 @@ +{ + "$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" + } + ] + }, + "text_value": { + "type": "string" + }, + "named_field": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/definitions/text_value", + "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![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)" + ] + } + } + }, + "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" + }, + "line_end": { + "type": "integer" + } + } + }, + "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 + ] + } + } + } + }, + "self": { + "version": "15.0.2" + }, + "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" + ] + } + } + } + }, + "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 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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + } + } + }, + "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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + }, + "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?://.+" + } + } + } + }, + "details": { + "$ref": "#/definitions/named_list/properties/items" + }, + "tracking": { + "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.", + "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." + }, + "iid": { + "description": "ID that identifies the dependency in the scope of a dependency file.", + "type": "number" + }, + "direct": { + "type": "boolean", + "description": "Tells whether this is a direct, top-level dependency of the scanned project." + }, + "dependency_path": { + "type": "array", + "description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.", + "items": { + "type": "object", + "required": [ + "iid" + ], + "properties": { + "iid": { + "type": "number", + "description": "ID that is unique in the scope of a parent object, and specific to the resource type." + } + } + } + } + } + }, + "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.0.2/container-scanning-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/container-scanning-report-format.json new file mode 100644 index 00000000000..85671d03a27 --- /dev/null +++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/container-scanning-report-format.json @@ -0,0 +1,912 @@ +{ + "$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" + } + ] + }, + "text_value": { + "type": "string" + }, + "named_field": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/definitions/text_value", + "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![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)" + ] + } + } + }, + "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" + }, + "line_end": { + "type": "integer" + } + } + }, + "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 + ] + } + } + } + }, + "self": { + "version": "15.0.2" + }, + "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" + ] + } + } + } + }, + "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" + ] + }, + "primary_identifiers": { + "type": "array", + "description": "An 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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + } + } + }, + "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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + }, + "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?://.+" + } + } + } + }, + "details": { + "$ref": "#/definitions/named_list/properties/items" + }, + "tracking": { + "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.", + "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." + }, + "iid": { + "description": "ID that identifies the dependency in the scope of a dependency file.", + "type": "number" + }, + "direct": { + "type": "boolean", + "description": "Tells whether this is a direct, top-level dependency of the scanned project." + }, + "dependency_path": { + "type": "array", + "description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.", + "items": { + "type": "object", + "required": [ + "iid" + ], + "properties": { + "iid": { + "type": "number", + "description": "ID that is unique in the scope of a parent object, and specific to the resource type." + } + } + } + } + } + }, + "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.0.2/coverage-fuzzing-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/coverage-fuzzing-report-format.json new file mode 100644 index 00000000000..33568a246fa --- /dev/null +++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/coverage-fuzzing-report-format.json @@ -0,0 +1,870 @@ +{ + "$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" + } + ] + }, + "text_value": { + "type": "string" + }, + "named_field": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/definitions/text_value", + "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![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)" + ] + } + } + }, + "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" + }, + "line_end": { + "type": "integer" + } + } + }, + "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 + ] + } + } + } + }, + "self": { + "version": "15.0.2" + }, + "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" + ] + } + } + } + }, + "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 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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + } + } + }, + "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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + }, + "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?://.+" + } + } + } + }, + "details": { + "$ref": "#/definitions/named_list/properties/items" + }, + "tracking": { + "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.", + "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.0.2/dast-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/dast-report-format.json new file mode 100644 index 00000000000..eb141f044d5 --- /dev/null +++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/dast-report-format.json @@ -0,0 +1,1275 @@ +{ + "$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" + } + ] + }, + "text_value": { + "type": "string" + }, + "named_field": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/definitions/text_value", + "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![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)" + ] + } + } + }, + "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" + }, + "line_end": { + "type": "integer" + } + } + }, + "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 + ] + } + } + } + }, + "self": { + "version": "15.0.2" + }, + "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" + ] + } + } + } + }, + "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 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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + }, + "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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + }, + "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?://.+" + } + } + } + }, + "details": { + "$ref": "#/definitions/named_list/properties/items" + }, + "tracking": { + "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.", + "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.0.2/dependency-scanning-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/dependency-scanning-report-format.json new file mode 100644 index 00000000000..31905180019 --- /dev/null +++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/dependency-scanning-report-format.json @@ -0,0 +1,978 @@ +{ + "$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" + } + ] + }, + "text_value": { + "type": "string" + }, + "named_field": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/definitions/text_value", + "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![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)" + ] + } + } + }, + "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" + }, + "line_end": { + "type": "integer" + } + } + }, + "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 + ] + } + } + } + }, + "self": { + "version": "15.0.2" + }, + "required": [ + "dependency_files", + "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" + ] + } + } + } + }, + "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 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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + } + } + }, + "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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + }, + "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?://.+" + } + } + } + }, + "details": { + "$ref": "#/definitions/named_list/properties/items" + }, + "tracking": { + "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.", + "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." + }, + "iid": { + "description": "ID that identifies the dependency in the scope of a dependency file.", + "type": "number" + }, + "direct": { + "type": "boolean", + "description": "Tells whether this is a direct, top-level dependency of the scanned project." + }, + "dependency_path": { + "type": "array", + "description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.", + "items": { + "type": "object", + "required": [ + "iid" + ], + "properties": { + "iid": { + "type": "number", + "description": "ID that is unique in the scope of a parent object, and specific to the resource type." + } + } + } + } + } + } + } + } + } + } + }, + "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." + } + } + } + }, + "dependency_files": { + "type": "array", + "description": "List of dependency files identified in the project.", + "items": { + "type": "object", + "required": [ + "path", + "package_manager", + "dependencies" + ], + "properties": { + "path": { + "type": "string", + "minLength": 1 + }, + "package_manager": { + "type": "string", + "minLength": 1 + }, + "dependencies": { + "type": "array", + "items": { + "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." + }, + "iid": { + "description": "ID that identifies the dependency in the scope of a dependency file.", + "type": "number" + }, + "direct": { + "type": "boolean", + "description": "Tells whether this is a direct, top-level dependency of the scanned project." + }, + "dependency_path": { + "type": "array", + "description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.", + "items": { + "type": "object", + "required": [ + "iid" + ], + "properties": { + "iid": { + "type": "number", + "description": "ID that is unique in the scope of a parent object, and specific to the resource type." + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/sast-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/sast-report-format.json new file mode 100644 index 00000000000..efc9715aafb --- /dev/null +++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/sast-report-format.json @@ -0,0 +1,865 @@ +{ + "$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" + } + ] + }, + "text_value": { + "type": "string" + }, + "named_field": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/definitions/text_value", + "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![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)" + ] + } + } + }, + "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" + }, + "line_end": { + "type": "integer" + } + } + }, + "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 + ] + } + } + } + }, + "self": { + "version": "15.0.2" + }, + "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" + ] + } + } + } + }, + "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 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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + } + } + }, + "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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + }, + "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?://.+" + } + } + } + }, + "details": { + "$ref": "#/definitions/named_list/properties/items" + }, + "tracking": { + "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.", + "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.0.2/secret-detection-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/secret-detection-report-format.json new file mode 100644 index 00000000000..adbd01760d7 --- /dev/null +++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.2/secret-detection-report-format.json @@ -0,0 +1,888 @@ +{ + "$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" + } + ] + }, + "text_value": { + "type": "string" + }, + "named_field": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "$ref": "#/definitions/text_value", + "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![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)" + ] + } + } + }, + "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" + }, + "line_end": { + "type": "integer" + } + } + }, + "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 + ] + } + } + } + }, + "self": { + "version": "15.0.2" + }, + "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" + ] + } + } + } + }, + "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 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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + } + } + }, + "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?://.+" + }, + "value": { + "type": "string", + "description": "Value of the identifier, for matching purpose.", + "minLength": 1 + } + } + } + }, + "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?://.+" + } + } + } + }, + "details": { + "$ref": "#/definitions/named_list/properties/items" + }, + "tracking": { + "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.", + "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" + ], + "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/gon_helper.rb b/lib/gitlab/gon_helper.rb index 08a614edb4b..2cd0ee7072d 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -56,6 +56,7 @@ module Gitlab push_frontend_feature_flag(:new_header_search) push_frontend_feature_flag(:source_editor_toolbar) push_frontend_feature_flag(:gl_avatar_for_all_user_avatars) + push_frontend_feature_flag(:gl_listbox_for_sort_dropdowns) end # Exposes the state of a feature flag to the frontend code. diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 0a400fc074e..446268a39ea 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -45865,7 +45865,7 @@ msgstr "" msgid "You have successfully purchased %{product}. You'll receive a receipt by email. Your purchase may take a minute to sync, so refresh the page if you don't see it yet." msgstr "" -msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email. It might take a moment for GitLab.com to fully reflect your purchase." +msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email. Your purchase may take a minute to sync, so refresh the page if you don't see it yet." msgstr "" msgid "You have unsaved changes" diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb index 2cf56f93cf9..cb9188cf171 100644 --- a/spec/features/dashboard/user_filters_projects_spec.rb +++ b/spec/features/dashboard/user_filters_projects_spec.rb @@ -9,6 +9,8 @@ RSpec.describe 'Dashboard > User filters projects' do let(:project2) { create(:project, name: 'Treasure', namespace: user2.namespace, created_at: 1.second.ago, updated_at: 1.second.ago) } before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) + project.add_maintainer(user) sign_in(user) diff --git a/spec/features/groups/labels/sort_labels_spec.rb b/spec/features/groups/labels/sort_labels_spec.rb index fba166449f8..af4d39bc6fa 100644 --- a/spec/features/groups/labels/sort_labels_spec.rb +++ b/spec/features/groups/labels/sort_labels_spec.rb @@ -9,6 +9,8 @@ RSpec.describe 'Sort labels', :js do let!(:label2) { create(:group_label, title: 'Bar', description: 'Fusce consequat', group: group) } before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) + group.add_maintainer(user) sign_in(user) diff --git a/spec/features/groups/milestones_sorting_spec.rb b/spec/features/groups/milestones_sorting_spec.rb index 22d7ff91d41..631aa940270 100644 --- a/spec/features/groups/milestones_sorting_spec.rb +++ b/spec/features/groups/milestones_sorting_spec.rb @@ -14,6 +14,7 @@ RSpec.describe 'Milestones sorting', :js do let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user } before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) sign_in(user) end diff --git a/spec/features/help_dropdown_spec.rb b/spec/features/help_dropdown_spec.rb index e64c19d4708..a9c014a9408 100644 --- a/spec/features/help_dropdown_spec.rb +++ b/spec/features/help_dropdown_spec.rb @@ -59,6 +59,10 @@ RSpec.describe "Help Dropdown", :js do expect(page).to have_text('Your GitLab Version') expect(page).to have_text("#{Gitlab.version_info.major}.#{Gitlab.version_info.minor}") expect(page).to have_selector('.version-check-badge') + expect(page).to have_selector( + 'a[data-testid="gitlab-version-container"][href="/help/update/index"]' + ) + expect(page).to have_selector('.version-check-badge[href="/help/update/index"]') expect(page).to have_text(ui_text) end end diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index 727f9aa486e..361a07ebd0b 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' RSpec.describe 'Branches' do - let(:user) { create(:user) } - let(:project) { create(:project, :public, :repository) } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :public, :repository) } let(:repository) { project.repository } context 'logged in as developer' do @@ -175,7 +175,7 @@ RSpec.describe 'Branches' do search_for_branch('fix') expect(page).not_to have_content('fix') - expect(all('.all-branches').last).to have_selector('li', count: 0) + expect(all('.all-branches', wait: false).last).to have_selector('li', count: 0) end end @@ -233,7 +233,7 @@ RSpec.describe 'Branches' do end context 'with one or more pipeline', :js do - let(:project) { create(:project, :public, :empty_repo) } + let_it_be(:project) { create(:project, :public, :empty_repo) } before do sha = create_file(branch_name: "branch") diff --git a/spec/features/projects/labels/sort_labels_spec.rb b/spec/features/projects/labels/sort_labels_spec.rb index ecbc4b524dc..6a16f474056 100644 --- a/spec/features/projects/labels/sort_labels_spec.rb +++ b/spec/features/projects/labels/sort_labels_spec.rb @@ -9,6 +9,8 @@ RSpec.describe 'Sort labels', :js do let!(:label2) { create(:label, title: 'Bar', description: 'Fusce consequat', project: project) } before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) + project.add_maintainer(user) sign_in(user) diff --git a/spec/features/projects/milestones/milestones_sorting_spec.rb b/spec/features/projects/milestones/milestones_sorting_spec.rb index c47350fb663..5c379ac1034 100644 --- a/spec/features/projects/milestones/milestones_sorting_spec.rb +++ b/spec/features/projects/milestones/milestones_sorting_spec.rb @@ -21,6 +21,7 @@ RSpec.describe 'Milestones sorting', :js do end before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) create(:milestone, start_date: 7.days.from_now, due_date: 10.days.from_now, title: "a", project: project) create(:milestone, start_date: 6.days.from_now, due_date: 11.days.from_now, title: "c", project: project) create(:milestone, start_date: 5.days.from_now, due_date: 12.days.from_now, title: "b", project: project) diff --git a/spec/features/projects/user_sorts_projects_spec.rb b/spec/features/projects/user_sorts_projects_spec.rb index b9b28398279..15f7dae502d 100644 --- a/spec/features/projects/user_sorts_projects_spec.rb +++ b/spec/features/projects/user_sorts_projects_spec.rb @@ -44,6 +44,7 @@ RSpec.describe 'User sorts projects and order persists' do context "from explore projects" do before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) sign_in(user) visit(explore_projects_path) find('#sort-projects-dropdown').click @@ -55,6 +56,7 @@ RSpec.describe 'User sorts projects and order persists' do context 'from dashboard projects' do before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) sign_in(user) visit(dashboard_projects_path) find('#sort-projects-dropdown').click @@ -66,6 +68,7 @@ RSpec.describe 'User sorts projects and order persists' do context 'from group homepage', :js do before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) stub_feature_flags(group_overview_tabs_vue: false) sign_in(user) visit(group_canonical_path(group)) @@ -80,6 +83,7 @@ RSpec.describe 'User sorts projects and order persists' do context 'from group details', :js do before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) stub_feature_flags(group_overview_tabs_vue: false) sign_in(user) visit(details_group_path(group)) diff --git a/spec/features/projects/wikis_spec.rb b/spec/features/projects/wikis_spec.rb index 879ffd2932b..8ac17413df3 100644 --- a/spec/features/projects/wikis_spec.rb +++ b/spec/features/projects/wikis_spec.rb @@ -3,6 +3,10 @@ require "spec_helper" RSpec.describe 'Project wikis', :js do + before do + stub_feature_flags(gl_listbox_for_sort_dropdowns: false) + end + let_it_be(:user) { create(:user) } let(:wiki) { create(:project_wiki, user: user, project: project) } diff --git a/spec/fixtures/packages/rubygems/package.gemspec b/spec/fixtures/packages/rubygems/package.gemspec index ea03414cc6f..60acd078fad 100644 --- a/spec/fixtures/packages/rubygems/package.gemspec +++ b/spec/fixtures/packages/rubygems/package.gemspec @@ -30,7 +30,7 @@ Gem::Specification.new do |s| s.platform = Gem::Platform::RUBY s.post_install_message = 'Installed, thank you!' s.rdoc_options = ['--main', 'README.md'] - s.required_ruby_version = '>= 2.7.0' + s.required_ruby_version = '>= 2.7.0' # rubocop:disable Gemspec/RequiredRubyVersion s.required_rubygems_version = '>= 1.8.11' s.requirements = 'A high powered server or calculator' s.rubygems_version = '1.8.09' diff --git a/spec/frontend/listbox/index_spec.js b/spec/frontend/listbox/index_spec.js index 07c6cca535a..c973960e683 100644 --- a/spec/frontend/listbox/index_spec.js +++ b/spec/frontend/listbox/index_spec.js @@ -1,6 +1,6 @@ import { nextTick } from 'vue'; -import { getAllByRole, getByRole } from '@testing-library/dom'; -import { GlDropdown } from '@gitlab/ui'; +import { getAllByRole, getByRole, getByTestId } from '@testing-library/dom'; +import { GlDropdown, GlListbox } from '@gitlab/ui'; import { createWrapper } from '@vue/test-utils'; import { initListbox, parseAttributes } from '~/listbox'; import { getFixture, setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; @@ -28,20 +28,6 @@ describe('initListbox', () => { instance = initListbox(...args); }; - // TODO: Rewrite these finders to use better semantics once the - // implementation is switched to GlListbox - // https://gitlab.com/gitlab-org/gitlab/-/issues/348738 - const findToggleButton = () => document.body.querySelector('.gl-dropdown-toggle'); - const findItem = (text) => getByRole(document.body, 'menuitem', { name: text }); - const findItems = () => getAllByRole(document.body, 'menuitem'); - const findSelectedItems = () => - findItems().filter( - (menuitem) => - !menuitem - .querySelector('.gl-new-dropdown-item-check-icon') - .classList.contains('gl-visibility-hidden'), - ); - it('returns null given no element', () => { setup(); @@ -53,63 +39,141 @@ describe('initListbox', () => { }); describe('given a valid element', () => { - let onChangeSpy; + describe('when `glListboxForSortDropdowns` FF is enabled', () => { + let onChangeSpy; - beforeEach(async () => { - setHTMLFixture(fixture); - onChangeSpy = jest.fn(); - setup(document.querySelector('.js-redirect-listbox'), { onChange: onChangeSpy }); + const listbox = () => createWrapper(instance).findComponent(GlListbox); + const findToggleButton = () => getByTestId(document.body, 'base-dropdown-toggle'); + const findSelectedItems = () => getAllByRole(document.body, 'option', { selected: true }); - await nextTick(); - }); + beforeEach(async () => { + window.gon.features = { glListboxForSortDropdowns: true }; + setHTMLFixture(fixture); + onChangeSpy = jest.fn(); + setup(document.querySelector('.js-redirect-listbox'), { onChange: onChangeSpy }); - afterEach(() => { - resetHTMLFixture(); - }); + await nextTick(); + }); - it('returns an instance', () => { - expect(instance).not.toBe(null); - }); + afterEach(() => { + resetHTMLFixture(); + }); - it('renders button with selected item text', () => { - expect(findToggleButton().textContent.trim()).toBe('Bar'); - }); + it('returns an instance', () => { + expect(instance).not.toBe(null); + }); - it('has the correct item selected', () => { - const selectedItems = findSelectedItems(); - expect(selectedItems).toHaveLength(1); - expect(selectedItems[0].textContent.trim()).toBe('Bar'); - }); + it('renders button with selected item text', () => { + expect(findToggleButton().textContent.trim()).toBe('Bar'); + }); - it('applies additional classes from the original element', () => { - expect(instance.$el.classList).toContain('test-class-1', 'test-class-2'); + it('has the correct item selected', () => { + const selectedItems = findSelectedItems(); + expect(selectedItems).toHaveLength(1); + expect(selectedItems[0].textContent.trim()).toBe('Bar'); + }); + + it('applies additional classes from the original element', () => { + expect(instance.$el.classList).toContain('test-class-1', 'test-class-2'); + }); + + describe.each(parsedAttributes.items)('selecting an item', (item) => { + beforeEach(async () => { + listbox().vm.$emit('select', item.value); + await nextTick(); + }); + + it('calls the onChange callback with the item', () => { + expect(onChangeSpy).toHaveBeenCalledWith(item); + }); + + it('updates the toggle button text', () => { + expect(findToggleButton().textContent.trim()).toBe(item.text); + }); + + it('marks the item as selected', () => { + const selectedItems = findSelectedItems(); + expect(selectedItems).toHaveLength(1); + expect(selectedItems[0].textContent.trim()).toBe(item.text); + }); + }); + + it('passes the "right" prop through to the underlying component', () => { + expect(listbox().props('right')).toBe(parsedAttributes.right); + }); }); - describe.each(parsedAttributes.items)('clicking on an item', (item) => { + describe('when `glListboxForSortDropdowns` FF is disabled', () => { + let onChangeSpy; + + const ITEM_ROLE = 'menuitem'; + const dropdown = () => createWrapper(instance).findComponent(GlDropdown); + + const findToggleButton = () => document.body.querySelector('.gl-dropdown-toggle'); + const findItem = (text) => getByRole(document.body, ITEM_ROLE, { name: text }); + const findItems = () => getAllByRole(document.body, ITEM_ROLE); + const findSelectedItems = () => + findItems().filter( + (item) => + !item + .querySelector('.gl-new-dropdown-item-check-icon') + .classList.contains('gl-visibility-hidden'), + ); beforeEach(async () => { - findItem(item.text).click(); + window.gon.features = { glListboxForSortDropdowns: false }; + setHTMLFixture(fixture); + onChangeSpy = jest.fn(); + setup(document.querySelector('.js-redirect-listbox'), { onChange: onChangeSpy }); await nextTick(); }); - it('calls the onChange callback with the item', () => { - expect(onChangeSpy).toHaveBeenCalledWith(item); + afterEach(() => { + resetHTMLFixture(); + }); + + it('returns an instance', () => { + expect(instance).not.toBe(null); }); - it('updates the toggle button text', () => { - expect(findToggleButton().textContent.trim()).toBe(item.text); + it('renders button with selected item text', () => { + expect(findToggleButton().textContent.trim()).toBe('Bar'); }); - it('marks the item as selected', () => { + it('has the correct item selected', () => { const selectedItems = findSelectedItems(); expect(selectedItems).toHaveLength(1); - expect(selectedItems[0].textContent.trim()).toBe(item.text); + expect(selectedItems[0].textContent.trim()).toBe('Bar'); + }); + + it('applies additional classes from the original element', () => { + expect(instance.$el.classList).toContain('test-class-1', 'test-class-2'); }); - }); - it('passes the "right" prop through to the underlying component', () => { - const wrapper = createWrapper(instance).findComponent(GlDropdown); - expect(wrapper.props('right')).toBe(parsedAttributes.right); + describe.each(parsedAttributes.items)('selecting an item', (item) => { + beforeEach(async () => { + findItem(item.text).click(); + await nextTick(); + }); + + it('calls the onChange callback with the item', () => { + expect(onChangeSpy).toHaveBeenCalledWith(item); + }); + + it('updates the toggle button text', () => { + expect(findToggleButton().textContent.trim()).toBe(item.text); + }); + + it('marks the item as selected', () => { + const selectedItems = findSelectedItems(); + expect(selectedItems).toHaveLength(1); + expect(selectedItems[0].textContent.trim()).toBe(item.text); + }); + }); + + it('passes the "right" prop through to the underlying component', () => { + expect(dropdown().props('right')).toBe(parsedAttributes.right); + }); }); }); }); diff --git a/spec/frontend/repository/components/blob_controls_spec.js b/spec/frontend/repository/components/blob_controls_spec.js index 6da1861ea7c..0d52542397f 100644 --- a/spec/frontend/repository/components/blob_controls_spec.js +++ b/spec/frontend/repository/components/blob_controls_spec.js @@ -8,9 +8,13 @@ import blobControlsQuery from '~/repository/queries/blob_controls.query.graphql' import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import createRouter from '~/repository/router'; import { updateElementsVisibility } from '~/repository/utils/dom'; +import ShortcutsBlob from '~/behaviors/shortcuts/shortcuts_blob'; +import BlobLinePermalinkUpdater from '~/blob/blob_line_permalink_updater'; import { blobControlsDataMock, refMock } from '../mock_data'; jest.mock('~/repository/utils/dom'); +jest.mock('~/behaviors/shortcuts/shortcuts_blob'); +jest.mock('~/blob/blob_line_permalink_updater'); let router; let wrapper; @@ -82,4 +86,12 @@ describe('Blob controls component', () => { expect(updateElementsVisibility).toHaveBeenCalledWith('.tree-controls', true); }, ); + + it('loads the ShortcutsBlob', () => { + expect(ShortcutsBlob).toHaveBeenCalled(); + }); + + it('loads the BlobLinePermalinkUpdater', () => { + expect(BlobLinePermalinkUpdater).toHaveBeenCalled(); + }); }); diff --git a/spec/frontend/vue_shared/components/gitlab_version_check_spec.js b/spec/frontend/vue_shared/components/gitlab_version_check_spec.js index 6699ae5fb69..f6bb8f5de6c 100644 --- a/spec/frontend/vue_shared/components/gitlab_version_check_spec.js +++ b/spec/frontend/vue_shared/components/gitlab_version_check_spec.js @@ -2,6 +2,7 @@ import { GlBadge } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import waitForPromises from 'helpers/wait_for_promises'; +import { helpPagePath } from '~/helpers/help_page_helper'; import axios from '~/lib/utils/axios_utils'; import GitlabVersionCheck from '~/vue_shared/components/gitlab_version_check.vue'; @@ -9,6 +10,8 @@ describe('GitlabVersionCheck', () => { let wrapper; let mock; + const UPGRADE_DOCS_URL = helpPagePath('update/index'); + const defaultResponse = { code: 200, res: { severity: 'success' }, @@ -102,6 +105,10 @@ describe('GitlabVersionCheck', () => { it(`variant is ${expectedUI.variant}`, () => { expect(findGlBadge().attributes('variant')).toBe(expectedUI.variant); }); + + it(`link is ${UPGRADE_DOCS_URL}`, () => { + expect(findGlBadge().attributes('href')).toBe(UPGRADE_DOCS_URL); + }); }); }); }); 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 b047e0dc8d7..b5111fdcae4 100644 --- a/spec/frontend/work_items/components/work_item_detail_spec.js +++ b/spec/frontend/work_items/components/work_item_detail_spec.js @@ -19,6 +19,7 @@ import { i18n } from '~/work_items/constants'; import workItemQuery from '~/work_items/graphql/work_item.query.graphql'; import workItemDatesSubscription from '~/work_items/graphql/work_item_dates.subscription.graphql'; import workItemTitleSubscription from '~/work_items/graphql/work_item_title.subscription.graphql'; +import workItemAssigneesSubscription from '~/work_items/graphql/work_item_assignees.subscription.graphql'; import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql'; import updateWorkItemTaskMutation from '~/work_items/graphql/update_work_item_task.mutation.graphql'; import { temporaryConfig } from '~/graphql_shared/issuable_client'; @@ -29,6 +30,7 @@ import { workItemResponseFactory, workItemTitleSubscriptionResponse, workItemWeightSubscriptionResponse, + workItemAssigneesSubscriptionResponse, } from '../mock_data'; describe('WorkItemDetail component', () => { @@ -46,6 +48,9 @@ describe('WorkItemDetail component', () => { const successHandler = jest.fn().mockResolvedValue(workItemQueryResponse); const datesSubscriptionHandler = jest.fn().mockResolvedValue(workItemDatesSubscriptionResponse); const titleSubscriptionHandler = jest.fn().mockResolvedValue(workItemTitleSubscriptionResponse); + const assigneesSubscriptionHandler = jest + .fn() + .mockResolvedValue(workItemAssigneesSubscriptionResponse); const weightSubscriptionHandler = jest.fn().mockResolvedValue(workItemWeightSubscriptionResponse); const findAlert = () => wrapper.findComponent(GlAlert); @@ -80,6 +85,7 @@ describe('WorkItemDetail component', () => { [workItemQuery, handler], [workItemTitleSubscription, subscriptionHandler], [workItemDatesSubscription, datesSubscriptionHandler], + [workItemAssigneesSubscription, assigneesSubscriptionHandler], confidentialityMock, ]; @@ -413,6 +419,30 @@ describe('WorkItemDetail component', () => { }); }); + describe('assignees subscription', () => { + describe('when the assignees widget exists', () => { + it('calls the assignees subscription', async () => { + createComponent(); + await waitForPromises(); + + expect(assigneesSubscriptionHandler).toHaveBeenCalledWith({ + issuableId: workItemQueryResponse.data.workItem.id, + }); + }); + }); + + describe('when the assignees widget does not exist', () => { + it('does not call the assignees subscription', async () => { + const response = workItemResponseFactory({ assigneesWidgetPresent: false }); + const handler = jest.fn().mockResolvedValue(response); + createComponent({ handler, workItemsMvc2Enabled: true }); + await waitForPromises(); + + expect(assigneesSubscriptionHandler).not.toHaveBeenCalled(); + }); + }); + }); + describe('dates subscription', () => { describe('when the due date widget exists', () => { it('calls the dates subscription', async () => { diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js index e1bc8d2f6b7..d1108a57e23 100644 --- a/spec/frontend/work_items/mock_data.js +++ b/spec/frontend/work_items/mock_data.js @@ -444,6 +444,22 @@ export const workItemWeightSubscriptionResponse = { }, }; +export const workItemAssigneesSubscriptionResponse = { + data: { + issuableAssigneesUpdated: { + id: 'gid://gitlab/WorkItem/1', + widgets: [ + { + __typename: 'WorkItemAssigneesWeight', + assignees: { + nodes: [mockAssignees[0]], + }, + }, + ], + }, + }, +}; + export const workItemHierarchyEmptyResponse = { data: { workItem: { diff --git a/spec/frontend/work_items/router_spec.js b/spec/frontend/work_items/router_spec.js index ab370e2ca8b..39e8eb837c0 100644 --- a/spec/frontend/work_items/router_spec.js +++ b/spec/frontend/work_items/router_spec.js @@ -4,6 +4,7 @@ import VueApollo from 'vue-apollo'; import workItemWeightSubscription from 'ee_component/work_items/graphql/work_item_weight.subscription.graphql'; import createMockApollo from 'helpers/mock_apollo_helper'; import { + workItemAssigneesSubscriptionResponse, workItemDatesSubscriptionResponse, workItemResponseFactory, workItemTitleSubscriptionResponse, @@ -13,6 +14,7 @@ import App from '~/work_items/components/app.vue'; import workItemQuery from '~/work_items/graphql/work_item.query.graphql'; import workItemDatesSubscription from '~/work_items/graphql/work_item_dates.subscription.graphql'; import workItemTitleSubscription from '~/work_items/graphql/work_item_title.subscription.graphql'; +import workItemAssigneesSubscription from '~/work_items/graphql/work_item_assignees.subscription.graphql'; import CreateWorkItem from '~/work_items/pages/create_work_item.vue'; import WorkItemsRoot from '~/work_items/pages/work_item_root.vue'; import { createRouter } from '~/work_items/router'; @@ -26,6 +28,9 @@ describe('Work items router', () => { const datesSubscriptionHandler = jest.fn().mockResolvedValue(workItemDatesSubscriptionResponse); const titleSubscriptionHandler = jest.fn().mockResolvedValue(workItemTitleSubscriptionResponse); const weightSubscriptionHandler = jest.fn().mockResolvedValue(workItemWeightSubscriptionResponse); + const assigneesSubscriptionHandler = jest + .fn() + .mockResolvedValue(workItemAssigneesSubscriptionResponse); const createComponent = async (routeArg) => { const router = createRouter('/work_item'); @@ -37,6 +42,7 @@ describe('Work items router', () => { [workItemQuery, workItemQueryHandler], [workItemDatesSubscription, datesSubscriptionHandler], [workItemTitleSubscription, titleSubscriptionHandler], + [workItemAssigneesSubscription, assigneesSubscriptionHandler], ]; if (IS_EE) { diff --git a/spec/graphql/mutations/work_items/update_widgets_spec.rb b/spec/graphql/mutations/work_items/update_widgets_spec.rb deleted file mode 100644 index 2e54b81b5c7..00000000000 --- a/spec/graphql/mutations/work_items/update_widgets_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Mutations::WorkItems::UpdateWidgets do - include GraphqlHelpers - - let_it_be(:project) { create(:project) } - let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } } - - let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } - - describe '#resolve' do - before do - stub_spam_services - end - - context 'when no work item matches the given id' do - let(:current_user) { developer } - let(:gid) { global_id_of(id: non_existing_record_id, model_name: WorkItem.name) } - - it 'raises an error' do - expect { mutation.resolve(id: gid, resolve: true) }.to raise_error( - Gitlab::Graphql::Errors::ResourceNotAvailable, - Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR - ) - end - end - - context 'when user can access the requested work item', :aggregate_failures do - let(:current_user) { developer } - let(:args) { {} } - - let_it_be(:work_item) { create(:work_item, project: project) } - - subject { mutation.resolve(id: work_item.to_global_id, **args) } - - context 'when `:work_items` is disabled for a project' do - let_it_be(:project2) { create(:project) } - - it 'returns an error' do - stub_feature_flags(work_items: project2) # only enable `work_item` for project2 - - expect(subject[:errors]).to contain_exactly('`work_items` feature flag disabled for this project') - end - end - - context 'when resolved with an input for description widget' do - let(:args) { { description_widget: { description: "updated description" } } } - - it 'returns the updated work item' do - expect(subject[:work_item].description).to eq("updated description") - expect(subject[:errors]).to be_empty - end - end - end - end -end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 00e620832b3..0b6e51c26f5 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -388,22 +388,30 @@ RSpec.describe GroupsHelper do end describe '#show_thanks_for_purchase_alert?' do - subject { helper.show_thanks_for_purchase_alert? } + subject { helper.show_thanks_for_purchase_alert?(quantity) } - it 'returns true with purchased_quantity present in params' do - allow(controller).to receive(:params) { { purchased_quantity: '1' } } + context 'with quantity present' do + let(:quantity) { 1 } - is_expected.to be_truthy + it 'returns true' do + is_expected.to be_truthy + end end - it 'returns false with purchased_quantity not present in params' do - is_expected.to be_falsey + context 'with quantity not present' do + let(:quantity) { nil } + + it 'returns false' do + is_expected.to be_falsey + end end - it 'returns false with purchased_quantity is empty in params' do - allow(controller).to receive(:params) { { purchased_quantity: '' } } + context 'with quantity empty' do + let(:quantity) { '' } - is_expected.to be_falsey + it 'returns false' do + is_expected.to be_falsey + end end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 7ee381b29ea..190227080cd 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -5362,7 +5362,7 @@ RSpec.describe Ci::Build do end describe '#clone' do - let_it_be(:user) { FactoryBot.build(:user) } + let_it_be(:user) { create(:user) } context 'when given new job variables' do context 'when the cloned build has an action' do diff --git a/spec/presenters/commit_presenter_spec.rb b/spec/presenters/commit_presenter_spec.rb index df3ee69621b..eba393da2b7 100644 --- a/spec/presenters/commit_presenter_spec.rb +++ b/spec/presenters/commit_presenter_spec.rb @@ -3,11 +3,12 @@ require 'spec_helper' RSpec.describe CommitPresenter do - let(:project) { create(:project, :repository) } let(:commit) { project.commit } - let(:user) { create(:user) } let(:presenter) { described_class.new(commit, current_user: user) } + let_it_be(:user) { build_stubbed(:user) } + let_it_be(:project) { create(:project, :repository) } + describe '#web_path' do it { expect(presenter.web_path).to eq("/#{project.full_path}/-/commit/#{commit.sha}") } end diff --git a/spec/presenters/projects/security/configuration_presenter_spec.rb b/spec/presenters/projects/security/configuration_presenter_spec.rb index 05e5a9d4f1d..ca7f96b567d 100644 --- a/spec/presenters/projects/security/configuration_presenter_spec.rb +++ b/spec/presenters/projects/security/configuration_presenter_spec.rb @@ -6,9 +6,8 @@ RSpec.describe Projects::Security::ConfigurationPresenter do include Gitlab::Routing.url_helpers using RSpec::Parameterized::TableSyntax - let(:project_with_repo) { create(:project, :repository) } - let(:project_with_no_repo) { create(:project) } - let(:current_user) { create(:user) } + let_it_be(:current_user) { build_stubbed(:user) } + let(:presenter) { described_class.new(project, current_user: current_user) } before do @@ -19,9 +18,9 @@ RSpec.describe Projects::Security::ConfigurationPresenter do subject(:html_data) { presenter.to_html_data_attribute } context 'when latest default branch pipeline`s source is not auto devops' do - let(:project) { project_with_repo } + let_it_be(:project) { create(:project, :repository) } - let(:pipeline) do + let_it_be(:pipeline) do create( :ci_pipeline, project: project, @@ -119,6 +118,16 @@ RSpec.describe Projects::Security::ConfigurationPresenter do context 'when the job has more than one report' do let(:features) { Gitlab::Json.parse(html_data[:features]) } + let(:project) { create(:project, :repository) } + + let(:pipeline) do + create( + :ci_pipeline, + project: project, + ref: project.default_branch, + sha: project.commit.sha + ) + end let!(:artifacts) do { artifacts: { reports: { other_job: ['gl-other-report.json'], sast: ['gl-sast-report.json'] } } } @@ -161,6 +170,8 @@ RSpec.describe Projects::Security::ConfigurationPresenter do end context "while retrieving information about gitlab ci file" do + let(:project) { create(:project, :repository) } + context 'when a .gitlab-ci.yml file exists' do let!(:ci_config) do project.repository.create_file( @@ -189,7 +200,7 @@ RSpec.describe Projects::Security::ConfigurationPresenter do end context 'when the project is empty' do - let(:project) { project_with_no_repo } + let(:project) { create(:project) } it 'includes a blank gitlab_ci history path' do expect(html_data[:gitlab_ci_history_path]).to eq('') @@ -197,7 +208,7 @@ RSpec.describe Projects::Security::ConfigurationPresenter do end context 'when the project has no default branch set' do - let(:project) { project_with_repo } + let(:project) { create(:project, :repository) } it 'includes the path to gitlab_ci history' do allow(project).to receive(:default_branch).and_return(nil) @@ -207,9 +218,9 @@ RSpec.describe Projects::Security::ConfigurationPresenter do end context "when the latest default branch pipeline's source is auto devops" do - let(:project) { project_with_repo } + let_it_be(:project) { create(:project, :repository) } - let(:pipeline) do + let_it_be(:pipeline) do create( :ci_pipeline, :auto_devops_source, @@ -256,7 +267,7 @@ RSpec.describe Projects::Security::ConfigurationPresenter do end context 'when the project has no default branch pipeline' do - let(:project) { project_with_repo } + let_it_be(:project) { create(:project, :repository) } it 'reports that auto devops is disabled' do expect(html_data[:auto_devops_enabled]).to be_falsy diff --git a/spec/requests/api/graphql/milestone_spec.rb b/spec/requests/api/graphql/milestone_spec.rb index f6835936418..78e7ec39ee3 100644 --- a/spec/requests/api/graphql/milestone_spec.rb +++ b/spec/requests/api/graphql/milestone_spec.rb @@ -5,8 +5,12 @@ require 'spec_helper' RSpec.describe 'Querying a Milestone' do include GraphqlHelpers + let_it_be(:group) { create(:group, :public) } + let_it_be(:project) { create(:project, group: group) } let_it_be(:guest) { create(:user) } - let_it_be(:project) { create(:project) } + let_it_be(:inherited_guest) { create(:user) } + let_it_be(:inherited_reporter) { create(:user) } + let_it_be(:inherited_developer) { create(:user) } let_it_be(:milestone) { create(:milestone, project: project) } let_it_be(:release_a) { create(:release, project: project) } let_it_be(:release_b) { create(:release, project: project) } @@ -14,116 +18,137 @@ RSpec.describe 'Querying a Milestone' do before_all do milestone.releases << [release_a, release_b] project.add_guest(guest) + group.add_guest(inherited_guest) + group.add_reporter(inherited_reporter) + group.add_developer(inherited_developer) end let(:expected_release_nodes) do contain_exactly(a_graphql_entity_for(release_a), a_graphql_entity_for(release_b)) end - context 'when we post the query' do - let(:current_user) { nil } - let(:query) do - graphql_query_for('milestone', { id: milestone.to_global_id.to_s }, all_graphql_fields_for('Milestone')) - end + shared_examples 'returns the milestone successfully' do + it_behaves_like 'a working graphql query' - subject { graphql_data['milestone'] } + it { is_expected.to include('title' => milestone.name) } - before do - post_graphql(query, current_user: current_user) + it 'contains release information' do + is_expected.to include('releases' => include('nodes' => expected_release_nodes)) end + end - context 'when the user has access to the milestone' do - let(:current_user) { guest } - - it_behaves_like 'a working graphql query' - - it { is_expected.to include('title' => milestone.name) } - - it 'contains release information' do - is_expected.to include('releases' => include('nodes' => expected_release_nodes)) + context 'when we post the query' do + context 'and the project is private' do + let(:query) do + graphql_query_for('milestone', { id: milestone.to_global_id.to_s }, all_graphql_fields_for('Milestone')) end - end - context 'when the user does not have access to the milestone' do - it_behaves_like 'a working graphql query' - - it { is_expected.to be_nil } - end + subject { graphql_data['milestone'] } - context 'when ID argument is missing' do - let(:query) do - graphql_query_for('milestone', {}, 'title') + before do + post_graphql(query, current_user: current_user) end - it 'raises an exception' do - expect(graphql_errors).to include(a_hash_including('message' => "Field 'milestone' is missing required arguments: id")) + context 'when the user is a direct project member' do + context 'and the user is a guest' do + let(:current_user) { guest } + + it_behaves_like 'returns the milestone successfully' + + context 'when there are two milestones' do + let_it_be(:milestone_b) { create(:milestone, project: project) } + + let(:milestone_fields) do + <<~GQL + fragment milestoneFields on Milestone { + #{all_graphql_fields_for('Milestone', max_depth: 1)} + releases { nodes { #{all_graphql_fields_for('Release', max_depth: 1)} } } + } + GQL + end + + let(:single_query) do + <<~GQL + query ($id_a: MilestoneID!) { + a: milestone(id: $id_a) { ...milestoneFields } + } + + #{milestone_fields} + GQL + end + + let(:multi_query) do + <<~GQL + query ($id_a: MilestoneID!, $id_b: MilestoneID!) { + a: milestone(id: $id_a) { ...milestoneFields } + b: milestone(id: $id_b) { ...milestoneFields } + } + #{milestone_fields} + GQL + end + + it 'returns the correct releases associated with each milestone' do + r = run_with_clean_state(multi_query, + context: { current_user: current_user }, + variables: { + id_a: global_id_of(milestone).to_s, + id_b: milestone_b.to_global_id.to_s + }) + + expect(r.to_h['errors']).to be_blank + expect(graphql_dig_at(r.to_h, :data, :a, :releases, :nodes)).to match expected_release_nodes + expect(graphql_dig_at(r.to_h, :data, :b, :releases, :nodes)).to be_empty + end + + it 'does not suffer from N+1 performance issues' do + baseline = ActiveRecord::QueryRecorder.new do + run_with_clean_state(single_query, + context: { current_user: current_user }, + variables: { id_a: milestone.to_global_id.to_s }) + end + + multi = ActiveRecord::QueryRecorder.new do + run_with_clean_state(multi_query, + context: { current_user: current_user }, + variables: { + id_a: milestone.to_global_id.to_s, + id_b: milestone_b.to_global_id.to_s + }) + end + + expect(multi).not_to exceed_query_limit(baseline) + end + end + end end - end - end - context 'when there are two milestones' do - let_it_be(:milestone_b) { create(:milestone, project: project) } - - let(:current_user) { guest } - let(:milestone_fields) do - <<~GQL - fragment milestoneFields on Milestone { - #{all_graphql_fields_for('Milestone', max_depth: 1)} - releases { nodes { #{all_graphql_fields_for('Release', max_depth: 1)} } } - } - GQL - end + context 'when the user is an inherited member from the group' do + where(:user) { [ref(:inherited_guest), ref(:inherited_reporter), ref(:inherited_developer)] } - let(:single_query) do - <<~GQL - query ($id_a: MilestoneID!) { - a: milestone(id: $id_a) { ...milestoneFields } - } + with_them do + let(:current_user) { user } - #{milestone_fields} - GQL - end + it_behaves_like 'returns the milestone successfully' + end + end - let(:multi_query) do - <<~GQL - query ($id_a: MilestoneID!, $id_b: MilestoneID!) { - a: milestone(id: $id_a) { ...milestoneFields } - b: milestone(id: $id_b) { ...milestoneFields } - } - #{milestone_fields} - GQL - end + context 'when unauthenticated' do + let(:current_user) { nil } - it 'produces correct results' do - r = run_with_clean_state(multi_query, - context: { current_user: current_user }, - variables: { - id_a: global_id_of(milestone).to_s, - id_b: milestone_b.to_global_id.to_s - }) - - expect(r.to_h['errors']).to be_blank - expect(graphql_dig_at(r.to_h, :data, :a, :releases, :nodes)).to match expected_release_nodes - expect(graphql_dig_at(r.to_h, :data, :b, :releases, :nodes)).to be_empty - end + it_behaves_like 'a working graphql query' - it 'does not suffer from N+1 performance issues' do - baseline = ActiveRecord::QueryRecorder.new do - run_with_clean_state(single_query, - context: { current_user: current_user }, - variables: { id_a: milestone.to_global_id.to_s }) - end + it { is_expected.to be_nil } - multi = ActiveRecord::QueryRecorder.new do - run_with_clean_state(multi_query, - context: { current_user: current_user }, - variables: { - id_a: milestone.to_global_id.to_s, - id_b: milestone_b.to_global_id.to_s - }) - end + context 'when ID argument is missing' do + let(:query) do + graphql_query_for('milestone', {}, 'title') + end - expect(multi).not_to exceed_query_limit(baseline) + it 'raises an exception' do + expect(graphql_errors).to include(a_hash_including('message' => "Field 'milestone' is missing required arguments: id")) + end + end + end end end end diff --git a/spec/requests/api/graphql/mutations/work_items/update_widgets_spec.rb b/spec/requests/api/graphql/mutations/work_items/update_widgets_spec.rb deleted file mode 100644 index 2a5cb937a2f..00000000000 --- a/spec/requests/api/graphql/mutations/work_items/update_widgets_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Update work item widgets' do - include GraphqlHelpers - - let_it_be(:project) { create(:project) } - let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } } - let_it_be(:work_item, refind: true) { create(:work_item, project: project) } - - let(:input) { { 'descriptionWidget' => { 'description' => 'updated description' } } } - let(:mutation_response) { graphql_mutation_response(:work_item_update_widgets) } - let(:mutation) do - graphql_mutation(:workItemUpdateWidgets, input.merge('id' => work_item.to_global_id.to_s), <<~FIELDS) - errors - workItem { - description - widgets { - type - ... on WorkItemWidgetDescription { - description - } - } - } - FIELDS - end - - context 'the user is not allowed to update a work item' do - let(:current_user) { create(:user) } - - it_behaves_like 'a mutation that returns a top-level access error' - end - - context 'when user has permissions to update a work item', :aggregate_failures do - let(:current_user) { developer } - - it_behaves_like 'update work item description widget' do - let(:new_description) { 'updated description' } - end - - it_behaves_like 'has spam protection' do - let(:mutation_class) { ::Mutations::WorkItems::UpdateWidgets } - end - - context 'when the work_items feature flag is disabled' do - before do - stub_feature_flags(work_items: false) - end - - it 'does not update the work item and returns and error' do - expect do - post_graphql_mutation(mutation, current_user: current_user) - work_item.reload - end.to not_change(work_item, :description) - - expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project') - end - end - end -end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 6169bc9b2a2..02d29601ceb 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -505,13 +505,35 @@ RSpec.describe API::Groups do group3.add_maintainer(user2) end - it 'returns an array of groups the user has at least master access' do - get api('/groups', user2), params: { min_access_level: 40 } + context 'with min_access_level parameter' do + it 'returns an array of groups the user has at least master access' do + get api('/groups', user2), params: { min_access_level: 40 } - expect(response).to have_gitlab_http_status(:ok) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(response_groups).to contain_exactly(group2.id, group3.id) + expect(response).to have_gitlab_http_status(:ok) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(response_groups).to contain_exactly(group2.id, group3.id) + end + + context 'distinct count with present_groups_select_all feature flag' do + subject { get api('/groups', user2), params: { min_access_level: 40 } } + + it 'counts with *' do + count_sql = /#{Regexp.escape('SELECT count(*)')}/i + expect { subject }.to make_queries_matching count_sql + end + + context 'when present_groups_select_all feature flag is disabled' do + before do + stub_feature_flags(present_groups_select_all: false) + end + + it 'counts with count_column' do + count_sql = /#{Regexp.escape('SELECT count(count_column)')}/i + expect { subject }.to make_queries_matching count_sql + end + end + end end end diff --git a/spec/support/matchers/event_store.rb b/spec/support/matchers/event_store.rb index 7cf25468eb2..582ea202187 100644 --- a/spec/support/matchers/event_store.rb +++ b/spec/support/matchers/event_store.rb @@ -6,7 +6,7 @@ RSpec::Matchers.define :publish_event do |expected_event_class| supports_block_expectations match do |proc| - raise ArgumentError, 'This matcher only supports block expectation' unless proc.respond_to?(:call) + raise ArgumentError, 'publish_event matcher only supports block expectation' unless proc.respond_to?(:call) @events ||= [] @@ -22,6 +22,8 @@ RSpec::Matchers.define :publish_event do |expected_event_class| end def match_data?(actual, expected) + return if actual.blank? || expected.blank? + values_match?(actual.keys, expected.keys) && actual.keys.all? do |key| values_match?(expected[key], actual[key]) @@ -33,7 +35,7 @@ RSpec::Matchers.define :publish_event do |expected_event_class| end failure_message do - message = "expected #{expected_event_class} with #{@expected_data} to be published" + message = "expected #{expected_event_class} with #{@expected_data || 'no data'} to be published" if @events.present? <<~MESSAGE @@ -46,7 +48,7 @@ RSpec::Matchers.define :publish_event do |expected_event_class| end match_when_negated do |proc| - raise ArgumentError, 'This matcher only supports block expectation' unless proc.respond_to?(:call) + raise ArgumentError, 'publish_event matcher only supports block expectation' unless proc.respond_to?(:call) allow(Gitlab::EventStore).to receive(:publish) @@ -57,7 +59,45 @@ RSpec::Matchers.define :publish_event do |expected_event_class| def events_list @events.map do |event| - " - #{event.class.name} #{event.data}" + " - #{event.class.name} with #{event.data}" end.join("\n") end end + +# not_publish_event enables multiple assertions on a single block, for example: +# expect { Model.create(invalid: :attribute) } +# .to not_change(Model, :count) +# .and not_publish_event(ModelCreated) +RSpec::Matchers.define :not_publish_event do |expected_event_class| + include RSpec::Matchers::Composable + + supports_block_expectations + + match do |proc| + raise ArgumentError, 'not_publish_event matcher only supports block expectation' unless proc.respond_to?(:call) + + @events ||= [] + + allow(Gitlab::EventStore).to receive(:publish) do |published_event| + @events << published_event + end + + proc.call + + @events.none? do |event| + event.instance_of?(expected_event_class) + end + end + + failure_message do + "expected #{expected_event_class} not to be published" + end + + chain :with do |_| # rubocop: disable Lint/UnreachableLoop + raise ArgumentError, 'not_publish_event does not permit .with to avoid ambiguity' + end + + match_when_negated do |proc| + raise ArgumentError, 'not_publish_event matcher does not support negation. Use `expect {}.to publish_event` instead' + end +end diff --git a/spec/support_specs/matchers/event_store_spec.rb b/spec/support_specs/matchers/event_store_spec.rb new file mode 100644 index 00000000000..3614d05fde8 --- /dev/null +++ b/spec/support_specs/matchers/event_store_spec.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'json_schemer' + +load File.expand_path('../../../spec/support/matchers/event_store.rb', __dir__) + +RSpec.describe 'event store matchers', :aggregate_errors do + let(:event_type1) do + Class.new(Gitlab::EventStore::Event) do + def schema + { + 'type' => 'object', + 'properties' => { + 'id' => { 'type' => 'integer' } + }, + 'required' => %w[id] + } + end + end + end + + let(:event_type2) do + Class.new(Gitlab::EventStore::Event) do + def schema + { + 'type' => 'object', + 'properties' => { + 'id' => { 'type' => 'integer' } + }, + 'required' => %w[id] + } + end + end + end + + before do + stub_const('FakeEventType1', event_type1) + stub_const('FakeEventType2', event_type2) + end + + def publishing_event(event_type, data = {}) + ::Gitlab::EventStore.publish(event_type.new(data: data)) + end + + describe 'publish_event' do + it 'requires a block matcher' do + matcher = -> { expect(:anything).to publish_event(:anything) } # rubocop: disable RSpec/ExpectActual + + expect(&matcher).to raise_error( + ArgumentError, + 'publish_event matcher only supports block expectation' + ) + end + + it 'validates the event type' do + valid_event_type = -> do + expect { publishing_event(FakeEventType1, { 'id' => 1 }) } + .to publish_event(FakeEventType1).with('id' => 1) + end + + expect(&valid_event_type).not_to raise_error + + invalid_event_type = -> do + expect { publishing_event(FakeEventType1, { 'id' => 1 }) } + .to publish_event(FakeEventType2).with('id' => 1) + end + + expect(&invalid_event_type).to raise_error <<~MESSAGE + expected FakeEventType2 with {"id"=>1} to be published, but only the following events were published: + - FakeEventType1 with {"id"=>1} + MESSAGE + end + + it 'validates the event data' do + missing_data = -> do + expect { publishing_event(FakeEventType1, { 'id' => 1 }) } + .to publish_event(FakeEventType1) + end + + expect(&missing_data).to raise_error <<~MESSAGE + expected FakeEventType1 with no data to be published, but only the following events were published: + - FakeEventType1 with {"id"=>1} + MESSAGE + + different_data = -> do + expect { publishing_event(FakeEventType1, { 'id' => 1 }) } + .to publish_event(FakeEventType1).with({ 'id' => 2 }) + end + + expect(&different_data).to raise_error <<~MESSAGE + expected FakeEventType1 with {"id"=>2} to be published, but only the following events were published: + - FakeEventType1 with {"id"=>1} + MESSAGE + end + end + + describe 'not_publish_event' do + it 'requires a block matcher' do + matcher = -> { expect(:anything).to not_publish_event(:anything) } # rubocop: disable RSpec/ExpectActual + + expect(&matcher) + .to raise_error(ArgumentError, 'not_publish_event matcher only supports block expectation') + end + + it 'does not permit .with' do + matcher = -> do + expect { publishing_event(FakeEventType1, { 'id' => 1 }) } + .to not_publish_event(FakeEventType2).with({ 'id' => 1 }) + end + + expect(&matcher) + .to raise_error(ArgumentError, 'not_publish_event does not permit .with to avoid ambiguity') + end + + it 'validates the event type' do + matcher = -> do + expect { publishing_event(FakeEventType1, { 'id' => 1 }) } + .to not_publish_event(FakeEventType1) + end + + expect(&matcher) + .to raise_error('expected FakeEventType1 not to be published') + end + end +end diff --git a/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb b/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb index 0e24810f835..2f423c72ca6 100644 --- a/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb +++ b/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb @@ -12,5 +12,11 @@ RSpec.describe 'layouts/header/_gitlab_version' do it 'renders the version check badge' do expect(rendered).to have_selector('.js-gitlab-version-check') end + + it 'renders the container as a link' do + expect(rendered).to have_selector( + 'a[data-testid="gitlab-version-container"][href="/help/update/index"]' + ) + end end end |