From 02f4740a2f20ce413f58bee2d48c661479d95078 Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Fri, 21 Nov 2025 14:24:17 -0700 Subject: [PATCH 01/12] Add duo sast VR enabled setting Add the sast VR setting to the database. --- ...ity_resolution_enabled_to_project_settings.rb | 9 +++++++++ ...ility_resolution_enabled_cascading_setting.rb | 16 ++++++++++++++++ db/schema_migrations/20251121205957 | 1 + db/schema_migrations/20251121210038 | 1 + db/structure.sql | 9 +++++++-- 5 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb create mode 100644 db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb create mode 100644 db/schema_migrations/20251121205957 create mode 100644 db/schema_migrations/20251121210038 diff --git a/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb b/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb new file mode 100644 index 00000000000000..4c79fc493ada4e --- /dev/null +++ b/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddDuoSastVulnerabilityResolutionEnabledToProjectSettings < Gitlab::Database::Migration[2.3] + milestone '18.7' + + def change + add_column :project_settings, :duo_sast_vulnerability_resolution_enabled, :boolean, default: true, null: false + end +end diff --git a/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb b/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb new file mode 100644 index 00000000000000..95c5d63df13899 --- /dev/null +++ b/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class AddDuoSastVulnerabilityResolutionEnabledCascadingSetting < Gitlab::Database::Migration[2.3] + milestone '18.7' + disable_ddl_transaction! + + include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings + + def up + add_cascading_namespace_setting :duo_sast_vulnerability_resolution_enabled, :boolean, default: true, null: false + end + + def down + remove_cascading_namespace_setting :duo_sast_vulnerability_resolution_enabled + end +end diff --git a/db/schema_migrations/20251121205957 b/db/schema_migrations/20251121205957 new file mode 100644 index 00000000000000..40297fa23ca8af --- /dev/null +++ b/db/schema_migrations/20251121205957 @@ -0,0 +1 @@ +2f91ce6fa3313a1bfa8c4b4df7fd44ad451b118679a2edb160215aa7bcb35ade \ No newline at end of file diff --git a/db/schema_migrations/20251121210038 b/db/schema_migrations/20251121210038 new file mode 100644 index 00000000000000..436b24294f2867 --- /dev/null +++ b/db/schema_migrations/20251121210038 @@ -0,0 +1 @@ +5031d42f0557dca63b31f944a12b50b31746f92e184e7a52bcb74a8fde3df3e6 \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 3ce3ab37724117..67842a4a8e3b77 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -6124,7 +6124,7 @@ PARTITION BY LIST (partition_id); CREATE TABLE p_ci_finished_build_ch_sync_events ( build_id bigint NOT NULL, - partition bigint DEFAULT 1 NOT NULL, + partition bigint DEFAULT 2 NOT NULL, build_finished_at timestamp without time zone NOT NULL, processed boolean DEFAULT false NOT NULL, project_id bigint NOT NULL @@ -6134,7 +6134,7 @@ PARTITION BY LIST (partition); CREATE TABLE p_ci_finished_pipeline_ch_sync_events ( pipeline_id bigint NOT NULL, project_namespace_id bigint NOT NULL, - partition bigint DEFAULT 1 NOT NULL, + partition bigint DEFAULT 2 NOT NULL, pipeline_finished_at timestamp without time zone NOT NULL, processed boolean DEFAULT false NOT NULL ) @@ -12281,6 +12281,8 @@ CREATE TABLE application_settings ( iframe_rendering_allowlist text, database_settings jsonb DEFAULT '{}'::jsonb NOT NULL, usage_billing jsonb DEFAULT '{}'::jsonb NOT NULL, + duo_sast_vulnerability_resolution_enabled boolean DEFAULT false NOT NULL, + lock_duo_sast_vulnerability_resolution_enabled boolean DEFAULT false 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_dep_proxy_ttl_policies_worker_capacity_positive CHECK ((dependency_proxy_ttl_group_policy_worker_capacity >= 0)), CONSTRAINT app_settings_ext_pipeline_validation_service_url_text_limit CHECK ((char_length(external_pipeline_validation_service_url) <= 255)), @@ -21492,6 +21494,8 @@ CREATE TABLE namespace_settings ( duo_sast_fp_detection_enabled boolean, lock_duo_sast_fp_detection_enabled boolean DEFAULT false NOT NULL, usage_billing jsonb DEFAULT '{}'::jsonb NOT NULL, + duo_sast_vulnerability_resolution_enabled boolean, + lock_duo_sast_vulnerability_resolution_enabled boolean DEFAULT false NOT NULL, CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)), CONSTRAINT check_d9644d516f CHECK ((char_length(step_up_auth_required_oauth_provider) <= 255)), CONSTRAINT check_namespace_settings_security_policies_is_hash CHECK ((jsonb_typeof(security_policies) = 'object'::text)), @@ -25242,6 +25246,7 @@ CREATE TABLE project_settings ( duo_remote_flows_enabled boolean, duo_foundational_flows_enabled boolean, duo_sast_fp_detection_enabled boolean DEFAULT false NOT NULL, + duo_sast_vulnerability_resolution_enabled boolean DEFAULT false NOT NULL, CONSTRAINT check_1a30456322 CHECK ((char_length(pages_unique_domain) <= 63)), CONSTRAINT check_237486989c CHECK ((char_length(merge_request_title_regex_description) <= 255)), CONSTRAINT check_3a03e7557a CHECK ((char_length(previous_default_branch) <= 4096)), -- GitLab From 983357733bf98c69f142b87553c6fe99acfabb0e Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Fri, 21 Nov 2025 15:05:51 -0700 Subject: [PATCH 02/12] Add vulnerability resolution setting Add setting to models, helpers, controllers, etc. --- app/helpers/projects_helper.rb | 5 +++++ app/models/project_setting.rb | 3 ++- ...o_sast_vulnerability_resolution_enabled.yml | 11 +++++++++++ ...o_sast_vulnerability_resolution_enabled.yml | 11 +++++++++++ .../controllers/concerns/ee/groups/params.rb | 4 +++- ee/app/controllers/ee/projects_controller.rb | 4 ++++ .../helpers/ee/application_settings_helper.rb | 2 ++ ee/app/helpers/ee/groups/settings_helper.rb | 4 +++- ee/app/helpers/ee/projects_helper.rb | 1 + ee/app/models/ee/application_setting.rb | 14 ++++++++++++++ ee/app/models/ee/group.rb | 1 + ee/app/models/ee/namespace.rb | 1 + ee/app/models/ee/namespace_setting.rb | 18 +++++++++++++++++- ee/app/models/ee/project.rb | 2 ++ ee/app/models/ee/project_setting.rb | 2 +- .../admin/ai_configuration_presenter.rb | 2 ++ .../ai/cascade_duo_settings_service.rb | 1 + .../ee/application_settings/update_service.rb | 2 +- ee/app/services/ee/groups/update_service.rb | 2 +- .../assign_attributes_service.rb | 8 ++++++++ ee/lib/ee/api/entities/project.rb | 1 + ee/lib/ee/api/groups.rb | 5 +++++ ee/lib/ee/api/helpers/groups_helpers.rb | 3 ++- ee/lib/ee/api/helpers/projects_helpers.rb | 7 +++++++ 24 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 config/application_setting_columns/duo_sast_vulnerability_resolution_enabled.yml create mode 100644 config/application_setting_columns/lock_duo_sast_vulnerability_resolution_enabled.yml diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index fb82a2d4501c5c..62117ce128629c 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -1052,6 +1052,11 @@ def gitlab_duo_settings_data(project) :duo_sast_fp_detection_enabled, project, method(:edit_group_path) + ), + duo_sast_vulnerability_resolution_cascading_settings: project_cascading_namespace_settings_tooltip_data( + :duo_sast_vulnerability_resolution_enabled, + project, + method(:edit_group_path) ) } end diff --git a/app/models/project_setting.rb b/app/models/project_setting.rb index 5cb9a202f240d0..fd5c14abe1f005 100644 --- a/app/models/project_setting.rb +++ b/app/models/project_setting.rb @@ -9,7 +9,8 @@ class ProjectSetting < ApplicationRecord include AfterCommitQueue include SafelyChangeColumnDefault - columns_changing_default :auto_duo_code_review_enabled, :duo_remote_flows_enabled, :duo_sast_fp_detection_enabled + columns_changing_default :auto_duo_code_review_enabled, :duo_remote_flows_enabled, :duo_sast_fp_detection_enabled, + :duo_sast_vulnerability_resolution_enabled ALLOWED_TARGET_PLATFORMS = %w[ios osx tvos watchos android].freeze diff --git a/config/application_setting_columns/duo_sast_vulnerability_resolution_enabled.yml b/config/application_setting_columns/duo_sast_vulnerability_resolution_enabled.yml new file mode 100644 index 00000000000000..e5997b30e2a1cb --- /dev/null +++ b/config/application_setting_columns/duo_sast_vulnerability_resolution_enabled.yml @@ -0,0 +1,11 @@ +api_type: +attr: duo_sast_vulnerability_resolution_enabled +clusterwide: false +column: duo_sast_vulnerability_resolution_enabled +db_type: boolean +default: 'true' +description: +encrypted: false +gitlab_com_different_than_default: false +jihu: false +not_null: true diff --git a/config/application_setting_columns/lock_duo_sast_vulnerability_resolution_enabled.yml b/config/application_setting_columns/lock_duo_sast_vulnerability_resolution_enabled.yml new file mode 100644 index 00000000000000..0693395d644cfb --- /dev/null +++ b/config/application_setting_columns/lock_duo_sast_vulnerability_resolution_enabled.yml @@ -0,0 +1,11 @@ +api_type: +attr: lock_duo_sast_vulnerability_resolution_enabled +clusterwide: false +column: lock_duo_sast_vulnerability_resolution_enabled +db_type: boolean +default: 'false' +description: +encrypted: false +gitlab_com_different_than_default: false +jihu: false +not_null: true diff --git a/ee/app/controllers/concerns/ee/groups/params.rb b/ee/app/controllers/concerns/ee/groups/params.rb index a41d50c3817f91..c71b6b80dad342 100644 --- a/ee/app/controllers/concerns/ee/groups/params.rb +++ b/ee/app/controllers/concerns/ee/groups/params.rb @@ -71,7 +71,9 @@ def group_params_ee params_ee.push(%i[duo_features_enabled duo_core_features_enabled lock_duo_features_enabled duo_availability duo_remote_flows_availability prompt_cache_enabled duo_remote_flows_enabled lock_duo_remote_flows_enabled duo_foundational_flows_enabled lock_duo_foundational_flows_enabled - duo_sast_fp_detection_enabled lock_duo_sast_fp_detection_enabled enabled_foundational_flows]) + duo_sast_fp_detection_enabled lock_duo_sast_fp_detection_enabled enabled_foundational_flows + duo_sast_fp_detection_enabled lock_duo_sast_fp_detection_enabled enabled_foundational_flows + duo_sast_vulnerability_resolution_enabled lock_duo_sast_vulnerability_resolution_enabled]) end params_ee << :disable_personal_access_tokens if current_group&.disable_personal_access_tokens_available? diff --git a/ee/app/controllers/ee/projects_controller.rb b/ee/app/controllers/ee/projects_controller.rb index 384e36c3da6f20..b23aa844663850 100644 --- a/ee/app/controllers/ee/projects_controller.rb +++ b/ee/app/controllers/ee/projects_controller.rb @@ -104,6 +104,10 @@ def duo_feature_attributes attributes << :duo_sast_fp_detection_enabled end + unless project&.project_setting&.duo_sast_vulnerability_resolution_enabled_locked? + attributes << :duo_sast_vulnerability_resolution_enabled + end + attributes end diff --git a/ee/app/helpers/ee/application_settings_helper.rb b/ee/app/helpers/ee/application_settings_helper.rb index c7d1d261db535d..e0d74ab401d89c 100644 --- a/ee/app/helpers/ee/application_settings_helper.rb +++ b/ee/app/helpers/ee/application_settings_helper.rb @@ -92,6 +92,8 @@ def visible_attributes :duo_foundational_flows_availability, :duo_sast_fp_detection_enabled, :duo_sast_fp_detection_availability, + :duo_sast_vulnerability_resolution_enabled, + :duo_sast_vulnerability_resolution_availability, :enabled_expanded_logging, :foundational_agents_default_enabled, :foundational_agents_statuses, diff --git a/ee/app/helpers/ee/groups/settings_helper.rb b/ee/app/helpers/ee/groups/settings_helper.rb index dd04113b7ee9ac..8e907b7fad432e 100644 --- a/ee/app/helpers/ee/groups/settings_helper.rb +++ b/ee/app/helpers/ee/groups/settings_helper.rb @@ -84,7 +84,8 @@ def duo_cascading_settings_data duo_availability_cascading_settings: cascading_tooltip_data(:duo_features_enabled), duo_remote_flows_cascading_settings: cascading_tooltip_data(:duo_remote_flows_enabled), duo_foundational_flows_cascading_settings: cascading_tooltip_data(:duo_foundational_flows_enabled), - duo_sast_fp_detection_cascading_settings: cascading_tooltip_data(:duo_sast_fp_detection_enabled) + duo_sast_fp_detection_cascading_settings: cascading_tooltip_data(:duo_sast_fp_detection_enabled), + duo_sast_vulnerability_resolution_cascading_settings: cascading_tooltip_data(:duo_sast_vulnerability_resolution_enabled) } end @@ -120,6 +121,7 @@ def foundational_flows_settings_data duo_remote_flows_availability: @group.namespace_settings.duo_remote_flows_availability.to_s, duo_foundational_flows_availability: @group.namespace_settings.duo_foundational_flows_availability.to_s, duo_sast_fp_detection_availability: @group.namespace_settings.duo_sast_fp_detection_availability.to_s, + duo_sast_vulnerability_resolution_availability: @group.namespace_settings.duo_sast_vulnerability_resolution_availability.to_s, available_foundational_flows: available_foundational_flows_json, selected_foundational_flows: selected_foundational_flows_json } diff --git a/ee/app/helpers/ee/projects_helper.rb b/ee/app/helpers/ee/projects_helper.rb index 01d9f227d81104..7b1e73c4426ce5 100644 --- a/ee/app/helpers/ee/projects_helper.rb +++ b/ee/app/helpers/ee/projects_helper.rb @@ -59,6 +59,7 @@ def gitlab_duo_settings_data(project) initialDuoRemoteFlowsAvailability: project.duo_remote_flows_enabled, initialDuoFoundationalFlowsAvailability: project.duo_foundational_flows_enabled, initialDuoSastFpDetectionEnabled: project.duo_sast_fp_detection_enabled, + initialDuoSastVulnerabilityResolutionEnabled: project.duo_sast_vulnerability_resolution_enabled, experimentFeaturesEnabled: experiment_features_enabled, paidDuoTier: paid_duo_tier_for_project(project) }) diff --git a/ee/app/models/ee/application_setting.rb b/ee/app/models/ee/application_setting.rb index 25b113db46c2f4..9a45c2e040ab49 100644 --- a/ee/app/models/ee/application_setting.rb +++ b/ee/app/models/ee/application_setting.rb @@ -795,6 +795,20 @@ def duo_sast_fp_detection_availability=(value) end end + def duo_sast_vulnerability_resolution_availability + duo_sast_vulnerability_resolution_enabled + end + + def duo_sast_vulnerability_resolution_availability=(value) + self.duo_sast_vulnerability_resolution_enabled = value + + self.lock_duo_sast_vulnerability_resolution_enabled = if value + false + else + true + end + end + def duo_never_on? duo_availability == :never_on end diff --git a/ee/app/models/ee/group.rb b/ee/app/models/ee/group.rb index ee1ccc80cf84d8..58668b7673c52e 100644 --- a/ee/app/models/ee/group.rb +++ b/ee/app/models/ee/group.rb @@ -117,6 +117,7 @@ module Group delegate :duo_remote_flows_availability, :duo_remote_flows_availability=, to: :namespace_settings delegate :duo_foundational_flows_availability, :duo_foundational_flows_availability=, to: :namespace_settings delegate :duo_sast_fp_detection_availability, :duo_sast_fp_detection_availability=, to: :namespace_settings + delegate :duo_sast_vulnerability_resolution_availability, :duo_sast_vulnerability_resolution_availability=, to: :namespace_settings delegate :experiment_settings_allowed?, :prompt_cache_settings_allowed?, to: :namespace_settings delegate :user_cap_enabled?, to: :namespace_settings diff --git a/ee/app/models/ee/namespace.rb b/ee/app/models/ee/namespace.rb index 14efb9757a0130..ea87f9f92ce27e 100644 --- a/ee/app/models/ee/namespace.rb +++ b/ee/app/models/ee/namespace.rb @@ -181,6 +181,7 @@ module Namespace :duo_remote_flows_enabled, :lock_duo_remote_flows_enabled, :duo_foundational_flows_enabled, :lock_duo_foundational_flows_enabled, :duo_sast_fp_detection_enabled, :lock_duo_sast_fp_detection_enabled, + :duo_sast_vulnerability_resolution_enabled, :lock_duo_sast_vulnerability_resolution_enabled, to: :namespace_settings, allow_nil: true delegate :pipeline_execution_policies_per_configuration_limit, :pipeline_execution_policies_per_configuration_limit=, :scan_execution_policies_per_configuration_limit, diff --git a/ee/app/models/ee/namespace_setting.rb b/ee/app/models/ee/namespace_setting.rb index ea18f6cc544b15..b562bf7ccad028 100644 --- a/ee/app/models/ee/namespace_setting.rb +++ b/ee/app/models/ee/namespace_setting.rb @@ -9,7 +9,8 @@ module NamespaceSetting DORMANT_REVIEW_PERIOD = 18.hours.ago cascading_attr :duo_features_enabled, :model_prompt_cache_enabled, :auto_duo_code_review_enabled, - :duo_remote_flows_enabled, :duo_foundational_flows_enabled, :duo_sast_fp_detection_enabled + :duo_remote_flows_enabled, :duo_foundational_flows_enabled, :duo_sast_fp_detection_enabled, + :duo_sast_vulnerability_resolution_enabled scope :requiring_dormant_member_review, ->(limit) do # look for settings that have not been reviewed in more than @@ -209,6 +210,19 @@ def duo_sast_fp_detection_availability=(value) end end + def duo_sast_vulnerability_resolution_availability + duo_sast_vulnerability_resolution_enabled + end + + def duo_sast_vulnerability_resolution_availability=(value) + self.duo_sast_vulnerability_resolution_enabled = value + self.lock_duo_sast_vulnerability_resolution_enabled = if value + false + else + true + end + end + def duo_availability if duo_features_enabled && !duo_features_enabled_locked?(include_self: true) :default_on @@ -310,6 +324,8 @@ def experiment_features_allowed duo_remote_flows_availability duo_sast_fp_detection_enabled lock_duo_sast_fp_detection_enabled + duo_sast_vulnerability_resolution_enabled + lock_duo_sast_vulnerability_resolution_enabled enterprise_users_extensions_marketplace_opt_in_status allow_enterprise_bypass_placeholder_confirmation web_based_commit_signing_enabled diff --git a/ee/app/models/ee/project.rb b/ee/app/models/ee/project.rb index e4d6dddcf1e133..aa8007aadf3d7a 100644 --- a/ee/app/models/ee/project.rb +++ b/ee/app/models/ee/project.rb @@ -547,6 +547,8 @@ def lock_for_confirmation!(id) :duo_foundational_flows_enabled=, :duo_sast_fp_detection_enabled, :duo_sast_fp_detection_enabled=, + :duo_sast_vulnerability_resolution_enabled, + :duo_sast_vulnerability_resolution_enabled=, to: :project_setting with_options prefix: :delegated, to: :project_setting do delegate :require_reauthentication_to_approve= diff --git a/ee/app/models/ee/project_setting.rb b/ee/app/models/ee/project_setting.rb index 281e47f0a0b676..9221eff98cf65e 100644 --- a/ee/app/models/ee/project_setting.rb +++ b/ee/app/models/ee/project_setting.rb @@ -8,7 +8,7 @@ module ProjectSetting prepended do cascading_attr :duo_features_enabled, :spp_repository_pipeline_access, :model_prompt_cache_enabled, :auto_duo_code_review_enabled, :duo_remote_flows_enabled, :duo_foundational_flows_enabled, - :duo_sast_fp_detection_enabled + :duo_sast_fp_detection_enabled, :duo_sast_vulnerability_resolution_enabled belongs_to :push_rule diff --git a/ee/app/presenters/admin/ai_configuration_presenter.rb b/ee/app/presenters/admin/ai_configuration_presenter.rb index e92441724169ca..607da13aa0f3a5 100644 --- a/ee/app/presenters/admin/ai_configuration_presenter.rb +++ b/ee/app/presenters/admin/ai_configuration_presenter.rb @@ -11,6 +11,7 @@ class AiConfigurationPresenter :duo_chat_expiration_column, :duo_chat_expiration_days, :duo_sast_fp_detection_availability, + :duo_sast_vulnerability_resolution_availability, :enabled_expanded_logging, :gitlab_dedicated_instance?, :instance_level_ai_beta_features_enabled, @@ -45,6 +46,7 @@ def settings duo_core_features_enabled: duo_core_features_enabled?, duo_pro_visible: active_duo_add_ons_exist?, duo_sast_fp_detection_availability: duo_sast_fp_detection_availability, + duo_sast_vulnerability_resolution_availability: duo_sast_vulnerability_resolution_availability, enabled_expanded_logging: enabled_expanded_logging, experiment_features_enabled: instance_level_ai_beta_features_enabled, on_general_settings_page: false, diff --git a/ee/app/services/ai/cascade_duo_settings_service.rb b/ee/app/services/ai/cascade_duo_settings_service.rb index 107f0a11ff28c1..0d19ccb7ce28fc 100644 --- a/ee/app/services/ai/cascade_duo_settings_service.rb +++ b/ee/app/services/ai/cascade_duo_settings_service.rb @@ -8,6 +8,7 @@ class CascadeDuoSettingsService auto_duo_code_review_enabled duo_foundational_flows_enabled duo_sast_fp_detection_enabled + duo_sast_vulnerability_resolution_enabled enabled_foundational_flows ].freeze diff --git a/ee/app/services/ee/application_settings/update_service.rb b/ee/app/services/ee/application_settings/update_service.rb index b4c7726d083f52..584ab736ef32fb 100644 --- a/ee/app/services/ee/application_settings/update_service.rb +++ b/ee/app/services/ee/application_settings/update_service.rb @@ -111,7 +111,7 @@ def filter_auto_duo_code_review_param def cascade_duo_features_settings previous_changes = application_setting.previous_changes cascading_ai_settings = [:duo_features_enabled, :duo_remote_flows_enabled, :auto_duo_code_review_enabled, - :duo_foundational_flows_enabled, :duo_sast_fp_detection_enabled] + :duo_foundational_flows_enabled, :duo_sast_fp_detection_enabled, :duo_sast_vulnerability_resolution_enabled] # Collect all changed AI settings and their values changed_ai_settings = cascading_ai_settings.filter_map do |setting| diff --git a/ee/app/services/ee/groups/update_service.rb b/ee/app/services/ee/groups/update_service.rb index 61e896120347ff..89e3dd25287c91 100644 --- a/ee/app/services/ee/groups/update_service.rb +++ b/ee/app/services/ee/groups/update_service.rb @@ -171,7 +171,7 @@ def update_cascading_settings return unless previous_changes.present? cascading_ai_settings = [:duo_features_enabled, :duo_remote_flows_enabled, :auto_duo_code_review_enabled, - :duo_foundational_flows_enabled, :duo_sast_fp_detection_enabled] + :duo_foundational_flows_enabled, :duo_sast_fp_detection_enabled, :duo_sast_vulnerability_resolution_enabled] # Collect all changed AI settings and their values changed_ai_settings = cascading_ai_settings.filter_map do |setting| if previous_changes.include?(setting) diff --git a/ee/app/services/ee/namespace_settings/assign_attributes_service.rb b/ee/app/services/ee/namespace_settings/assign_attributes_service.rb index 374282654297cd..51ed7c33ba2ebf 100644 --- a/ee/app/services/ee/namespace_settings/assign_attributes_service.rb +++ b/ee/app/services/ee/namespace_settings/assign_attributes_service.rb @@ -55,6 +55,14 @@ def execute param_key: :lock_duo_sast_fp_detection_enabled, user_policy: :admin_group ) + validate_settings_param_for_admin( + param_key: :duo_sast_vulnerability_resolution_enabled, + user_policy: :admin_group + ) + validate_settings_param_for_admin( + param_key: :lock_duo_sast_vulnerability_resolution_enabled, + user_policy: :admin_group + ) validate_settings_param_for_root_group( param_key: :disable_invite_members, user_policy: :owner_access diff --git a/ee/lib/ee/api/entities/project.rb b/ee/lib/ee/api/entities/project.rb index 3e36db278d0c07..ff654b8b38c4c6 100644 --- a/ee/lib/ee/api/entities/project.rb +++ b/ee/lib/ee/api/entities/project.rb @@ -68,6 +68,7 @@ def preload_relation(projects_relation, options = {}) expose :duo_remote_flows_enabled, if: ->(_, _) { ::Ai::DuoWorkflow.enabled? } expose :duo_foundational_flows_enabled, if: ->(_, _) { ::Ai::DuoWorkflow.enabled? } expose :duo_sast_fp_detection_enabled, if: ->(project, _) { project.licensed_feature_available?(:ai_features) && ::Feature.enabled?(:ai_experiment_sast_fp_detection, project) } + expose :duo_sast_vulnerability_resolution_enabled, if: ->(project, _) { project.licensed_feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, project) } expose :web_based_commit_signing_enabled, if: ->(project, options) do ::Gitlab::Saas.feature_available?(:repositories_web_based_commit_signing) && Ability.allowed?(options[:current_user], :admin_project, project) diff --git a/ee/lib/ee/api/groups.rb b/ee/lib/ee/api/groups.rb index e4bad4723799ec..9c8a20fdceafae 100644 --- a/ee/lib/ee/api/groups.rb +++ b/ee/lib/ee/api/groups.rb @@ -92,6 +92,11 @@ def remove_unlicensed_params(group) params.delete(:duo_sast_fp_detection_availability) end + unless group.licensed_feature_available?(:ai_features) && ::Feature.enabled?( + :enable_vulnerability_resolution, group) + params.delete(:duo_sast_vulnerability_resolution_availability) + end + return if group.licensed_feature_available?(:group_level_merge_checks_setting) params.delete(:only_allow_merge_if_pipeline_succeeds) diff --git a/ee/lib/ee/api/helpers/groups_helpers.rb b/ee/lib/ee/api/helpers/groups_helpers.rb index b6cc393bb641df..26cb75a6583f5f 100644 --- a/ee/lib/ee/api/helpers/groups_helpers.rb +++ b/ee/lib/ee/api/helpers/groups_helpers.rb @@ -32,7 +32,8 @@ module GroupsHelpers optional :duo_availability, type: String, values: %w[default_on default_off never_on], desc: 'Duo availability. One of `default_on`, `default_off` or `never_on`' optional :duo_remote_flows_availability, type: ::Grape::API::Boolean, desc: 'Enable GitLab Duo remote flows for this group' optional :duo_foundational_flows_availability, type: ::Grape::API::Boolean, desc: 'Enable GitLab foundational Duo flows for this group' - optional :duo_sast_fp_detection_availability, type: ::Grape::API::Boolean, desc: 'Enable GitLab Duo SAST false position detection for this group' + optional :duo_sast_fp_detection_availability, type: ::Grape::API::Boolean, desc: 'Enable GitLab Duo SAST false positive detection for this group' + optional :duo_sast_vulnerability_resolution_availability, type: ::Grape::API::Boolean, desc: 'Enable GitLab Duo SAST vulnerability resolution for this group' optional :amazon_q_auto_review_enabled, type: ::Grape::API::Boolean, desc: 'Enable Amazon Q auto review for merge request' optional :experiment_features_enabled, type: ::Grape::API::Boolean, desc: 'Enable experiment features for this group' optional :model_prompt_cache_enabled, type: ::Grape::API::Boolean, desc: 'Enable model prompt cache for this group' diff --git a/ee/lib/ee/api/helpers/projects_helpers.rb b/ee/lib/ee/api/helpers/projects_helpers.rb index 101080226b5ef9..17404d0963e98d 100644 --- a/ee/lib/ee/api/helpers/projects_helpers.rb +++ b/ee/lib/ee/api/helpers/projects_helpers.rb @@ -26,6 +26,7 @@ module ProjectsHelpers optional :auto_duo_code_review_enabled, type: Grape::API::Boolean, desc: 'Enable automatic reviews by GitLab Duo on merge requests' optional :duo_remote_flows_enabled, type: Grape::API::Boolean, desc: 'Enable GitLab Duo remote flows for this project' optional :duo_sast_fp_detection_enabled, type: Grape::API::Boolean, desc: 'Enable GitLab Duo SAST false positive detection for this project' + optional :duo_sast_vulnerability_resolution_enabled, type: Grape::API::Boolean, desc: 'Enable GitLab Duo SAST vulnerability resolution for this project' optional :spp_repository_pipeline_access, type: Grape::API::Boolean, desc: 'Grant read-only access to security policy configurations for enforcement in linked CI/CD projects' end @@ -55,6 +56,7 @@ module ProjectsHelpers desc: 'Enable web based commit signing for this project' optional :duo_remote_flows_enabled, type: Grape::API::Boolean, desc: 'Enable GitLab Duo remote flows for this project' optional :duo_sast_fp_detection_enabled, type: Grape::API::Boolean, desc: 'Enable GitLab Duo SAST false positive detection for this project' + optional :duo_sast_vulnerability_resolution_enabled, type: Grape::API::Boolean, desc: 'Enable GitLab Duo SAST vulnerability resolution for this project' optional :spp_repository_pipeline_access, type: Grape::API::Boolean, desc: 'Grant read-only access to security policy configurations for enforcement in linked CI/CD projects' end @@ -76,6 +78,7 @@ def update_params_at_least_one_of :auto_duo_code_review_enabled, :duo_remote_flows_enabled, :duo_sast_fp_detection_enabled, + :duo_sast_vulnerability_resolution_enabled, :allow_pipeline_trigger_approve_deployment, :only_allow_merge_if_all_status_checks_passed, :approvals_before_merge, @@ -134,6 +137,10 @@ def filter_attributes_using_license!(attrs) attrs.delete(:duo_sast_fp_detection_enabled) end + unless License.feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, current_user) + attrs.delete(:duo_sast_vulnerability_resolution_enabled) + end + return if ::License.feature_available?(:security_orchestration_policies) attrs.delete(:spp_repository_pipeline_access) -- GitLab From 79f15ef2fd836612d70c8b84c9c03ee54091f5b2 Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Mon, 24 Nov 2025 11:28:09 -0700 Subject: [PATCH 03/12] Update specs for new setting --- doc/api/openapi/openapi_v2.yaml | 38 ++++++++++++++- .../ee/projects_controller_spec.rb | 43 +++++++++++++++++ .../helpers/ee/groups/settings_helper_spec.rb | 4 ++ ee/spec/helpers/projects_helper_spec.rb | 1 + ee/spec/lib/ee/api/entities/project_spec.rb | 37 ++++++++++++++ .../namespace_setting_changes_auditor_spec.rb | 1 + ee/spec/models/application_setting_spec.rb | 23 +++++++++ ee/spec/models/ee/namespace_spec.rb | 2 + ee/spec/models/ee/project_setting_spec.rb | 5 ++ ee/spec/models/namespace_setting_spec.rb | 20 ++++++++ .../admin/ai_configuration_presenter_spec.rb | 2 + ee/spec/requests/api/groups_spec.rb | 48 +++++++++++++++++++ ee/spec/requests/api/projects_spec.rb | 45 +++++++++++++++++ .../update_service_spec.rb | 8 ++++ .../services/groups/update_service_spec.rb | 4 ++ spec/requests/api/project_attributes.yml | 1 + 16 files changed, 280 insertions(+), 2 deletions(-) diff --git a/doc/api/openapi/openapi_v2.yaml b/doc/api/openapi/openapi_v2.yaml index 6b8098a6220f1c..c8983b4b219223 100644 --- a/doc/api/openapi/openapi_v2.yaml +++ b/doc/api/openapi/openapi_v2.yaml @@ -32075,6 +32075,11 @@ paths: description: Enable GitLab Duo SAST false positive detection for this project type: boolean required: false + - in: formData + name: override_params[duo_sast_vulnerability_resolution_enabled] + description: Enable GitLab Duo SAST vulnerability resolution for this project + type: boolean + required: false - in: formData name: override_params[spp_repository_pipeline_access] description: Grant read-only access to security policy configurations for @@ -32792,6 +32797,11 @@ paths: description: Enable GitLab Duo SAST false positive detection for this project type: boolean required: false + - in: formData + name: override_params[duo_sast_vulnerability_resolution_enabled] + description: Enable GitLab Duo SAST vulnerability resolution for this project + type: boolean + required: false - in: formData name: override_params[spp_repository_pipeline_access] description: Grant read-only access to security policy configurations for @@ -33588,6 +33598,11 @@ paths: description: Enable GitLab Duo SAST false positive detection for this project type: boolean required: false + - in: formData + name: override_params[duo_sast_vulnerability_resolution_enabled] + description: Enable GitLab Duo SAST vulnerability resolution for this project + type: boolean + required: false - in: formData name: override_params[spp_repository_pipeline_access] description: Grant read-only access to security policy configurations for @@ -48207,7 +48222,10 @@ definitions: description: Enable GitLab foundational Duo flows for this group duo_sast_fp_detection_availability: type: boolean - description: Enable GitLab Duo SAST false position detection for this group + description: Enable GitLab Duo SAST false positive detection for this group + duo_sast_vulnerability_resolution_availability: + type: boolean + description: Enable GitLab Duo SAST vulnerability resolution for this group amazon_q_auto_review_enabled: type: boolean description: Enable Amazon Q auto review for merge request @@ -48473,7 +48491,10 @@ definitions: description: Enable GitLab foundational Duo flows for this group duo_sast_fp_detection_availability: type: boolean - description: Enable GitLab Duo SAST false position detection for this group + description: Enable GitLab Duo SAST false positive detection for this group + duo_sast_vulnerability_resolution_availability: + type: boolean + description: Enable GitLab Duo SAST vulnerability resolution for this group amazon_q_auto_review_enabled: type: boolean description: Enable Amazon Q auto review for merge request @@ -49222,6 +49243,8 @@ definitions: type: string duo_sast_fp_detection_enabled: type: string + duo_sast_vulnerability_resolution_enabled: + type: string web_based_commit_signing_enabled: type: string spp_repository_pipeline_access: @@ -64557,6 +64580,9 @@ definitions: duo_sast_fp_detection_enabled: type: boolean description: Enable GitLab Duo SAST false positive detection for this project + duo_sast_vulnerability_resolution_enabled: + type: boolean + description: Enable GitLab Duo SAST vulnerability resolution for this project spp_repository_pipeline_access: type: boolean description: Grant read-only access to security policy configurations for @@ -65003,6 +65029,9 @@ definitions: duo_sast_fp_detection_enabled: type: boolean description: Enable GitLab Duo SAST false positive detection for this project + duo_sast_vulnerability_resolution_enabled: + type: boolean + description: Enable GitLab Duo SAST vulnerability resolution for this project spp_repository_pipeline_access: type: boolean description: Grant read-only access to security policy configurations for @@ -65452,6 +65481,8 @@ definitions: type: string duo_sast_fp_detection_enabled: type: string + duo_sast_vulnerability_resolution_enabled: + type: string web_based_commit_signing_enabled: type: string spp_repository_pipeline_access: @@ -65934,6 +65965,9 @@ definitions: duo_sast_fp_detection_enabled: type: boolean description: Enable GitLab Duo SAST false positive detection for this project + duo_sast_vulnerability_resolution_enabled: + type: boolean + description: Enable GitLab Duo SAST vulnerability resolution for this project spp_repository_pipeline_access: type: boolean description: Grant read-only access to security policy configurations for diff --git a/ee/spec/controllers/ee/projects_controller_spec.rb b/ee/spec/controllers/ee/projects_controller_spec.rb index 5ea12e09fdbd69..21323078e63ec5 100644 --- a/ee/spec/controllers/ee/projects_controller_spec.rb +++ b/ee/spec/controllers/ee/projects_controller_spec.rb @@ -962,6 +962,49 @@ end end end + + context 'when duo_sast_vulnerability_resolution_enabled param is specified' do + let(:params) { { project_setting_attributes: { duo_sast_vulnerability_resolution_enabled: true } } } + + let(:request) do + put :update, params: { namespace_id: project.namespace, id: project, project: params } + end + + it 'updates duo_sast_vulnerability_resolution_enabled' do + project.project_setting.duo_sast_vulnerability_resolution_enabled = false + project.project_setting.save! + + request + + expect(project.reload.project_setting.duo_sast_vulnerability_resolution_enabled).to eq(true) + end + + context 'when duo sast vulnerability resolution is locked by the ancestor' do + before do + project.project_setting.duo_sast_vulnerability_resolution_enabled = false + project.project_setting.save! + + project.namespace.namespace_settings.lock_duo_sast_vulnerability_resolution_enabled = true + project.namespace.namespace_settings.duo_sast_vulnerability_resolution_enabled = false + project.namespace.namespace_settings.save! + end + + it 'does not update duo sast vulnerability resolution' do + expect { request }.not_to change { project.reload.project_setting.duo_sast_vulnerability_resolution_enabled }.from(false) + end + + context 'with more params passed' do + let(:params) do + { project_setting_attributes: { duo_sast_vulnerability_resolution_enabled: true }, description: 'Settings test' } + end + + it 'does not update duo sast vulnerability resolution, but updates other attributes' do + expect { request }.not_to change { project.reload.project_setting.duo_sast_vulnerability_resolution_enabled }.from(false) + expect(project.description).to eq('Settings test') + end + end + end + end end describe '#download_export', feature_category: :importers do diff --git a/ee/spec/helpers/ee/groups/settings_helper_spec.rb b/ee/spec/helpers/ee/groups/settings_helper_spec.rb index 2d165688a4fba9..1b7f77a06816d3 100644 --- a/ee/spec/helpers/ee/groups/settings_helper_spec.rb +++ b/ee/spec/helpers/ee/groups/settings_helper_spec.rb @@ -111,6 +111,10 @@ duo_sast_fp_detection_cascading_settings: "{\"locked_by_application_setting\":false," \ "\"locked_by_ancestor\":false}", duo_sast_fp_detection_availability: group.namespace_settings.duo_sast_fp_detection_availability.to_s, + duo_sast_vulnerability_resolution_cascading_settings: "{\"locked_by_application_setting\":false," \ + "\"locked_by_ancestor\":false}", + duo_sast_vulnerability_resolution_availability: group.namespace_settings + .duo_sast_vulnerability_resolution_availability.to_s, duo_core_features_enabled: group.namespace_settings.duo_core_features_enabled.to_s, are_duo_settings_locked: group.namespace_settings.duo_features_enabled_locked?.to_s, experiment_features_enabled: group.namespace_settings.experiment_features_enabled.to_s, diff --git a/ee/spec/helpers/projects_helper_spec.rb b/ee/spec/helpers/projects_helper_spec.rb index 57f2ec20ea4c42..ebe02d30855ae8 100644 --- a/ee/spec/helpers/projects_helper_spec.rb +++ b/ee/spec/helpers/projects_helper_spec.rb @@ -704,6 +704,7 @@ initialDuoRemoteFlowsAvailability: true, initialDuoFoundationalFlowsAvailability: true, initialDuoSastFpDetectionEnabled: false, + initialDuoSastVulnerabilityResolutionEnabled: true, experimentFeaturesEnabled: false } end diff --git a/ee/spec/lib/ee/api/entities/project_spec.rb b/ee/spec/lib/ee/api/entities/project_spec.rb index 8679b216b7e34f..e5dc510c3d1249 100644 --- a/ee/spec/lib/ee/api/entities/project_spec.rb +++ b/ee/spec/lib/ee/api/entities/project_spec.rb @@ -232,6 +232,43 @@ def mock_available end end + describe 'duo_sast_vulnerability_resolution_enabled' do + context 'when project is licensed to use ai_features and feature flag is enabled' do + before do + stub_licensed_features(ai_features: true) + stub_feature_flags(enable_vulnerability_resolution: true) + end + + it 'returns a boolean value' do + expect(subject[:duo_sast_vulnerability_resolution_enabled]).to be_in([true, false]) + end + end + + context 'when project is licensed to use ai_features but feature flag is disabled' do + before do + stub_licensed_features(ai_features: true) + stub_feature_flags(enable_vulnerability_resolution: false) + end + + it 'returns nil' do + expect(subject[:duo_sast_vulnerability_resolution_enabled]).to be_nil + end + end + + context 'when project is not licensed to use ai_features' do + let(:current_user) { developer } + + before do + stub_licensed_features(ai_features: false) + stub_feature_flags(enable_vulnerability_resolution: true) + end + + it 'returns nil' do + expect(subject[:duo_sast_vulnerability_resolution_enabled]).to be_nil + end + end + end + describe 'web_based_commit_signing_enabled' do before do stub_saas_features(repositories_web_based_commit_signing: repositories_web_based_commit_signing) diff --git a/ee/spec/lib/namespaces/namespace_setting_changes_auditor_spec.rb b/ee/spec/lib/namespaces/namespace_setting_changes_auditor_spec.rb index 1e54928522a304..6f72ada249e2c7 100644 --- a/ee/spec/lib/namespaces/namespace_setting_changes_auditor_spec.rb +++ b/ee/spec/lib/namespaces/namespace_setting_changes_auditor_spec.rb @@ -130,6 +130,7 @@ web_based_commit_signing_enabled allow_enterprise_bypass_placeholder_confirmation enterprise_bypass_expires_at allow_personal_snippets lock_auto_duo_code_review_enabled auto_duo_code_review_enabled lock_duo_remote_flows_enabled duo_remote_flows_enabled lock_duo_foundational_flows_enabled + lock_duo_sast_vulnerability_resolution_enabled duo_sast_vulnerability_resolution_enabled duo_foundational_flows_enabled lock_duo_sast_fp_detection_enabled duo_sast_fp_detection_enabled] columns_to_audit = Namespaces::NamespaceSettingChangesAuditor::EVENT_NAME_PER_COLUMN.keys.map(&:to_s) diff --git a/ee/spec/models/application_setting_spec.rb b/ee/spec/models/application_setting_spec.rb index 1b54705ca97210..7166c685128281 100644 --- a/ee/spec/models/application_setting_spec.rb +++ b/ee/spec/models/application_setting_spec.rb @@ -765,6 +765,29 @@ end end + describe '#duo_sast_vulnerability_resolution_availability=' do + using RSpec::Parameterized::TableSyntax + + where(:duo_sast_vulnerability_resolution_availability, :duo_sast_vulnerability_resolution_enabled_expectation, + :lock_duo_sast_vulnerability_resolution_enabled_expectation) do + true | true | false + false | false | true + end + + with_them do + before do + setting.duo_sast_vulnerability_resolution_availability = duo_sast_vulnerability_resolution_availability + end + + it 'returns the expected response' do + expect(setting.duo_sast_vulnerability_resolution_enabled) + .to be duo_sast_vulnerability_resolution_enabled_expectation + expect(setting.lock_duo_sast_vulnerability_resolution_enabled) + .to be lock_duo_sast_vulnerability_resolution_enabled_expectation + end + end + end + describe '#enabled_expanded_logging' do it "updates ::Ai::Settings.instance.enabled_instance_verbose_ai_logs" do ::Ai::Setting.instance.update!(enabled_instance_verbose_ai_logs: false) diff --git a/ee/spec/models/ee/namespace_spec.rb b/ee/spec/models/ee/namespace_spec.rb index 78e9ac95929c3a..0fd90194a10ed6 100644 --- a/ee/spec/models/ee/namespace_spec.rb +++ b/ee/spec/models/ee/namespace_spec.rb @@ -57,6 +57,8 @@ it { is_expected.to delegate_method(:lock_duo_remote_flows_enabled).to(:namespace_settings).allow_nil } it { is_expected.to delegate_method(:duo_sast_fp_detection_enabled).to(:namespace_settings).allow_nil } it { is_expected.to delegate_method(:lock_duo_sast_fp_detection_enabled).to(:namespace_settings).allow_nil } + it { is_expected.to delegate_method(:duo_sast_vulnerability_resolution_enabled).to(:namespace_settings).allow_nil } + it { is_expected.to delegate_method(:lock_duo_sast_vulnerability_resolution_enabled).to(:namespace_settings).allow_nil } it { is_expected.to delegate_method(:security_policy_management_project).to(:security_orchestration_policy_configuration) } it { is_expected.to delegate_method(:allow_enterprise_bypass_placeholder_confirmation).to(:namespace_settings).allow_nil } it { is_expected.to delegate_method(:allow_enterprise_bypass_placeholder_confirmation=).to(:namespace_settings).with_arguments(:args) } diff --git a/ee/spec/models/ee/project_setting_spec.rb b/ee/spec/models/ee/project_setting_spec.rb index 711a253a5ad846..59f7da3a183830 100644 --- a/ee/spec/models/ee/project_setting_spec.rb +++ b/ee/spec/models/ee/project_setting_spec.rb @@ -180,6 +180,11 @@ settings_attribute_name: :duo_sast_fp_detection_enabled end + describe '#duo_sast_vulnerability_resolution_enabled' do + it_behaves_like 'a cascading project setting boolean attribute', + settings_attribute_name: :duo_sast_vulnerability_resolution_enabled + end + describe '#enabled_foundational_flows' do let(:setting) { build(:project_setting) } diff --git a/ee/spec/models/namespace_setting_spec.rb b/ee/spec/models/namespace_setting_spec.rb index 04ba22c432d3c6..d2ee60d17dcebe 100644 --- a/ee/spec/models/namespace_setting_spec.rb +++ b/ee/spec/models/namespace_setting_spec.rb @@ -652,6 +652,26 @@ end end + describe '#duo_sast_vulnerability_resolution_availability=' do + using RSpec::Parameterized::TableSyntax + + where(:duo_sast_vulnerability_resolution_availability, :duo_sast_vulnerability_resolution_enabled_expectation, :lock_duo_sast_vulnerability_resolution_enabled_expectation) do + true | true | false + false | false | true + end + + with_them do + before do + setting.duo_sast_vulnerability_resolution_availability = duo_sast_vulnerability_resolution_availability + end + + it 'returns the expected response' do + expect(setting.duo_sast_vulnerability_resolution_enabled).to be duo_sast_vulnerability_resolution_enabled_expectation + expect(setting.lock_duo_sast_vulnerability_resolution_enabled).to be lock_duo_sast_vulnerability_resolution_enabled_expectation + end + end + end + describe 'validating new_user_signup_cap' do using RSpec::Parameterized::TableSyntax diff --git a/ee/spec/presenters/admin/ai_configuration_presenter_spec.rb b/ee/spec/presenters/admin/ai_configuration_presenter_spec.rb index d97cb8c34068fa..586d0d4e04dcca 100644 --- a/ee/spec/presenters/admin/ai_configuration_presenter_spec.rb +++ b/ee/spec/presenters/admin/ai_configuration_presenter_spec.rb @@ -19,6 +19,7 @@ duo_remote_flows_availability: true, duo_foundational_flows_availability: false, duo_sast_fp_detection_availability: true, + duo_sast_vulnerability_resolution_availability: true, duo_chat_expiration_column: 'last_updated_at', duo_chat_expiration_days: '30', enabled_expanded_logging: true, @@ -86,6 +87,7 @@ duo_remote_flows_availability: 'true', duo_foundational_flows_availability: 'false', duo_sast_fp_detection_availability: 'true', + duo_sast_vulnerability_resolution_availability: 'true', duo_chat_expiration_column: 'last_updated_at', duo_chat_expiration_days: '30', duo_core_features_enabled: 'true', diff --git a/ee/spec/requests/api/groups_spec.rb b/ee/spec/requests/api/groups_spec.rb index 6c766272b6345d..4c6492b48ab683 100644 --- a/ee/spec/requests/api/groups_spec.rb +++ b/ee/spec/requests/api/groups_spec.rb @@ -918,6 +918,54 @@ end end + context 'duo_sast_vulnerability_resolution_availability' do + context 'when licence is available and feature flag is enabled' do + before do + stub_licensed_features(ai_features: true) + stub_feature_flags(enable_vulnerability_resolution: true) + end + + it 'updates duo_sast_vulnerability_resolution_enabled field of namespace settings' do + expect do + put api("/groups/#{group.id}", user), params: { duo_sast_vulnerability_resolution_availability: false } + end.to change { group.reload.namespace_settings.duo_sast_vulnerability_resolution_enabled }.from(true).to(false) + .and change { group.reload.namespace_settings.lock_duo_sast_vulnerability_resolution_enabled }.from(false).to(true) + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when licence is available but feature flag is disabled' do + before do + stub_licensed_features(ai_features: true) + stub_feature_flags(enable_vulnerability_resolution: false) + end + + it 'does not update duo_sast_vulnerability_resolution_enabled field of namespace settings' do + expect do + put api("/groups/#{group.id}", user), params: { duo_sast_vulnerability_resolution_availability: false } + end.not_to change { group.reload.namespace_settings.duo_sast_vulnerability_resolution_enabled } + + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when licence is not available' do + before do + stub_licensed_features(ai_features: false) + stub_feature_flags(enable_vulnerability_resolution: true) + end + + it 'does not update duo_sast_vulnerability_resolution_enabled field of namespace settings' do + expect do + put api("/groups/#{group.id}", user), params: { duo_sast_vulnerability_resolution_availability: false } + end.not_to change { group.reload.namespace_settings.duo_sast_vulnerability_resolution_enabled } + + expect(response).to have_gitlab_http_status(:ok) + end + end + end + context 'auto_duo_code_review_enabled', :saas do using RSpec::Parameterized::TableSyntax diff --git a/ee/spec/requests/api/projects_spec.rb b/ee/spec/requests/api/projects_spec.rb index 9e56d0853da0a6..c7cecb800d37a5 100644 --- a/ee/spec/requests/api/projects_spec.rb +++ b/ee/spec/requests/api/projects_spec.rb @@ -2267,6 +2267,51 @@ def decode_cursor(cursor) end end + context 'when setting duo_sast_vulnerability_resolution_enabled' do + let(:project_params) { { duo_sast_vulnerability_resolution_enabled: false } } + + context 'when licence is available and feature flag is enabled' do + before do + stub_licensed_features(ai_features: true) + stub_feature_flags(enable_vulnerability_resolution: true) + end + + it 'updates the value' do + expect { subject }.to change { project.reload.duo_sast_vulnerability_resolution_enabled } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['duo_sast_vulnerability_resolution_enabled']).to eq false + end + end + + context 'when licence is available but feature flag is disabled' do + before do + stub_licensed_features(ai_features: true) + stub_feature_flags(enable_vulnerability_resolution: false) + end + + it 'does not update the value and does not expose it in response' do + expect { subject }.not_to change { project.reload.duo_sast_vulnerability_resolution_enabled } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['duo_sast_vulnerability_resolution_enabled']).to be_nil + end + end + + context 'when licence is not available' do + before do + stub_feature_flags(enable_vulnerability_resolution: true) + end + + it 'does not update the value and does not expose it in response' do + expect { subject }.not_to change { project.reload.duo_sast_vulnerability_resolution_enabled } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['duo_sast_vulnerability_resolution_enabled']).to be_nil + end + end + end + context 'updating web_based_commit_signing_enabled' do using RSpec::Parameterized::TableSyntax diff --git a/ee/spec/services/application_settings/update_service_spec.rb b/ee/spec/services/application_settings/update_service_spec.rb index b15cade53eeda4..6570cf2f3b7ed5 100644 --- a/ee/spec/services/application_settings/update_service_spec.rb +++ b/ee/spec/services/application_settings/update_service_spec.rb @@ -388,6 +388,14 @@ it_behaves_like 'when updating duo settings', :duo_sast_fp_detection_enabled, false end + context 'when updating duo_sast_vulnerability_resolution_enabled' do + before do + setting.update!(duo_sast_vulnerability_resolution_enabled: true) + end + + it_behaves_like 'when updating duo settings', :duo_sast_vulnerability_resolution_enabled, false + end + context 'when updating duo_agent_platform_enabled' do let(:opts) { { duo_agent_platform_enabled: false } } diff --git a/ee/spec/services/groups/update_service_spec.rb b/ee/spec/services/groups/update_service_spec.rb index 78ee7bb03b9ee3..9c5d9ba773e91d 100644 --- a/ee/spec/services/groups/update_service_spec.rb +++ b/ee/spec/services/groups/update_service_spec.rb @@ -690,6 +690,10 @@ def update_file_template_project_id(id) it_behaves_like 'when updating duo settings', :duo_sast_fp_detection_enabled, false end + context 'when updating duo_sast_vulnerability_resolution_enabled' do + it_behaves_like 'when updating duo settings', :duo_sast_vulnerability_resolution_enabled, false + end + context 'when updating lock_duo_features_enabled' do let_it_be_with_reload(:user) { create(:user) } let_it_be_with_reload(:group) { create(:group, :public) } diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml index d045911061dbff..edef593aeaf189 100644 --- a/spec/requests/api/project_attributes.yml +++ b/spec/requests/api/project_attributes.yml @@ -205,6 +205,7 @@ project_setting: - duo_remote_flows_enabled - duo_foundational_flows_enabled - duo_sast_fp_detection_enabled + - duo_sast_vulnerability_resolution_enabled - enabled_foundational_flows build_service_desk_setting: # service_desk_setting unexposed_attributes: -- GitLab From 23912392673cae0050f5b8ef96c9ad8e8ceb6371 Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Wed, 10 Dec 2025 11:22:26 -0700 Subject: [PATCH 04/12] Fix rubocop error after rebase --- ee/lib/ee/api/helpers/projects_helpers.rb | 61 ++++++++++++----------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/ee/lib/ee/api/helpers/projects_helpers.rb b/ee/lib/ee/api/helpers/projects_helpers.rb index 17404d0963e98d..0b9747af123e0c 100644 --- a/ee/lib/ee/api/helpers/projects_helpers.rb +++ b/ee/lib/ee/api/helpers/projects_helpers.rb @@ -104,46 +104,47 @@ def update_params_at_least_one_of def filter_attributes_using_license!(attrs) super - unless ::License.feature_available?(:external_authorization_service_api_management) - attrs.delete(:external_authorization_classification_label) - end + delete_if_license_unavailable(attrs, :external_authorization_classification_label, :external_authorization_service_api_management) + delete_if_license_unavailable(attrs, :allow_pipeline_trigger_approve_deployment, :protected_environments) + delete_if_license_unavailable(attrs, :prevent_merge_without_jira_issue, :jira_issue_association_enforcement) + delete_if_license_unavailable(attrs, :ci_restrict_pipeline_cancellation_role, :ci_pipeline_cancellation_restrictions) + delete_auto_duo_code_review_if_unavailable(attrs) + delete_if_license_unavailable(attrs, :duo_remote_flows_enabled, :ai_workflows) + delete_duo_sast_fp_detection_if_unavailable(attrs) + delete_duo_sast_vulnerability_resolution_if_unavailable(attrs) + delete_if_license_unavailable(attrs, :spp_repository_pipeline_access, :security_orchestration_policies) + end - unless ::License.feature_available?(:protected_environments) - attrs.delete(:allow_pipeline_trigger_approve_deployment) - end + private - unless ::License.feature_available?(:jira_issue_association_enforcement) - attrs.delete(:prevent_merge_without_jira_issue) - end + def delete_if_license_unavailable(attrs, attr_key, license_feature) + attrs.delete(attr_key) unless ::License.feature_available?(license_feature) + end - unless ::License.feature_available?(:ci_pipeline_cancellation_restrictions) - attrs.delete(:ci_restrict_pipeline_cancellation_role) + def delete_duo_sast_fp_detection_if_unavailable(attrs) + if ::License.feature_available?(:ai_features) && ::Feature.enabled?(:ai_experiment_sast_fp_detection, current_user) + return end - if params[:id].present? - # Existing project (update) - check both license and availability - unless ::License.feature_available?(:review_merge_request) && - user_project.auto_duo_code_review_settings_available? - attrs.delete(:auto_duo_code_review_enabled) - end - else - # New project (creation) - only check license - attrs.delete(:auto_duo_code_review_enabled) unless ::License.feature_available?(:review_merge_request) - end - - attrs.delete(:duo_remote_flows_enabled) unless License.feature_available?(:ai_workflows) + attrs.delete(:duo_sast_fp_detection_enabled) + end - unless License.feature_available?(:ai_features) && ::Feature.enabled?(:ai_experiment_sast_fp_detection, current_user) - attrs.delete(:duo_sast_fp_detection_enabled) + def delete_duo_sast_vulnerability_resolution_if_unavailable(attrs) + if ::License.feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, current_user) + return end - unless License.feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, current_user) - attrs.delete(:duo_sast_vulnerability_resolution_enabled) - end + attrs.delete(:duo_sast_vulnerability_resolution_enabled) + end + + def delete_auto_duo_code_review_if_unavailable(attrs) + return if ::License.feature_available?(:review_merge_request) && user_project_available_for_auto_review? - return if ::License.feature_available?(:security_orchestration_policies) + attrs.delete(:auto_duo_code_review_enabled) + end - attrs.delete(:spp_repository_pipeline_access) + def user_project_available_for_auto_review? + params[:id].present? ? user_project.auto_duo_code_review_settings_available? : true end end end -- GitLab From 9e9a38723d792cacbce68dceed8b8110723ba017 Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Fri, 12 Dec 2025 11:03:23 -0700 Subject: [PATCH 05/12] Update feature flag scope --- ee/lib/ee/api/entities/project.rb | 2 +- ee/lib/ee/api/groups.rb | 2 +- ee/lib/ee/api/helpers/projects_helpers.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ee/lib/ee/api/entities/project.rb b/ee/lib/ee/api/entities/project.rb index ff654b8b38c4c6..61da89fc837094 100644 --- a/ee/lib/ee/api/entities/project.rb +++ b/ee/lib/ee/api/entities/project.rb @@ -68,7 +68,7 @@ def preload_relation(projects_relation, options = {}) expose :duo_remote_flows_enabled, if: ->(_, _) { ::Ai::DuoWorkflow.enabled? } expose :duo_foundational_flows_enabled, if: ->(_, _) { ::Ai::DuoWorkflow.enabled? } expose :duo_sast_fp_detection_enabled, if: ->(project, _) { project.licensed_feature_available?(:ai_features) && ::Feature.enabled?(:ai_experiment_sast_fp_detection, project) } - expose :duo_sast_vulnerability_resolution_enabled, if: ->(project, _) { project.licensed_feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, project) } + expose :duo_sast_vulnerability_resolution_enabled, if: ->(project, _) { project.licensed_feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, project.root_ancestor) } expose :web_based_commit_signing_enabled, if: ->(project, options) do ::Gitlab::Saas.feature_available?(:repositories_web_based_commit_signing) && Ability.allowed?(options[:current_user], :admin_project, project) diff --git a/ee/lib/ee/api/groups.rb b/ee/lib/ee/api/groups.rb index 9c8a20fdceafae..a6bbebd094b85d 100644 --- a/ee/lib/ee/api/groups.rb +++ b/ee/lib/ee/api/groups.rb @@ -93,7 +93,7 @@ def remove_unlicensed_params(group) end unless group.licensed_feature_available?(:ai_features) && ::Feature.enabled?( - :enable_vulnerability_resolution, group) + :enable_vulnerability_resolution, group.root_ancestor) params.delete(:duo_sast_vulnerability_resolution_availability) end diff --git a/ee/lib/ee/api/helpers/projects_helpers.rb b/ee/lib/ee/api/helpers/projects_helpers.rb index 0b9747af123e0c..2ad2e645dc3432 100644 --- a/ee/lib/ee/api/helpers/projects_helpers.rb +++ b/ee/lib/ee/api/helpers/projects_helpers.rb @@ -130,7 +130,7 @@ def delete_duo_sast_fp_detection_if_unavailable(attrs) end def delete_duo_sast_vulnerability_resolution_if_unavailable(attrs) - if ::License.feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, current_user) + if ::License.feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, project.root_ancestor) return end -- GitLab From 7af88aa826597f8643cdfa3d819a8d39cc00b648 Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Fri, 12 Dec 2025 11:10:39 -0700 Subject: [PATCH 06/12] Disabled organization rubocop --- ee/app/presenters/admin/ai_configuration_presenter.rb | 2 ++ ee/app/services/ee/application_settings/update_service.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/ee/app/presenters/admin/ai_configuration_presenter.rb b/ee/app/presenters/admin/ai_configuration_presenter.rb index 607da13aa0f3a5..56b692f636919c 100644 --- a/ee/app/presenters/admin/ai_configuration_presenter.rb +++ b/ee/app/presenters/admin/ai_configuration_presenter.rb @@ -98,7 +98,9 @@ def application_settings strong_memoize_attr :application_settings def foundational_agents_statuses + # rubocop:disable Gitlab/AvoidDefaultOrganization -- needs to use default organization ::Organizations::Organization.default_organization&.foundational_agents_statuses + # rubocop:enable Gitlab/AvoidDefaultOrganization end def ai_settings diff --git a/ee/app/services/ee/application_settings/update_service.rb b/ee/app/services/ee/application_settings/update_service.rb index 584ab736ef32fb..603a25e29f4073 100644 --- a/ee/app/services/ee/application_settings/update_service.rb +++ b/ee/app/services/ee/application_settings/update_service.rb @@ -49,7 +49,9 @@ def execute def handle_organization_settings return unless params.has_key?(:foundational_agents_statuses) + # rubocop:disable Gitlab/AvoidDefaultOrganization -- needs to use default organization default_organization = ::Organizations::Organization.default_organization + # rubocop:enable Gitlab/AvoidDefaultOrganization default_organization.update(foundational_agents_statuses: params.delete(:foundational_agents_statuses)) -- GitLab From 73cc56f9ad41b33e274ba65ca120eedc99c37988 Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Fri, 12 Dec 2025 13:22:57 -0700 Subject: [PATCH 07/12] Fix failing spec --- ee/lib/ee/api/helpers/projects_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ee/lib/ee/api/helpers/projects_helpers.rb b/ee/lib/ee/api/helpers/projects_helpers.rb index 2ad2e645dc3432..2decbef9494670 100644 --- a/ee/lib/ee/api/helpers/projects_helpers.rb +++ b/ee/lib/ee/api/helpers/projects_helpers.rb @@ -130,7 +130,7 @@ def delete_duo_sast_fp_detection_if_unavailable(attrs) end def delete_duo_sast_vulnerability_resolution_if_unavailable(attrs) - if ::License.feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, project.root_ancestor) + if ::License.feature_available?(:ai_features) && ::Feature.enabled?(:enable_vulnerability_resolution, user_project.root_ancestor) return end -- GitLab From 82689e4559956fd7a7d92f6de6c1bc790920f82c Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Mon, 15 Dec 2025 12:13:34 -0700 Subject: [PATCH 08/12] Update migration milestone --- ...sast_vulnerability_resolution_enabled_to_project_settings.rb | 2 +- ...o_sast_vulnerability_resolution_enabled_cascading_setting.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb b/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb index 4c79fc493ada4e..9523471463bb3b 100644 --- a/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb +++ b/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class AddDuoSastVulnerabilityResolutionEnabledToProjectSettings < Gitlab::Database::Migration[2.3] - milestone '18.7' + milestone '18.8' def change add_column :project_settings, :duo_sast_vulnerability_resolution_enabled, :boolean, default: true, null: false diff --git a/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb b/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb index 95c5d63df13899..f04bbb9db381c0 100644 --- a/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb +++ b/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class AddDuoSastVulnerabilityResolutionEnabledCascadingSetting < Gitlab::Database::Migration[2.3] - milestone '18.7' + milestone '18.8' disable_ddl_transaction! include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings -- GitLab From 356704d20531f5ab0eeaf1eff7d75ebffe37e17f Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Mon, 15 Dec 2025 15:54:52 -0700 Subject: [PATCH 09/12] Switch to default false Switch setting to be opt-in instead of opt-out. --- .../duo_sast_vulnerability_resolution_enabled.yml | 2 +- ...sast_vulnerability_resolution_enabled_to_project_settings.rb | 2 +- ...o_sast_vulnerability_resolution_enabled_cascading_setting.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/application_setting_columns/duo_sast_vulnerability_resolution_enabled.yml b/config/application_setting_columns/duo_sast_vulnerability_resolution_enabled.yml index e5997b30e2a1cb..628a3ef89f85e6 100644 --- a/config/application_setting_columns/duo_sast_vulnerability_resolution_enabled.yml +++ b/config/application_setting_columns/duo_sast_vulnerability_resolution_enabled.yml @@ -3,7 +3,7 @@ attr: duo_sast_vulnerability_resolution_enabled clusterwide: false column: duo_sast_vulnerability_resolution_enabled db_type: boolean -default: 'true' +default: 'false' description: encrypted: false gitlab_com_different_than_default: false diff --git a/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb b/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb index 9523471463bb3b..f4de3557f8561e 100644 --- a/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb +++ b/db/migrate/20251121205957_add_duo_sast_vulnerability_resolution_enabled_to_project_settings.rb @@ -4,6 +4,6 @@ class AddDuoSastVulnerabilityResolutionEnabledToProjectSettings < Gitlab::Databa milestone '18.8' def change - add_column :project_settings, :duo_sast_vulnerability_resolution_enabled, :boolean, default: true, null: false + add_column :project_settings, :duo_sast_vulnerability_resolution_enabled, :boolean, default: false, null: false end end diff --git a/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb b/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb index f04bbb9db381c0..4c14533948edcb 100644 --- a/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb +++ b/db/migrate/20251121210038_add_duo_sast_vulnerability_resolution_enabled_cascading_setting.rb @@ -7,7 +7,7 @@ class AddDuoSastVulnerabilityResolutionEnabledCascadingSetting < Gitlab::Databas include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings def up - add_cascading_namespace_setting :duo_sast_vulnerability_resolution_enabled, :boolean, default: true, null: false + add_cascading_namespace_setting :duo_sast_vulnerability_resolution_enabled, :boolean, default: false, null: false end def down -- GitLab From 5c4c4a31f28df60d156db9db7b8a79cb85882a2e Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Tue, 16 Dec 2025 10:50:58 -0700 Subject: [PATCH 10/12] Update failing specs --- ee/spec/helpers/projects_helper_spec.rb | 2 +- ee/spec/requests/api/groups_spec.rb | 4 ++-- ee/spec/requests/api/projects_spec.rb | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ee/spec/helpers/projects_helper_spec.rb b/ee/spec/helpers/projects_helper_spec.rb index ebe02d30855ae8..b1d9460b87548e 100644 --- a/ee/spec/helpers/projects_helper_spec.rb +++ b/ee/spec/helpers/projects_helper_spec.rb @@ -704,7 +704,7 @@ initialDuoRemoteFlowsAvailability: true, initialDuoFoundationalFlowsAvailability: true, initialDuoSastFpDetectionEnabled: false, - initialDuoSastVulnerabilityResolutionEnabled: true, + initialDuoSastVulnerabilityResolutionEnabled: false, experimentFeaturesEnabled: false } end diff --git a/ee/spec/requests/api/groups_spec.rb b/ee/spec/requests/api/groups_spec.rb index 4c6492b48ab683..fecfe36483ba74 100644 --- a/ee/spec/requests/api/groups_spec.rb +++ b/ee/spec/requests/api/groups_spec.rb @@ -927,8 +927,8 @@ it 'updates duo_sast_vulnerability_resolution_enabled field of namespace settings' do expect do - put api("/groups/#{group.id}", user), params: { duo_sast_vulnerability_resolution_availability: false } - end.to change { group.reload.namespace_settings.duo_sast_vulnerability_resolution_enabled }.from(true).to(false) + put api("/groups/#{group.id}", user), params: { duo_sast_vulnerability_resolution_availability: true } + end.to change { group.reload.namespace_settings.duo_sast_vulnerability_resolution_enabled }.from(false).to(true) .and change { group.reload.namespace_settings.lock_duo_sast_vulnerability_resolution_enabled }.from(false).to(true) expect(response).to have_gitlab_http_status(:ok) diff --git a/ee/spec/requests/api/projects_spec.rb b/ee/spec/requests/api/projects_spec.rb index c7cecb800d37a5..be34d1ef7e1782 100644 --- a/ee/spec/requests/api/projects_spec.rb +++ b/ee/spec/requests/api/projects_spec.rb @@ -2268,7 +2268,7 @@ def decode_cursor(cursor) end context 'when setting duo_sast_vulnerability_resolution_enabled' do - let(:project_params) { { duo_sast_vulnerability_resolution_enabled: false } } + let(:project_params) { { duo_sast_vulnerability_resolution_enabled: true } } context 'when licence is available and feature flag is enabled' do before do @@ -2280,7 +2280,7 @@ def decode_cursor(cursor) expect { subject }.to change { project.reload.duo_sast_vulnerability_resolution_enabled } expect(response).to have_gitlab_http_status(:ok) - expect(json_response['duo_sast_vulnerability_resolution_enabled']).to eq false + expect(json_response['duo_sast_vulnerability_resolution_enabled']).to eq true end end -- GitLab From 3f1cafeb13ae1ad1c5c04d1b6f43cf5fec02de8f Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Tue, 16 Dec 2025 15:11:11 -0700 Subject: [PATCH 11/12] Fix structure.sql file --- db/structure.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/db/structure.sql b/db/structure.sql index 67842a4a8e3b77..eaa912abe15f9d 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -6124,7 +6124,7 @@ PARTITION BY LIST (partition_id); CREATE TABLE p_ci_finished_build_ch_sync_events ( build_id bigint NOT NULL, - partition bigint DEFAULT 2 NOT NULL, + partition bigint DEFAULT 1 NOT NULL, build_finished_at timestamp without time zone NOT NULL, processed boolean DEFAULT false NOT NULL, project_id bigint NOT NULL @@ -6134,7 +6134,7 @@ PARTITION BY LIST (partition); CREATE TABLE p_ci_finished_pipeline_ch_sync_events ( pipeline_id bigint NOT NULL, project_namespace_id bigint NOT NULL, - partition bigint DEFAULT 2 NOT NULL, + partition bigint DEFAULT 1 NOT NULL, pipeline_finished_at timestamp without time zone NOT NULL, processed boolean DEFAULT false NOT NULL ) -- GitLab From 63a8eeaa22055041c2486ca0c9a4bee37378926b Mon Sep 17 00:00:00 2001 From: Scott Hampton Date: Wed, 17 Dec 2025 09:07:25 -0700 Subject: [PATCH 12/12] Make suggested changes --- ee/app/models/ee/application_setting.rb | 6 +----- ee/app/models/ee/namespace_setting.rb | 6 +----- ee/spec/lib/ee/api/entities/project_spec.rb | 2 -- ee/spec/requests/api/groups_spec.rb | 6 +++--- ee/spec/requests/api/projects_spec.rb | 5 ----- 5 files changed, 5 insertions(+), 20 deletions(-) diff --git a/ee/app/models/ee/application_setting.rb b/ee/app/models/ee/application_setting.rb index 9a45c2e040ab49..6aefd8d9f76151 100644 --- a/ee/app/models/ee/application_setting.rb +++ b/ee/app/models/ee/application_setting.rb @@ -802,11 +802,7 @@ def duo_sast_vulnerability_resolution_availability def duo_sast_vulnerability_resolution_availability=(value) self.duo_sast_vulnerability_resolution_enabled = value - self.lock_duo_sast_vulnerability_resolution_enabled = if value - false - else - true - end + self.lock_duo_sast_vulnerability_resolution_enabled = !value end def duo_never_on? diff --git a/ee/app/models/ee/namespace_setting.rb b/ee/app/models/ee/namespace_setting.rb index b562bf7ccad028..cf716f538df1c3 100644 --- a/ee/app/models/ee/namespace_setting.rb +++ b/ee/app/models/ee/namespace_setting.rb @@ -216,11 +216,7 @@ def duo_sast_vulnerability_resolution_availability def duo_sast_vulnerability_resolution_availability=(value) self.duo_sast_vulnerability_resolution_enabled = value - self.lock_duo_sast_vulnerability_resolution_enabled = if value - false - else - true - end + self.lock_duo_sast_vulnerability_resolution_enabled = !value end def duo_availability diff --git a/ee/spec/lib/ee/api/entities/project_spec.rb b/ee/spec/lib/ee/api/entities/project_spec.rb index e5dc510c3d1249..6d2fefe58e038b 100644 --- a/ee/spec/lib/ee/api/entities/project_spec.rb +++ b/ee/spec/lib/ee/api/entities/project_spec.rb @@ -236,7 +236,6 @@ def mock_available context 'when project is licensed to use ai_features and feature flag is enabled' do before do stub_licensed_features(ai_features: true) - stub_feature_flags(enable_vulnerability_resolution: true) end it 'returns a boolean value' do @@ -260,7 +259,6 @@ def mock_available before do stub_licensed_features(ai_features: false) - stub_feature_flags(enable_vulnerability_resolution: true) end it 'returns nil' do diff --git a/ee/spec/requests/api/groups_spec.rb b/ee/spec/requests/api/groups_spec.rb index fecfe36483ba74..6d282bbf0e9517 100644 --- a/ee/spec/requests/api/groups_spec.rb +++ b/ee/spec/requests/api/groups_spec.rb @@ -922,13 +922,13 @@ context 'when licence is available and feature flag is enabled' do before do stub_licensed_features(ai_features: true) - stub_feature_flags(enable_vulnerability_resolution: true) + group.namespace_settings.update!(duo_sast_vulnerability_resolution_availability: true) end it 'updates duo_sast_vulnerability_resolution_enabled field of namespace settings' do expect do - put api("/groups/#{group.id}", user), params: { duo_sast_vulnerability_resolution_availability: true } - end.to change { group.reload.namespace_settings.duo_sast_vulnerability_resolution_enabled }.from(false).to(true) + put api("/groups/#{group.id}", user), params: { duo_sast_vulnerability_resolution_availability: false } + end.to change { group.reload.namespace_settings.duo_sast_vulnerability_resolution_enabled }.from(true).to(false) .and change { group.reload.namespace_settings.lock_duo_sast_vulnerability_resolution_enabled }.from(false).to(true) expect(response).to have_gitlab_http_status(:ok) diff --git a/ee/spec/requests/api/projects_spec.rb b/ee/spec/requests/api/projects_spec.rb index be34d1ef7e1782..aa24ecfa788977 100644 --- a/ee/spec/requests/api/projects_spec.rb +++ b/ee/spec/requests/api/projects_spec.rb @@ -2273,7 +2273,6 @@ def decode_cursor(cursor) context 'when licence is available and feature flag is enabled' do before do stub_licensed_features(ai_features: true) - stub_feature_flags(enable_vulnerability_resolution: true) end it 'updates the value' do @@ -2299,10 +2298,6 @@ def decode_cursor(cursor) end context 'when licence is not available' do - before do - stub_feature_flags(enable_vulnerability_resolution: true) - end - it 'does not update the value and does not expose it in response' do expect { subject }.not_to change { project.reload.duo_sast_vulnerability_resolution_enabled } -- GitLab