From 0614dda6ce999ffa4d6dc61524b654593b9e7466 Mon Sep 17 00:00:00 2001 From: Furkan Ayhan Date: Tue, 30 Sep 2025 15:32:45 +0200 Subject: [PATCH] Draft: Add admin setting to restrict CI/CD Catalog publishing This POC introduces an allowlist mechanism that enables administrators to control which projects can publish components to the CI/CD Catalog. Changes: - Add `ci_cd_catalog_projects_allowlist` application setting to store allowed project paths as an array - Create new "Catalog" section in admin CI/CD settings page with a text area for managing the allowlist - Implement `check_project_access` validation in the release service to enforce the allowlist during component publishing Behavior: - When the allowlist is empty (default), all projects can publish - When populated, only projects whose full_path matches an entry in the allowlist can publish to the Catalog - Projects not in the allowlist receive an error message when attempting to publish This POC is intentionally incomplete: - No tests included - No documentation - Missing UI changes (e.g., disabling the "Set component project as a CI/CD Catalog project." toggle) --- app/helpers/application_settings_helper.rb | 1 + app/models/application_setting.rb | 3 ++- app/models/application_setting_implementation.rb | 8 ++++++++ app/services/ci/catalog/resources/release_service.rb | 12 ++++++++++-- .../application_settings/_ci_cd_catalog.html.haml | 12 ++++++++++++ app/views/admin/application_settings/ci_cd.html.haml | 9 +++++++++ 6 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 app/views/admin/application_settings/_ci_cd_catalog.html.haml diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 70a882832a6820..39ef92f17fb79e 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -279,6 +279,7 @@ def visible_attributes :autocomplete_users_limit, :autocomplete_users_unauthenticated_limit, :allow_bypass_placeholder_confirmation, + :ci_cd_catalog_projects_allowlist_raw, :ci_delete_pipelines_in_seconds_limit_human_readable, :ci_job_live_trace_enabled, :ci_partitions_size_limit, diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 7595b03993d03d..fd5cbd8a9d1ede 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -524,7 +524,8 @@ def self.kroki_formats_attributes ci_job_live_trace_enabled: [:boolean, { default: false }], ci_partitions_size_limit: [::Gitlab::Database::Type::JsonbInteger.new, { default: 100.gigabytes }], ci_delete_pipelines_in_seconds_limit: [:integer, { default: ChronicDuration.parse('1 year') }], - git_push_pipeline_limit: [:integer, { default: 4 }] + git_push_pipeline_limit: [:integer, { default: 4 }], + ci_cd_catalog_projects_allowlist: [:string, { array: true, default: [] }] chronic_duration_attr :ci_delete_pipelines_in_seconds_limit_human_readable, :ci_delete_pipelines_in_seconds_limit diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index cdbba3ef20fcd4..884e142add271d 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -438,6 +438,14 @@ def outbound_local_requests_allowlist_raw=(values) self.outbound_local_requests_whitelist = strings_to_array(values) end + def ci_cd_catalog_projects_allowlist_raw + array_to_string(ci_cd_catalog_projects_allowlist) + end + + def ci_cd_catalog_projects_allowlist_raw=(values) + self.ci_cd_catalog_projects_allowlist = strings_to_array(values) + end + def add_to_outbound_local_requests_whitelist(values_array) clear_memoization(:outbound_local_requests_allowlist_arrays) diff --git a/app/services/ci/catalog/resources/release_service.rb b/app/services/ci/catalog/resources/release_service.rb index 68856bd90b623e..d5d9e7831f85cd 100644 --- a/app/services/ci/catalog/resources/release_service.rb +++ b/app/services/ci/catalog/resources/release_service.rb @@ -14,7 +14,8 @@ def initialize(release, user, metadata) def execute resource_version = track_release_duration do - check_access + check_user_access + check_project_access validate_catalog_resource create_version end @@ -46,12 +47,19 @@ def track_release_duration result end - def check_access + def check_user_access return if Ability.allowed?(user, :publish_catalog_version, release) errors << 'You are not authorized to publish a version to the CI/CD catalog' end + def check_project_access + projects_allowlist = Gitlab::CurrentSettings.ci_cd_catalog_projects_allowlist + return if projects_allowlist.blank? || projects_allowlist.include?(project.full_path) + + errors << 'The project is not authorized to publish a version to the CI/CD catalog' + end + def validate_catalog_resource return if errors.present? diff --git a/app/views/admin/application_settings/_ci_cd_catalog.html.haml b/app/views/admin/application_settings/_ci_cd_catalog.html.haml new file mode 100644 index 00000000000000..91586bfd0eb726 --- /dev/null +++ b/app/views/admin/application_settings/_ci_cd_catalog.html.haml @@ -0,0 +1,12 @@ +.settings-content + = gitlab_ui_form_for @application_setting, url: ci_cd_admin_application_settings_path(anchor: 'js-catalog-settings'), html: { class: 'fieldset-form' } do |f| + = form_errors(@application_setting) + + %fieldset + .form-group + = f.label :ci_cd_catalog_projects_allowlist_raw, s_('AdminSettings|CI/CD Catalog publishing restrictions'), class: 'label-bold' + = f.text_area :ci_cd_catalog_projects_allowlist_raw, class: 'form-control gl-form-input', rows: 5, placeholder: 'gitlab-org/component-project' + .form-text.gl-text-subtle + = s_('AdminSettings|Restrict which projects can publish components to the CI/CD Catalog. Enter one project path per line (for example, %{code_start}namespace/project%{code_end}). If empty, all projects can publish to the Catalog.').html_safe % { code_start: ''.html_safe, code_end: ''.html_safe } + + = f.submit _('Save changes'), pajamas_button: true diff --git a/app/views/admin/application_settings/ci_cd.html.haml b/app/views/admin/application_settings/ci_cd.html.haml index 906c9d202bb69f..3b5ff6e9d53be8 100644 --- a/app/views/admin/application_settings/ci_cd.html.haml +++ b/app/views/admin/application_settings/ci_cd.html.haml @@ -33,6 +33,15 @@ - c.with_body do = render 'ci_cd' += render ::Layouts::SettingsBlockComponent.new(_('Catalog'), + id: 'js-catalog-settings', + testid: 'catalog-settings', + expanded: expanded_by_default?) do |c| + - c.with_description do + = _('Configure CI/CD Catalog settings, including publishing restrictions.') + - c.with_body do + = render 'ci_cd_catalog' + = render_if_exists 'admin/application_settings/required_instance_ci_setting', expanded: expanded_by_default? = render_if_exists 'admin/application_settings/package_registry', expanded: expanded_by_default? -- GitLab