diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 177adb36cd44a341765885eecf19336b5bf44098..98261316e00e1ba4194179c9b78fcb467469755e 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -530,6 +530,7 @@ def visible_attributes else settings << :deactivate_dormant_users settings << :deactivate_dormant_users_period + settings << :nuget_skip_metadata_url_validation end end end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 0eb1a79dfe14ce7ee3f4dab343feb7a34c3d8e92..ce00cf0055aab2042a5039e27621506086752d79 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -32,6 +32,8 @@ class ApplicationSetting < MainClusterwide::ApplicationRecord # matches the size set in the database constraint DEFAULT_BRANCH_PROTECTIONS_DEFAULT_MAX_SIZE = 1.kilobyte + PACKAGE_REGISTRY_SETTINGS = [:nuget_skip_metadata_url_validation].freeze + enum whats_new_variant: { all_tiers: 0, current_tier: 1, disabled: 2 }, _prefix: true enum email_confirmation_setting: { off: 0, soft: 1, hard: 2 }, _prefix: true @@ -621,6 +623,10 @@ def self.kroki_formats_attributes validates :rate_limits, json_schema: { filename: "application_setting_rate_limits" } + jsonb_accessor :package_registry, nuget_skip_metadata_url_validation: [:boolean, { default: false }] + + validates :package_registry, json_schema: { filename: 'application_setting_package_registry' } + validates :search_rate_limit_allowlist, length: { maximum: 100, message: N_('is too long (maximum is 100 entries)') }, allow_nil: false diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb index e715bc86693027be22dc871a99a6912541f4f684..ff050b05a1b7590e7a949ecd5c16e47b829d61be 100644 --- a/app/models/application_setting_implementation.rb +++ b/app/models/application_setting_implementation.rb @@ -285,7 +285,8 @@ def defaults # rubocop:disable Metrics/AbcSize security_approval_policies_limit: 5, downstream_pipeline_trigger_limit_per_project_user_sha: 0, asciidoc_max_includes: 32, - use_clickhouse_for_analytics: false + use_clickhouse_for_analytics: false, + nuget_skip_metadata_url_validation: false }.tap do |hsh| hsh.merge!(non_production_defaults) unless Rails.env.production? end diff --git a/app/models/packages/nuget/metadatum.rb b/app/models/packages/nuget/metadatum.rb index 1025af0fd24a602752d3ffb5e69ae53f7ae862fd..71c173354a9f9ef197d6e808be5d074fc0ab9fe1 100644 --- a/app/models/packages/nuget/metadatum.rb +++ b/app/models/packages/nuget/metadatum.rb @@ -10,9 +10,17 @@ class Packages::Nuget::Metadatum < ApplicationRecord belongs_to :package, -> { where(package_type: :nuget) }, inverse_of: :nuget_metadatum validates :package, presence: true - validates :license_url, public_url: { allow_blank: true }, length: { maximum: MAX_URL_LENGTH } - validates :project_url, public_url: { allow_blank: true }, length: { maximum: MAX_URL_LENGTH } - validates :icon_url, public_url: { allow_blank: true }, length: { maximum: MAX_URL_LENGTH } + validate :ensure_valid_urls + with_options if: :url_validation_enabled?, public_url: { allow_blank: true } do + validates :license_url + validates :project_url + validates :icon_url + end + with_options length: { maximum: MAX_URL_LENGTH } do + validates :license_url + validates :project_url + validates :icon_url + end validates :authors, presence: true, length: { maximum: MAX_AUTHORS_LENGTH } validates :description, presence: true, length: { maximum: MAX_DESCRIPTION_LENGTH } validates :normalized_version, presence: true @@ -25,9 +33,23 @@ class Packages::Nuget::Metadatum < ApplicationRecord private + def url_validation_enabled? + !Gitlab::CurrentSettings.current_application_settings.nuget_skip_metadata_url_validation + end + def ensure_nuget_package_type return if package&.nuget? errors.add(:base, _('Package type must be NuGet')) end + + def ensure_valid_urls + %w[license_url project_url icon_url].each do |field| + value = attributes[field] + + next if value.blank? + + errors.add(field, _('is an invalid URL')) unless Gitlab::UrlSanitizer.valid_web?(value) + end + end end diff --git a/app/validators/json_schemas/application_setting_package_registry.json b/app/validators/json_schemas/application_setting_package_registry.json new file mode 100644 index 0000000000000000000000000000000000000000..bf2e67c6f421500744e7a87cca76540303ffbf63 --- /dev/null +++ b/app/validators/json_schemas/application_setting_package_registry.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Application Package Registry related settings", + "type": "object", + "properties": { + "nuget_skip_metadata_url_validation": { + "type": "boolean", + "description": "Indicates whether to skip metadata URL validation for the NuGet package" + } + }, + "additionalProperties": false +} diff --git a/app/views/admin/application_settings/_nuget_skip_metadata_url_validation.haml b/app/views/admin/application_settings/_nuget_skip_metadata_url_validation.haml new file mode 100644 index 0000000000000000000000000000000000000000..0daa61b18ea4a8bbd333b5c11ab23fc44a837f45 --- /dev/null +++ b/app/views/admin/application_settings/_nuget_skip_metadata_url_validation.haml @@ -0,0 +1,17 @@ +- return if Gitlab.com? + +%h5 + = s_('PackageRegistry|Skip metadata URL validation for the NuGet package') +%p + = s_('PackageRegistry|By default, the NuGet package validates the %{code_open}projectUrl%{code_close}, %{code_open}iconUrl%{code_close}, and %{code_open}licenseUrl%{code_close} metadata. In an offline environment, you cannot upload the NuGet package with this validation because these URLs cannot be resolved. You might want to select the checkbox to skip validation.').html_safe % { code_open: ''.html_safe, code_close: ''.html_safe } +%p + = s_('PackageRegistry|Validate these URLs manually to ensure malicious packages are not uploaded to the NuGet package registry. Selecting and clearing the checkbox might lead to invalid records in the package registry that you cannot update.') += gitlab_ui_form_for @application_setting, url: ci_cd_admin_application_settings_path(anchor: 'js-package-settings'), html: { class: 'fieldset-form' }, data: { testid: 'forward-package-requests-form' } do |f| + = form_errors(@application_setting) + + %fieldset + .form-group + = f.gitlab_ui_checkbox_component :nuget_skip_metadata_url_validation, + s_('PackageRegistry|Skip metadata URL validation for the NuGet package') + + = f.submit _('Save changes'), pajamas_button: true diff --git a/app/views/admin/application_settings/_package_registry.html.haml b/app/views/admin/application_settings/_package_registry.html.haml index 23251c8f5c93a9fa9f5b86fc580f16cb405d2710..b370891b169c00f81a24b78df3b8fce20f936c42 100644 --- a/app/views/admin/application_settings/_package_registry.html.haml +++ b/app/views/admin/application_settings/_package_registry.html.haml @@ -10,6 +10,8 @@ .settings-content = render_if_exists 'admin/application_settings/ee_package_registry' + = render 'admin/application_settings/nuget_skip_metadata_url_validation' unless Gitlab.ee? + .gl-mt-7 %h4 diff --git a/db/migrate/20240318014850_add_package_registry_in_application_setting.rb b/db/migrate/20240318014850_add_package_registry_in_application_setting.rb new file mode 100644 index 0000000000000000000000000000000000000000..c2900e88f8eec3d2b2f5adba0be9b99d78fb8f89 --- /dev/null +++ b/db/migrate/20240318014850_add_package_registry_in_application_setting.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddPackageRegistryInApplicationSetting < Gitlab::Database::Migration[2.2] + milestone '17.0' + disable_ddl_transaction! + + CONSTRAINT_NAME = 'check_application_settings_package_registry_is_hash' + + def up + add_column :application_settings, :package_registry, :jsonb, default: {}, null: false + add_check_constraint(:application_settings, "(jsonb_typeof(package_registry) = 'object')", CONSTRAINT_NAME) + end + + def down + remove_column :application_settings, :package_registry + end +end diff --git a/db/schema_migrations/20240318014850 b/db/schema_migrations/20240318014850 new file mode 100644 index 0000000000000000000000000000000000000000..c91e5497651275c382b2d0db9d5f10e04e528eb7 --- /dev/null +++ b/db/schema_migrations/20240318014850 @@ -0,0 +1 @@ +28a65d98279742cbd77415037f7c6c2f96015508f38a81ed8b76a28aeb9b2df1 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 19a29fe7a4ed497aa0d30cec5634318ec1c13d7c..dba8566cca9ceb02aca17ccb3aa945e934f72bbf 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -4415,6 +4415,7 @@ CREATE TABLE application_settings ( include_optional_metrics_in_service_ping boolean DEFAULT true NOT NULL, zoekt_settings jsonb DEFAULT '{}'::jsonb NOT NULL, service_ping_settings jsonb DEFAULT '{}'::jsonb NOT NULL, + package_registry jsonb DEFAULT '{}'::jsonb NOT NULL, rate_limits_unauthenticated_git_http jsonb DEFAULT '{}'::jsonb NOT NULL, CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)), CONSTRAINT app_settings_container_registry_pre_import_tags_rate_positive CHECK ((container_registry_pre_import_tags_rate >= (0)::numeric)), @@ -4467,6 +4468,7 @@ CREATE TABLE application_settings ( CONSTRAINT check_app_settings_namespace_storage_forks_cost_factor_range CHECK (((namespace_storage_forks_cost_factor >= (0)::double precision) AND (namespace_storage_forks_cost_factor <= (1)::double precision))), CONSTRAINT check_app_settings_sentry_clientside_traces_sample_rate_range CHECK (((sentry_clientside_traces_sample_rate >= (0)::double precision) AND (sentry_clientside_traces_sample_rate <= (1)::double precision))), CONSTRAINT check_application_settings_clickhouse_is_hash CHECK ((jsonb_typeof(clickhouse) = 'object'::text)), + CONSTRAINT check_application_settings_package_registry_is_hash CHECK ((jsonb_typeof(package_registry) = 'object'::text)), CONSTRAINT check_application_settings_rate_limits_is_hash CHECK ((jsonb_typeof(rate_limits) = 'object'::text)), CONSTRAINT check_application_settings_rate_limits_unauth_git_http_is_hash CHECK ((jsonb_typeof(rate_limits_unauthenticated_git_http) = 'object'::text)), CONSTRAINT check_application_settings_service_ping_settings_is_hash CHECK ((jsonb_typeof(service_ping_settings) = 'object'::text)), diff --git a/doc/api/settings.md b/doc/api/settings.md index e6a6c89297219054c00415777e738924461919ae..b1f76dfe483329ee6ec32063c375dcc0e9ce2937 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -664,6 +664,7 @@ listed in the descriptions of the relevant settings. | `asciidoc_max_includes` | integer | no | Maximum limit of AsciiDoc include directives being processed in any one document. Default: 32. Maximum: 64. | | `duo_features_enabled` | boolean | no | Indicates whether GitLab Duo features are enabled for this instance. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144931) in GitLab 16.10. Self-managed, Premium and Ultimate only. | | `lock_duo_features_enabled` | boolean | no | Indicates whether the GitLab Duo features enabled setting is enforced for all subgroups. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144931) in GitLab 16.10. Self-managed, Premium and Ultimate only. | +| `nuget_skip_metadata_url_validation` | boolean | no | Indicates whether to skip metadata URL validation for the NuGet package. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/145887) in GitLab 17.0. | ### Configure inactive project deletion diff --git a/doc/development/packages/settings.md b/doc/development/packages/settings.md index 491d681486f8892966d3fb1a238e1787a71c1b26..95d2e573abc559cfbf02791b60506600928a91fa 100644 --- a/doc/development/packages/settings.md +++ b/doc/development/packages/settings.md @@ -14,6 +14,7 @@ This page includes an exhaustive list of settings related to and maintained by t | Setting | Table | Description | | ------- | ----- | -----------| +| `nuget_skip_metadata_url_validation` | `application_settings` | Indicates whether to skip metadata URL validation for the NuGet package. | | `npm_package_requests_forwarding` | `application_settings` | Enables or disables npm package forwarding at the instance level. | | `pypi_package_requests_forwarding` | `application_settings` | Enables or disables PyPI package forwarding at the instance level. | | `packages_cleanup_package_file_worker_capacity` | `application_settings` | Number of concurrent workers allowed for package file cleanup. | diff --git a/ee/app/views/admin/application_settings/_ee_package_registry.haml b/ee/app/views/admin/application_settings/_ee_package_registry.haml index f29400642e58e5b02d4ec08a1acfb68ca29feae6..5cff7a83177afb55a91475f94a59ae331c19deb9 100644 --- a/ee/app/views/admin/application_settings/_ee_package_registry.haml +++ b/ee/app/views/admin/application_settings/_ee_package_registry.haml @@ -5,7 +5,7 @@ %p - docs_link = link_to('', help_page_path('user/packages/package_registry/supported_functionality', { anchor: 'deleting-packages' })) = safe_format(s_('PackageRegistry|There are security risks if packages are deleted while request forwarding is enabled. %{docs_link_start}What are the risks?%{docs_link_end}'), tag_pair(docs_link, :docs_link_start, :docs_link_end)) -= gitlab_ui_form_for @application_setting, url: ci_cd_admin_application_settings_path(anchor: 'js-package-settings'), html: { class: 'fieldset-form' } do |f| += gitlab_ui_form_for @application_setting, url: ci_cd_admin_application_settings_path(anchor: 'js-package-settings'), html: { class: 'fieldset-form' }, data: { testid: 'forward-package-requests-form' } do |f| = form_errors(@application_setting) %fieldset @@ -28,4 +28,17 @@ = f.gitlab_ui_checkbox_component :lock_maven_package_requests_forwarding, s_('PackageRegistry|Enforce %{package_type} setting for all subgroups') % { package_type: 'Maven' } + - unless Gitlab.com? + %h5 + = s_('PackageRegistry|Skip metadata URL validation for the NuGet package') + %p + = s_('PackageRegistry|By default, the NuGet package validates the %{code_open}projectUrl%{code_close}, %{code_open}iconUrl%{code_close}, and %{code_open}licenseUrl%{code_close} metadata. In an offline environment, you cannot upload the NuGet package with this validation because these URLs cannot be resolved. You might want to select the checkbox to skip validation.').html_safe % { code_open: ''.html_safe, code_close: ''.html_safe } + %p + = s_('PackageRegistry|Validate these URLs manually to ensure malicious packages are not uploaded to the NuGet package registry. Selecting and clearing the checkbox might lead to invalid records in the package registry that you cannot update.') + + %fieldset + .form-group + = f.gitlab_ui_checkbox_component :nuget_skip_metadata_url_validation, + s_('PackageRegistry|Skip metadata URL validation for the NuGet package') + = f.submit _('Save changes'), pajamas_button: true diff --git a/ee/spec/features/admin/admin_settings_spec.rb b/ee/spec/features/admin/admin_settings_spec.rb index db78043531a348792fd641a45c2f9044f2d70c54..ba65a6da0d7a071463cd8efbb1efbc76af16a740 100644 --- a/ee/spec/features/admin/admin_settings_spec.rb +++ b/ee/spec/features/admin/admin_settings_spec.rb @@ -247,7 +247,7 @@ end it 'allows you to change the maven_forwarding setting' do - page.within('#js-package-settings') do + within_testid('forward-package-requests-form') do check 'Forward Maven package requests' click_button 'Save' end @@ -256,7 +256,7 @@ end it 'allows you to change the maven_lock setting' do - page.within('#js-package-settings') do + within_testid('forward-package-requests-form') do check 'Enforce Maven setting for all subgroups' click_button 'Save' end @@ -265,7 +265,7 @@ end it 'allows you to change the npm_forwarding setting' do - page.within('#js-package-settings') do + within_testid('forward-package-requests-form') do check 'Forward npm package requests' click_button 'Save' end @@ -274,7 +274,7 @@ end it 'allows you to change the npm_lock setting' do - page.within('#js-package-settings') do + within_testid('forward-package-requests-form') do check 'Enforce npm setting for all subgroups' click_button 'Save' end @@ -283,7 +283,7 @@ end it 'allows you to change the pypi_forwarding setting' do - page.within('#js-package-settings') do + within_testid('forward-package-requests-form') do check 'Forward PyPI package requests' click_button 'Save' end @@ -292,7 +292,7 @@ end it 'allows you to change the pypi_lock setting' do - page.within('#js-package-settings') do + within_testid('forward-package-requests-form') do check 'Enforce PyPI setting for all subgroups' click_button 'Save' end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d8ef2caa09263e8c1136d529097d7fd13a72721f..32cad95daa96bd2551c0654533cdc6b9505cfc9c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -36347,6 +36347,9 @@ msgstr "" msgid "PackageRegistry|Built by pipeline %{link} triggered %{datetime} by %{author}" msgstr "" +msgid "PackageRegistry|By default, the NuGet package validates the %{code_open}projectUrl%{code_close}, %{code_open}iconUrl%{code_close}, and %{code_open}licenseUrl%{code_close} metadata. In an offline environment, you cannot upload the NuGet package with this validation because these URLs cannot be resolved. You might want to select the checkbox to skip validation." +msgstr "" + msgid "PackageRegistry|Composer" msgstr "" @@ -36736,6 +36739,9 @@ msgstr "" msgid "PackageRegistry|Show Yarn commands" msgstr "" +msgid "PackageRegistry|Skip metadata URL validation for the NuGet package" +msgstr "" + msgid "PackageRegistry|Some of the selected package formats allow request forwarding. Deleting a package while request forwarding is enabled for the project can pose a security risk. Do you want to proceed with deleting the selected packages? %{docLinkStart}What are the risks?%{docLinkEnd}" msgstr "" @@ -36817,6 +36823,9 @@ msgstr "" msgid "PackageRegistry|Users with at least the Developer role for this project will be able to publish, edit, and delete packages." msgstr "" +msgid "PackageRegistry|Validate these URLs manually to ensure malicious packages are not uploaded to the NuGet package registry. Selecting and clearing the checkbox might lead to invalid records in the package registry that you cannot update." +msgstr "" + msgid "PackageRegistry|When a package is protected then only certain user roles are able to update and delete the protected package. This helps to avoid tampering with the package." msgstr "" @@ -61206,6 +61215,9 @@ msgstr "" msgid "is an invalid IP address range" msgstr "" +msgid "is an invalid URL" +msgstr "" + msgid "is blocked by" msgstr "" diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 4869779cb5358af3caa29198863b507afa81fbef..ad08dcb638667355f2bfd4deb49fbfcfb840bf34 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -27,7 +27,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'uncheck all restricted visibility levels' do @@ -41,7 +41,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' within_testid('restricted-visibility-levels') do expect(find_field(s_('VisibilityLevel|Public'))).not_to be_checked @@ -58,7 +58,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.import_sources).to eq(['git']) end @@ -77,7 +77,7 @@ expect(current_settings.project_export_enabled).to be_falsey expect(current_settings.bulk_import_enabled).to be(true) - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'change Keys settings' do @@ -109,7 +109,7 @@ end expect(current_settings.gravatar_enabled).to be_falsey - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'change Maximum export size' do @@ -119,7 +119,7 @@ end expect(current_settings.max_export_size).to eq 25 - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'change Maximum import size' do @@ -129,7 +129,7 @@ end expect(current_settings.max_import_size).to eq 15 - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'change New users set to external', :js do @@ -230,7 +230,7 @@ end expect(current_settings.require_admin_approval_after_user_signup).to be_truthy - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end end @@ -246,7 +246,7 @@ end expect(current_settings.email_confirmation_setting).to eq('hard') - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end end end @@ -258,7 +258,7 @@ end expect(current_settings.home_page_url).to eq "https://about.gitlab.com/" - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'terms of Service', :js do @@ -288,7 +288,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.disabled_oauth_sign_in_sources).to include('google_oauth2') page.within('.as-signin') do @@ -296,7 +296,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.disabled_oauth_sign_in_sources).not_to include('google_oauth2') end @@ -308,7 +308,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.disabled_oauth_sign_in_sources).to include('google_oauth2') # Remove google_oauth2 from the Omniauth strategies @@ -319,7 +319,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.disabled_oauth_sign_in_sources).to include('google_oauth2') end @@ -329,7 +329,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.terminal_max_session_time).to eq(15) end @@ -359,7 +359,7 @@ expect(current_settings.jira_connect_application_key).to eq('1234') expect(current_settings.jira_connect_proxy_url).to eq('https://example.com') expect(current_settings.jira_connect_public_key_storage_enabled).to eq(true) - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end end @@ -420,7 +420,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.hide_third_party_offers).to be true end @@ -469,7 +469,7 @@ expect(current_settings.suggest_pipeline_enabled).to be false expect(current_settings.ci_max_includes).to be 200 expect(current_settings.downstream_pipeline_trigger_limit_per_project_user_sha).to be 500 - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'changes CI/CD limits', :aggregate_failures do @@ -497,6 +497,22 @@ expect(page).to have_content 'Application limits saved successfully' end + context 'Skip NuGet package metadata url validation' do + it 'updates skip NuGet url validation' do + allow(Gitlab).to receive(:com?).and_return(false) + + visit ci_cd_admin_application_settings_path + + within_testid('forward-package-requests-form') do + check 'Skip metadata URL validation for the NuGet package' + click_button 'Save changes' + end + + expect(current_settings.nuget_skip_metadata_url_validation).to be true + expect(page).to have_content 'Application settings saved successfully' + end + end + context 'Runner Registration' do it 'allows admins to control who has access to register runners' do visit ci_cd_admin_application_settings_path @@ -510,7 +526,7 @@ end expect(current_settings.valid_runner_registrars).to eq([]) - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end end @@ -541,7 +557,7 @@ end expect(current_settings.public_send(setting)).to eq(400) - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end end end @@ -558,7 +574,7 @@ end expect(current_settings.container_registry_expiration_policies_caching).to eq(!old_value) - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end end end @@ -624,7 +640,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.recaptcha_enabled).to be true expect(current_settings.login_recaptcha_protection_enabled).to be true expect(current_settings.unique_ips_limit_per_user).to eq(15) @@ -645,7 +661,7 @@ end expect(current_settings.prometheus_metrics_enabled?).to be true - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'change Performance bar settings' do @@ -657,7 +673,7 @@ click_on 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(find_field('Allow non-administrators access to the performance bar')).to be_checked expect(find_field('Allow access to members of the following group').value).to eq group.path @@ -729,7 +745,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.allow_local_requests_from_web_hooks_and_services).to be true expect(current_settings.allow_local_requests_from_system_hooks).to be false expect(current_settings.dns_rebinding_protection_enabled).to be false @@ -762,7 +778,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings).to have_attributes( throttle_unauthenticated_api_enabled: true, @@ -790,7 +806,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.issues_create_limit).to eq(0) end @@ -802,7 +818,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.pipeline_limit_per_project_user_sha).to eq(10) end @@ -815,7 +831,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.users_get_by_id_limit).to eq(0) expect(current_settings.users_get_by_id_limit_allowlist).to eq(%w[someone someone_else]) end @@ -828,7 +844,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.gitlab_shell_operation_limit).to eq(100) end @@ -840,7 +856,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.projects_api_rate_limit_unauthenticated).to eq(100) end @@ -860,7 +876,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings).to have_attributes( "throttle_unauthenticated_#{fragment}_enabled" => true, @@ -903,7 +919,7 @@ click_button 'Save changes' end - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' expect(current_settings.search_rate_limit).to eq(98) expect(current_settings.search_rate_limit_unauthenticated).to eq(76) end @@ -946,7 +962,7 @@ expect(current_settings.help_page_hide_commercial_content).to be_truthy expect(current_settings.help_page_support_url).to eq new_support_url expect(current_settings.help_page_documentation_base_url).to eq new_documentation_url - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'change Pages settings' do @@ -958,7 +974,7 @@ expect(current_settings.max_pages_size).to eq 15 expect(current_settings.pages_domain_verification_enabled?).to be_truthy - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'change Real-time features settings' do @@ -968,7 +984,7 @@ end expect(current_settings.polling_interval_multiplier).to eq 5.0 - expect(page).to have_content "Application settings saved successfully" + expect(page).to have_content 'Application settings saved successfully' end it 'shows an error when validation fails' do diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 55d78e13cc1365dea68a5ddaf4a8b77649c5c585..fe79b36e9c987d98b549ccefadf71c99cda304a6 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -34,6 +34,7 @@ it { expect(setting.concurrent_github_import_jobs_limit).to eq(1000) } it { expect(setting.concurrent_bitbucket_import_jobs_limit).to eq(100) } it { expect(setting.concurrent_bitbucket_server_import_jobs_limit).to eq(100) } + it { expect(setting.nuget_skip_metadata_url_validation).to eq(false) } end describe 'validations' do @@ -65,6 +66,7 @@ end it { expect(described_class).to validate_jsonb_schema(['application_setting_rate_limits']) } + it { expect(described_class).to validate_jsonb_schema(['application_setting_package_registry']) } it { expect(described_class).to validate_jsonb_schema(['application_setting_service_ping_settings']) } diff --git a/spec/models/packages/nuget/metadatum_spec.rb b/spec/models/packages/nuget/metadatum_spec.rb index c8e052baf6f3b674278af67252696afe0e8e5314..04dc2706049c532b16e1841983146112541fc1b1 100644 --- a/spec/models/packages/nuget/metadatum_spec.rb +++ b/spec/models/packages/nuget/metadatum_spec.rb @@ -27,6 +27,15 @@ it { is_expected.to validate_length_of(url).is_at_most(described_class::MAX_URL_LENGTH) } end + describe "skip #{url} validation" do + before do + stub_application_setting(nuget_skip_metadata_url_validation: true) + end + + it { is_expected.not_to allow_value('123').for(url) } + it { is_expected.not_to allow_value('sandbox.com').for(url) } + end + describe '#ensure_nuget_package_type' do subject { build(:nuget_metadatum) } diff --git a/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb b/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb index cb41f2e636ead1dfe696979f4dc09f421be779e5..5af4330d7b0d03b653ac0f37a980d1b762ce2d2c 100644 --- a/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb +++ b/spec/views/admin/application_settings/_package_registry.html.haml_spec.rb @@ -66,4 +66,23 @@ expect(page).to have_content('Ultimate') end end + + context 'skip nuget package metadata url validation' do + before do + assign(:plans, [default_plan_limits.plan]) + end + + it 'renders nothing when saas', :saas do + subject + + expect(rendered).not_to have_field(s_('PackageRegistry|Skip metadata URL validation for the NuGet package'), type: 'checkbox') + end + + it 'renders the setting checkbox when self-managed' do + subject + + expect(rendered).to have_field(s_('PackageRegistry|Skip metadata URL validation for the NuGet package'), type: 'checkbox') + expect(page.find_field(s_('PackageRegistry|Skip metadata URL validation for the NuGet package'))).not_to be_checked + end + end end