diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-08 03:15:27 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-08 03:15:27 +0300 |
commit | d52f8933ea07f083dfc05d4bed50d4de8baf8dd9 (patch) | |
tree | 6cf2d2b4180ddd59c2f6dedabc272cc6f40ea81d | |
parent | 0f6fb8a8c9ccad0d0f4b8c5e2f72aa50d35a0d0d (diff) |
Add latest changes from gitlab-org/gitlab@master
27 files changed, 696 insertions, 328 deletions
diff --git a/.rubocop_todo/rails/include_url_helper.yml b/.rubocop_todo/rails/include_url_helper.yml deleted file mode 100644 index e5b504d8b9a..00000000000 --- a/.rubocop_todo/rails/include_url_helper.yml +++ /dev/null @@ -1,10 +0,0 @@ ---- -Rails/IncludeUrlHelper: - Exclude: - - ee/spec/helpers/ee/projects/security/configuration_helper_spec.rb - - ee/spec/lib/banzai/filter/cross_project_issuable_information_filter_spec.rb - - spec/helpers/merge_requests_helper_spec.rb - - spec/helpers/nav/top_nav_helper_spec.rb - - spec/helpers/notify_helper_spec.rb - - spec/lib/banzai/filter/reference_redactor_filter_spec.rb - - spec/lib/banzai/reference_redactor_spec.rb diff --git a/app/assets/javascripts/integrations/constants.js b/app/assets/javascripts/integrations/constants.js index 7daa6433fb8..edc355fdc8d 100644 --- a/app/assets/javascripts/integrations/constants.js +++ b/app/assets/javascripts/integrations/constants.js @@ -25,3 +25,11 @@ export const I18N_SUCCESSFUL_CONNECTION_MESSAGE = s__('Integrations|Connection s export const settingsTabTitle = __('Settings'); export const overridesTabTitle = s__('Integrations|Projects using custom settings'); + +export const integrationFormSections = { + CONNECTION: 'connection', +}; + +export const integrationFormSectionComponents = { + [integrationFormSections.CONNECTION]: 'IntegrationSectionConnection', +}; diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue index f955cc1b432..872b8d0b2b7 100644 --- a/app/assets/javascripts/integrations/edit/components/integration_form.vue +++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue @@ -10,6 +10,7 @@ import { I18N_DEFAULT_ERROR_MESSAGE, I18N_SUCCESSFUL_CONNECTION_MESSAGE, integrationLevels, + integrationFormSectionComponents, } from '~/integrations/constants'; import { refreshCurrentPage } from '~/lib/utils/url_utility'; import csrf from '~/lib/utils/csrf'; @@ -34,6 +35,10 @@ export default { DynamicField, ConfirmationModal, ResetConfirmationModal, + IntegrationSectionConnection: () => + import( + /* webpackChunkName: 'integrationSectionConnection' */ '~/integrations/edit/components/sections/connection.vue' + ), GlButton, GlForm, }, @@ -80,9 +85,23 @@ export default { disableButtons() { return Boolean(this.isSaving || this.isResetting || this.isTesting); }, + sectionsEnabled() { + return this.glFeatures.integrationFormSections; + }, + hasSections() { + return this.sectionsEnabled && this.customState.sections.length !== 0; + }, + fieldsWithoutSection() { + return this.sectionsEnabled + ? this.propsSource.fields.filter((field) => !field.section) + : this.propsSource.fields; + }, }, methods: { ...mapActions(['setOverride', 'requestJiraIssueTypes']), + fieldsForSection(section) { + return this.propsSource.fields.filter((field) => field.section === section.type); + }, form() { return this.$refs.integrationForm.$el; }, @@ -158,6 +177,7 @@ export default { FORBID_ATTR: [], // This is trusted input so we can override the default config to allow data-* attributes }, csrf, + integrationFormSectionComponents, }; </script> @@ -186,15 +206,40 @@ export default { @change="setOverride" /> + <template v-if="hasSections"> + <div + v-for="section in customState.sections" + :key="section.type" + class="gl-border-b gl-mb-5" + data-testid="integration-section" + > + <div class="row"> + <div class="col-lg-4"> + <h4 class="gl-mt-0">{{ section.title }}</h4> + <p v-safe-html="section.description"></p> + </div> + + <div class="col-lg-8"> + <component + :is="$options.integrationFormSectionComponents[section.type]" + :fields="fieldsForSection(section)" + :is-validated="isValidated" + @toggle-integration-active="onToggleIntegrationState" + /> + </div> + </div> + </div> + </template> + <div class="row"> <div class="col-lg-4"></div> <div class="col-lg-8"> <!-- helpHtml is trusted input --> - <div v-if="helpHtml" v-safe-html:[$options.helpHtmlConfig]="helpHtml"></div> + <div v-if="helpHtml && !hasSections" v-safe-html:[$options.helpHtmlConfig]="helpHtml"></div> <active-checkbox - v-if="propsSource.showActive" + v-if="propsSource.showActive && !hasSections" :key="`${currentKey}-active-checkbox`" @toggle-integration-active="onToggleIntegrationState" /> @@ -211,7 +256,7 @@ export default { :type="propsSource.type" /> <dynamic-field - v-for="field in propsSource.fields" + v-for="field in fieldsWithoutSection" :key="`${currentKey}-${field.name}`" v-bind="field" :is-validated="isValidated" diff --git a/app/assets/javascripts/integrations/edit/components/sections/connection.vue b/app/assets/javascripts/integrations/edit/components/sections/connection.vue new file mode 100644 index 00000000000..364e9324e43 --- /dev/null +++ b/app/assets/javascripts/integrations/edit/components/sections/connection.vue @@ -0,0 +1,45 @@ +<script> +import { mapGetters } from 'vuex'; + +import ActiveCheckbox from '../active_checkbox.vue'; +import DynamicField from '../dynamic_field.vue'; + +export default { + name: 'IntegrationSectionConnection', + components: { + ActiveCheckbox, + DynamicField, + }, + props: { + fields: { + type: Array, + required: false, + default: () => [], + }, + isValidated: { + type: Boolean, + required: false, + default: false, + }, + }, + computed: { + ...mapGetters(['currentKey', 'propsSource']), + }, +}; +</script> + +<template> + <div> + <active-checkbox + v-if="propsSource.showActive" + :key="`${currentKey}-active-checkbox`" + @toggle-integration-active="$emit('toggle-integration-active', $event)" + /> + <dynamic-field + v-for="field in fields" + :key="`${currentKey}-${field.name}`" + v-bind="field" + :is-validated="isValidated" + /> + </div> +</template> diff --git a/app/graphql/resolvers/concerns/resolves_pipelines.rb b/app/graphql/resolvers/concerns/resolves_pipelines.rb index 2b2a4fd926f..764ed9b15fd 100644 --- a/app/graphql/resolvers/concerns/resolves_pipelines.rb +++ b/app/graphql/resolvers/concerns/resolves_pipelines.rb @@ -24,6 +24,14 @@ module ResolvesPipelines GraphQL::Types::String, required: false, description: "Filter pipelines by their source." + + argument :updated_after, Types::TimeType, + required: false, + description: 'Pipelines updated after this date.' + argument :updated_before, Types::TimeType, + required: false, + description: 'Pipelines updated before this date.' + argument :username, GraphQL::Types::String, required: false, diff --git a/db/post_migrate/20220302203410_create_index_security_ci_builds_on_name_and_id_parser_with_new_features.rb b/db/post_migrate/20220302203410_create_index_security_ci_builds_on_name_and_id_parser_with_new_features.rb new file mode 100644 index 00000000000..5be6bb00269 --- /dev/null +++ b/db/post_migrate/20220302203410_create_index_security_ci_builds_on_name_and_id_parser_with_new_features.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class CreateIndexSecurityCiBuildsOnNameAndIdParserWithNewFeatures < Gitlab::Database::Migration[1.0] + TABLE = "ci_builds" + COLUMNS = %i[name id] + INDEX_NAME = "index_security_ci_builds_on_name_and_id_parser_features" + CONSTRAINTS = "(name::text = ANY (ARRAY['container_scanning'::character varying::text, + 'dast'::character varying::text, + 'dependency_scanning'::character varying::text, + 'license_management'::character varying::text, + 'sast'::character varying::text, + 'secret_detection'::character varying::text, + 'coverage_fuzzing'::character varying::text, + 'license_scanning'::character varying::text, + 'apifuzzer_fuzz'::character varying::text, + 'apifuzzer_fuzz_dnd'::character varying::text]) + ) AND type::text = 'Ci::Build'::text" + + disable_ddl_transaction! + + def up + add_concurrent_index(TABLE, COLUMNS, name: INDEX_NAME, where: CONSTRAINTS) + end + + def down + remove_concurrent_index(TABLE, COLUMNS, name: INDEX_NAME, where: CONSTRAINTS) + end +end diff --git a/db/post_migrate/20220304201847_add_unique_index_on_security_training_providers.rb b/db/post_migrate/20220304201847_add_unique_index_on_security_training_providers.rb new file mode 100644 index 00000000000..e78b8fd48ca --- /dev/null +++ b/db/post_migrate/20220304201847_add_unique_index_on_security_training_providers.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class AddUniqueIndexOnSecurityTrainingProviders < Gitlab::Database::Migration[1.0] + INDEX_NAME = 'index_security_training_providers_on_unique_name' + + disable_ddl_transaction! + + def up + add_concurrent_index :security_training_providers, :name, unique: true, name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :security_training_providers, INDEX_NAME + end +end diff --git a/db/schema_migrations/20220302203410 b/db/schema_migrations/20220302203410 new file mode 100644 index 00000000000..70326d38a97 --- /dev/null +++ b/db/schema_migrations/20220302203410 @@ -0,0 +1 @@ +873aac965684e58cfdb6098b20891cbb73614aff833f235d76bfd379498f6fda
\ No newline at end of file diff --git a/db/schema_migrations/20220304201847 b/db/schema_migrations/20220304201847 new file mode 100644 index 00000000000..1dafb1b821e --- /dev/null +++ b/db/schema_migrations/20220304201847 @@ -0,0 +1 @@ +d60a313ac68b0edfe1ae219690aacbe74c038b90bc4239f67d14f9ced36d67f6
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 2622794b2a4..4161008598d 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -28935,6 +28935,8 @@ CREATE UNIQUE INDEX index_scim_oauth_access_tokens_on_group_id_and_token_encrypt CREATE INDEX index_secure_ci_builds_on_user_id_name_created_at ON ci_builds USING btree (user_id, name, created_at) WHERE (((type)::text = 'Ci::Build'::text) AND ((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('license_scanning'::character varying)::text, ('sast'::character varying)::text, ('coverage_fuzzing'::character varying)::text, ('apifuzzer_fuzz'::character varying)::text, ('apifuzzer_fuzz_dnd'::character varying)::text, ('secret_detection'::character varying)::text]))); +CREATE INDEX index_security_ci_builds_on_name_and_id_parser_features ON ci_builds USING btree (name, id) WHERE (((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('sast'::character varying)::text, ('secret_detection'::character varying)::text, ('coverage_fuzzing'::character varying)::text, ('license_scanning'::character varying)::text, ('apifuzzer_fuzz'::character varying)::text, ('apifuzzer_fuzz_dnd'::character varying)::text])) AND ((type)::text = 'Ci::Build'::text)); + CREATE INDEX index_security_ci_builds_on_name_and_id_parser_features_old ON ci_builds USING btree (name, id) WHERE (((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('sast'::character varying)::text, ('secret_detection'::character varying)::text, ('coverage_fuzzing'::character varying)::text, ('license_scanning'::character varying)::text])) AND ((type)::text = 'Ci::Build'::text)); CREATE INDEX index_security_findings_on_confidence ON security_findings USING btree (confidence); @@ -28957,6 +28959,8 @@ CREATE INDEX index_security_scans_on_pipeline_id ON security_scans USING btree ( CREATE INDEX index_security_scans_on_project_id ON security_scans USING btree (project_id); +CREATE UNIQUE INDEX index_security_training_providers_on_unique_name ON security_training_providers USING btree (name); + CREATE INDEX index_security_trainings_on_project_id ON security_trainings USING btree (project_id); CREATE INDEX index_security_trainings_on_provider_id ON security_trainings USING btree (provider_id); diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 42636361edb..40269eae869 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -9521,6 +9521,8 @@ four standard [pagination arguments](#connection-pagination-arguments): | <a id="commitpipelinessha"></a>`sha` | [`String`](#string) | Filter pipelines by the sha of the commit they are run for. | | <a id="commitpipelinessource"></a>`source` | [`String`](#string) | Filter pipelines by their source. | | <a id="commitpipelinesstatus"></a>`status` | [`PipelineStatusEnum`](#pipelinestatusenum) | Filter pipelines by their status. | +| <a id="commitpipelinesupdatedafter"></a>`updatedAfter` | [`Time`](#time) | Pipelines updated after this date. | +| <a id="commitpipelinesupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Pipelines updated before this date. | | <a id="commitpipelinesusername"></a>`username` | [`String`](#string) | Filter pipelines by the user that triggered the pipeline. | ### `ComplianceFramework` @@ -12416,6 +12418,8 @@ four standard [pagination arguments](#connection-pagination-arguments): | <a id="mergerequestpipelinessha"></a>`sha` | [`String`](#string) | Filter pipelines by the sha of the commit they are run for. | | <a id="mergerequestpipelinessource"></a>`source` | [`String`](#string) | Filter pipelines by their source. | | <a id="mergerequestpipelinesstatus"></a>`status` | [`PipelineStatusEnum`](#pipelinestatusenum) | Filter pipelines by their status. | +| <a id="mergerequestpipelinesupdatedafter"></a>`updatedAfter` | [`Time`](#time) | Pipelines updated after this date. | +| <a id="mergerequestpipelinesupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Pipelines updated before this date. | | <a id="mergerequestpipelinesusername"></a>`username` | [`String`](#string) | Filter pipelines by the user that triggered the pipeline. | ##### `MergeRequest.reference` @@ -14464,6 +14468,8 @@ four standard [pagination arguments](#connection-pagination-arguments): | <a id="projectpipelinessha"></a>`sha` | [`String`](#string) | Filter pipelines by the sha of the commit they are run for. | | <a id="projectpipelinessource"></a>`source` | [`String`](#string) | Filter pipelines by their source. | | <a id="projectpipelinesstatus"></a>`status` | [`PipelineStatusEnum`](#pipelinestatusenum) | Filter pipelines by their status. | +| <a id="projectpipelinesupdatedafter"></a>`updatedAfter` | [`Time`](#time) | Pipelines updated after this date. | +| <a id="projectpipelinesupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Pipelines updated before this date. | | <a id="projectpipelinesusername"></a>`username` | [`String`](#string) | Filter pipelines by the user that triggered the pipeline. | ##### `Project.projectMembers` diff --git a/doc/ci/runners/runners_scope.md b/doc/ci/runners/runners_scope.md index 7cfd8e50f6c..aa7e268e800 100644 --- a/doc/ci/runners/runners_scope.md +++ b/doc/ci/runners/runners_scope.md @@ -236,6 +236,10 @@ To enable or disable a specific runner for a project: 1. Go to the project's **Settings > CI/CD** and expand the **Runners** section. 1. Click **Enable for this project** or **Disable for this project**. +You can edit a specific runner from any of the projects it's enabled for. +The modifications, which include unlocking, editing tags and the description, +affect all projects that use the runner. + ### Prevent a specific runner from being enabled for other projects You can configure a specific runner so it is "locked" and cannot be enabled for other projects. diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md index d9f35fd4b76..91e9d0c703d 100644 --- a/doc/development/documentation/styleguide/index.md +++ b/doc/development/documentation/styleguide/index.md @@ -655,52 +655,39 @@ This is overridden by the [documentation-specific punctuation rules](#punctuatio ## Headings -- Add only one H1 in each document, by adding `#` at the beginning of - it (when using Markdown). The `h1` becomes the document `<title>`. -- Start with an `h2` (`##`), and respect the order `h2` > `h3` > `h4` > `h5` > `h6`. - Never skip the hierarchy level, such as `h2` > `h4` -- Avoid putting numbers in headings. Numbers shift, hence documentation anchor - links shift too, which eventually leads to dead links. If you think it is - compelling to add numbers in headings, make sure to at least discuss it with - someone in the merge request. -- [Avoid using symbols and special characters](https://gitlab.com/gitlab-org/gitlab-docs/-/issues/84) - in headers. Whenever possible, they should be plain and short text. -- When possible, avoid including words that might change in the future. Changing +In the Markdown document: + +- Add one H1 (`#`) at the start of the page. The `h1` becomes the document `<title>`. +- After the H1, follow the order `h2` > `h3` > `h4` > `h5` > `h6`. +- Do not skip a level. For example: `h2` > `h4`. +- Leave one blank line before and after the heading. + +For the heading text, **do**: + +- Be clear and direct. Make every word count. +- Use active verbs for tasks. For example, `Configure GDK` instead of `Configuring GDK`. +- Talk about what the product does, realistically but from a positive perspective. Instead of + `Limitations`, move the content near other similar information. If you must, you can + use the title `Known issues`. +- Use articles and prepositions. +- Add the [product badge](#product-tier-badges) that corresponds to the license tier. +- Follow [capitalization](#capitalization) guidelines. + +For the heading text, **do not**: + +- Use generic words like `Overview` or `Use cases`. Instead, incorporate + the information under a concept heading. +- Use `How it works`. Incorporate this information under a concept, or use a + noun followed by `workflow`. For example, `Merge request workflow`. +- Use `Important Notes`. Incorporate this information closer to where it belongs. +- Use numbers to indicate steps. If the numbers change, the anchor links changes, + which eventually leads to dead links. If you think you must add numbers in headings, + at least discuss it with a writer in the merge request. +- Use words that might change in the future. Changing a heading changes its anchor URL, which affects other linked pages. -- When introducing a new document, be careful for the headings to be - grammatically and syntactically correct. Mention an [assigned technical writer (TW)](https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments) - for review, based upon the [product category](https://about.gitlab.com/handbook/product/categories/). - This is to ensure that no document with wrong heading is going live without an - audit, thus preventing dead links and redirection issues when corrected. -- Use the context provided by parent section headings. That is, don't repeat the parent heading's text in each - subsection's heading. -- Use articles and prepositions in headings where it would make sense in regular text. -- Leave exactly one blank line before and after a heading. -- Do not use links in headings. -- Add the corresponding [product badge](#product-tier-badges) according to the tier the - feature belongs. -- Our documentation site search engine prioritizes words used in headings and - subheadings. Make your subheading titles clear, descriptive, and complete to help - users find the right example, as shown in the section on [heading titles](#heading-titles). -- See [Capitalization](#capitalization) for guidelines on capitalizing headings. - -### Heading titles - -Keep heading titles clear and direct. Make every word count. To accommodate -search engine optimization (SEO), use the imperative, where possible. - -| Do | Don't | -|:--------------------------------------|:------------------------------------------------------------| -| Configure GDK | Configuring GDK | -| GitLab Release and Maintenance Policy | This section covers the GitLab Release and Maintenance Policy | -| Backport to older releases | Backporting to older releases | -| GitLab Pages examples | Examples | - -For guidelines on capitalizing headings, see the section on [capitalization](#capitalization). - -NOTE: -If you change an existing title, be careful. In-page [anchor links](#anchor-links), -links in the GitLab application, and links from external sites can break. +- Repeat text from earlier headings. For example, instead of `Troubleshooting merge requests`, + use `Troubleshooting`. +- Use links. ### Anchor links diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 829fe1410ec..c90f575e83a 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -4,7 +4,7 @@ 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 --- -# Permissions and roles +# Permissions and roles **(FREE)** Users have different abilities depending on the role they have in a particular group or project. If a user is both in a project's group and the @@ -54,155 +54,155 @@ The following table lists project permissions available for each role: <!-- Keep this table sorted: By topic first, then by minimum role, then alphabetically. --> -| Action | Guest | Reporter | Developer | Maintainer | Owner | -|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|----------|-----------|------------|-------| -| [Analytics](analytics/index.md):<br>View issue analytics **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Analytics](analytics/index.md):<br>View [merge request analytics](analytics/merge_request_analytics.md) **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Analytics](analytics/index.md):<br>View value stream analytics | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Analytics](analytics/index.md):<br>View [DORA metrics](analytics/ci_cd_analytics.md) | | ✓ | ✓ | ✓ | ✓ | -| [Analytics](analytics/index.md):<br>View [CI/CD analytics](analytics/ci_cd_analytics.md) | | ✓ | ✓ | ✓ | ✓ | -| [Analytics](analytics/index.md):<br>View [code review analytics](analytics/code_review_analytics.md) **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ | -| [Analytics](analytics/index.md):<br>View [repository analytics](analytics/repository_analytics.md) | | ✓ | ✓ | ✓ | ✓ | -| [Application security](application_security/index.md):<br>View licenses in [dependency list](application_security/dependency_list/index.md) **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| [Application security](application_security/index.md):<br>Create and run [on-demand DAST scans](application_security/dast/index.md#on-demand-scans) **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Application security](application_security/index.md):<br>Manage [security policy](application_security/policies/index.md) **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Application security](application_security/index.md):<br>View [dependency list](application_security/dependency_list/index.md) **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Application security](application_security/index.md):<br>View [threats list](application_security/threat_monitoring/index.md#threat-monitoring) **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Application security](application_security/index.md):<br>Create a [CVE ID Request](application_security/cve_id_request.md) **(FREE SAAS)** | | | | ✓ | ✓ | -| [Application security](application_security/index.md):<br>Create or assign [security policy project](application_security/policies/index.md) **(ULTIMATE)** | | | | | ✓ | -| [Clusters](infrastructure/clusters/index.md):<br>View [pod logs](project/clusters/kubernetes_pod_logs.md) | | | ✓ | ✓ | ✓ | -| [Clusters](infrastructure/clusters/index.md):<br>View clusters | | | ✓ | ✓ | ✓ | -| [Clusters](infrastructure/clusters/index.md):<br>Manage clusters | | | | ✓ | ✓ | -| [Container Registry](packages/container_registry/index.md):<br>Create, edit, delete cleanup policies | | | ✓ | ✓ | ✓ | -| [Container Registry](packages/container_registry/index.md):<br>Push an image to the Container Registry | | | ✓ | ✓ | ✓ | -| [Container Registry](packages/container_registry/index.md):<br>Pull an image from the Container Registry | ✓ (*20*) | ✓ (*20*) | ✓ | ✓ | ✓ | -| [Container Registry](packages/container_registry/index.md):<br>Remove a Container Registry image | | | ✓ | ✓ | ✓ | -| [GitLab Pages](project/pages/index.md):<br>View Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control) | ✓ | ✓ | ✓ | ✓ | ✓ | -| [GitLab Pages](project/pages/index.md):<br>Manage | | | | ✓ | ✓ | -| [GitLab Pages](project/pages/index.md):<br>Manage GitLab Pages domains and certificates | | | | ✓ | ✓ | -| [GitLab Pages](project/pages/index.md):<br>Remove GitLab Pages | | | | ✓ | ✓ | -| [Incident Management](../operations/incident_management/index.md):<br>View [alerts](../operations/incident_management/alerts.md) | | ✓ | ✓ | ✓ | ✓ | -| [Incident Management](../operations/incident_management/index.md):<br>Assign an alert | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Incident Management](../operations/incident_management/index.md):<br>View [incident](../operations/incident_management/incidents.md) | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Incident Management](../operations/incident_management/index.md):<br>Create [incident](../operations/incident_management/incidents.md) | (*16*) | ✓ | ✓ | ✓ | ✓ | -| [Incident Management](../operations/incident_management/index.md):<br>View [on-call schedules](../operations/incident_management/oncall_schedules.md) | | ✓ | ✓ | ✓ | ✓ | -| [Incident Management](../operations/incident_management/index.md):<br>Participate in on-call rotation | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Incident Management](../operations/incident_management/index.md):<br>View [escalation policies](../operations/incident_management/escalation_policies.md) | | ✓ | ✓ | ✓ | ✓ | -| [Incident Management](../operations/incident_management/index.md):<br>Manage [on-call schedules](../operations/incident_management/oncall_schedules.md) | | | | ✓ | ✓ | -| [Incident Management](../operations/incident_management/index.md):<br>Manage [escalation policies](../operations/incident_management/escalation_policies.md) | | | | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Add Labels | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Assign | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Create (*18*) | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Create [confidential issues](project/issues/confidential_issues.md) | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>View related issues | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Set weight | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>View [confidential issues](project/issues/confidential_issues.md) | (*2*) | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Close / reopen (*19*) | | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Lock threads | | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Manage related issues | | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Manage tracker | | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Move issues (*14*) | | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Set issue [time tracking](project/time_tracking.md) estimate and time spent | | ✓ | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Upload [Design Management](project/issues/design_management.md) files | | | ✓ | ✓ | ✓ | -| [Issues](project/issues/index.md):<br>Delete | | | | | ✓ | -| [License Compliance](compliance/license_compliance/index.md):<br>View allowed and denied licenses **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| [License Compliance](compliance/license_compliance/index.md):<br>View License Compliance reports **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| [License Compliance](compliance/license_compliance/index.md):<br>View License list **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ | -| [License Compliance](compliance/license_compliance/index.md):<br>Manage license policy **(ULTIMATE)** | | | | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Assign reviewer | | ✓ | ✓ | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>See list | | ✓ | ✓ | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Apply code change suggestions | | | ✓ | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Approve (*8*) | | | ✓ | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Assign | | | ✓ | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Create (*17*) | | | ✓ | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Add labels | | | ✓ | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Lock threads | | | ✓ | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Manage or accept | | | ✓ | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Manage merge approval rules (project settings) | | | | ✓ | ✓ | -| [Merge requests](project/merge_requests/index.md):<br>Delete | | | | | ✓ | -| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>Manage user-starred metrics dashboards (*6*) | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>View metrics dashboard annotations | | ✓ | ✓ | ✓ | ✓ | -| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ | -| [Package registry](packages/index.md):<br>Pull a package | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| [Package registry](packages/index.md):<br>Publish a package | | | ✓ | ✓ | ✓ | -| [Package registry](packages/index.md):<br>Delete a package | | | | ✓ | ✓ | -| [Package registry](packages/index.md):<br>Delete a file associated with a package | | | | ✓ | ✓ | -| [Project operations](../operations/index.md):<br>View [Error Tracking](../operations/error_tracking.md) list | | ✓ | ✓ | ✓ | ✓ | -| [Project operations](../operations/index.md):<br>Manage [Feature Flags](../operations/feature_flags.md) **(PREMIUM)** | | | ✓ | ✓ | ✓ | -| [Project operations](../operations/index.md):<br>Manage [Error Tracking](../operations/error_tracking.md) | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Download project | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>Reposition comments on images (posted by any user) | ✓ (*9*) | ✓ (*9*) | ✓ (*9*) | ✓ | ✓ | -| [Projects](project/index.md):<br>View Insights **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>View [releases](project/releases/index.md) | ✓ (*5*) | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>View Requirements **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>View [time tracking](project/time_tracking.md) reports | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>View [wiki](project/wiki/index.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>Create [snippets](snippets.md) | | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>Manage labels | | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>View [project traffic statistics](../api/project_statistics.md) | | ✓ | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>Create, edit, delete [milestones](project/milestones/index.md). | | | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>Create, edit, delete [releases](project/releases/index.md) | | | ✓ (*12*) | ✓ (*12*) | ✓ (*12*) | -| [Projects](project/index.md):<br>Create, edit [wiki](project/wiki/index.md) pages | | | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>Enable Review Apps | | | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>View project [Audit Events](../administration/audit_events.md) | | | ✓ (*10*) | ✓ | ✓ | -| [Projects](project/index.md):<br>Add deploy keys | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Add new team members | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Change [project features visibility](../public_access/public_access.md) level | | | | ✓ (*13*) | ✓ | -| [Projects](project/index.md):<br>Configure [webhooks](project/integrations/webhooks.md) | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Delete [wiki](project/wiki/index.md) pages | | | ✓ | ✓ | ✓ | -| [Projects](project/index.md):<br>Edit comments (posted by any user) | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Edit project badges | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Edit project settings | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Export project | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Manage [project access tokens](project/settings/project_access_tokens.md) **(FREE SELF)** **(PREMIUM SAAS)** (*11*) | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Manage [Project Operations](../operations/index.md) | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Rename project | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Share (invite) projects with groups | | | | ✓ (*7*) | ✓ (*7*) | -| [Projects](project/index.md):<br>View 2FA status of members | | | | ✓ | ✓ | -| [Projects](project/index.md):<br>Administer project compliance frameworks | | | | | ✓ | -| [Projects](project/index.md):<br>Archive project | | | | | ✓ | -| [Projects](project/index.md):<br>Change project visibility level | | | | | ✓ | -| [Projects](project/index.md):<br>Delete project | | | | | ✓ | -| [Projects](project/index.md):<br>Disable notification emails | | | | | ✓ | -| [Projects](project/index.md):<br>Transfer project to another namespace | | | | | ✓ | -| [Repository](project/repository/index.md):<br>Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>View project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>View a commit status | | ✓ | ✓ | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Add tags | | | ✓ | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Create new branches | | | ✓ | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Create or update commit status | | | ✓ (*4*) | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Force push to non-protected branches | | | ✓ | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Push to non-protected branches | | | ✓ | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Remove non-protected branches | | | ✓ | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Rewrite or remove Git tags | | | ✓ | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Enable or disable branch protection | | | | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Enable or disable tag protection | | | | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Manage [push rules](project/repository/push_rules.md) | | | | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Push to protected branches (*4*) | | | | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Turn on or off protected branch push for developers | | | | ✓ | ✓ | -| [Repository](project/repository/index.md):<br>Remove fork relationship | | | | | ✓ | -| [Repository](project/repository/index.md):<br>Force push to protected branches (*3*) | | | | | | -| [Repository](project/repository/index.md):<br>Remove protected branches (*3*) | | | | | | -| [Requirements Management](project/requirements/index.md):<br>Archive / reopen **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ | -| [Requirements Management](project/requirements/index.md):<br>Create / edit **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ | -| [Requirements Management](project/requirements/index.md):<br>Import / export **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ | -| [Security dashboard](application_security/security_dashboard/index.md):<br>Create issue from vulnerability finding **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Security dashboard](application_security/security_dashboard/index.md):<br>Create vulnerability from vulnerability finding **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Security dashboard](application_security/security_dashboard/index.md):<br>Dismiss vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Security dashboard](application_security/security_dashboard/index.md):<br>Dismiss vulnerability finding **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Security dashboard](application_security/security_dashboard/index.md):<br>Resolve vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Security dashboard](application_security/security_dashboard/index.md):<br>Revert vulnerability to detected state **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Security dashboard](application_security/security_dashboard/index.md):<br>Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Security dashboard](application_security/security_dashboard/index.md):<br>View vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Security dashboard](application_security/security_dashboard/index.md):<br>View vulnerability findings in [dependency list](application_security/dependency_list/index.md) **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| [Terraform](infrastructure/index.md):<br>Read Terraform state | | | ✓ | ✓ | ✓ | -| [Terraform](infrastructure/index.md):<br>Manage Terraform state | | | | ✓ | ✓ | -| [Test cases](../ci/test_cases/index.md):<br>Archive | | ✓ | ✓ | ✓ | ✓ | -| [Test cases](../ci/test_cases/index.md):<br>Create | | ✓ | ✓ | ✓ | ✓ | -| [Test cases](../ci/test_cases/index.md):<br>Move | | ✓ | ✓ | ✓ | ✓ | -| [Test cases](../ci/test_cases/index.md):<br>Reopen | | ✓ | ✓ | ✓ | ✓ | +| Action | Guest | Reporter | Developer | Maintainer | Owner | +|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|----------|-----------|------------|----------| +| [Analytics](analytics/index.md):<br>View issue analytics | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Analytics](analytics/index.md):<br>View [merge request analytics](analytics/merge_request_analytics.md) | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Analytics](analytics/index.md):<br>View value stream analytics | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Analytics](analytics/index.md):<br>View [DORA metrics](analytics/ci_cd_analytics.md) | | ✓ | ✓ | ✓ | ✓ | +| [Analytics](analytics/index.md):<br>View [CI/CD analytics](analytics/ci_cd_analytics.md) | | ✓ | ✓ | ✓ | ✓ | +| [Analytics](analytics/index.md):<br>View [code review analytics](analytics/code_review_analytics.md) | | ✓ | ✓ | ✓ | ✓ | +| [Analytics](analytics/index.md):<br>View [repository analytics](analytics/repository_analytics.md) | | ✓ | ✓ | ✓ | ✓ | +| [Application security](application_security/index.md):<br>View licenses in [dependency list](application_security/dependency_list/index.md) | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | +| [Application security](application_security/index.md):<br>Create and run [on-demand DAST scans](application_security/dast/index.md#on-demand-scans) | | | ✓ | ✓ | ✓ | +| [Application security](application_security/index.md):<br>Manage [security policy](application_security/policies/index.md) | | | ✓ | ✓ | ✓ | +| [Application security](application_security/index.md):<br>View [dependency list](application_security/dependency_list/index.md) | | | ✓ | ✓ | ✓ | +| [Application security](application_security/index.md):<br>View [threats list](application_security/threat_monitoring/index.md#threat-monitoring) | | | ✓ | ✓ | ✓ | +| [Application security](application_security/index.md):<br>Create a [CVE ID Request](application_security/cve_id_request.md) | | | | ✓ | ✓ | +| [Application security](application_security/index.md):<br>Create or assign [security policy project](application_security/policies/index.md) | | | | | ✓ | +| [Clusters](infrastructure/clusters/index.md):<br>View [pod logs](project/clusters/kubernetes_pod_logs.md) | | | ✓ | ✓ | ✓ | +| [Clusters](infrastructure/clusters/index.md):<br>View clusters | | | ✓ | ✓ | ✓ | +| [Clusters](infrastructure/clusters/index.md):<br>Manage clusters | | | | ✓ | ✓ | +| [Container Registry](packages/container_registry/index.md):<br>Create, edit, delete cleanup policies | | | ✓ | ✓ | ✓ | +| [Container Registry](packages/container_registry/index.md):<br>Push an image to the Container Registry | | | ✓ | ✓ | ✓ | +| [Container Registry](packages/container_registry/index.md):<br>Pull an image from the Container Registry | ✓ (*20*) | ✓ (*20*) | ✓ | ✓ | ✓ | +| [Container Registry](packages/container_registry/index.md):<br>Remove a Container Registry image | | | ✓ | ✓ | ✓ | +| [GitLab Pages](project/pages/index.md):<br>View Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control) | ✓ | ✓ | ✓ | ✓ | ✓ | +| [GitLab Pages](project/pages/index.md):<br>Manage | | | | ✓ | ✓ | +| [GitLab Pages](project/pages/index.md):<br>Manage GitLab Pages domains and certificates | | | | ✓ | ✓ | +| [GitLab Pages](project/pages/index.md):<br>Remove GitLab Pages | | | | ✓ | ✓ | +| [Incident Management](../operations/incident_management/index.md):<br>View [alerts](../operations/incident_management/alerts.md) | | ✓ | ✓ | ✓ | ✓ | +| [Incident Management](../operations/incident_management/index.md):<br>Assign an alert | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Incident Management](../operations/incident_management/index.md):<br>View [incident](../operations/incident_management/incidents.md) | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Incident Management](../operations/incident_management/index.md):<br>Create [incident](../operations/incident_management/incidents.md) | (*16*) | ✓ | ✓ | ✓ | ✓ | +| [Incident Management](../operations/incident_management/index.md):<br>View [on-call schedules](../operations/incident_management/oncall_schedules.md) | | ✓ | ✓ | ✓ | ✓ | +| [Incident Management](../operations/incident_management/index.md):<br>Participate in on-call rotation | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Incident Management](../operations/incident_management/index.md):<br>View [escalation policies](../operations/incident_management/escalation_policies.md) | | ✓ | ✓ | ✓ | ✓ | +| [Incident Management](../operations/incident_management/index.md):<br>Manage [on-call schedules](../operations/incident_management/oncall_schedules.md) | | | | ✓ | ✓ | +| [Incident Management](../operations/incident_management/index.md):<br>Manage [escalation policies](../operations/incident_management/escalation_policies.md) | | | | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Add Labels | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Assign | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Create (*18*) | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Create [confidential issues](project/issues/confidential_issues.md) | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>View related issues | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Set weight | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>View [confidential issues](project/issues/confidential_issues.md) | (*2*) | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Close / reopen (*19*) | | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Lock threads | | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Manage related issues | | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Manage tracker | | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Move issues (*14*) | | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Set issue [time tracking](project/time_tracking.md) estimate and time spent | | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Upload [Design Management](project/issues/design_management.md) files | | | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Delete | | | | | ✓ | +| [License Compliance](compliance/license_compliance/index.md):<br>View allowed and denied licenses | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | +| [License Compliance](compliance/license_compliance/index.md):<br>View License Compliance reports | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | +| [License Compliance](compliance/license_compliance/index.md):<br>View License list | | ✓ | ✓ | ✓ | ✓ | +| [License Compliance](compliance/license_compliance/index.md):<br>Manage license policy | | | | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Assign reviewer | | ✓ | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>See list | | ✓ | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Apply code change suggestions | | | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Approve (*8*) | | | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Assign | | | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Create (*17*) | | | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Add labels | | | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Lock threads | | | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Manage or accept | | | ✓ | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Manage merge approval rules (project settings) | | | | ✓ | ✓ | +| [Merge requests](project/merge_requests/index.md):<br>Delete | | | | | ✓ | +| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>Manage user-starred metrics dashboards (*6*) | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>View metrics dashboard annotations | | ✓ | ✓ | ✓ | ✓ | +| [Metrics dashboards](../operations/metrics/dashboards/index.md):<br>Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ | +| [Package registry](packages/index.md):<br>Pull a package | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | +| [Package registry](packages/index.md):<br>Publish a package | | | ✓ | ✓ | ✓ | +| [Package registry](packages/index.md):<br>Delete a package | | | | ✓ | ✓ | +| [Package registry](packages/index.md):<br>Delete a file associated with a package | | | | ✓ | ✓ | +| [Project operations](../operations/index.md):<br>View [Error Tracking](../operations/error_tracking.md) list | | ✓ | ✓ | ✓ | ✓ | +| [Project operations](../operations/index.md):<br>Manage [Feature Flags](../operations/feature_flags.md) | | | ✓ | ✓ | ✓ | +| [Project operations](../operations/index.md):<br>Manage [Error Tracking](../operations/error_tracking.md) | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Download project | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>Reposition comments on images (posted by any user) | ✓ (*9*) | ✓ (*9*) | ✓ (*9*) | ✓ | ✓ | +| [Projects](project/index.md):<br>View Insights | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>View [releases](project/releases/index.md) | ✓ (*5*) | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>View Requirements | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>View [time tracking](project/time_tracking.md) reports | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>View [wiki](project/wiki/index.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>Create [snippets](snippets.md) | | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>Manage labels | | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>View [project traffic statistics](../api/project_statistics.md) | | ✓ | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>Create, edit, delete [milestones](project/milestones/index.md). | | | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>Create, edit, delete [releases](project/releases/index.md) | | | ✓ (*12*) | ✓ (*12*) | ✓ (*12*) | +| [Projects](project/index.md):<br>Create, edit [wiki](project/wiki/index.md) pages | | | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>Enable Review Apps | | | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>View project [Audit Events](../administration/audit_events.md) | | | ✓ (*10*) | ✓ | ✓ | +| [Projects](project/index.md):<br>Add deploy keys | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Add new team members | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Change [project features visibility](../public_access/public_access.md) level | | | | ✓ (*13*) | ✓ | +| [Projects](project/index.md):<br>Configure [webhooks](project/integrations/webhooks.md) | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Delete [wiki](project/wiki/index.md) pages | | | ✓ | ✓ | ✓ | +| [Projects](project/index.md):<br>Edit comments (posted by any user) | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Edit project badges | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Edit project settings | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Export project | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Manage [project access tokens](project/settings/project_access_tokens.md) (*11*) | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Manage [Project Operations](../operations/index.md) | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Rename project | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Share (invite) projects with groups | | | | ✓ (*7*) | ✓ (*7*) | +| [Projects](project/index.md):<br>View 2FA status of members | | | | ✓ | ✓ | +| [Projects](project/index.md):<br>Administer project compliance frameworks | | | | | ✓ | +| [Projects](project/index.md):<br>Archive project | | | | | ✓ | +| [Projects](project/index.md):<br>Change project visibility level | | | | | ✓ | +| [Projects](project/index.md):<br>Delete project | | | | | ✓ | +| [Projects](project/index.md):<br>Disable notification emails | | | | | ✓ | +| [Projects](project/index.md):<br>Transfer project to another namespace | | | | | ✓ | +| [Repository](project/repository/index.md):<br>Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>View project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>View a commit status | | ✓ | ✓ | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Add tags | | | ✓ | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Create new branches | | | ✓ | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Create or update commit status | | | ✓ (*4*) | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Force push to non-protected branches | | | ✓ | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Push to non-protected branches | | | ✓ | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Remove non-protected branches | | | ✓ | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Rewrite or remove Git tags | | | ✓ | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Enable or disable branch protection | | | | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Enable or disable tag protection | | | | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Manage [push rules](project/repository/push_rules.md) | | | | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Push to protected branches (*4*) | | | | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Turn on or off protected branch push for developers | | | | ✓ | ✓ | +| [Repository](project/repository/index.md):<br>Remove fork relationship | | | | | ✓ | +| [Repository](project/repository/index.md):<br>Force push to protected branches (*3*) | | | | | | +| [Repository](project/repository/index.md):<br>Remove protected branches (*3*) | | | | | | +| [Requirements Management](project/requirements/index.md):<br>Archive / reopen | | ✓ | ✓ | ✓ | ✓ | +| [Requirements Management](project/requirements/index.md):<br>Create / edit | | ✓ | ✓ | ✓ | ✓ | +| [Requirements Management](project/requirements/index.md):<br>Import / export | | ✓ | ✓ | ✓ | ✓ | +| [Security dashboard](application_security/security_dashboard/index.md):<br>Create issue from vulnerability finding | | | ✓ | ✓ | ✓ | +| [Security dashboard](application_security/security_dashboard/index.md):<br>Create vulnerability from vulnerability finding | | | ✓ | ✓ | ✓ | +| [Security dashboard](application_security/security_dashboard/index.md):<br>Dismiss vulnerability | | | ✓ | ✓ | ✓ | +| [Security dashboard](application_security/security_dashboard/index.md):<br>Dismiss vulnerability finding | | | ✓ | ✓ | ✓ | +| [Security dashboard](application_security/security_dashboard/index.md):<br>Resolve vulnerability | | | ✓ | ✓ | ✓ | +| [Security dashboard](application_security/security_dashboard/index.md):<br>Revert vulnerability to detected state | | | ✓ | ✓ | ✓ | +| [Security dashboard](application_security/security_dashboard/index.md):<br>Use security dashboard | | | ✓ | ✓ | ✓ | +| [Security dashboard](application_security/security_dashboard/index.md):<br>View vulnerability | | | ✓ | ✓ | ✓ | +| [Security dashboard](application_security/security_dashboard/index.md):<br>View vulnerability findings in [dependency list](application_security/dependency_list/index.md) | | | ✓ | ✓ | ✓ | +| [Terraform](infrastructure/index.md):<br>Read Terraform state | | | ✓ | ✓ | ✓ | +| [Terraform](infrastructure/index.md):<br>Manage Terraform state | | | | ✓ | ✓ | +| [Test cases](../ci/test_cases/index.md):<br>Archive | | ✓ | ✓ | ✓ | ✓ | +| [Test cases](../ci/test_cases/index.md):<br>Create | | ✓ | ✓ | ✓ | ✓ | +| [Test cases](../ci/test_cases/index.md):<br>Move | | ✓ | ✓ | ✓ | ✓ | +| [Test cases](../ci/test_cases/index.md):<br>Reopen | | ✓ | ✓ | ✓ | ✓ | <!-- markdownlint-disable MD029 --> @@ -251,33 +251,33 @@ More details about the permissions for some project-level features follow. - [Pipeline visibility](../ci/enable_or_disable_ci.md#enable-cicd-in-a-project): When set to **Everyone with Access**, gives access to certain CI/CD "view" features to *non-project* members. -| Action | Non-member | Guest | Reporter | Developer | Maintainer | Owner | -|-----------------------------------------------------------------------------------|------------|---------|----------|-----------|------------|-------| -| See that artifacts exist | ✓ (*3*) | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ | -| View a list of jobs | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | -| View and download artifacts | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | -| View [environments](../ci/environments/index.md) | ✓ (*3*) | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ | -| View job logs and job details page | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | -| View pipeline details page | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | -| View pipelines page | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | -| View pipelines tab in MR | ✓ (*3*) | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ | -| [View vulnerabilities in a pipeline](application_security/security_dashboard/index.md#view-vulnerabilities-in-a-pipeline) | | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | -| Cancel and retry jobs | | | | ✓ | ✓ | ✓ | -| Create new [environments](../ci/environments/index.md) | | | | ✓ | ✓ | ✓ | -| Delete job logs or job artifacts | | | | ✓ (*4*) | ✓ | ✓ | -| Run CI/CD pipeline for a protected branch | | | | ✓ (*5*) | ✓ (*5*) | ✓ | -| Stop [environments](../ci/environments/index.md) | | | | ✓ | ✓ | ✓ | -| View a job with [debug logging](../ci/variables/index.md#debug-logging) | | | | ✓ | ✓ | ✓ | -| Use pipeline editor | | | | ✓ | ✓ | ✓ | -| Run [interactive web terminals](../ci/interactive_web_terminal/index.md) | | | | ✓ | ✓ | ✓ | -| Add specific runners to project | | | | | ✓ | ✓ | -| Clear runner caches manually | | | | | ✓ | ✓ | -| Enable shared runners in project | | | | | ✓ | ✓ | -| Manage CI/CD settings | | | | | ✓ | ✓ | -| Manage job triggers | | | | | ✓ | ✓ | -| Manage project-level CI/CD variables | | | | | ✓ | ✓ | -| Use [environment terminals](../ci/environments/index.md#web-terminals-deprecated) | | | | | ✓ | ✓ | -| Delete pipelines | | | | | | ✓ | +| Action | Non-member | Guest | Reporter | Developer | Maintainer | Owner | +|---------------------------------------------------------------------------------------------------------------------------|------------|---------|----------|-----------|------------|-------| +| See that artifacts exist | ✓ (*3*) | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ | +| View a list of jobs | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | +| View and download artifacts | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | +| View [environments](../ci/environments/index.md) | ✓ (*3*) | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ | +| View job logs and job details page | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | +| View pipeline details page | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | +| View pipelines page | ✓ (*1*) | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | +| View pipelines tab in MR | ✓ (*3*) | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ | +| [View vulnerabilities in a pipeline](application_security/security_dashboard/index.md#view-vulnerabilities-in-a-pipeline) | | ✓ (*2*) | ✓ | ✓ | ✓ | ✓ | +| Cancel and retry jobs | | | | ✓ | ✓ | ✓ | +| Create new [environments](../ci/environments/index.md) | | | | ✓ | ✓ | ✓ | +| Delete job logs or job artifacts | | | | ✓ (*4*) | ✓ | ✓ | +| Run CI/CD pipeline for a protected branch | | | | ✓ (*5*) | ✓ (*5*) | ✓ | +| Stop [environments](../ci/environments/index.md) | | | | ✓ | ✓ | ✓ | +| View a job with [debug logging](../ci/variables/index.md#debug-logging) | | | | ✓ | ✓ | ✓ | +| Use pipeline editor | | | | ✓ | ✓ | ✓ | +| Run [interactive web terminals](../ci/interactive_web_terminal/index.md) | | | | ✓ | ✓ | ✓ | +| Add specific runners to project | | | | | ✓ | ✓ | +| Clear runner caches manually | | | | | ✓ | ✓ | +| Enable shared runners in project | | | | | ✓ | ✓ | +| Manage CI/CD settings | | | | | ✓ | ✓ | +| Manage job triggers | | | | | ✓ | ✓ | +| Manage project-level CI/CD variables | | | | | ✓ | ✓ | +| Use [environment terminals](../ci/environments/index.md#web-terminals-deprecated) | | | | | ✓ | ✓ | +| Delete pipelines | | | | | | ✓ | <!-- markdownlint-disable MD029 --> @@ -296,20 +296,20 @@ More details about the permissions for some project-level features follow. This table shows granted privileges for jobs triggered by specific types of users: -| Action | Guest, Reporter | Developer | Maintainer| Administrator | -|---------------------------------------------|-----------------|-----------|-----------|---------------| -| Run CI job | | ✓ | ✓ | ✓ | -| Clone source and LFS from current project | | ✓ | ✓ | ✓ | -| Clone source and LFS from public projects | | ✓ | ✓ | ✓ | -| Clone source and LFS from internal projects | | ✓ (*1*) | ✓ (*1*) | ✓ | -| Clone source and LFS from private projects | | ✓ (*2*) | ✓ (*2*) | ✓ (*2*) | -| Pull container images from current project | | ✓ | ✓ | ✓ | -| Pull container images from public projects | | ✓ | ✓ | ✓ | -| Pull container images from internal projects| | ✓ (*1*) | ✓ (*1*) | ✓ | -| Pull container images from private projects | | ✓ (*2*) | ✓ (*2*) | ✓ (*2*) | -| Push container images to current project | | ✓ | ✓ | ✓ | -| Push container images to other projects | | | | | -| Push source and LFS | | | | | +| Action | Guest, Reporter | Developer | Maintainer | Administrator | +|----------------------------------------------|-----------------|-----------|------------|---------------| +| Run CI job | | ✓ | ✓ | ✓ | +| Clone source and LFS from current project | | ✓ | ✓ | ✓ | +| Clone source and LFS from public projects | | ✓ | ✓ | ✓ | +| Clone source and LFS from internal projects | | ✓ (*1*) | ✓ (*1*) | ✓ | +| Clone source and LFS from private projects | | ✓ (*2*) | ✓ (*2*) | ✓ (*2*) | +| Pull container images from current project | | ✓ | ✓ | ✓ | +| Pull container images from public projects | | ✓ | ✓ | ✓ | +| Pull container images from internal projects | | ✓ (*1*) | ✓ (*1*) | ✓ | +| Pull container images from private projects | | ✓ (*2*) | ✓ (*2*) | ✓ (*2*) | +| Push container images to current project | | ✓ | ✓ | ✓ | +| Push container images to other projects | | | | | +| Push source and LFS | | | | | 1. Only if the triggering user is not an external one. 1. Only if the triggering user is a member of the project. @@ -369,60 +369,60 @@ The following table lists group permissions available for each role: <!-- Keep this table sorted: first, by minimum role, then alphabetically. --> -| Action | Guest | Reporter | Developer | Maintainer | Owner | -|--------------------------------------------------------------------------|-------|----------|-----------|------------|-------| -| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ | -| Pull a container image using the dependency proxy | ✓ | ✓ | ✓ | ✓ | ✓ | -| View Contribution analytics | ✓ | ✓ | ✓ | ✓ | ✓ | -| View group epic **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ | -| View group wiki pages **(PREMIUM)** | ✓ (6) | ✓ | ✓ | ✓ | ✓ | -| View Insights **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ | -| View Insights charts **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ | -| View Issue analytics **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ | -| View value stream analytics | ✓ | ✓ | ✓ | ✓ | ✓ | -| Create/edit group epic **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ | -| Create/edit/delete epic boards **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ | -| Manage group labels | | ✓ | ✓ | ✓ | ✓ | -| Publish [packages](packages/index.md) | | | ✓ | ✓ | ✓ | -| Pull [packages](packages/index.md) | | ✓ | ✓ | ✓ | ✓ | -| Delete [packages](packages/index.md | | | | ✓ | ✓ | -| Pull a Container Registry image | ✓ (7) | ✓ | ✓ | ✓ | ✓ | -| Remove a Container Registry image | | | ✓ | ✓ | ✓ | -| View Group DevOps Adoption **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ | -| View metrics dashboard annotations | | ✓ | ✓ | ✓ | ✓ | -| View Productivity analytics **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ | -| View Usage quota data | | ✓ | ✓ | ✓ | ✓ | -| Create and edit group wiki pages **(PREMIUM)** | | | ✓ | ✓ | ✓ | -| Create project in group | | | ✓ (3)(5) | ✓ (3) | ✓ (3) | -| Create/edit/delete group milestones | | | ✓ | ✓ | ✓ | -| Create/edit/delete iterations | | | ✓ | ✓ | ✓ | -| Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ | -| Enable/disable a dependency proxy | | | ✓ | ✓ | ✓ | -| Purge the dependency proxy for a group | | | | | ✓ | -| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ | -| View group Audit Events | | | ✓ (7) | ✓ (7) | ✓ | -| Create subgroup | | | | ✓ (1) | ✓ | -| Delete group wiki pages **(PREMIUM)** | | | ✓ | ✓ | ✓ | -| Edit epic comments (posted by any user) **(ULTIMATE)** | | | | ✓ (2) | ✓ (2) | -| List group deploy tokens | | | | ✓ | ✓ | -| Manage [group push rules](group/index.md#group-push-rules) **(PREMIUM)** | | | | ✓ | ✓ | -| View/manage group-level Kubernetes cluster | | | | ✓ | ✓ | -| Administer project compliance frameworks | | | | | ✓ | -| Create/Delete group deploy tokens | | | | | ✓ | -| Change group visibility level | | | | | ✓ | -| Delete group | | | | | ✓ | -| Delete group epic **(PREMIUM)** | | | | | ✓ | -| Disable notification emails | | | | | ✓ | -| Edit group settings | | | | | ✓ | -| Edit SAML SSO **(PREMIUM SAAS)** | | | | | ✓ (4) | -| Filter members by 2FA status | | | | | ✓ | -| Manage group level CI/CD variables | | | | | ✓ | -| Manage group members | | | | | ✓ | -| Share (invite) groups with groups | | | | | ✓ | -| View 2FA status of members | | | | | ✓ | -| View Billing **(FREE SAAS)** | | | | | ✓ (4) | -| View Usage Quotas Page **(FREE SAAS)** | | | | ✓ | ✓ (4) | -| Manage runners | | | | | ✓ | +| Action | Guest | Reporter | Developer | Maintainer | Owner | +|-----------------------------------------------------------------------------------------|-------|----------|-----------|------------|-------| +| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ | +| Pull a container image using the dependency proxy | ✓ | ✓ | ✓ | ✓ | ✓ | +| View Contribution analytics | ✓ | ✓ | ✓ | ✓ | ✓ | +| View group [epic](group/epics/index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | +| View [group wiki](project/wiki/group.md) pages | ✓ (6) | ✓ | ✓ | ✓ | ✓ | +| View [Insights](project/insights/index.md) | ✓ | ✓ | ✓ | ✓ | ✓ | +| View [Insights](project/insights/index.md) charts | ✓ | ✓ | ✓ | ✓ | ✓ | +| View [Issue analytics](analytics/issue_analytics.md) | ✓ | ✓ | ✓ | ✓ | ✓ | +| View value stream analytics | ✓ | ✓ | ✓ | ✓ | ✓ | +| Create/edit group [epic](group/epics/index.md) | | ✓ | ✓ | ✓ | ✓ | +| Create/edit/delete [epic boards](group/epics/epic_boards.md) | | ✓ | ✓ | ✓ | ✓ | +| Manage group labels | | ✓ | ✓ | ✓ | ✓ | +| Publish [packages](packages/index.md) | | | ✓ | ✓ | ✓ | +| Pull [packages](packages/index.md) | | ✓ | ✓ | ✓ | ✓ | +| Delete [packages](packages/index.md) | | | | ✓ | ✓ | +| Pull a Container Registry image | ✓ (7) | ✓ | ✓ | ✓ | ✓ | +| Remove a Container Registry image | | | ✓ | ✓ | ✓ | +| View [Group DevOps Adoption](group/devops_adoption/index.md) | | ✓ | ✓ | ✓ | ✓ | +| View metrics dashboard annotations | | ✓ | ✓ | ✓ | ✓ | +| View [Productivity analytics](analytics/productivity_analytics.md) | | ✓ | ✓ | ✓ | ✓ | +| View Usage quota data | | ✓ | ✓ | ✓ | ✓ | +| Create and edit [group wiki](project/wiki/group.md) pages | | | ✓ | ✓ | ✓ | +| Create project in group | | | ✓ (3)(5) | ✓ (3) | ✓ (3) | +| Create/edit/delete group milestones | | | ✓ | ✓ | ✓ | +| Create/edit/delete iterations | | | ✓ | ✓ | ✓ | +| Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ | +| Enable/disable a dependency proxy | | | ✓ | ✓ | ✓ | +| Purge the dependency proxy for a group | | | | | ✓ | +| Use [security dashboard](application_security/security_dashboard/index.md) | | | ✓ | ✓ | ✓ | +| View group Audit Events | | | ✓ (7) | ✓ (7) | ✓ | +| Create subgroup | | | | ✓ (1) | ✓ | +| Delete [group wiki](project/wiki/group.md) pages | | | ✓ | ✓ | ✓ | +| Edit [epic](group/epics/index.md) comments (posted by any user) | | | | ✓ (2) | ✓ (2) | +| List group deploy tokens | | | | ✓ | ✓ | +| Manage [group push rules](group/index.md#group-push-rules) | | | | ✓ | ✓ | +| View/manage group-level Kubernetes cluster | | | | ✓ | ✓ | +| Administer project compliance frameworks | | | | | ✓ | +| Create/Delete group deploy tokens | | | | | ✓ | +| Change group visibility level | | | | | ✓ | +| Delete group | | | | | ✓ | +| Delete group [epic](group/epics/index.md) | | | | | ✓ | +| Disable notification emails | | | | | ✓ | +| Edit group settings | | | | | ✓ | +| Edit [SAML SSO](group/saml_sso/index.md) | | | | | ✓ (4) | +| Filter members by 2FA status | | | | | ✓ | +| Manage group level CI/CD variables | | | | | ✓ | +| Manage group members | | | | | ✓ | +| Share (invite) groups with groups | | | | | ✓ | +| View 2FA status of members | | | | | ✓ | +| View [Billing](../subscriptions/gitlab_com/index.md#view-your-gitlab-saas-subscription) | | | | | ✓ (4) | +| View [Usage Quotas](usage_quotas.md) Page | | | | ✓ | ✓ (4) | +| Manage runners | | | | | ✓ | <!-- markdownlint-disable MD029 --> @@ -486,7 +486,7 @@ An administrator can flag a user as external by either of the following methods: 1. On the left sidebar, select **Overview > Users** to create a new user or edit an existing one. There, you can find the option to flag the user as external. -Additionally users can be set as external users using: +Additionally, users can be set as external users using: - [SAML groups](../integration/saml.md#external-groups). - [LDAP groups](../administration/auth/ldap/ldap_synchronization.md#external-groups). @@ -551,7 +551,7 @@ with the permissions described on the documentation on [auditor users permission ## Users with minimal access **(PREMIUM)** -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40942) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.4. +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40942) in GitLab 13.4. Owners can add members with a "minimal access" role to a parent group. Such users don't automatically have access to projects and subgroups underneath. Owners must explicitly add these "minimal access" users to the specific subgroups and diff --git a/lib/gitlab/background_migration/backfill_jira_tracker_deployment_type2.rb b/lib/gitlab/background_migration/backfill_jira_tracker_deployment_type2.rb index 61145f6a445..669e5338dd1 100644 --- a/lib/gitlab/background_migration/backfill_jira_tracker_deployment_type2.rb +++ b/lib/gitlab/background_migration/backfill_jira_tracker_deployment_type2.rb @@ -79,7 +79,7 @@ module Gitlab end def mark_jobs_as_succeeded(*arguments) - Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded(self.class.name, arguments) + Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded(self.class.name.demodulize, arguments) end end end diff --git a/scripts/ingest-reports-to-siem b/scripts/ingest-reports-to-siem index 5f5397fcd72..fbd41dc3a8e 100755 --- a/scripts/ingest-reports-to-siem +++ b/scripts/ingest-reports-to-siem @@ -32,7 +32,7 @@ function getMD5HashFromFile(data) { if (err.name === 'CredentialsProviderError' || err.name === 'AuthorizationHeaderMalformed') console.log('Could not upload the report. Are AWS credentials configured in ~/.aws/credentials?') else - console.log('Unexpected error during upload.') + console.log('Unexpected error during upload: ', err.message) process.exit(1) } })() diff --git a/spec/frontend/integrations/edit/components/integration_form_spec.js b/spec/frontend/integrations/edit/components/integration_form_spec.js index 7be519b6cde..51b3a9752a7 100644 --- a/spec/frontend/integrations/edit/components/integration_form_spec.js +++ b/spec/frontend/integrations/edit/components/integration_form_spec.js @@ -14,6 +14,8 @@ import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_field import OverrideDropdown from '~/integrations/edit/components/override_dropdown.vue'; import ResetConfirmationModal from '~/integrations/edit/components/reset_confirmation_modal.vue'; import TriggerFields from '~/integrations/edit/components/trigger_fields.vue'; +import IntegrationSectionConnection from '~/integrations/edit/components/sections/connection.vue'; + import { integrationLevels, I18N_SUCCESSFUL_CONNECTION_MESSAGE, @@ -22,7 +24,7 @@ import { import { createStore } from '~/integrations/edit/store'; import httpStatus from '~/lib/utils/http_status'; import { refreshCurrentPage } from '~/lib/utils/url_utility'; -import { mockIntegrationProps, mockField } from '../mock_data'; +import { mockIntegrationProps, mockField, mockSectionConnection } from '../mock_data'; jest.mock('@sentry/browser'); jest.mock('~/lib/utils/url_utility'); @@ -78,6 +80,11 @@ describe('IntegrationForm', () => { const findGlForm = () => wrapper.findComponent(GlForm); const findRedirectToField = () => wrapper.findByTestId('redirect-to-field'); const findDynamicField = () => wrapper.findComponent(DynamicField); + const findAllDynamicFields = () => wrapper.findAllComponents(DynamicField); + const findAllSections = () => wrapper.findAllByTestId('integration-section'); + const findConnectionSection = () => findAllSections().at(0); + const findConnectionSectionComponent = () => + findConnectionSection().findComponent(IntegrationSectionConnection); beforeEach(() => { mockAxios = new MockAdapter(axios); @@ -253,23 +260,32 @@ describe('IntegrationForm', () => { }); describe('fields is present', () => { - it('renders DynamicField for each field', () => { - const fields = [ - { name: 'username', type: 'text' }, - { name: 'API token', type: 'password' }, + it('renders DynamicField for each field without a section', () => { + const sectionFields = [ + { name: 'username', type: 'text', section: mockSectionConnection.type }, + { name: 'API token', type: 'password', section: mockSectionConnection.type }, + ]; + + const nonSectionFields = [ + { name: 'branch', type: 'text' }, + { name: 'labels', type: 'select' }, ]; createComponent({ + provide: { + glFeatures: { integrationFormSections: true }, + }, customStateProps: { - fields, + sections: [mockSectionConnection], + fields: [...sectionFields, ...nonSectionFields], }, }); - const dynamicFields = wrapper.findAll(DynamicField); + const dynamicFields = findAllDynamicFields(); expect(dynamicFields).toHaveLength(2); dynamicFields.wrappers.forEach((field, index) => { - expect(field.props()).toMatchObject(fields[index]); + expect(field.props()).toMatchObject(nonSectionFields[index]); }); }); }); @@ -344,6 +360,83 @@ describe('IntegrationForm', () => { }); }); + describe('when integration has sections', () => { + beforeEach(() => { + createComponent({ + provide: { + glFeatures: { integrationFormSections: true }, + }, + customStateProps: { + sections: [mockSectionConnection], + }, + }); + }); + + it('renders the expected number of sections', () => { + expect(findAllSections().length).toBe(1); + }); + + it('renders title, description and the correct dynamic component', () => { + const connectionSection = findConnectionSection(); + + expect(connectionSection.find('h4').text()).toBe(mockSectionConnection.title); + expect(connectionSection.find('p').text()).toBe(mockSectionConnection.description); + expect(findConnectionSectionComponent().exists()).toBe(true); + }); + + it('passes only fields with section type', () => { + const sectionFields = [ + { name: 'username', type: 'text', section: mockSectionConnection.type }, + { name: 'API token', type: 'password', section: mockSectionConnection.type }, + ]; + + const nonSectionFields = [ + { name: 'branch', type: 'text' }, + { name: 'labels', type: 'select' }, + ]; + + createComponent({ + provide: { + glFeatures: { integrationFormSections: true }, + }, + customStateProps: { + sections: [mockSectionConnection], + fields: [...sectionFields, ...nonSectionFields], + }, + }); + + expect(findConnectionSectionComponent().props('fields')).toEqual(sectionFields); + }); + + describe.each` + formActive | novalidate + ${true} | ${undefined} + ${false} | ${'true'} + `( + 'when `toggle-integration-active` is emitted with $formActive', + ({ formActive, novalidate }) => { + beforeEach(() => { + createComponent({ + provide: { + glFeatures: { integrationFormSections: true }, + }, + customStateProps: { + sections: [mockSectionConnection], + showActive: true, + initialActivated: false, + }, + }); + + findConnectionSectionComponent().vm.$emit('toggle-integration-active', formActive); + }); + + it(`sets noValidate to ${novalidate}`, () => { + expect(findGlForm().attributes('novalidate')).toBe(novalidate); + }); + }, + ); + }); + describe('ActiveCheckbox', () => { describe.each` showActive @@ -368,7 +461,7 @@ describe('IntegrationForm', () => { `( 'when `toggle-integration-active` is emitted with $formActive', ({ formActive, novalidate }) => { - beforeEach(async () => { + beforeEach(() => { createComponent({ customStateProps: { showActive: true, @@ -376,7 +469,7 @@ describe('IntegrationForm', () => { }, }); - await findActiveCheckbox().vm.$emit('toggle-integration-active', formActive); + findActiveCheckbox().vm.$emit('toggle-integration-active', formActive); }); it(`sets noValidate to ${novalidate}`, () => { diff --git a/spec/frontend/integrations/edit/components/sections/connection_spec.js b/spec/frontend/integrations/edit/components/sections/connection_spec.js new file mode 100644 index 00000000000..1eb92e80723 --- /dev/null +++ b/spec/frontend/integrations/edit/components/sections/connection_spec.js @@ -0,0 +1,77 @@ +import { shallowMount } from '@vue/test-utils'; + +import IntegrationSectionConnection from '~/integrations/edit/components/sections/connection.vue'; +import ActiveCheckbox from '~/integrations/edit/components/active_checkbox.vue'; +import DynamicField from '~/integrations/edit/components/dynamic_field.vue'; +import { createStore } from '~/integrations/edit/store'; + +import { mockIntegrationProps } from '../../mock_data'; + +describe('IntegrationSectionConnection', () => { + let wrapper; + + const createComponent = ({ customStateProps = {}, props = {} } = {}) => { + const store = createStore({ + customState: { ...mockIntegrationProps, ...customStateProps }, + }); + wrapper = shallowMount(IntegrationSectionConnection, { + propsData: { ...props }, + store, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + const findActiveCheckbox = () => wrapper.findComponent(ActiveCheckbox); + const findAllDynamicFields = () => wrapper.findAllComponents(DynamicField); + + describe('template', () => { + describe('ActiveCheckbox', () => { + describe.each` + showActive + ${true} + ${false} + `('when `showActive` is $showActive', ({ showActive }) => { + it(`${showActive ? 'renders' : 'does not render'} ActiveCheckbox`, () => { + createComponent({ + customStateProps: { + showActive, + }, + }); + + expect(findActiveCheckbox().exists()).toBe(showActive); + }); + }); + }); + + describe('DynamicField', () => { + it('renders DynamicField for each field', () => { + const fields = [ + { name: 'username', type: 'text' }, + { name: 'API token', type: 'password' }, + ]; + + createComponent({ + props: { + fields, + }, + }); + + const dynamicFields = findAllDynamicFields(); + + expect(dynamicFields).toHaveLength(2); + dynamicFields.wrappers.forEach((field, index) => { + expect(field.props()).toMatchObject(fields[index]); + }); + }); + + it('does not render DynamicField when field is empty', () => { + createComponent(); + + expect(findAllDynamicFields()).toHaveLength(0); + }); + }); + }); +}); diff --git a/spec/frontend/integrations/edit/mock_data.js b/spec/frontend/integrations/edit/mock_data.js index c8b292dcf6a..36850a0a33a 100644 --- a/spec/frontend/integrations/edit/mock_data.js +++ b/spec/frontend/integrations/edit/mock_data.js @@ -10,6 +10,7 @@ export const mockIntegrationProps = { }, jiraIssuesProps: {}, triggerEvents: [], + sections: [], fields: [], type: '', inheritFromId: 25, @@ -30,3 +31,9 @@ export const mockField = { type: 'text', value: '1', }; + +export const mockSectionConnection = { + type: 'connection', + title: 'Connection details', + description: 'Learn more on how to configure this integration.', +}; diff --git a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb index 716853ea76a..38f5a644985 100644 --- a/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb +++ b/spec/graphql/resolvers/concerns/resolves_pipelines_spec.rb @@ -39,7 +39,7 @@ RSpec.describe ResolvesPipelines do project.add_developer(current_user) end - it { is_expected.to have_graphql_arguments(:status, :scope, :ref, :sha, :source, :username) } + it { is_expected.to have_graphql_arguments(:status, :scope, :ref, :sha, :source, :updated_after, :updated_before, :username) } it 'finds all pipelines' do expect(resolve_pipelines).to contain_exactly(*all_pipelines) @@ -77,6 +77,28 @@ RSpec.describe ResolvesPipelines do expect(resolve_pipelines(username: current_user.username)).to contain_exactly(username_pipeline) end + context 'filtering by updated_at' do + let_it_be(:old_pipeline) { create(:ci_pipeline, project: project, updated_at: 2.days.ago) } + let_it_be(:older_pipeline) { create(:ci_pipeline, project: project, updated_at: 5.days.ago) } + + it 'filters by updated_after' do + expect(resolve_pipelines(updated_after: 3.days.ago)).to contain_exactly(old_pipeline, *all_pipelines) + end + + it 'filters by updated_before' do + expect(resolve_pipelines(updated_before: 3.days.ago)).to contain_exactly(older_pipeline) + end + + it 'filters by both updated_after and updated_before with valid date range' do + expect(resolve_pipelines(updated_after: 10.days.ago, updated_before: 3.days.ago)).to contain_exactly(older_pipeline) + end + + it 'filters by both updated_after and updated_before with invalid date range' do + # updated_after is before updated_before so result set is empty - impossible + expect(resolve_pipelines(updated_after: 3.days.ago, updated_before: 10.days.ago)).to be_empty + end + end + it 'does not return any pipelines if the user does not have access' do expect(resolve_pipelines({}, {})).to be_empty end diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb index b9eddefcc5f..38f2efd75a8 100644 --- a/spec/helpers/merge_requests_helper_spec.rb +++ b/spec/helpers/merge_requests_helper_spec.rb @@ -3,7 +3,6 @@ require 'spec_helper' RSpec.describe MergeRequestsHelper do - include ActionView::Helpers::UrlHelper include ProjectForksHelper describe '#state_name_with_icon' do diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb index ef6a6827826..e4422dde407 100644 --- a/spec/helpers/nav/top_nav_helper_spec.rb +++ b/spec/helpers/nav/top_nav_helper_spec.rb @@ -3,8 +3,6 @@ require 'spec_helper' RSpec.describe Nav::TopNavHelper do - include ActionView::Helpers::UrlHelper - let_it_be(:user) { build_stubbed(:user) } let_it_be(:admin) { build_stubbed(:user, :admin) } let_it_be(:external_user) { build_stubbed(:user, :external, can_create_group: false) } diff --git a/spec/helpers/notify_helper_spec.rb b/spec/helpers/notify_helper_spec.rb index e2a7a212b1b..654fb9bb3f8 100644 --- a/spec/helpers/notify_helper_spec.rb +++ b/spec/helpers/notify_helper_spec.rb @@ -3,7 +3,6 @@ require 'spec_helper' RSpec.describe NotifyHelper do - include ActionView::Helpers::UrlHelper using RSpec::Parameterized::TableSyntax describe 'merge_request_reference_link' do diff --git a/spec/lib/banzai/filter/reference_redactor_filter_spec.rb b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb index d0336e9e059..a2f34d42814 100644 --- a/spec/lib/banzai/filter/reference_redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb @@ -3,7 +3,6 @@ require 'spec_helper' RSpec.describe Banzai::Filter::ReferenceRedactorFilter do - include ActionView::Helpers::UrlHelper include FilterSpecHelper it 'ignores non-GFM links' do @@ -14,7 +13,7 @@ RSpec.describe Banzai::Filter::ReferenceRedactorFilter do end def reference_link(data) - link_to('text', '', class: 'gfm', data: data) + ActionController::Base.helpers.link_to('text', '', class: 'gfm', data: data) end it 'skips when the skip_redaction flag is set' do diff --git a/spec/lib/banzai/reference_redactor_spec.rb b/spec/lib/banzai/reference_redactor_spec.rb index 78cceedd0e5..45e14032a98 100644 --- a/spec/lib/banzai/reference_redactor_spec.rb +++ b/spec/lib/banzai/reference_redactor_spec.rb @@ -106,13 +106,12 @@ RSpec.describe Banzai::ReferenceRedactor do end context 'when the user cannot read cross project' do - include ActionView::Helpers::UrlHelper let(:project) { create(:project) } let(:other_project) { create(:project, :public) } def create_link(issuable) type = issuable.class.name.underscore.downcase - link_to(issuable.to_reference, '', + ActionController::Base.helpers.link_to(issuable.to_reference, '', class: 'gfm has-tooltip', title: issuable.title, data: { diff --git a/spec/requests/api/graphql/ci/pipelines_spec.rb b/spec/requests/api/graphql/ci/pipelines_spec.rb index 5ae68be46a2..741af676b6d 100644 --- a/spec/requests/api/graphql/ci/pipelines_spec.rb +++ b/spec/requests/api/graphql/ci/pipelines_spec.rb @@ -528,4 +528,37 @@ RSpec.describe 'Query.project(fullPath).pipelines' do end.not_to exceed_query_limit(control_count) end end + + describe 'filtering' do + let(:query) do + %( + query { + project(fullPath: "#{project.full_path}") { + pipelines(updatedAfter: "#{updated_after_arg}", updatedBefore: "#{updated_before_arg}") { + nodes { + id + }}}} + ) + end + + context 'when filtered by updated_at' do + let_it_be(:oldish_pipeline) { create(:ci_empty_pipeline, project: project, updated_at: 3.days.ago) } + let_it_be(:older_pipeline) { create(:ci_empty_pipeline, project: project, updated_at: 10.days.ago) } + + let(:updated_after_arg) { 5.days.ago } + let(:updated_before_arg) { 1.day.ago } + + before do + post_graphql(query, current_user: user) + end + + it_behaves_like 'a working graphql query' + + it 'accepts filter params' do + pipeline_ids = graphql_data.dig('project', 'pipelines', 'nodes').map { |pipeline| pipeline.fetch('id') } + + expect(pipeline_ids).to match_array(oldish_pipeline.to_global_id.to_s) + end + end + end end diff --git a/spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb index 213f084be17..771ab89972c 100644 --- a/spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb +++ b/spec/support/shared_examples/lib/gitlab/database/background_migration_job_shared_examples.rb @@ -2,7 +2,7 @@ RSpec.shared_examples 'marks background migration job records' do it 'marks each job record as succeeded after processing' do - create(:background_migration_job, class_name: "::#{described_class.name}", + create(:background_migration_job, class_name: "::#{described_class.name.demodulize}", arguments: arguments) expect(::Gitlab::Database::BackgroundMigrationJob).to receive(:mark_all_as_succeeded).and_call_original @@ -13,7 +13,7 @@ RSpec.shared_examples 'marks background migration job records' do end it 'returns the number of job records marked as succeeded' do - create(:background_migration_job, class_name: "::#{described_class.name}", + create(:background_migration_job, class_name: "::#{described_class.name.demodulize}", arguments: arguments) jobs_updated = subject.perform(*arguments) |