diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 86e0055efa9..9215e25cba2 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -e0204f0c2b736bb4b72f622c64bbf8220ede14bc +3bec5af36c5d3304174566c706807806eee8996d diff --git a/Gemfile b/Gemfile index 1949a156843..5672854d267 100644 --- a/Gemfile +++ b/Gemfile @@ -303,7 +303,7 @@ gem 'gitlab-sidekiq-fetcher', gem 'fugit', '~> 1.11.1', feature_category: :continuous_integration # HTTP requests -gem 'httparty', '~> 0.21.0', feature_category: :shared +gem 'httparty', '~> 0.22.0', feature_category: :shared # Colored output to console gem 'rainbow', '~> 3.0', feature_category: :shared diff --git a/Gemfile.checksum b/Gemfile.checksum index f91b8824c4b..eb9520c3e85 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -330,7 +330,7 @@ {"name":"http-accept","version":"1.7.0","platform":"ruby","checksum":"c626860682bfbb3b46462f8c39cd470fd7b0584f61b3cc9df5b2e9eb9972a126"}, {"name":"http-cookie","version":"1.0.5","platform":"ruby","checksum":"73756d46c7dbdc7023deecdb8a171348ea95a1b99810b31cfe8b4fb4e9a6318f"}, {"name":"http-form_data","version":"2.3.0","platform":"ruby","checksum":"cc4eeb1361d9876821e31d7b1cf0b68f1cf874b201d27903480479d86448a5f3"}, -{"name":"httparty","version":"0.21.0","platform":"ruby","checksum":"00ef7bf9a71f30a3bff88edeb5b16a34bea883ab67c246b3f0db2d6794fe1214"}, +{"name":"httparty","version":"0.22.0","platform":"ruby","checksum":"78652a5c9471cf0093d3b2083c2295c9c8f12b44c65112f1846af2b71430fa6c"}, {"name":"httpclient","version":"2.8.3","platform":"ruby","checksum":"2951e4991214464c3e92107e46438527d23048e634f3aee91c719e0bdfaebda6"}, {"name":"i18n","version":"1.14.4","platform":"ruby","checksum":"c7deedead0866ea9102975a4eab7968f53de50793a0c211a37808f75dd187551"}, {"name":"i18n_data","version":"0.13.1","platform":"ruby","checksum":"e5aa99b09a69b463bb0443fc1f9540351a49f3d1541c5e91316bafa035c63f66"}, diff --git a/Gemfile.lock b/Gemfile.lock index 182538de138..c947479821c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -74,7 +74,7 @@ PATH gitlab-http (0.1.0) activesupport (~> 7) concurrent-ruby (~> 1.2) - httparty (~> 0.21.0) + httparty (~> 0.21) ipaddress (~> 0.8.3) net-http (= 0.6.0) railties (~> 7) @@ -1015,7 +1015,8 @@ GEM http-cookie (1.0.5) domain_name (~> 0.5) http-form_data (2.3.0) - httparty (0.21.0) + httparty (0.22.0) + csv mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) httpclient (2.8.3) @@ -2161,7 +2162,7 @@ DEPENDENCIES health_check (~> 3.0) html-pipeline (~> 2.14.3) html2text - httparty (~> 0.21.0) + httparty (~> 0.22.0) i18n_data (~> 0.13.1) icalendar (~> 2.10.1) influxdb-client (~> 3.1) @@ -2363,4 +2364,4 @@ DEPENDENCIES yajl-ruby (~> 1.4.3) BUNDLED WITH - 2.5.11 + 2.6.5 diff --git a/Gemfile.next.checksum b/Gemfile.next.checksum index a3d40c7060c..d72dd4ed50a 100644 --- a/Gemfile.next.checksum +++ b/Gemfile.next.checksum @@ -330,7 +330,7 @@ {"name":"http-accept","version":"1.7.0","platform":"ruby","checksum":"c626860682bfbb3b46462f8c39cd470fd7b0584f61b3cc9df5b2e9eb9972a126"}, {"name":"http-cookie","version":"1.0.5","platform":"ruby","checksum":"73756d46c7dbdc7023deecdb8a171348ea95a1b99810b31cfe8b4fb4e9a6318f"}, {"name":"http-form_data","version":"2.3.0","platform":"ruby","checksum":"cc4eeb1361d9876821e31d7b1cf0b68f1cf874b201d27903480479d86448a5f3"}, -{"name":"httparty","version":"0.21.0","platform":"ruby","checksum":"00ef7bf9a71f30a3bff88edeb5b16a34bea883ab67c246b3f0db2d6794fe1214"}, +{"name":"httparty","version":"0.22.0","platform":"ruby","checksum":"78652a5c9471cf0093d3b2083c2295c9c8f12b44c65112f1846af2b71430fa6c"}, {"name":"httpclient","version":"2.8.3","platform":"ruby","checksum":"2951e4991214464c3e92107e46438527d23048e634f3aee91c719e0bdfaebda6"}, {"name":"i18n","version":"1.14.4","platform":"ruby","checksum":"c7deedead0866ea9102975a4eab7968f53de50793a0c211a37808f75dd187551"}, {"name":"i18n_data","version":"0.13.1","platform":"ruby","checksum":"e5aa99b09a69b463bb0443fc1f9540351a49f3d1541c5e91316bafa035c63f66"}, @@ -802,8 +802,8 @@ {"name":"webmock","version":"3.25.0","platform":"ruby","checksum":"573c23fc4887008c830f22da588db339ca38b6d59856fd57f5a068959474198e"}, {"name":"webrick","version":"1.8.2","platform":"ruby","checksum":"431746a349199546ff9dd272cae10849c865f938216e41c402a6489248f12f21"}, {"name":"websocket","version":"1.2.10","platform":"ruby","checksum":"2cc1a4a79b6e63637b326b4273e46adcddf7871caa5dc5711f2ca4061a629fa8"}, -{"name":"websocket-driver","version":"0.7.7","platform":"java","checksum":"e2520a6049feb88691e042d631063fa96d50620fb7f53b30180ae6fb2cf75eb1"}, -{"name":"websocket-driver","version":"0.7.7","platform":"ruby","checksum":"056d99f2cd545712cfb1291650fde7478e4f2661dc1db6a0fa3b966231a146b4"}, +{"name":"websocket-driver","version":"0.7.6","platform":"java","checksum":"bc894b9e9d5aee55ac04b61003e1957c4ef411a5a048199587d0499785b505c3"}, +{"name":"websocket-driver","version":"0.7.6","platform":"ruby","checksum":"f69400be7bc197879726ad8e6f5869a61823147372fd8928836a53c2c741d0db"}, {"name":"websocket-extensions","version":"0.1.5","platform":"ruby","checksum":"1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241"}, {"name":"wikicloth","version":"0.8.1","platform":"ruby","checksum":"7ac8a9ca0a948cf472851e521afc6c2a6b04a8f91ef1d824ba6a61ffbd60e6ca"}, {"name":"wisper","version":"2.0.1","platform":"ruby","checksum":"ce17bc5c3a166f241a2e6613848b025c8146fce2defba505920c1d1f3f88fae6"}, diff --git a/Gemfile.next.lock b/Gemfile.next.lock index 55cba922a60..f8e6a8ce9f8 100644 --- a/Gemfile.next.lock +++ b/Gemfile.next.lock @@ -74,7 +74,7 @@ PATH gitlab-http (0.1.0) activesupport (~> 7) concurrent-ruby (~> 1.2) - httparty (~> 0.21.0) + httparty (~> 0.21) ipaddress (~> 0.8.3) net-http (= 0.6.0) railties (~> 7) @@ -1027,7 +1027,8 @@ GEM http-cookie (1.0.5) domain_name (~> 0.5) http-form_data (2.3.0) - httparty (0.21.0) + httparty (0.22.0) + csv mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) httpclient (2.8.3) @@ -2007,8 +2008,7 @@ GEM hashdiff (>= 0.4.0, < 2.0.0) webrick (1.8.2) websocket (1.2.10) - websocket-driver (0.7.7) - base64 + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) wikicloth (0.8.1) @@ -2196,7 +2196,7 @@ DEPENDENCIES health_check (~> 3.0) html-pipeline (~> 2.14.3) html2text - httparty (~> 0.21.0) + httparty (~> 0.22.0) i18n_data (~> 0.13.1) icalendar (~> 2.10.1) influxdb-client (~> 3.1) @@ -2398,4 +2398,4 @@ DEPENDENCIES yajl-ruby (~> 1.4.3) BUNDLED WITH - 2.5.11 + 2.6.5 diff --git a/app/assets/javascripts/authentication/password/components/password_input.vue b/app/assets/javascripts/authentication/password/components/password_input.vue index 0a3c3781248..aebd105cf73 100644 --- a/app/assets/javascripts/authentication/password/components/password_input.vue +++ b/app/assets/javascripts/authentication/password/components/password_input.vue @@ -51,6 +51,11 @@ export default { type: String, required: true, }, + disabled: { + type: Boolean, + required: false, + default: false, + }, }, data() { return { @@ -89,6 +94,7 @@ export default { :data-track-action-for-errors="trackActionForErrors" :title="title" :type="type" + :disabled="disabled" /> diff --git a/app/assets/javascripts/authentication/password/index.js b/app/assets/javascripts/authentication/password/index.js index 2af4dcad00d..3628d66b325 100644 --- a/app/assets/javascripts/authentication/password/index.js +++ b/app/assets/javascripts/authentication/password/index.js @@ -20,9 +20,11 @@ export const initPasswordInput = () => { required, autocomplete, name, + disabled, } = el.dataset; const requiredAttr = required ? parseBoolean(required) : true; + const disabledAttr = disabled ? parseBoolean(disabled) : false; // eslint-disable-next-line no-new new Vue({ @@ -39,6 +41,7 @@ export const initPasswordInput = () => { autocomplete, name, required: requiredAttr, + disabled: disabledAttr, }, }); }, diff --git a/app/assets/javascripts/pages/admin/users/index.js b/app/assets/javascripts/pages/admin/users/index.js index 0add5f24e2c..6f13c3ed030 100644 --- a/app/assets/javascripts/pages/admin/users/index.js +++ b/app/assets/javascripts/pages/admin/users/index.js @@ -5,9 +5,11 @@ import { initDeleteUserModals, } from '~/admin/users'; import initConfirmModal from '~/confirm_modal'; +import { initPasswordInput } from '~/authentication/password'; initAdminUsersFilterApp(); initAdminUserActions(); initAdminUsersApp(); initDeleteUserModals(); initConfirmModal(); +initPasswordInput(); diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 2a9088fa705..f35449a52af 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -788,14 +788,9 @@ module Ci return unless project return if user&.blocked? - if Feature.enabled?(:ci_async_build_hooks_execution, project) - return unless project.has_active_hooks?(:job_hooks) || project.has_active_integrations?(:job_hooks) + return unless project.has_active_hooks?(:job_hooks) || project.has_active_integrations?(:job_hooks) - Ci::ExecuteBuildHooksWorker.perform_async(project.id, build_data) - else - project.execute_hooks(build_data.dup, :job_hooks) if project.has_active_hooks?(:job_hooks) - project.execute_integrations(build_data.dup, :job_hooks) if project.has_active_integrations?(:job_hooks) - end + Ci::ExecuteBuildHooksWorker.perform_async(project.id, build_data) end def browsable_artifacts? diff --git a/app/models/concerns/integrations/base/discord.rb b/app/models/concerns/integrations/base/discord.rb index 6d2e378aebf..cd05762835e 100644 --- a/app/models/concerns/integrations/base/discord.rb +++ b/app/models/concerns/integrations/base/discord.rb @@ -24,7 +24,7 @@ module Integrations build_help_page_url( 'user/project/integrations/discord_notifications.md', s_("DiscordService|Send notifications about project events to a Discord channel."), - _('How do I set up this integration?') + link_text: _('How do I set up this integration?') ) end diff --git a/app/models/concerns/integrations/base/hangouts_chat.rb b/app/models/concerns/integrations/base/hangouts_chat.rb index b342eee78dd..8fe463e52e8 100644 --- a/app/models/concerns/integrations/base/hangouts_chat.rb +++ b/app/models/concerns/integrations/base/hangouts_chat.rb @@ -29,7 +29,7 @@ module Integrations 'user/project/integrations/hangouts_chat.md', 'Before enabling this integration, create a webhook for the space in Google Chat where you want to ' \ 'receive notifications from this project.', - _('How do I set up a Google Chat webhook?') + link_text: _('How do I set up a Google Chat webhook?') ) end diff --git a/app/models/concerns/integrations/base/integration.rb b/app/models/concerns/integrations/base/integration.rb index 191c16482aa..53605d23312 100644 --- a/app/models/concerns/integrations/base/integration.rb +++ b/app/models/concerns/integrations/base/integration.rb @@ -424,7 +424,7 @@ module Integrations @field_storage || :properties end - def build_help_page_url(url_path, help_text, link_text = _("Learn More"), options = {}) + def build_help_page_url(url_path, help_text, options = {}, link_text: _("Learn More")) docs_link = ActionController::Base.helpers.link_to( '', Rails.application.routes.url_helpers.help_page_url(url_path, **options), # rubocop:disable Gitlab/DocumentationLinks/Link: -- existing code moved as is diff --git a/app/models/integrations/datadog.rb b/app/models/integrations/datadog.rb index 727f5c0683b..954774acd7f 100644 --- a/app/models/integrations/datadog.rb +++ b/app/models/integrations/datadog.rb @@ -196,7 +196,7 @@ module Integrations build_help_page_url( 'integration/datadog.md', s_('DatadogIntegration|Connect your GitLab projects to your Datadog account to synchronize repository metadata and enrich telemetry on your Datadog account.'), - _('How do I set up this integration?') + link_text: _('How do I set up this integration?') ) end diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index d933b2fcb77..f8d72fbe7bd 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -31,13 +31,13 @@ - c.with_body do = s_('AdminUsers|Reset link will be generated and sent to the user. User will be forced to set the password on first sign in.') - else - .form-group.gl-form-group{ role: 'group' } + .form-group.gl-form-group.gl-form-input-lg{ role: 'group' } = f.label :password, _('Password'), class: 'gl-block col-form-label' - = f.password_field :password, disabled: f.object.force_random_password, autocomplete: 'new-password', class: 'form-control gl-form-input js-password-complexity-validation gl-form-input-lg' + = f.password_field :password, class: 'form-control gl-form-input js-password-complexity-validation js-password', data: { autocomplete: 'new-password', disabled: f.object.force_random_password, required: false, id: 'user_password', name: 'user[password]' } = render_if_exists 'shared/password_requirements_list' - .form-group.gl-form-group{ role: 'group' } + .form-group.gl-form-group.gl-form-input-lg{ role: 'group' } = f.label :password_confirmation, _('Password confirmation'), class: 'gl-block col-form-label' - = f.password_field :password_confirmation, disabled: f.object.force_random_password, autocomplete: 'new-password', class: 'form-control gl-form-input gl-form-input-lg' + = f.password_field :password_confirmation, class: 'form-control gl-form-input js-password', data: { autocomplete: 'new-password', disabled: f.object.force_random_password, required: false, id: 'user_password_confirmation', name: 'user[password_confirmation]' } = render partial: 'access', locals: { f: f } diff --git a/app/workers/ci/execute_build_hooks_worker.rb b/app/workers/ci/execute_build_hooks_worker.rb index 2c0fbaf7e09..021bd11b8aa 100644 --- a/app/workers/ci/execute_build_hooks_worker.rb +++ b/app/workers/ci/execute_build_hooks_worker.rb @@ -15,6 +15,8 @@ module Ci project = Project.find_by_id(project_id) return unless project + build_data = build_data.with_indifferent_access + project.execute_hooks(build_data, :job_hooks) if project.has_active_hooks?(:job_hooks) project.execute_integrations(build_data, :job_hooks) if project.has_active_integrations?(:job_hooks) end diff --git a/config/feature_flags/gitlab_com_derisk/ci_async_build_hooks_execution.yml b/config/feature_flags/gitlab_com_derisk/ci_async_build_hooks_execution.yml deleted file mode 100644 index 3a029edb775..00000000000 --- a/config/feature_flags/gitlab_com_derisk/ci_async_build_hooks_execution.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: ci_async_build_hooks_execution -feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/499290 -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/177706 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/512832 -milestone: '17.9' -group: group::pipeline authoring -type: gitlab_com_derisk -default_enabled: false diff --git a/doc/administration/internal_users.md b/doc/administration/internal_users.md index 6f8172708f8..56e2ef3ea10 100644 --- a/doc/administration/internal_users.md +++ b/doc/administration/internal_users.md @@ -47,7 +47,7 @@ Other examples of internal users: [GitLab Admin Bot](https://gitlab.com/gitlab-org/gitlab/-/blob/1d38cfdbed081f8b3fa14b69dd743440fe85081b/lib/users/internal.rb#L104) is an internal user that cannot be accessed or modified by regular users and is responsible for many tasks including: -- Applying [default compliance frameworks](../user/group/compliance_frameworks.md#default-compliance-frameworks) to +- Applying [default compliance frameworks](../user/compliance/compliance_frameworks.md#default-compliance-frameworks) to projects. - [Automatically deactivating dormant users](moderate_users.md#automatically-deactivate-dormant-users). - [Automatically deleting unconfirmed users](moderate_users.md#automatically-delete-unconfirmed-users). diff --git a/doc/administration/server_hooks.md b/doc/administration/server_hooks.md index 362c999e5d9..b503dba3af3 100644 --- a/doc/administration/server_hooks.md +++ b/doc/administration/server_hooks.md @@ -43,16 +43,16 @@ If you don't have access to the `gitaly` command, alternatives to server hooks i ## Set server hooks for a repository -{{< tabs >}} - -{{< tab title="GitLab 15.11 and later" >}} - {{< history >}} - [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/4629) in GitLab 15.11, `hooks set` command replaces direct file system access. Existing Git hooks don't need migrating for the `hooks set` command. {{< /history >}} +{{< tabs >}} + +{{< tab title="GitLab 15.11 and later" >}} + Prerequisites: - The [storage name](gitaly/configure_gitaly.md#gitlab-requires-a-default-repository-storage), path to the Gitaly configuration file @@ -181,16 +181,16 @@ subdirectories. ## Remove server hooks for a repository -{{< tabs >}} - -{{< tab title="GitLab 15.11 and later" >}} - {{< history >}} - [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/4629) in GitLab 15.11, `hooks set` command replaces direct file system access. {{< /history >}} +{{< tabs >}} + +{{< tab title="GitLab 15.11 and later" >}} + Prerequisites: - The [storage name and relative path](repository_storage_paths.md#from-project-name-to-hashed-path) for the repository. diff --git a/doc/administration/settings/continuous_integration.md b/doc/administration/settings/continuous_integration.md index 3fb414975f2..a2311492727 100644 --- a/doc/administration/settings/continuous_integration.md +++ b/doc/administration/settings/continuous_integration.md @@ -521,7 +521,7 @@ To set the maximum file size: This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/389467) in GitLab 15.9 and was removed in 17.0. From 17.4, it is available only behind the feature flag `required_pipelines`, disabled by default. -Use [compliance pipelines](../../user/group/compliance_pipelines.md) instead. This change is a breaking change. +Use [compliance pipelines](../../user/compliance/compliance_pipelines.md) instead. This change is a breaking change. {{< /alert >}} diff --git a/doc/ci/pipelines/_index.md b/doc/ci/pipelines/_index.md index 1ea4c46ffb2..71758850b26 100644 --- a/doc/ci/pipelines/_index.md +++ b/doc/ci/pipelines/_index.md @@ -141,9 +141,9 @@ In this example: {{< alert type="note" >}} -Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/382857), projects that use [compliance pipelines](../../user/group/compliance_pipelines.md) can have prefilled variables not appear +Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/382857), projects that use [compliance pipelines](../../user/compliance/compliance_pipelines.md) can have prefilled variables not appear when running a pipeline manually. To workaround this issue, -[change the compliance pipeline configuration](../../user/group/compliance_pipelines.md#prefilled-variables-are-not-shown). +[change the compliance pipeline configuration](../../user/compliance/compliance_pipelines.md#prefilled-variables-are-not-shown). {{< /alert >}} diff --git a/doc/ci/yaml/_index.md b/doc/ci/yaml/_index.md index d518467549c..18ea1471629 100644 --- a/doc/ci/yaml/_index.md +++ b/doc/ci/yaml/_index.md @@ -554,7 +554,7 @@ start. Jobs in the current stage are not stopped and continue to run. - If a job does not specify a [`stage`](#stage), the job is assigned the `test` stage. - If a stage is defined but no jobs use it, the stage is not visible in the pipeline, - which can help [compliance pipeline configurations](../../user/group/compliance_pipelines.md): + which can help [compliance pipeline configurations](../../user/compliance/compliance_pipelines.md): - Stages can be defined in the compliance configuration but remain hidden if not used. - The defined stages become visible when developers use them in job definitions. @@ -4651,7 +4651,7 @@ In this example: section. The project containing the `include` section can be different than the project running the pipeline when using: - [Nested includes](includes.md#use-nested-includes). - - [Compliance pipelines](../../user/group/compliance_pipelines.md). + - [Compliance pipelines](../../user/compliance/compliance_pipelines.md). - `rules:exists` cannot search for the presence of [artifacts](../jobs/job_artifacts.md), because `rules` evaluation happens before jobs run and artifacts are fetched. diff --git a/doc/development/internal_analytics/product_analytics.md b/doc/development/internal_analytics/product_analytics.md index f8c32edb026..4860f2eba2b 100644 --- a/doc/development/internal_analytics/product_analytics.md +++ b/doc/development/internal_analytics/product_analytics.md @@ -106,6 +106,12 @@ you must enable and configure product analytics. ### Product analytics provider +{{< history >}} + +- Self-managed provider [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117804) in GitLab 16.0. + +{{< /history >}} + Your GitLab instance connects to a product analytics provider. A product analytics provider is the collection of services required to receive, process, store and query your analytics data. @@ -114,12 +120,6 @@ process, store and query your analytics data. {{< tab title="GitLab-managed provider" >}} -{{< details >}} - -- Offering: GitLab.com - -{{< /details >}} - On GitLab.com you can use a GitLab-managed provider offered only in the Google Cloud Platform zone `us-central-1`. If GitLab manages your product analytics provider, then your analytics data is retained for one year. @@ -129,8 +129,6 @@ You can request to delete your data at any time by [contacting support](https:// {{< tab title="Self-managed provider" >}} ->[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117804) in GitLab 16.0. - A self-managed product analytics provider is a deployed instance of the [product analytics Helm charts](https://gitlab.com/gitlab-org/analytics-section/product-analytics/helm-charts). diff --git a/doc/tutorials/compliance_pipeline/_index.md b/doc/tutorials/compliance_pipeline/_index.md index ddef7f10dea..885e3922a62 100644 --- a/doc/tutorials/compliance_pipeline/_index.md +++ b/doc/tutorials/compliance_pipeline/_index.md @@ -18,13 +18,13 @@ title: 'Tutorial: Create a compliance pipeline (deprecated)' This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/159841) in GitLab 17.3 and is planned for removal in 18.0. Use [pipeline execution policy type](../../user/application_security/policies/pipeline_execution_policies.md) instead. -This change is a breaking change. For more information, see the [migration guide](../../user/group/compliance_pipelines.md#pipeline-execution-policies-migration). +This change is a breaking change. For more information, see the [migration guide](../../user/compliance/compliance_pipelines.md#pipeline-execution-policies-migration). {{< /alert >}} -You can use [compliance pipelines](../../user/group/compliance_pipelines.md) to ensure specific +You can use [compliance pipelines](../../user/compliance/compliance_pipelines.md) to ensure specific compliance-related jobs are run on pipelines for all projects in a group. Compliance pipelines are applied -to projects through [compliance frameworks](../../user/group/compliance_frameworks.md). +to projects through [compliance frameworks](../../user/compliance/compliance_frameworks.md). In this tutorial, you: @@ -57,7 +57,7 @@ To create the new group: ## Create a new compliance pipeline project Now you're ready to create a compliance pipeline project. This project contains the -[compliance pipeline configuration](../../user/group/compliance_pipelines.md#example-configuration) to apply to all +[compliance pipeline configuration](../../user/compliance/compliance_pipelines.md#example-configuration) to apply to all projects with the compliance framework applied. To create the compliance pipeline project: @@ -191,6 +191,6 @@ Notice the pipeline runs two jobs in a **test** stage: Congratulations, you've created and configured a compliance pipeline! -See more [example compliance pipeline configurations](../../user/group/compliance_pipelines.md#example-configuration). +See more [example compliance pipeline configurations](../../user/compliance/compliance_pipelines.md#example-configuration). diff --git a/doc/user/application_security/_index.md b/doc/user/application_security/_index.md index a6d39429e31..27994f65240 100644 --- a/doc/user/application_security/_index.md +++ b/doc/user/application_security/_index.md @@ -193,7 +193,7 @@ Security and compliance teams must ensure that security scans: GitLab provides two methods of accomplishing this, each with advantages and disadvantages. -- [Compliance framework pipelines](../group/compliance_pipelines.md) +- [Compliance framework pipelines](../compliance/compliance_pipelines.md) are recommended when: - Scan execution enforcement is required for any scanner that uses a GitLab template, such as SAST IaC, DAST, Dependency Scanning, diff --git a/doc/user/compliance/_index.md b/doc/user/compliance/_index.md index 40bb5312c50..acd321233d0 100644 --- a/doc/user/compliance/_index.md +++ b/doc/user/compliance/_index.md @@ -32,8 +32,8 @@ compliance: | Feature | Instances | Groups | Projects | Description | |:-----------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------|:-------------------------------------|:-------------------------------------|:------------| -| [Compliance frameworks](../group/compliance_frameworks.md) | {{< icon name="dotted-circle" >}} No | {{< icon name="check-circle" >}} Yes | {{< icon name="dotted-circle" >}} No | Describe the type of compliance requirements projects must follow. | -| [Compliance pipelines](../group/compliance_pipelines.md) | {{< icon name="dotted-circle" >}} No | {{< icon name="check-circle" >}} Yes | {{< icon name="dotted-circle" >}} No | Define a pipeline configuration to run for any projects with a given compliance framework. | +| [Compliance frameworks](../compliance/compliance_frameworks.md) | {{< icon name="dotted-circle" >}} No | {{< icon name="check-circle" >}} Yes | {{< icon name="dotted-circle" >}} No | Describe the type of compliance requirements projects must follow. | +| [Compliance pipelines](../compliance/compliance_pipelines.md) | {{< icon name="dotted-circle" >}} No | {{< icon name="check-circle" >}} Yes | {{< icon name="dotted-circle" >}} No | Define a pipeline configuration to run for any projects with a given compliance framework. | | [Merge request approval policy approval settings](../application_security/policies/merge_request_approval_policies.md#approval_settings) | {{< icon name="check-circle" >}} Yes | {{< icon name="check-circle" >}} Yes | {{< icon name="check-circle" >}} Yes | Enforce a merge request approval policy enforcing multiple approvers and override various project settings in all enforced groups or projects across your GitLab instance or group. | ## Audit management diff --git a/doc/user/compliance/compliance_center/compliance_frameworks_report.md b/doc/user/compliance/compliance_center/compliance_frameworks_report.md index 00067bf1b02..7e20e2e75d6 100644 --- a/doc/user/compliance/compliance_center/compliance_frameworks_report.md +++ b/doc/user/compliance/compliance_center/compliance_frameworks_report.md @@ -78,6 +78,34 @@ To delete a compliance framework from the compliance frameworks report: 1. Hover over framework and select **Edit the framework**. 1. Select the **Delete framework** to delete compliance framework. +## Set and remove a compliance framework as default + +{{< history >}} + +- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181500) in GitLab 17.10. + +{{< /history >}} + +Prerequisites: + +- You must be an administrator or have the Owner role for the group. + +To set a compliance framework as [default](../compliance_frameworks.md#default-compliance-frameworks)] from the compliance frameworks report: + +1. On the left sidebar, select **Search or go to** and find your group. +1. Select **Secure > Compliance center**. +1. On the page, select the **Frameworks** tab. +1. Next to the compliance framework you want to set as default, select {{< icon name="pencil" >}} action. +1. Select the **Set as default** to set as default. + +To remove a compliance framework as default from the compliance frameworks report: + +1. On the left sidebar, select **Search or go to** and find your group. +1. Select **Secure > Compliance center**. +1. On the page, select the **Frameworks** tab. +1. Next to the compliance framework that is default, select {{< icon name="pencil" >}} action. +1. Select the **Remove as default** to remove as default. + ## Export a report of compliance frameworks in a group {{< history >}} diff --git a/doc/user/compliance/compliance_frameworks.md b/doc/user/compliance/compliance_frameworks.md new file mode 100644 index 00000000000..e6cd990c3ef --- /dev/null +++ b/doc/user/compliance/compliance_frameworks.md @@ -0,0 +1,112 @@ +--- +stage: Software Supply Chain Security +group: Compliance +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments +title: Compliance frameworks +--- + +{{< details >}} + +- Tier: Premium, Ultimate +- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated + +{{< /details >}} + +You can create a compliance framework that is a label to identify that your project has certain compliance +requirements or needs additional oversight. + +In the Ultimate tier, the compliance framework can optionally enforce +[compliance pipeline configuration](compliance_pipelines.md) and +[security policies](../application_security/policies/_index.md#scope) to the projects on which it is applied. + +Compliance frameworks are created on top-level groups. If a project is moved outside of its existing top-level group, +its frameworks are removed. + +You can apply up to 20 compliance frameworks to each project. + +For a click-through demo, see [Compliance frameworks](https://gitlab.navattic.com/compliance). + + +## Prerequisites + +- To create, edit, and delete compliance frameworks, users must have either: + - The Owner role for the top-level group. + - Be assigned a [custom role](../custom_roles.md) with the `admin_compliance_framework` + [custom permission](../custom_roles/abilities.md#compliance-management). +- To add or remove a compliance framework to or from a project, the group to which the project belongs must have a + compliance framework. + +## Create, edit, or delete a compliance framework + +You can create, edit, or delete a compliance framework from a compliance framework report. For more information, see: + +- [Create a new compliance framework](../compliance/compliance_center/compliance_frameworks_report.md#create-a-new-compliance-framework). +- [Edit a compliance framework](../compliance/compliance_center/compliance_frameworks_report.md#edit-a-compliance-framework). +- [Delete a compliance framework](../compliance/compliance_center/compliance_frameworks_report.md#delete-a-compliance-framework). + +You can create, edit, or delete a compliance framework from a compliance projects report. For more information, see: + +- [Create a new compliance framework](../compliance/compliance_center/compliance_projects_report.md#create-a-new-compliance-framework). +- [Edit a compliance framework](../compliance/compliance_center/compliance_projects_report.md#edit-a-compliance-framework). +- [Delete a compliance framework](../compliance/compliance_center/compliance_projects_report.md#delete-a-compliance-framework). + +Subgroups and projects have access to all compliance frameworks created on their top-level group. However, compliance frameworks cannot be created, edited, +or deleted at the subgroup or project level. Project owners can choose a framework to apply to their projects. + +## Apply a compliance framework to a project + +{{< history >}} + +- Assigning multiple compliance frameworks [introduced](https://gitlab.com/groups/gitlab-org/-/epics/13294) in GitLab 17.3. + +{{< /history >}} + +You can apply multiple compliance frameworks to a project but cannot apply compliance frameworks to projects in personal namespaces. + +To apply a compliance framework to a project, apply the compliance framework through the +[Compliance projects report](../compliance/compliance_center/compliance_projects_report.md#apply-a-compliance-framework-to-projects-in-a-group). + +You can use the [GraphQL API](../../api/graphql/reference/_index.md#mutationprojectupdatecomplianceframeworks) to apply one or many +compliance frameworks to a project. + +If you create compliance frameworks on subgroups with GraphQL, the framework is created on the root ancestor if the user +has the correct permissions. The GitLab UI presents a read-only view to discourage this behavior. + +## Default compliance frameworks + +{{< history >}} + +- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375036) in GitLab 15.6. + +{{< /history >}} + +Group owners can set a default compliance framework. The default framework is applied to all the new and imported +projects that are created in that group. It does not affect the framework applied to the existing projects. The +default framework cannot be deleted. + +A compliance framework that is set to default has a **default** label. + +### Set and remove a default by using the compliance center + +To set as default (or remove the default) from [compliance projects report](../compliance/compliance_center/compliance_projects_report.md): + +1. On the left sidebar, select **Search or go to** and find your group. +1. Select **Secure > Compliance center**. +1. On the page, select the **Projects** tab. +1. Hover over a compliance framework, select the **Edit Framework** tab. +1. Select **Set as default**. +1. Select **Save changes**. + +To set as default (or remove the default) from [compliance framework report](../compliance/compliance_center/compliance_frameworks_report.md): + +1. On the left sidebar, select **Search or go to** and find your group. +1. Select **Secure > Compliance center**. +1. On the page, select the **Frameworks** tab. +1. Hover over a compliance framework, select the **Edit Framework** tab. +1. Select **Set as default**. +1. Select **Save changes**. + +## Remove a compliance framework from a project + +To remove a compliance framework from one or multiple project in a group, remove the compliance framework through the +[Compliance projects report](../compliance/compliance_center/compliance_projects_report.md#remove-a-compliance-framework-from-projects-in-a-group). diff --git a/doc/user/compliance/compliance_pipelines.md b/doc/user/compliance/compliance_pipelines.md new file mode 100644 index 00000000000..59372d7a79d --- /dev/null +++ b/doc/user/compliance/compliance_pipelines.md @@ -0,0 +1,416 @@ +--- +stage: Software Supply Chain Security +group: Compliance +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments +title: Compliance pipelines (deprecated) +--- + + + +{{< details >}} + +- Tier: Ultimate +- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated + +{{< /details >}} + +{{< alert type="warning" >}} + +This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/159841) in GitLab 17.3 +and is planned for removal in 19.0. Use [pipeline execution policy type](../application_security/policies/pipeline_execution_policies.md) instead. +This change is a breaking change. For more information, see the [migration guide](#pipeline-execution-policies-migration). + +{{< /alert >}} + +Group owners can configure a compliance pipeline in a project separate to other projects. By default, the compliance +pipeline configuration (for example, `.compliance-gitlab-ci.yml`) is run instead of the pipeline configuration (for example, `.gitlab-ci.yml`) of labeled +projects. + +However, the compliance pipeline configuration can reference the `.gitlab-ci.yml` file of the labeled projects so that: + +- The compliance pipeline can also run jobs of labeled project pipelines. This allows for centralized control of + pipeline configuration. +- Jobs and variables defined in the compliance pipeline can't be changed by variables in the labeled project's + `.gitlab-ci.yml` file. + +{{< alert type="note" >}} + +Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/414004), project pipelines must be included first at the top of compliance pipeline configuration +to prevent projects overriding settings downstream. + +{{< /alert >}} + +For more information, see: + +- [Example configuration](#example-configuration) for help configuring a compliance pipeline that runs jobs from + labeled project pipeline configuration. +- The [Create a compliance pipeline](../../tutorials/compliance_pipeline/_index.md) tutorial. + +## Pipeline execution policies migration + +To consolidate and simplify scan and pipeline enforcement, we have introduced pipeline execution policies. We deprecated +compliance pipelines in GitLab 17.3 and will remove compliance pipelines in GitLab 19.0. + +Pipeline execution policies extend a project's `.gitlab-ci.yml` file with the configuration provided in separate YAML file +(for example, `pipeline-execution.yml`) linked in the pipeline execution policy. + +By default, when creating a new compliance framework, you are directed to use the pipeline execution policy type instead +of compliance pipelines. + +Existing compliance pipelines must be migrated. Customers should migrate from compliance pipelines to the new +[pipeline execution policy type](../application_security/policies/pipeline_execution_policies.md) as soon as possible. + +### Migrate an existing compliance framework + +To migrate an existing compliance framework to use the pipeline execution policy type: + +1. On the left sidebar, select **Search or go to** and find your group. +1. Select **Secure > Compliance center**. +1. [Edit](compliance_frameworks.md#create-edit-or-delete-a-compliance-framework) the existing compliance framework. +1. In the banner than appears, select **Migrate pipeline to a policy** to create a new policy in the security policies. +1. Edit the compliance framework again to remove the compliance pipeline. + +For more information, see [Security policy project](../application_security/policies/_index.md#security-policy-project). + +If you receive a `Pipeline execution policy error: Job names must be unique` error during the migration, see the +[relevant troubleshooting information](#error-job-names-must-be-unique). + +## Effect on labeled projects + +Users have no way of knowing that a compliance pipeline has been configured and might be confused why their own +pipelines are not running at all, or include jobs that they did not define themselves. + +When authoring pipelines on a labeled project, there is no indication that a compliance pipeline has been configured. +The only marker at the project level is the compliance framework label itself, but the label does not say whether the +framework has a compliance pipeline configured or not. + +Therefore, communicate with project users about compliance pipeline configuration to reduce uncertainty and confusion. + +### Multiple compliance frameworks + +You can [apply to a single project](compliance_frameworks.md#apply-a-compliance-framework-to-a-project) multiple compliance frameworks with compliance pipelines configured. +In this case, only the first compliance framework applied to a project has its compliance pipeline included in the project pipeline. + +To ensure that the correct compliance pipeline is included in a project: + +1. Remove all compliance frameworks from the project. +1. Apply the compliance framework with the correct compliance pipeline to the project. +1. Apply additional compliance frameworks to the project. + +## Configure a compliance pipeline + +{{< history >}} + +- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383209) in GitLab 15.11, compliance frameworks moved to compliance center. + +{{< /history >}} + +To configure a compliance pipeline: + +1. On the left sidebar, select **Search or go to** and find your group. +1. Select **Secure** > **Compliance Center**. +1. Select **Frameworks** section. +1. Select **New framework** section, add information of compliance framework including path to the compliance framework configuration. Use the + `path/file.y[a]ml@group-name/project-name` format. For example: + + - `.compliance-ci.yml@gitlab-org/gitlab`. + - `.compliance-ci.yaml@gitlab-org/gitlab`. + +This configuration is inherited by projects where the compliance framework label is +[applied](../project/working_with_projects.md#add-a-compliance-framework-to-a-project). In projects with the applied compliance +framework label, the compliance pipeline configuration is run instead of the labeled project's own pipeline configuration. + +The user running the pipeline in the labeled project must at least have the Reporter role on the compliance project. + +When used to enforce scan execution, this feature has some overlap with +[scan execution policies](../application_security/policies/scan_execution_policies.md). We have not +[unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312). For details on +the similarities and differences between these features, see [Enforce scan execution](../application_security/_index.md#enforce-scan-execution). + +### Example configuration + +The following example `.compliance-gitlab-ci.yml` includes the `include` keyword to ensure labeled project pipeline +configuration is also executed. + +```yaml +include: # Execute individual project's configuration (if project contains .gitlab-ci.yml) + - project: '$CI_PROJECT_PATH' + file: '$CI_CONFIG_PATH' + ref: '$CI_COMMIT_SHA' # Must be defined or MR pipelines always use the use default branch + rules: + - if: $CI_PROJECT_PATH != "my-group/project-1" # Must run on projects other than the one hosting this configuration. + +# Allows compliance team to control the ordering and interweaving of stages/jobs. +# Stages without jobs defined will remain hidden. +stages: + - pre-compliance + - build + - test + - pre-deploy-compliance + - deploy + - post-compliance + +variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml + FOO: sast + +sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml + variables: + FOO: sast + image: ruby:2.6 + stage: pre-compliance + rules: + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push" + when: never + - when: always # or when: on_success + allow_failure: false + before_script: + - "# No before scripts." + script: + - echo "running $FOO" + after_script: + - "# No after scripts." + +sanity check: + image: ruby:2.6 + stage: pre-deploy-compliance + rules: + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push" + when: never + - when: always # or when: on_success + allow_failure: false + before_script: + - "# No before scripts." + script: + - echo "running $FOO" + after_script: + - "# No after scripts." + +audit trail: + image: ruby:2.7 + stage: post-compliance + rules: + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push" + when: never + - when: always # or when: on_success + allow_failure: false + before_script: + - "# No before scripts." + script: + - echo "running $FOO" + after_script: + - "# No after scripts." +``` + +The `rules` configuration in the `include` definition avoids circular inclusion in case the compliance pipeline must be able to run in the host project itself. +You can leave it out if your compliance pipeline only ever runs in labeled projects. + +#### Compliance pipelines and custom pipeline configuration hosted externally + +The example above assumes that all projects host their pipeline configuration in the same project. +If any projects use [configuration hosted externally](../../ci/pipelines/settings.md#specify-a-custom-cicd-configuration-file), +the example configuration does not work. See [issue 393960](https://gitlab.com/gitlab-org/gitlab/-/issues/393960) +for more details. + +With projects that use externally hosted configuration, you can try the this workaround: + +- The `include` section in the example compliance pipeline configuration must be adjusted. + For example, using [`include:rules`](../../ci/yaml/includes.md#use-rules-with-include): + + ```yaml + include: + # If the custom path variables are defined, include the project's external config file. + - project: '$PROTECTED_PIPELINE_CI_PROJECT_PATH' + file: '$PROTECTED_PIPELINE_CI_CONFIG_PATH' + ref: '$PROTECTED_PIPELINE_CI_REF' + rules: + - if: $PROTECTED_PIPELINE_CI_PROJECT_PATH && $PROTECTED_PIPELINE_CI_CONFIG_PATH && $PROTECTED_PIPELINE_CI_REF + # If any custom path variable is not defined, include the project's internal config file as normal. + - project: '$CI_PROJECT_PATH' + file: '$CI_CONFIG_PATH' + ref: '$CI_COMMIT_SHA' + rules: + - if: $PROTECTED_PIPELINE_CI_PROJECT_PATH == null || $PROTECTED_PIPELINE_CI_CONFIG_PATH == null || $PROTECTED_PIPELINE_CI_REF == null + ``` + +- [CI/CD variables](../../ci/variables/_index.md) must be added to projects with external + pipeline configuration. In this example: + + - `PROTECTED_PIPELINE_CI_PROJECT_PATH`: The path to the project hosting the configuration file, for example `group/subgroup/project`. + - `PROTECTED_PIPELINE_CI_CONFIG_PATH`: The path to the configuration file in the project, for example `path/to/.gitlab-ci.yml`. + - `PROTECTED_PIPELINE_CI_REF`: The ref to use when retrieving the configuration file, for example `main`. + +#### Compliance pipelines in merge requests originating in project forks + +When a merge request originates in a fork, the branch to be merged usually only exists in the fork. +When creating such a merge request against a project with compliance pipelines, the above snippet fails with a +`Project reference does not exist!` error message. +This error occurs because in the context of the target project, `$CI_COMMIT_REF_NAME` evaluates to a non-existing +branch name. + +To get the correct context, use `$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` instead of `$CI_PROJECT_PATH`. +This variable is only available in +[merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). + +For example, for a configuration that supports both merge request pipelines originating in project forks and branch pipelines, +you need to [combine both `include` directives with `rules:if`](../../ci/yaml/includes.md#use-rules-with-include): + +```yaml +include: # Execute individual project's configuration (if project contains .gitlab-ci.yml) + - project: '$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH' + file: '$CI_CONFIG_PATH' + ref: '$CI_COMMIT_REF_NAME' + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - project: '$CI_PROJECT_PATH' + file: '$CI_CONFIG_PATH' + ref: '$CI_COMMIT_REF_NAME' + rules: + - if: $CI_PIPELINE_SOURCE != 'merge_request_event' +``` + +#### Compliance pipelines in projects with no configuration file + +The [example configuration](#example-configuration) above assumes that all projects contain +a pipeline configuration file (`.gitlab-ci.yml` by default). However, in projects +with no configuration file (and therefore no pipelines by default), the compliance pipeline +fails because the file specified in `include:project` is required. + +To only include a configuration file if it exists in a target project, use +[`rules:exists:project`](../../ci/yaml/_index.md#rulesexistsproject): + +```yaml +include: # Execute individual project's configuration + - project: '$CI_PROJECT_PATH' + file: '$CI_CONFIG_PATH' + ref: '$CI_COMMIT_SHA' + rules: + - exists: + paths: + - '$CI_CONFIG_PATH' + project: '$CI_PROJECT_PATH' + ref: '$CI_COMMIT_SHA' +``` + +In this example, a configuration file is only included if it exists for the given `ref` +in the project in `exists:project: $CI_PROJECT_PATH'`. + +If `exists:project` is not specified in the compliance pipeline configuration, it searches for files in the project +in which the `include` is defined. In compliance pipelines, the `include` from the example above +is defined in the project hosting the compliance pipeline configuration file, not the project +running the pipeline. + +## Ensure compliance jobs are always run + +Compliance pipelines [use GitLab CI/CD](../../ci/_index.md) to give you an incredible amount of flexibility +for defining any sort of compliance jobs you like. Depending on your goals, these jobs +can be configured to be: + +- Modified by users. +- Non-modifiable. + +Generally, if a value in a compliance job: + +- Is set, it cannot be changed or overridden by project-level configurations. +- Is not set, a project-level configuration may be set. + +Either might be wanted or not depending on your use case. + +The following are a few best practices for ensuring that these jobs are always run exactly +as you define them and that downstream, project-level pipeline configurations +cannot change them: + +- Add [a `rules:when:always` block](../../ci/yaml/_index.md#when) to each of your compliance jobs. This ensures they are + non-modifiable and are always run. +- Explicitly set any [variables](../../ci/yaml/_index.md#variables) the job references. This: + - Ensures that project-level pipeline configurations do not set them and alter their + behavior. For example, see `before_script` and `after_script` configuration in the [example configuration](#example-configuration). + - Includes any jobs that drive the logic of your job. +- Explicitly set the [container image](../../ci/yaml/_index.md#image) to run the job in. This ensures that your script + steps execute in the correct environment. +- Explicitly set any relevant GitLab pre-defined [job keywords](../../ci/yaml/_index.md#job-keywords). + This ensures that your job uses the settings you intend and that they are not overridden by + project-level pipelines. + +## Troubleshooting + +### Compliance jobs are overwritten by target repository + +If you use the `extends` statement in a compliance pipeline configuration, compliance jobs are overwritten by the target repository job. For example, +you could have the following `.compliance-gitlab-ci.yml` configuration: + +```yaml +"compliance job": + extends: + - .compliance_template + stage: build + +.compliance_template: + script: + - echo "take compliance action" +``` + +You could also have the following `.gitlab-ci.yml` configuration: + +```yaml +"compliance job": + stage: test + script: + - echo "overwriting compliance action" +``` + +This configuration results in the target repository pipeline overwriting the compliance pipeline, and you get the following message: +`overwriting compliance action`. + +To avoid overwriting a compliance job, don't use the `extends` keyword in compliance pipeline configuration. For example, +you could have the following `.compliance-gitlab-ci.yml` configuration: + +```yaml +"compliance job": + stage: build + script: + - echo "take compliance action" +``` + +You could also have the following `.gitlab-ci.yml` configuration: + +```yaml +"compliance job": + stage: test + script: + - echo "overwriting compliance action" +``` + +This configuration doesn't overwrite the compliance pipeline and you get the following message: +`take compliance action`. + +### Prefilled variables are not shown + +Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/382857), +compliance pipelines in GitLab 15.3 and later can prevent +[prefilled variables](../../ci/pipelines/_index.md#prefill-variables-in-manual-pipelines) +from appearing when manually starting a pipeline. + +To workaround this issue, use `ref: '$CI_COMMIT_SHA'` instead of `ref: '$CI_COMMIT_REF_NAME'` +in the `include:` statement that executes the individual project's configuration. + +The [example configuration](#example-configuration) has been updated with this change: + +```yaml +include: + - project: '$CI_PROJECT_PATH' + file: '$CI_CONFIG_PATH' + ref: '$CI_COMMIT_SHA' +``` + +### Error: `Job names must be unique` + +To configure a compliance pipeline, the [example configuration](#example-configuration) recommends including the +individual project configuration with `include.project`. + +The configuration can lead to an error when running the projects pipeline: `Pipeline execution policy error: Job names must be unique`. +This error occurs because the pipeline execution policy includes the project's `.gitlab-ci.yml` and tries to insert the +jobs when the jobs have already been declared in the pipeline. + +To resolve this error, remove `include.project` from the separate YAML file linked in the pipeline execution policy. + + diff --git a/doc/user/compliance/license_approval_policies.md b/doc/user/compliance/license_approval_policies.md index 220cd76de7b..620c2a2015b 100644 --- a/doc/user/compliance/license_approval_policies.md +++ b/doc/user/compliance/license_approval_policies.md @@ -43,7 +43,7 @@ License approval policies rely on the output of a dependency scanning job to ver To ensure enforcement of your policies, you should enable dependency scanning on your target development projects. You can achieve this a few different ways: - Create a global [scan execution policy](../application_security/policies/scan_execution_policies.md) that enforces Dependency Scanning to run in all target development projects. -- Use a [Compliance Pipeline](../group/compliance_frameworks.md) to define a Dependency Scanning job that is enforced on projects enforced by a given Compliance Framework. +- Use a [Compliance Pipeline](../compliance/compliance_frameworks.md) to define a Dependency Scanning job that is enforced on projects enforced by a given Compliance Framework. - Work with development teams to configure [Dependency Scanning](../application_security/dependency_scanning/_index.md) in each of their project's `.gitlab-ci.yml` files or enable by using the [Security Configuration panel](../application_security/configuration/_index.md). License approval policies require license information from [GitLab-supported packages](license_scanning_of_cyclonedx_files/_index.md#supported-languages-and-package-managers). diff --git a/doc/user/group/compliance_frameworks.md b/doc/user/group/compliance_frameworks.md index e6cd990c3ef..b6d6df66700 100644 --- a/doc/user/group/compliance_frameworks.md +++ b/doc/user/group/compliance_frameworks.md @@ -1,112 +1,13 @@ --- -stage: Software Supply Chain Security -group: Compliance -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments -title: Compliance frameworks +redirect_to: '../compliance/compliance_frameworks.md' +remove_date: '2025-05-25' --- -{{< details >}} + -- Tier: Premium, Ultimate -- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated +This document was moved to [another location](../compliance/compliance_frameworks.md). -{{< /details >}} - -You can create a compliance framework that is a label to identify that your project has certain compliance -requirements or needs additional oversight. - -In the Ultimate tier, the compliance framework can optionally enforce -[compliance pipeline configuration](compliance_pipelines.md) and -[security policies](../application_security/policies/_index.md#scope) to the projects on which it is applied. - -Compliance frameworks are created on top-level groups. If a project is moved outside of its existing top-level group, -its frameworks are removed. - -You can apply up to 20 compliance frameworks to each project. - -For a click-through demo, see [Compliance frameworks](https://gitlab.navattic.com/compliance). - - -## Prerequisites - -- To create, edit, and delete compliance frameworks, users must have either: - - The Owner role for the top-level group. - - Be assigned a [custom role](../custom_roles.md) with the `admin_compliance_framework` - [custom permission](../custom_roles/abilities.md#compliance-management). -- To add or remove a compliance framework to or from a project, the group to which the project belongs must have a - compliance framework. - -## Create, edit, or delete a compliance framework - -You can create, edit, or delete a compliance framework from a compliance framework report. For more information, see: - -- [Create a new compliance framework](../compliance/compliance_center/compliance_frameworks_report.md#create-a-new-compliance-framework). -- [Edit a compliance framework](../compliance/compliance_center/compliance_frameworks_report.md#edit-a-compliance-framework). -- [Delete a compliance framework](../compliance/compliance_center/compliance_frameworks_report.md#delete-a-compliance-framework). - -You can create, edit, or delete a compliance framework from a compliance projects report. For more information, see: - -- [Create a new compliance framework](../compliance/compliance_center/compliance_projects_report.md#create-a-new-compliance-framework). -- [Edit a compliance framework](../compliance/compliance_center/compliance_projects_report.md#edit-a-compliance-framework). -- [Delete a compliance framework](../compliance/compliance_center/compliance_projects_report.md#delete-a-compliance-framework). - -Subgroups and projects have access to all compliance frameworks created on their top-level group. However, compliance frameworks cannot be created, edited, -or deleted at the subgroup or project level. Project owners can choose a framework to apply to their projects. - -## Apply a compliance framework to a project - -{{< history >}} - -- Assigning multiple compliance frameworks [introduced](https://gitlab.com/groups/gitlab-org/-/epics/13294) in GitLab 17.3. - -{{< /history >}} - -You can apply multiple compliance frameworks to a project but cannot apply compliance frameworks to projects in personal namespaces. - -To apply a compliance framework to a project, apply the compliance framework through the -[Compliance projects report](../compliance/compliance_center/compliance_projects_report.md#apply-a-compliance-framework-to-projects-in-a-group). - -You can use the [GraphQL API](../../api/graphql/reference/_index.md#mutationprojectupdatecomplianceframeworks) to apply one or many -compliance frameworks to a project. - -If you create compliance frameworks on subgroups with GraphQL, the framework is created on the root ancestor if the user -has the correct permissions. The GitLab UI presents a read-only view to discourage this behavior. - -## Default compliance frameworks - -{{< history >}} - -- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375036) in GitLab 15.6. - -{{< /history >}} - -Group owners can set a default compliance framework. The default framework is applied to all the new and imported -projects that are created in that group. It does not affect the framework applied to the existing projects. The -default framework cannot be deleted. - -A compliance framework that is set to default has a **default** label. - -### Set and remove a default by using the compliance center - -To set as default (or remove the default) from [compliance projects report](../compliance/compliance_center/compliance_projects_report.md): - -1. On the left sidebar, select **Search or go to** and find your group. -1. Select **Secure > Compliance center**. -1. On the page, select the **Projects** tab. -1. Hover over a compliance framework, select the **Edit Framework** tab. -1. Select **Set as default**. -1. Select **Save changes**. - -To set as default (or remove the default) from [compliance framework report](../compliance/compliance_center/compliance_frameworks_report.md): - -1. On the left sidebar, select **Search or go to** and find your group. -1. Select **Secure > Compliance center**. -1. On the page, select the **Frameworks** tab. -1. Hover over a compliance framework, select the **Edit Framework** tab. -1. Select **Set as default**. -1. Select **Save changes**. - -## Remove a compliance framework from a project - -To remove a compliance framework from one or multiple project in a group, remove the compliance framework through the -[Compliance projects report](../compliance/compliance_center/compliance_projects_report.md#remove-a-compliance-framework-from-projects-in-a-group). + + + + \ No newline at end of file diff --git a/doc/user/group/compliance_pipelines.md b/doc/user/group/compliance_pipelines.md index 59372d7a79d..5e8d166a477 100644 --- a/doc/user/group/compliance_pipelines.md +++ b/doc/user/group/compliance_pipelines.md @@ -1,416 +1,13 @@ --- -stage: Software Supply Chain Security -group: Compliance -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments -title: Compliance pipelines (deprecated) +redirect_to: '../compliance/compliance_pipelines.md' +remove_date: '2025-05-25' --- - + -{{< details >}} +This document was moved to [another location](../compliance/compliance_pipelines.md). -- Tier: Ultimate -- Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated - -{{< /details >}} - -{{< alert type="warning" >}} - -This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/159841) in GitLab 17.3 -and is planned for removal in 19.0. Use [pipeline execution policy type](../application_security/policies/pipeline_execution_policies.md) instead. -This change is a breaking change. For more information, see the [migration guide](#pipeline-execution-policies-migration). - -{{< /alert >}} - -Group owners can configure a compliance pipeline in a project separate to other projects. By default, the compliance -pipeline configuration (for example, `.compliance-gitlab-ci.yml`) is run instead of the pipeline configuration (for example, `.gitlab-ci.yml`) of labeled -projects. - -However, the compliance pipeline configuration can reference the `.gitlab-ci.yml` file of the labeled projects so that: - -- The compliance pipeline can also run jobs of labeled project pipelines. This allows for centralized control of - pipeline configuration. -- Jobs and variables defined in the compliance pipeline can't be changed by variables in the labeled project's - `.gitlab-ci.yml` file. - -{{< alert type="note" >}} - -Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/414004), project pipelines must be included first at the top of compliance pipeline configuration -to prevent projects overriding settings downstream. - -{{< /alert >}} - -For more information, see: - -- [Example configuration](#example-configuration) for help configuring a compliance pipeline that runs jobs from - labeled project pipeline configuration. -- The [Create a compliance pipeline](../../tutorials/compliance_pipeline/_index.md) tutorial. - -## Pipeline execution policies migration - -To consolidate and simplify scan and pipeline enforcement, we have introduced pipeline execution policies. We deprecated -compliance pipelines in GitLab 17.3 and will remove compliance pipelines in GitLab 19.0. - -Pipeline execution policies extend a project's `.gitlab-ci.yml` file with the configuration provided in separate YAML file -(for example, `pipeline-execution.yml`) linked in the pipeline execution policy. - -By default, when creating a new compliance framework, you are directed to use the pipeline execution policy type instead -of compliance pipelines. - -Existing compliance pipelines must be migrated. Customers should migrate from compliance pipelines to the new -[pipeline execution policy type](../application_security/policies/pipeline_execution_policies.md) as soon as possible. - -### Migrate an existing compliance framework - -To migrate an existing compliance framework to use the pipeline execution policy type: - -1. On the left sidebar, select **Search or go to** and find your group. -1. Select **Secure > Compliance center**. -1. [Edit](compliance_frameworks.md#create-edit-or-delete-a-compliance-framework) the existing compliance framework. -1. In the banner than appears, select **Migrate pipeline to a policy** to create a new policy in the security policies. -1. Edit the compliance framework again to remove the compliance pipeline. - -For more information, see [Security policy project](../application_security/policies/_index.md#security-policy-project). - -If you receive a `Pipeline execution policy error: Job names must be unique` error during the migration, see the -[relevant troubleshooting information](#error-job-names-must-be-unique). - -## Effect on labeled projects - -Users have no way of knowing that a compliance pipeline has been configured and might be confused why their own -pipelines are not running at all, or include jobs that they did not define themselves. - -When authoring pipelines on a labeled project, there is no indication that a compliance pipeline has been configured. -The only marker at the project level is the compliance framework label itself, but the label does not say whether the -framework has a compliance pipeline configured or not. - -Therefore, communicate with project users about compliance pipeline configuration to reduce uncertainty and confusion. - -### Multiple compliance frameworks - -You can [apply to a single project](compliance_frameworks.md#apply-a-compliance-framework-to-a-project) multiple compliance frameworks with compliance pipelines configured. -In this case, only the first compliance framework applied to a project has its compliance pipeline included in the project pipeline. - -To ensure that the correct compliance pipeline is included in a project: - -1. Remove all compliance frameworks from the project. -1. Apply the compliance framework with the correct compliance pipeline to the project. -1. Apply additional compliance frameworks to the project. - -## Configure a compliance pipeline - -{{< history >}} - -- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/383209) in GitLab 15.11, compliance frameworks moved to compliance center. - -{{< /history >}} - -To configure a compliance pipeline: - -1. On the left sidebar, select **Search or go to** and find your group. -1. Select **Secure** > **Compliance Center**. -1. Select **Frameworks** section. -1. Select **New framework** section, add information of compliance framework including path to the compliance framework configuration. Use the - `path/file.y[a]ml@group-name/project-name` format. For example: - - - `.compliance-ci.yml@gitlab-org/gitlab`. - - `.compliance-ci.yaml@gitlab-org/gitlab`. - -This configuration is inherited by projects where the compliance framework label is -[applied](../project/working_with_projects.md#add-a-compliance-framework-to-a-project). In projects with the applied compliance -framework label, the compliance pipeline configuration is run instead of the labeled project's own pipeline configuration. - -The user running the pipeline in the labeled project must at least have the Reporter role on the compliance project. - -When used to enforce scan execution, this feature has some overlap with -[scan execution policies](../application_security/policies/scan_execution_policies.md). We have not -[unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312). For details on -the similarities and differences between these features, see [Enforce scan execution](../application_security/_index.md#enforce-scan-execution). - -### Example configuration - -The following example `.compliance-gitlab-ci.yml` includes the `include` keyword to ensure labeled project pipeline -configuration is also executed. - -```yaml -include: # Execute individual project's configuration (if project contains .gitlab-ci.yml) - - project: '$CI_PROJECT_PATH' - file: '$CI_CONFIG_PATH' - ref: '$CI_COMMIT_SHA' # Must be defined or MR pipelines always use the use default branch - rules: - - if: $CI_PROJECT_PATH != "my-group/project-1" # Must run on projects other than the one hosting this configuration. - -# Allows compliance team to control the ordering and interweaving of stages/jobs. -# Stages without jobs defined will remain hidden. -stages: - - pre-compliance - - build - - test - - pre-deploy-compliance - - deploy - - post-compliance - -variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml - FOO: sast - -sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml - variables: - FOO: sast - image: ruby:2.6 - stage: pre-compliance - rules: - - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push" - when: never - - when: always # or when: on_success - allow_failure: false - before_script: - - "# No before scripts." - script: - - echo "running $FOO" - after_script: - - "# No after scripts." - -sanity check: - image: ruby:2.6 - stage: pre-deploy-compliance - rules: - - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push" - when: never - - when: always # or when: on_success - allow_failure: false - before_script: - - "# No before scripts." - script: - - echo "running $FOO" - after_script: - - "# No after scripts." - -audit trail: - image: ruby:2.7 - stage: post-compliance - rules: - - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push" - when: never - - when: always # or when: on_success - allow_failure: false - before_script: - - "# No before scripts." - script: - - echo "running $FOO" - after_script: - - "# No after scripts." -``` - -The `rules` configuration in the `include` definition avoids circular inclusion in case the compliance pipeline must be able to run in the host project itself. -You can leave it out if your compliance pipeline only ever runs in labeled projects. - -#### Compliance pipelines and custom pipeline configuration hosted externally - -The example above assumes that all projects host their pipeline configuration in the same project. -If any projects use [configuration hosted externally](../../ci/pipelines/settings.md#specify-a-custom-cicd-configuration-file), -the example configuration does not work. See [issue 393960](https://gitlab.com/gitlab-org/gitlab/-/issues/393960) -for more details. - -With projects that use externally hosted configuration, you can try the this workaround: - -- The `include` section in the example compliance pipeline configuration must be adjusted. - For example, using [`include:rules`](../../ci/yaml/includes.md#use-rules-with-include): - - ```yaml - include: - # If the custom path variables are defined, include the project's external config file. - - project: '$PROTECTED_PIPELINE_CI_PROJECT_PATH' - file: '$PROTECTED_PIPELINE_CI_CONFIG_PATH' - ref: '$PROTECTED_PIPELINE_CI_REF' - rules: - - if: $PROTECTED_PIPELINE_CI_PROJECT_PATH && $PROTECTED_PIPELINE_CI_CONFIG_PATH && $PROTECTED_PIPELINE_CI_REF - # If any custom path variable is not defined, include the project's internal config file as normal. - - project: '$CI_PROJECT_PATH' - file: '$CI_CONFIG_PATH' - ref: '$CI_COMMIT_SHA' - rules: - - if: $PROTECTED_PIPELINE_CI_PROJECT_PATH == null || $PROTECTED_PIPELINE_CI_CONFIG_PATH == null || $PROTECTED_PIPELINE_CI_REF == null - ``` - -- [CI/CD variables](../../ci/variables/_index.md) must be added to projects with external - pipeline configuration. In this example: - - - `PROTECTED_PIPELINE_CI_PROJECT_PATH`: The path to the project hosting the configuration file, for example `group/subgroup/project`. - - `PROTECTED_PIPELINE_CI_CONFIG_PATH`: The path to the configuration file in the project, for example `path/to/.gitlab-ci.yml`. - - `PROTECTED_PIPELINE_CI_REF`: The ref to use when retrieving the configuration file, for example `main`. - -#### Compliance pipelines in merge requests originating in project forks - -When a merge request originates in a fork, the branch to be merged usually only exists in the fork. -When creating such a merge request against a project with compliance pipelines, the above snippet fails with a -`Project reference does not exist!` error message. -This error occurs because in the context of the target project, `$CI_COMMIT_REF_NAME` evaluates to a non-existing -branch name. - -To get the correct context, use `$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` instead of `$CI_PROJECT_PATH`. -This variable is only available in -[merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). - -For example, for a configuration that supports both merge request pipelines originating in project forks and branch pipelines, -you need to [combine both `include` directives with `rules:if`](../../ci/yaml/includes.md#use-rules-with-include): - -```yaml -include: # Execute individual project's configuration (if project contains .gitlab-ci.yml) - - project: '$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH' - file: '$CI_CONFIG_PATH' - ref: '$CI_COMMIT_REF_NAME' - rules: - - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - - project: '$CI_PROJECT_PATH' - file: '$CI_CONFIG_PATH' - ref: '$CI_COMMIT_REF_NAME' - rules: - - if: $CI_PIPELINE_SOURCE != 'merge_request_event' -``` - -#### Compliance pipelines in projects with no configuration file - -The [example configuration](#example-configuration) above assumes that all projects contain -a pipeline configuration file (`.gitlab-ci.yml` by default). However, in projects -with no configuration file (and therefore no pipelines by default), the compliance pipeline -fails because the file specified in `include:project` is required. - -To only include a configuration file if it exists in a target project, use -[`rules:exists:project`](../../ci/yaml/_index.md#rulesexistsproject): - -```yaml -include: # Execute individual project's configuration - - project: '$CI_PROJECT_PATH' - file: '$CI_CONFIG_PATH' - ref: '$CI_COMMIT_SHA' - rules: - - exists: - paths: - - '$CI_CONFIG_PATH' - project: '$CI_PROJECT_PATH' - ref: '$CI_COMMIT_SHA' -``` - -In this example, a configuration file is only included if it exists for the given `ref` -in the project in `exists:project: $CI_PROJECT_PATH'`. - -If `exists:project` is not specified in the compliance pipeline configuration, it searches for files in the project -in which the `include` is defined. In compliance pipelines, the `include` from the example above -is defined in the project hosting the compliance pipeline configuration file, not the project -running the pipeline. - -## Ensure compliance jobs are always run - -Compliance pipelines [use GitLab CI/CD](../../ci/_index.md) to give you an incredible amount of flexibility -for defining any sort of compliance jobs you like. Depending on your goals, these jobs -can be configured to be: - -- Modified by users. -- Non-modifiable. - -Generally, if a value in a compliance job: - -- Is set, it cannot be changed or overridden by project-level configurations. -- Is not set, a project-level configuration may be set. - -Either might be wanted or not depending on your use case. - -The following are a few best practices for ensuring that these jobs are always run exactly -as you define them and that downstream, project-level pipeline configurations -cannot change them: - -- Add [a `rules:when:always` block](../../ci/yaml/_index.md#when) to each of your compliance jobs. This ensures they are - non-modifiable and are always run. -- Explicitly set any [variables](../../ci/yaml/_index.md#variables) the job references. This: - - Ensures that project-level pipeline configurations do not set them and alter their - behavior. For example, see `before_script` and `after_script` configuration in the [example configuration](#example-configuration). - - Includes any jobs that drive the logic of your job. -- Explicitly set the [container image](../../ci/yaml/_index.md#image) to run the job in. This ensures that your script - steps execute in the correct environment. -- Explicitly set any relevant GitLab pre-defined [job keywords](../../ci/yaml/_index.md#job-keywords). - This ensures that your job uses the settings you intend and that they are not overridden by - project-level pipelines. - -## Troubleshooting - -### Compliance jobs are overwritten by target repository - -If you use the `extends` statement in a compliance pipeline configuration, compliance jobs are overwritten by the target repository job. For example, -you could have the following `.compliance-gitlab-ci.yml` configuration: - -```yaml -"compliance job": - extends: - - .compliance_template - stage: build - -.compliance_template: - script: - - echo "take compliance action" -``` - -You could also have the following `.gitlab-ci.yml` configuration: - -```yaml -"compliance job": - stage: test - script: - - echo "overwriting compliance action" -``` - -This configuration results in the target repository pipeline overwriting the compliance pipeline, and you get the following message: -`overwriting compliance action`. - -To avoid overwriting a compliance job, don't use the `extends` keyword in compliance pipeline configuration. For example, -you could have the following `.compliance-gitlab-ci.yml` configuration: - -```yaml -"compliance job": - stage: build - script: - - echo "take compliance action" -``` - -You could also have the following `.gitlab-ci.yml` configuration: - -```yaml -"compliance job": - stage: test - script: - - echo "overwriting compliance action" -``` - -This configuration doesn't overwrite the compliance pipeline and you get the following message: -`take compliance action`. - -### Prefilled variables are not shown - -Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/382857), -compliance pipelines in GitLab 15.3 and later can prevent -[prefilled variables](../../ci/pipelines/_index.md#prefill-variables-in-manual-pipelines) -from appearing when manually starting a pipeline. - -To workaround this issue, use `ref: '$CI_COMMIT_SHA'` instead of `ref: '$CI_COMMIT_REF_NAME'` -in the `include:` statement that executes the individual project's configuration. - -The [example configuration](#example-configuration) has been updated with this change: - -```yaml -include: - - project: '$CI_PROJECT_PATH' - file: '$CI_CONFIG_PATH' - ref: '$CI_COMMIT_SHA' -``` - -### Error: `Job names must be unique` - -To configure a compliance pipeline, the [example configuration](#example-configuration) recommends including the -individual project configuration with `include.project`. - -The configuration can lead to an error when running the projects pipeline: `Pipeline execution policy error: Job names must be unique`. -This error occurs because the pipeline execution policy includes the project's `.gitlab-ci.yml` and tries to insert the -jobs when the jobs have already been declared in the pipeline. - -To resolve this error, remove `include.project` from the separate YAML file linked in the pipeline execution policy. - - + + + + \ No newline at end of file diff --git a/doc/user/permissions.md b/doc/user/permissions.md index cc103ea4525..1aca8607b43 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -469,8 +469,8 @@ Group permissions for [compliance](compliance/_index.md) features including comp | View [audit events](compliance/audit_events.md) | | | | ✓ | ✓ | ✓ | Users can view only events based on their individual actions. For more details, see the [prerequisites](compliance/audit_events.md#prerequisites). | | View licenses in the [dependency list](application_security/dependency_list/_index.md) | | | | ✓ | ✓ | ✓ | | | View the [compliance center](compliance/compliance_center/_index.md) | | | | | | ✓ | | -| Manage [compliance frameworks](group/compliance_frameworks.md) | | | | | | ✓ | | -| Assign [compliance frameworks](group/compliance_frameworks.md) to projects | | | | | | ✓ | | +| Manage [compliance frameworks](compliance/compliance_frameworks.md) | | | | | | ✓ | | +| Assign [compliance frameworks](compliance/compliance_frameworks.md) to projects | | | | | | ✓ | | | Manage [audit streams](compliance/audit_event_streaming.md) | | | | | | ✓ | | ### GitLab Duo group permissions diff --git a/doc/user/project/working_with_projects.md b/doc/user/project/working_with_projects.md index 6327e75795e..2ff05bd53b7 100644 --- a/doc/user/project/working_with_projects.md +++ b/doc/user/project/working_with_projects.md @@ -597,7 +597,7 @@ To leave a project: {{< /details >}} -You can add compliance frameworks to projects in a group that has a [compliance framework](../group/compliance_frameworks.md). +You can add compliance frameworks to projects in a group that has a [compliance framework](../compliance/compliance_frameworks.md). ## Manage project access through LDAP groups diff --git a/gems/gitlab-http/Gemfile.lock b/gems/gitlab-http/Gemfile.lock index 1bf4da41da5..4785a657cf9 100644 --- a/gems/gitlab-http/Gemfile.lock +++ b/gems/gitlab-http/Gemfile.lock @@ -21,7 +21,7 @@ PATH gitlab-http (0.1.0) activesupport (~> 7) concurrent-ruby (~> 1.2) - httparty (~> 0.21.0) + httparty (~> 0.21) ipaddress (~> 0.8.3) net-http (= 0.6.0) railties (~> 7) @@ -62,6 +62,7 @@ GEM crack (0.4.5) rexml crass (1.0.6) + csv (3.3.2) debug_inspector (1.2.0) diff-lcs (1.5.0) erubi (1.12.0) @@ -75,7 +76,8 @@ GEM rubocop-rspec (~> 3.0.4) rubocop-rspec_rails (~> 2.30.0) hashdiff (1.0.1) - httparty (0.21.0) + httparty (0.22.0) + csv mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) i18n (1.14.1) diff --git a/gems/gitlab-http/gitlab-http.gemspec b/gems/gitlab-http/gitlab-http.gemspec index 359fddd209a..405573520d4 100644 --- a/gems/gitlab-http/gitlab-http.gemspec +++ b/gems/gitlab-http/gitlab-http.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'activesupport', '~> 7' spec.add_runtime_dependency 'concurrent-ruby', '~> 1.2' - spec.add_runtime_dependency 'httparty', '~> 0.21.0' + spec.add_runtime_dependency 'httparty', '~> 0.21' spec.add_runtime_dependency 'ipaddress', '~> 0.8.3' spec.add_runtime_dependency "railties", "~> 7" # See lib/net_http/connect_patch.rb diff --git a/lib/api/ci/job_artifacts.rb b/lib/api/ci/job_artifacts.rb index e64e8c348f6..86d606b64e4 100644 --- a/lib/api/ci/job_artifacts.rb +++ b/lib/api/ci/job_artifacts.rb @@ -70,7 +70,8 @@ module API 'available only on Premium and Ultimate tiers.' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_jobs + route_setting :authorization, job_token_policies: :read_jobs, + allow_public_access_for_enabled_project_features: [:repository, :builds] get ':id/jobs/artifacts/:ref_name/raw/*artifact_path', urgency: :low, format: false, diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb index 714322c4931..66369f450f4 100644 --- a/lib/api/ci/runner.rb +++ b/lib/api/ci/runner.rb @@ -392,7 +392,8 @@ module API optional :direct_download, default: false, type: Boolean, desc: 'Perform direct download from remote storage instead of proxying artifacts' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_jobs + route_setting :authorization, job_token_policies: :read_jobs, + allow_public_access_for_enabled_project_features: [:repository, :builds] get '/:id/artifacts', feature_category: :job_artifacts do authenticate_job_via_dependent_job! authorize_job_token_policies!(current_job.project) diff --git a/lib/api/composer_packages.rb b/lib/api/composer_packages.rb index 736a27ae8ff..5840ae8db72 100644 --- a/lib/api/composer_packages.rb +++ b/lib/api/composer_packages.rb @@ -204,7 +204,8 @@ module API requires :package_name, type: String, file_path: true, desc: 'The Composer package name', documentation: { example: 'my-composer-package' } end route_setting :authentication, job_token_allowed: :basic_auth, basic_auth_personal_access_token: true, deploy_token_allowed: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'archives/*package_name', urgency: :default do project = authorized_user_project(action: :read_package) authorize_job_token_policies!(project) diff --git a/lib/api/conan/v2/project_packages.rb b/lib/api/conan/v2/project_packages.rb index e1469bf5081..add60950f3d 100644 --- a/lib/api/conan/v2/project_packages.rb +++ b/lib/api/conan/v2/project_packages.rb @@ -59,7 +59,8 @@ module API tags %w[conan_packages] end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get urgency: :low do download_package_file(:recipe_file) end diff --git a/lib/api/concerns/packages/conan/v1_endpoints.rb b/lib/api/concerns/packages/conan/v1_endpoints.rb index cae70eb2de9..6faf8f10b4e 100644 --- a/lib/api/concerns/packages/conan/v1_endpoints.rb +++ b/lib/api/concerns/packages/conan/v1_endpoints.rb @@ -110,7 +110,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'packages/:conan_package_reference', urgency: :low do authorize_read_package!(project) @@ -137,7 +138,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get urgency: :low do authorize_read_package!(project) @@ -168,7 +170,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'packages/:conan_package_reference/digest', urgency: :low do present_package_download_urls @@ -186,7 +189,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'digest', urgency: :low do present_recipe_download_urls @@ -215,7 +219,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'packages/:conan_package_reference/download_urls', urgency: :low do present_package_download_urls @@ -233,7 +238,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'download_urls', urgency: :low do present_recipe_download_urls @@ -263,7 +269,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry post 'packages/:conan_package_reference/upload_urls', urgency: :low do authorize_read_package!(project) @@ -284,7 +291,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry post 'upload_urls', urgency: :low do authorize_read_package!(project) @@ -358,7 +366,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get urgency: :low do download_package_file(:recipe_file) @@ -430,7 +439,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get urgency: :low do download_package_file(:package_file) diff --git a/lib/api/concerns/packages/npm_endpoints.rb b/lib/api/concerns/packages/npm_endpoints.rb index 15053871925..65f944e36f0 100644 --- a/lib/api/concerns/packages/npm_endpoints.rb +++ b/lib/api/concerns/packages/npm_endpoints.rb @@ -79,7 +79,8 @@ module API end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true, authenticate_non_public: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'dist-tags', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do package_name = params[:package_name] @@ -194,7 +195,8 @@ module API tags %w[npm_packages] end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry post '-/npm/v1/security/advisories/bulk' do redirect_or_present_audit_report end @@ -214,7 +216,8 @@ module API tags %w[npm_packages] end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry post '-/npm/v1/security/audits/quick' do redirect_or_present_audit_report end diff --git a/lib/api/concerns/packages/npm_namespace_endpoints.rb b/lib/api/concerns/packages/npm_namespace_endpoints.rb index f3224702a3c..879db486540 100644 --- a/lib/api/concerns/packages/npm_namespace_endpoints.rb +++ b/lib/api/concerns/packages/npm_namespace_endpoints.rb @@ -59,7 +59,8 @@ module API end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true, authenticate_non_public: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get '*package_name', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do package_name = declared_params[:package_name] packages = diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb index ef93f70c4b5..17bcc029283 100644 --- a/lib/api/deployments.rb +++ b/lib/api/deployments.rb @@ -69,7 +69,8 @@ module API end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_deployments + route_setting :authorization, job_token_policies: :read_deployments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] get ':id/deployments' do authorize! :read_deployment, user_project @@ -95,7 +96,8 @@ module API requires :deployment_id, type: Integer, desc: 'The ID of the deployment' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_deployments + route_setting :authorization, job_token_policies: :read_deployments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] get ':id/deployments/:deployment_id' do authorize! :read_deployment, user_project @@ -251,7 +253,8 @@ module API use :merge_requests_base_params end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_deployments + route_setting :authorization, job_token_policies: :read_deployments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] get ':id/deployments/:deployment_id/merge_requests' do authorize! :read_deployment, user_project diff --git a/lib/api/environments.rb b/lib/api/environments.rb index 046cc171676..8a7dcdaa6ea 100644 --- a/lib/api/environments.rb +++ b/lib/api/environments.rb @@ -39,7 +39,8 @@ module API mutually_exclusive :name, :search, message: 'cannot be used together' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_environments + route_setting :authorization, job_token_policies: :read_environments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] get ':id/environments' do authorize! :read_environment, user_project @@ -271,7 +272,8 @@ module API requires :environment_id, type: Integer, desc: 'The ID of the environment' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_environments + route_setting :authorization, job_token_policies: :read_environments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] get ':id/environments/:environment_id' do authorize! :read_environment, user_project diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb index 9404e5e1397..5c28303c5ec 100644 --- a/lib/api/generic_packages.rb +++ b/lib/api/generic_packages.rb @@ -128,7 +128,8 @@ module API end route_setting :authentication, job_token_allowed: %i[request basic_auth], basic_auth_personal_access_token: true, deploy_token_allowed: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get do project = authorized_user_project(action: :read_package) diff --git a/lib/api/go_proxy.rb b/lib/api/go_proxy.rb index eaedc1531db..6badf5d79ef 100755 --- a/lib/api/go_proxy.rb +++ b/lib/api/go_proxy.rb @@ -69,7 +69,8 @@ module API end route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, authenticate_non_public: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do before do authorize_read_package!(project) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 74a9120a477..d72d9cf8f99 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -1038,6 +1038,7 @@ module API return true unless current_user&.from_ci_job_token? return true unless Feature.enabled?(:add_policies_to_ci_job_token, project) return true if skip_job_token_policies? + return true if publicly_accessible_feature?(project) current_user.ci_job_token_scope.policies_allowed?(project, job_token_policies) end @@ -1069,6 +1070,19 @@ module API route_setting(:authorization).try(:fetch, :skip_job_token_policies, false) end + + def publicly_accessible_feature?(project) + return false unless respond_to?(:route_setting) + return false unless project.public? || project.internal? + return false unless project&.project_feature + + project_features = Array(route_setting(:authorization).try(:fetch, :allow_public_access_for_enabled_project_features, nil)) + return false if project_features.empty? + + project_features.all? do |project_feature| + project.project_feature.access_level(project_feature) >= ProjectFeature::ENABLED + end + end end end diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb index 5e25f8b81e0..6eddd7f5a5b 100644 --- a/lib/api/maven_packages.rb +++ b/lib/api/maven_packages.rb @@ -102,7 +102,8 @@ module API use :path_and_file_name end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do # return a similar failure to authorize_read_package!(project) @@ -158,7 +159,8 @@ module API use :path_and_file_name end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get ':id/-/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do # return a similar failure to group = find_group(params[:id]) group = find_authorized_group!(action: :read_package_within_public_registries) @@ -200,7 +202,8 @@ module API use :path_and_file_name end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true, basic_auth_personal_access_token: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get ':id/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do project = authorized_user_project(action: :read_package) diff --git a/lib/api/npm_project_packages.rb b/lib/api/npm_project_packages.rb index 31529343901..e04063761a1 100644 --- a/lib/api/npm_project_packages.rb +++ b/lib/api/npm_project_packages.rb @@ -61,7 +61,8 @@ module API requires :file_name, type: String, desc: 'Package file name' end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get '*package_name/-/*file_name', format: false do authorize_read_package!(project) @@ -141,7 +142,8 @@ module API end route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true, authenticate_non_public: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get '*package_name', format: false, requirements: ::API::Helpers::Packages::Npm::NPM_ENDPOINT_REQUIREMENTS do package_name = declared_params[:package_name] packages = ::Packages::Npm::PackageFinder.new(project: project_or_nil, params: { package_name: package_name }).execute diff --git a/lib/api/package_files.rb b/lib/api/package_files.rb index df0ceddb5eb..9f9ad173d32 100644 --- a/lib/api/package_files.rb +++ b/lib/api/package_files.rb @@ -31,7 +31,8 @@ module API use :pagination end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get ':id/packages/:package_id/package_files' do package = ::Packages::PackageFinder .new(user_project, params[:package_id]).execute diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb index 9be1a97a4e7..99d9658d9d5 100644 --- a/lib/api/project_packages.rb +++ b/lib/api/project_packages.rb @@ -54,7 +54,8 @@ module API desc: 'Return packages with specified status' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get ':id/packages' do packages = ::Packages::PackagesFinder.new( user_project, @@ -77,7 +78,8 @@ module API requires :package_id, type: Integer, desc: 'The ID of a package' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get ':id/packages/:package_id' do render_api_error!('Package not found', 404) unless package.detailed_info? @@ -104,7 +106,8 @@ module API values: 1..20 end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get ':id/packages/:package_id/pipelines' do not_found!('Package not found') unless package.detailed_info? diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb index d50ce9a6798..37cd169c4e4 100644 --- a/lib/api/pypi_packages.rb +++ b/lib/api/pypi_packages.rb @@ -131,7 +131,8 @@ module API end route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'files/:sha256/*file_identifier' do group = find_authorized_group! authorize_read_package!(group) @@ -212,7 +213,8 @@ module API end route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'files/:sha256/*file_identifier' do project = project! authorize_job_token_policies!(project) @@ -240,7 +242,8 @@ module API # An API entry point but returns an HTML file instead of JSON. # PyPi simple API returns a list of packages as a simple HTML file. route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'simple', format: :txt do project = project! authorize_job_token_policies!(project) @@ -265,7 +268,8 @@ module API # An API entry point but returns an HTML file instead of JSON. # PyPi simple API returns the package descriptor as a simple HTML file. route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth - route_setting :authorization, job_token_policies: :read_packages + route_setting :authorization, job_token_policies: :read_packages, + allow_public_access_for_enabled_project_features: :package_registry get 'simple/*package_name', format: :txt do project = project! authorize_job_token_policies!(project) diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb index 06dd5e06754..e38b8a3049d 100644 --- a/lib/api/release/links.rb +++ b/lib/api/release/links.rb @@ -38,7 +38,8 @@ module API use :pagination end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_releases + route_setting :authorization, job_token_policies: :read_releases, + allow_public_access_for_enabled_project_features: :releases get 'links' do authorize! :read_release, release @@ -95,7 +96,8 @@ module API tags release_links_tags end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_releases + route_setting :authorization, job_token_policies: :read_releases, + allow_public_access_for_enabled_project_features: :releases get do authorize! :read_release, release diff --git a/lib/api/releases.rb b/lib/api/releases.rb index e02aad88d31..3a99271ca19 100644 --- a/lib/api/releases.rb +++ b/lib/api/releases.rb @@ -98,7 +98,8 @@ module API optional :updated_after, type: DateTime, desc: 'Return releases updated after the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_releases + route_setting :authorization, job_token_policies: :read_releases, + allow_public_access_for_enabled_project_features: [:repository, :releases] get ':id/releases' do releases = ::ReleasesFinder.new(user_project, current_user, declared_params.slice(:order_by, :sort, :updated_before, :updated_after)).execute @@ -134,7 +135,8 @@ module API desc: 'If `true`, a response includes HTML rendered markdown of the release description' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_releases + route_setting :authorization, job_token_policies: :read_releases, + allow_public_access_for_enabled_project_features: [:repository, :releases] get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do authorize_read_code! @@ -162,7 +164,8 @@ module API as: :filepath end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_releases + route_setting :authorization, job_token_policies: :read_releases, + allow_public_access_for_enabled_project_features: [:repository, :releases] get ':id/releases/:tag_name/downloads/*direct_asset_path', format: false, requirements: RELEASE_ENDPOINT_REQUIREMENTS do authorize_read_code! @@ -191,7 +194,8 @@ module API desc: 'The path to be suffixed to the latest release' end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_releases + route_setting :authorization, job_token_policies: :read_releases, + allow_public_access_for_enabled_project_features: [:repository, :releases] get ':id/releases/permalink/latest(/)(*suffix_path)', format: false, requirements: RELEASE_ENDPOINT_REQUIREMENTS do authorize_read_code! diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index 6a8358957e9..60f86704ba5 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -293,7 +293,8 @@ module API desc: "The file path to the configuration file as stored in the project's Git repository. Defaults to '.gitlab/changelog_config.yml'" end route_setting :authentication, job_token_allowed: true - route_setting :authorization, job_token_policies: :read_releases + route_setting :authorization, job_token_policies: :read_releases, + allow_public_access_for_enabled_project_features: :repository get ':id/repository/changelog' do check_rate_limit!(:project_repositories_changelog, scope: [current_user, user_project]) do render_api_error!({ error: 'This changelog has been requested too many times. Try again later.' }, 429) diff --git a/package.json b/package.json index d053ffcfa30..c4fbdc2ad44 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@gitlab/fonts": "^1.3.0", "@gitlab/query-language-rust": "0.4.0", "@gitlab/svgs": "3.123.0", - "@gitlab/ui": "108.3.1", + "@gitlab/ui": "108.4.1", "@gitlab/vue-router-vue3": "npm:vue-router@4.5.0", "@gitlab/vuex-vue3": "npm:vuex@4.1.0", "@gitlab/web-ide": "^0.0.1-dev-20250211142744", diff --git a/spec/frontend/authentication/password/components/password_input_spec.js b/spec/frontend/authentication/password/components/password_input_spec.js index c52baf87451..ee71184a270 100644 --- a/spec/frontend/authentication/password/components/password_input_spec.js +++ b/spec/frontend/authentication/password/components/password_input_spec.js @@ -40,6 +40,7 @@ describe('PasswordInput', () => { expect(passwordInput.attributes('data-testid')).toBe(propsData.testid); expect(passwordInput.attributes('title')).toBe(propsData.title); expect(passwordInput.attributes('required')).toBe('true'); + expect(passwordInput.attributes('disabled')).toBeUndefined(); }); describe('when password input is not required', () => { @@ -73,4 +74,13 @@ describe('PasswordInput', () => { }); }); }); + + describe('when password input is disabled', () => { + it('disables the input field and the toggle button', () => { + wrapper = createComponent({ disabled: true }); + + expect(findPasswordInput().attributes('disabled')).toBeDefined(); + expect(findToggleButton().attributes('disabled')).toBeDefined(); + }); + }); }); diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb index 6075a0aa8ad..375240a0ab8 100644 --- a/spec/lib/api/helpers_spec.rb +++ b/spec/lib/api/helpers_spec.rb @@ -334,6 +334,16 @@ RSpec.describe API::Helpers, feature_category: :shared do it { is_expected.to eq project } end + + context 'when the project feature is publicly accessible' do + let_it_be(:project) { create(:project, :public, :builds_enabled) } + + before do + allow(helper).to receive(:route_setting).with(:authorization).and_return(allow_public_access_for_enabled_project_features: :builds) + end + + it { is_expected.to eq project } + end end context 'when no policy is given' do diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 3a6e154641d..3842000a931 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -5112,79 +5112,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def build.clear_memoization(:build_data) end - context 'when ci_async_build_hooks_execution flag is disabled' do - before do - stub_feature_flags(ci_async_build_hooks_execution: false) - end - - context 'with project services' do - before do - create(:integration, active: true, job_events: true, project: project) - end - - it 'executes services' do - allow_next_instance_of(Integration) do |integration| - expect(integration).to receive(:async_execute) - end - - build.execute_hooks - end - end - - context 'without relevant project services' do - before do - create(:integration, active: true, job_events: false, project: project) - end - - it 'does not execute services' do - allow_next_instance_of(Integration) do |integration| - expect(integration).not_to receive(:async_execute) - end - - build.execute_hooks - end - end - - context 'with project hooks' do - let(:build_data) { double(:BuildData, dup: double(:DupedData)) } - - before do - create(:project_hook, project: project, job_events: true) - end - - it 'executes hooks' do - expect(::Gitlab::DataBuilder::Build) - .to receive(:build).with(build).and_return(build_data) - - expect(build.project) - .to receive(:execute_hooks).with(build_data.dup, :job_hooks) - - build.execute_hooks - end - - context 'with blocked users' do - before do - allow(build).to receive(:user) { FactoryBot.build(:user, :blocked) } - end - - it 'does not execute hooks' do - expect(build.project).not_to receive(:execute_hooks) - - build.execute_hooks - end - end - end - - context 'without project hooks' do - it 'does not execute hooks' do - expect(build.project).not_to receive(:execute_hooks) - - build.execute_hooks - end - end - end - - context 'when ci_async_build_hooks_execution flag is enabled' do + context 'when project hooks exists' do let(:build_data) { double(:BuildData) } before do diff --git a/spec/models/integrations/campfire_spec.rb b/spec/models/integrations/campfire_spec.rb index dc92b6b81ad..60c286f46ee 100644 --- a/spec/models/integrations/campfire_spec.rb +++ b/spec/models/integrations/campfire_spec.rb @@ -35,6 +35,12 @@ RSpec.describe Integrations::Campfire, feature_category: :integrations do end end + describe '.help' do + it 'links to the help page correctly' do + expect(described_class.help).to include('help/api/integrations.md#campfire', 'Learn More') + end + end + describe "#execute" do let(:user) { build_stubbed(:user) } let(:project) { build_stubbed(:project, :repository) } diff --git a/spec/models/integrations/datadog_spec.rb b/spec/models/integrations/datadog_spec.rb index 882b5722c46..ad6ed58b691 100644 --- a/spec/models/integrations/datadog_spec.rb +++ b/spec/models/integrations/datadog_spec.rb @@ -152,11 +152,10 @@ RSpec.describe Integrations::Datadog, feature_category: :integrations do end end - describe '#help' do - subject { instance.help } - - it { is_expected.to be_a(String) } - it { is_expected.not_to be_empty } + describe '.help' do + it 'links to the help page correctly' do + expect(described_class.help).to include('help/integration/datadog.md', 'How do I set up this integration?') + end end describe 'upgrade from previous version' do diff --git a/spec/requests/api/ci/job_artifacts_spec.rb b/spec/requests/api/ci/job_artifacts_spec.rb index 90b0540dd37..727f70943f3 100644 --- a/spec/requests/api/ci/job_artifacts_spec.rb +++ b/spec/requests/api/ci/job_artifacts_spec.rb @@ -506,10 +506,7 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :job_artifacts do it_behaves_like 'enforcing job token policies', :read_jobs do before do stub_licensed_features(cross_project_pipelines: true) - end - - around do |example| - Sidekiq::Testing.inline! { example.run } + pipeline.update!(status: :success) end let(:request) do @@ -701,6 +698,19 @@ RSpec.describe API::Ci::JobArtifacts, feature_category: :job_artifacts do expect(response.headers.to_h) .not_to include('Gitlab-Workhorse-Send-Data' => /artifacts-entry/) end + + it_behaves_like 'enforcing job token policies', :read_jobs, + allow_public_access_for_enabled_project_features: [:repository, :builds] do + before do + stub_licensed_features(cross_project_pipelines: true) + pipeline.update!(status: :success) + end + + let(:request) do + get api("/projects/#{source_project.id}/jobs/artifacts/#{pipeline.ref}/raw/#{artifact}"), + params: { job: job.name, job_token: target_job.token } + end + end end end diff --git a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb index e7f267c4565..ec239ecf510 100644 --- a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb +++ b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb @@ -1082,7 +1082,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego expect(response).to have_gitlab_http_status(:forbidden) end - it_behaves_like 'enforcing job token policies', :read_jobs do + it_behaves_like 'enforcing job token policies', :read_jobs, + allow_public_access_for_enabled_project_features: [:repository, :builds] do let(:token) { target_job.token } let(:request) { download_artifact } end diff --git a/spec/requests/api/composer_packages_spec.rb b/spec/requests/api/composer_packages_spec.rb index 7126a31d49f..555e53ec6eb 100644 --- a/spec/requests/api/composer_packages_spec.rb +++ b/spec/requests/api/composer_packages_spec.rb @@ -595,7 +595,8 @@ RSpec.describe API::ComposerPackages, feature_category: :package_registry do let(:branch) { project.repository.find_branch('master') } let(:sha) { branch.target } - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do before_all do project.add_developer(user) end diff --git a/spec/requests/api/conan/v2/project_packages_spec.rb b/spec/requests/api/conan/v2/project_packages_spec.rb index da6774abdda..707cce3c666 100644 --- a/spec/requests/api/conan/v2/project_packages_spec.rb +++ b/spec/requests/api/conan/v2/project_packages_spec.rb @@ -43,6 +43,11 @@ RSpec.describe API::Conan::V2::ProjectPackages, feature_category: :package_regis it_behaves_like 'accept get request on private project with access to package registry for everyone' it_behaves_like 'project not found by project id' + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do + let(:headers) { job_basic_auth_header(target_job) } + end + context 'when feature flag is disabled' do before do stub_feature_flags(conan_package_revisions_support: false) diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb index 51f979e3853..594d27457bd 100644 --- a/spec/requests/api/deployments_spec.rb +++ b/spec/requests/api/deployments_spec.rb @@ -23,7 +23,8 @@ RSpec.describe API::Deployments, feature_category: :continuous_delivery do get api("/projects/#{project.id}/deployments", user), params: params end - it_behaves_like 'enforcing job token policies', :read_deployments do + it_behaves_like 'enforcing job token policies', :read_deployments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] do let(:request) do get api("/projects/#{source_project.id}/deployments"), params: { job_token: target_job.token } end @@ -174,7 +175,8 @@ RSpec.describe API::Deployments, feature_category: :continuous_delivery do shared_examples "returns project deployments" do let(:project) { deployment.environment.project } - it_behaves_like 'enforcing job token policies', :read_deployments do + it_behaves_like 'enforcing job token policies', :read_deployments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] do let(:request) do get api("/projects/#{source_project.id}/deployments/#{deployment.id}"), params: { job_token: target_job.token } @@ -670,7 +672,8 @@ RSpec.describe API::Deployments, feature_category: :continuous_delivery do subject { get api("/projects/#{project.id}/deployments/#{deployment.id}/merge_requests", user) } - it_behaves_like 'enforcing job token policies', :read_deployments do + it_behaves_like 'enforcing job token policies', :read_deployments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] do let(:request) do get api("/projects/#{source_project.id}/deployments/#{deployment.id}/merge_requests"), params: { job_token: target_job.token } end diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index c08cc783fdf..cbbe67defaf 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -124,7 +124,8 @@ RSpec.describe API::Environments, feature_category: :continuous_delivery do end end - it_behaves_like 'enforcing job token policies', :read_environments do + it_behaves_like 'enforcing job token policies', :read_environments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] do let(:request) do get api("/projects/#{source_project.id}/environments"), params: { job_token: target_job.token } end @@ -646,7 +647,8 @@ RSpec.describe API::Environments, feature_category: :continuous_delivery do let_it_be(:bridge_job) { create(:ci_bridge, :running, project: project, user: user) } let_it_be(:build_job) { create(:ci_build, :running, project: project, user: user) } - it_behaves_like 'enforcing job token policies', :read_environments do + it_behaves_like 'enforcing job token policies', :read_environments, + allow_public_access_for_enabled_project_features: [:repository, :builds, :environments] do let(:request) do get api("/projects/#{source_project.id}/environments/#{environment.id}"), params: { job_token: target_job.token } diff --git a/spec/requests/api/generic_packages_spec.rb b/spec/requests/api/generic_packages_spec.rb index 948c0692c25..dc09ae26189 100644 --- a/spec/requests/api/generic_packages_spec.rb +++ b/spec/requests/api/generic_packages_spec.rb @@ -691,7 +691,8 @@ RSpec.describe API::GenericPackages, feature_category: :package_registry do let_it_be(:package) { create(:generic_package, project: project) } let_it_be(:package_file) { create(:package_file, :generic, package: package) } - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do before do source_project.add_developer(user) end diff --git a/spec/requests/api/go_proxy_spec.rb b/spec/requests/api/go_proxy_spec.rb index 6277647a749..7897086027b 100644 --- a/spec/requests/api/go_proxy_spec.rb +++ b/spec/requests/api/go_proxy_spec.rb @@ -190,7 +190,8 @@ RSpec.describe API::GoProxy, feature_category: :package_registry do it_behaves_like 'a missing module version list resource' end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:module_name) { base } let(:resource) { 'list' } let(:request) { get_resource(job_token: target_job.token) } @@ -250,7 +251,8 @@ RSpec.describe API::GoProxy, feature_category: :package_registry do end end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:module_name) { base } let(:resource) { 'v1.0.1.info' } let(:request) { get_resource(job_token: target_job.token) } @@ -278,7 +280,8 @@ RSpec.describe API::GoProxy, feature_category: :package_registry do it_behaves_like 'a missing module file resource', 'v1.0.1', path: '/mod' end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:module_name) { base } let(:resource) { 'v1.0.1.mod' } let(:request) { get_resource(job_token: target_job.token) } @@ -306,7 +309,8 @@ RSpec.describe API::GoProxy, feature_category: :package_registry do it_behaves_like 'a module archive resource', 'v2.0.0', ['go.mod', 'a.go', 'x.go'], path: '/v2' end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:module_name) { base } let(:resource) { 'v1.0.1.zip' } let(:request) { get_resource(job_token: target_job.token) } diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb index db9c7da710c..8f85a98bf76 100644 --- a/spec/requests/api/maven_packages_spec.rb +++ b/spec/requests/api/maven_packages_spec.rb @@ -475,7 +475,8 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do end end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do before_all do project.add_maintainer(user) end @@ -649,7 +650,8 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do end end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:request) do download_file(file_name: package_file.file_name, params: { job_token: target_job.token }) end @@ -842,7 +844,8 @@ RSpec.describe API::MavenPackages, feature_category: :package_registry do subject { download_file_with_token(file_name: package_file.file_name) } - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:request) do download_file(file_name: package_file.file_name, params: { job_token: target_job.token }) end diff --git a/spec/requests/api/npm_project_packages_spec.rb b/spec/requests/api/npm_project_packages_spec.rb index 37048305b20..59d97910359 100644 --- a/spec/requests/api/npm_project_packages_spec.rb +++ b/spec/requests/api/npm_project_packages_spec.rb @@ -203,7 +203,8 @@ RSpec.describe API::NpmProjectPackages, feature_category: :package_registry do project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:headers) { build_token_auth_header(target_job.token) } end diff --git a/spec/requests/api/package_files_spec.rb b/spec/requests/api/package_files_spec.rb index 910e82a5d2f..301e2cd81bf 100644 --- a/spec/requests/api/package_files_spec.rb +++ b/spec/requests/api/package_files_spec.rb @@ -23,7 +23,8 @@ RSpec.describe API::PackageFiles, feature_category: :package_registry do project.add_developer(user) end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:request) { get api(url), params: { job_token: target_job.token } } end diff --git a/spec/requests/api/project_packages_spec.rb b/spec/requests/api/project_packages_spec.rb index 52c2823cac6..d26bbdb7b06 100644 --- a/spec/requests/api/project_packages_spec.rb +++ b/spec/requests/api/project_packages_spec.rb @@ -22,7 +22,8 @@ RSpec.describe API::ProjectPackages, feature_category: :package_registry do subject(:request) { get api(url), params: params } - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:params) { { job_token: target_job.token } } end @@ -231,7 +232,8 @@ RSpec.describe API::ProjectPackages, feature_category: :package_registry do subject { get api(package_url, user) } - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:request) { get api(package_url), params: { job_token: target_job.token } } end @@ -421,7 +423,8 @@ RSpec.describe API::ProjectPackages, feature_category: :package_registry do end end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:request) { get api(package_pipelines_url), params: { job_token: target_job.token } } end diff --git a/spec/requests/api/release/links_spec.rb b/spec/requests/api/release/links_spec.rb index d6f37ca3dc3..b0c0f5ef5b7 100644 --- a/spec/requests/api/release/links_spec.rb +++ b/spec/requests/api/release/links_spec.rb @@ -25,7 +25,8 @@ RSpec.describe API::Release::Links, feature_category: :release_orchestration do end describe 'GET /projects/:id/releases/:tag_name/assets/links' do - it_behaves_like 'enforcing job token policies', :read_releases do + it_behaves_like 'enforcing job token policies', :read_releases, + allow_public_access_for_enabled_project_features: :releases do let_it_be(:user) { maintainer } let(:request) do get api("/projects/#{source_project.id}/releases/v0.1/assets/links"), @@ -114,7 +115,8 @@ RSpec.describe API::Release::Links, feature_category: :release_orchestration do describe 'GET /projects/:id/releases/:tag_name/assets/links/:link_id' do let!(:release_link) { create(:release_link, release: release) } - it_behaves_like 'enforcing job token policies', :read_releases do + it_behaves_like 'enforcing job token policies', :read_releases, + allow_public_access_for_enabled_project_features: :releases do let_it_be(:user) { maintainer } let(:request) do get api("/projects/#{source_project.id}/releases/v0.1/assets/links/#{release_link.id}"), diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb index 3836d4462e3..64bb6f16b07 100644 --- a/spec/requests/api/releases_spec.rb +++ b/spec/requests/api/releases_spec.rb @@ -19,7 +19,8 @@ RSpec.describe API::Releases, :aggregate_failures, feature_category: :release_or end describe 'GET /projects/:id/releases', :use_clean_rails_redis_caching do - it_behaves_like 'enforcing job token policies', :read_releases do + it_behaves_like 'enforcing job token policies', :read_releases, + allow_public_access_for_enabled_project_features: [:repository, :releases] do let(:user) { developer } let(:request) do get api("/projects/#{source_project.id}/releases"), params: { job_token: target_job.token } @@ -326,7 +327,8 @@ RSpec.describe API::Releases, :aggregate_failures, feature_category: :release_or ) end - it_behaves_like 'enforcing job token policies', :read_releases do + it_behaves_like 'enforcing job token policies', :read_releases, + allow_public_access_for_enabled_project_features: [:repository, :releases] do let(:user) { developer } let(:request) do get api("/projects/#{source_project.id}/releases/v0.1"), params: { job_token: target_job.token } @@ -595,7 +597,8 @@ RSpec.describe API::Releases, :aggregate_failures, feature_category: :release_or context 'with a valid release tag' do context 'when filepath is provided' do context 'when filepath exists' do - it_behaves_like 'enforcing job token policies', :read_releases, expected_success_status: :redirect do + it_behaves_like 'enforcing job token policies', :read_releases, expected_success_status: :redirect, + allow_public_access_for_enabled_project_features: [:repository, :releases] do let(:user) { developer } let(:request) do get api("/projects/#{source_project.id}/releases/v0.1/downloads#{filepath}"), @@ -731,7 +734,8 @@ RSpec.describe API::Releases, :aggregate_failures, feature_category: :release_or ) end - it_behaves_like 'enforcing job token policies', :read_releases, expected_success_status: :redirect do + it_behaves_like 'enforcing job token policies', :read_releases, expected_success_status: :redirect, + allow_public_access_for_enabled_project_features: [:repository, :releases] do let(:user) { developer } let(:request) do get api("/projects/#{source_project.id}/releases/permalink/latest"), params: { job_token: target_job.token } diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 303a14a8a80..247dd938cd6 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -855,7 +855,8 @@ RSpec.describe API::Repositories, feature_category: :source_code_management do end describe 'GET /projects/:id/repository/changelog' do - it_behaves_like 'enforcing job token policies', :read_releases do + it_behaves_like 'enforcing job token policies', :read_releases, + allow_public_access_for_enabled_project_features: :repository do before do allow(Repositories::ChangelogService).to receive(:new) .and_return(instance_spy(Repositories::ChangelogService)) diff --git a/spec/support/shared_examples/ci/job_token_policies_shared_examples.rb b/spec/support/shared_examples/ci/job_token_policies_shared_examples.rb index c4ea01e3b40..8aef52ffd27 100644 --- a/spec/support/shared_examples/ci/job_token_policies_shared_examples.rb +++ b/spec/support/shared_examples/ci/job_token_policies_shared_examples.rb @@ -1,13 +1,23 @@ # frozen_string_literal: true -RSpec.shared_examples 'enforcing job token policies' do |policies, expected_success_status: :success| +RSpec.shared_examples 'enforcing job token policies' do |policies, expected_success_status: :success, + allow_public_access_for_enabled_project_features: nil| + context 'when authenticating with a CI job token from another project' do let(:source_project) { project } - let(:target_job) { create(:ci_build, :running, user: user) } + let(:job_user) { user } + let(:target_job) { create(:ci_build, :running, user: job_user) } let(:allowed_policies) { Array(policies) } let(:default_permissions) { false } + let!(:features_state) do + source_project.project_feature.attributes + .slice(*::ProjectFeature::FEATURES.map { |feature| "#{feature}_access_level" }) + end before do + # Make all project features private + enable_project_features(source_project, nil) + create(:ci_job_token_project_scope_link, source_project: source_project, target_project: target_job.project, @@ -17,6 +27,11 @@ RSpec.shared_examples 'enforcing job token policies' do |policies, expected_succ ) end + after do + # Reinstate the initial project features + source_project.project_feature.update!(features_state) + end + subject(:do_request) do request response @@ -58,5 +73,59 @@ RSpec.shared_examples 'enforcing job token policies' do |policies, expected_succ it { is_expected.to have_gitlab_http_status(expected_success_status) } end end + + context 'when the source project is public and the target job user is not a member of the source project' do + let(:visibility_level) { source_project.visibility_level } + let(:job_user) { create(:user) } + + before do + if visibility_level != ::Gitlab::VisibilityLevel::PUBLIC + source_project.update!(visibility_level: ::Gitlab::VisibilityLevel::PUBLIC) + end + end + + after do + if visibility_level != ::Gitlab::VisibilityLevel::PUBLIC + source_project.update!(visibility_level: visibility_level) + end + end + + context 'when policies are not allowed, but the specified project features allow public access', + if: allow_public_access_for_enabled_project_features.present? do + let(:allowed_policies) { [] } + + context 'when all project features are private' do + it { is_expected.to have_gitlab_http_status(:forbidden) } + end + + context 'when the specified project features are public' do + before do + enable_project_features(source_project, allow_public_access_for_enabled_project_features) + end + + it { is_expected.to have_gitlab_http_status(expected_success_status) } + end + end + + context 'when policies are allowed and all project features are public', + unless: allow_public_access_for_enabled_project_features.present? do + before do + enable_project_features(source_project, ::ProjectFeature::FEATURES) + end + + it 'denies access' do + expect(do_request).to have_gitlab_http_status(:forbidden) + .or have_gitlab_http_status(:unauthorized) + .or have_gitlab_http_status(:bad_request) + end + end + end + end + + def enable_project_features(project, project_features) + attrs = ::ProjectFeature::FEATURES.index_with(::ProjectFeature::PRIVATE) + attrs.merge!(Array(project_features).index_with(::ProjectFeature::ENABLED)) if project_features.present? + attrs.transform_keys! { |feature| "#{feature}_access_level" } + project.project_feature.update!(attrs) end end diff --git a/spec/support/shared_examples/models/concerns/integrations/base/discord_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/base/discord_shared_examples.rb index 779e3eedb43..9c24790b62e 100644 --- a/spec/support/shared_examples/models/concerns/integrations/base/discord_shared_examples.rb +++ b/spec/support/shared_examples/models/concerns/integrations/base/discord_shared_examples.rb @@ -40,6 +40,15 @@ RSpec.shared_examples Integrations::Base::Discord do end end + describe '.help' do + it 'links to help page correctly' do + expect(described_class.help).to include( + 'user/project/integrations/discord_notifications.md', + 'How do I set up this integration?' + ) + end + end + describe '#execute' do include StubRequests diff --git a/spec/support/shared_examples/models/concerns/integrations/base/hangouts_chat_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/base/hangouts_chat_shared_examples.rb index 60de534f4da..14e63887bfb 100644 --- a/spec/support/shared_examples/models/concerns/integrations/base/hangouts_chat_shared_examples.rb +++ b/spec/support/shared_examples/models/concerns/integrations/base/hangouts_chat_shared_examples.rb @@ -16,6 +16,15 @@ RSpec.shared_examples Integrations::Base::HangoutsChat do let(:webhook_url_regex) { /\A#{webhook_url}.*/ } let(:query_params) { { messageReplyOption: Integrations::HangoutsChat::REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD } } + describe '.help' do + it 'links to help page correctly' do + expect(described_class.help).to include( + 'user/project/integrations/hangouts_chat.md', + 'How do I set up a Google Chat webhook?' + ) + end + end + describe "#execute" do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :repository, :wiki_repo) } diff --git a/spec/support/shared_examples/models/concerns/integrations/base/irker_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/base/irker_shared_examples.rb index 6f310c1339a..4b1817e4c11 100644 --- a/spec/support/shared_examples/models/concerns/integrations/base/irker_shared_examples.rb +++ b/spec/support/shared_examples/models/concerns/integrations/base/irker_shared_examples.rb @@ -23,6 +23,15 @@ RSpec.shared_examples Integrations::Base::Irker do end end + describe '.help' do + it 'links to help page correctly' do + expect(described_class.help).to include( + 'help/user/project/integrations/irker.md#set-up-an-irker-daemon', + 'Learn More' + ) + end + end + describe 'Execute' do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :repository) } diff --git a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb index 2e24d0005d8..2a7ee15aad2 100644 --- a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb @@ -131,7 +131,8 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project| end end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:headers) { build_token_auth_header(target_job.token) } end @@ -346,7 +347,8 @@ RSpec.shared_examples 'handling audit request' do |path:, scope: :project| it_behaves_like 'accept audit request', status: :ok end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: scope == :project ? :package_registry : nil do before_all do project.add_reporter(user) end @@ -491,7 +493,8 @@ RSpec.shared_examples 'handling get dist tags requests' do |scope: :project| end end - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:headers) { build_token_auth_header(target_job.token) } end diff --git a/spec/support/shared_examples/requests/api/packages_shared_examples.rb b/spec/support/shared_examples/requests/api/packages_shared_examples.rb index 28f9c60ec9d..1dbdbb04eb6 100644 --- a/spec/support/shared_examples/requests/api/packages_shared_examples.rb +++ b/spec/support/shared_examples/requests/api/packages_shared_examples.rb @@ -101,7 +101,8 @@ RSpec.shared_examples 'job token for package GET requests' do end RSpec.shared_examples 'enforcing read_packages job token policy' do - it_behaves_like 'enforcing job token policies', :read_packages do + it_behaves_like 'enforcing job token policies', :read_packages, + allow_public_access_for_enabled_project_features: :package_registry do let(:headers) { job_basic_auth_header(target_job) } end end diff --git a/spec/workers/ci/execute_build_hooks_worker_spec.rb b/spec/workers/ci/execute_build_hooks_worker_spec.rb index ecba8a4ce9c..154644eefce 100644 --- a/spec/workers/ci/execute_build_hooks_worker_spec.rb +++ b/spec/workers/ci/execute_build_hooks_worker_spec.rb @@ -24,6 +24,73 @@ RSpec.describe Ci::ExecuteBuildHooksWorker, feature_category: :pipeline_composit describe '#perform' do subject(:perform) { described_class.new.perform(project.id, build_data) } + context 'when build_data has string keys' do + let(:string_build_data) do + { + 'object_kind' => 'build', + 'ref' => 'main', + 'build_id' => build.id, + 'build_name' => build.name, + 'build_stage' => build.stage_name, + 'build_status' => build.status, + 'project_id' => project.id, + 'project_name' => project.full_name + } + end + + it 'converts data to indifferent access' do + allow_next_instance_of(Project) do |project| + expect(project).to receive(:execute_hooks).with( + kind_of(ActiveSupport::HashWithIndifferentAccess), + :job_hooks + ) + end + + described_class.new.perform(project.id, string_build_data) + end + + it 'allows both string and symbol access to build data' do + allow_next_instance_of(Project) do |project| + allow(project).to receive(:has_active_hooks?).and_return(true) + expect(project).to receive(:execute_hooks) do |data, _hook_type| + expect(data[:object_kind]).to eq('build') + expect(data['object_kind']).to eq('build') + expect(data[:build_name]).to eq(build.name) + expect(data['build_name']).to eq(build.name) + end + end + + described_class.new.perform(project.id, string_build_data) + end + end + + context 'when build_data has symbol keys' do + it 'converts data to indifferent access' do + allow_next_instance_of(Project) do |project| + expect(project).to receive(:execute_hooks).with( + kind_of(ActiveSupport::HashWithIndifferentAccess), + :job_hooks + ) + end + + perform + end + + it 'allows both string and symbol access to build data' do + allow_next_instance_of(Project) do |project| + allow(project).to receive(:has_active_hooks?).and_return(true) + expect(project).to receive(:execute_hooks) do |data, _hook_type| + expect(data[:object_kind]).to eq('build') + expect(data['object_kind']).to eq('build') + expect(data[:build_name]).to eq(build.name) + expect(data['build_name']).to eq(build.name) + end + end + + perform + end + end + context 'when project exists' do context 'with project services' do let!(:integration) { create(:integration, active: true, job_events: true, project: project) } diff --git a/yarn.lock b/yarn.lock index c986430a23c..25aa949cdf7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1436,10 +1436,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.123.0.tgz#1fa3b1a709755ff7c8ef67e18c0442101655ebf0" integrity sha512-yjVn+utOTIKk8d9JlvGo6EgJ4TQ+CKpe3RddflAqtsQqQuL/2MlVdtaUePybxYzWIaumFuh5LouQ6BrWyw1niQ== -"@gitlab/ui@108.3.1": - version "108.3.1" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-108.3.1.tgz#eb1db6c1ddc0ad7a239e6bcf21624fd1bc54b27b" - integrity sha512-O4haNCEJl3nHK8DB1mi01YRJOZomNXI0sBA600BLrbptm/NAO9oVE7O/U8sFEdXM7EtFHYwRYcF/LrWwfJmE9g== +"@gitlab/ui@108.4.1": + version "108.4.1" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-108.4.1.tgz#d45dbcc3a9f568694f53eebb795544157ddbf44f" + integrity sha512-o3mcR/AQ5tkKd3mMClMvsJIHhLWzU6n1L0m3bp4Yr4zaNtRG3c8gEGF7MR6pMhlnyb5r/FQk2wigxHaUuOSblQ== dependencies: "@floating-ui/dom" "1.4.3" echarts "^5.3.2"