From d76adc5e237c575d188231aa4d0cc222e62b6d7c Mon Sep 17 00:00:00 2001 From: SAM FIGUEROA Date: Wed, 17 Dec 2025 15:24:38 +0100 Subject: [PATCH 1/2] Implement trigger and data ingestion workflow for Secret Scanning FP detection - Hook into after_create_commit on vulnerabilities to trigger secret detection false positive workflows for high/critical severity secret_detection report types - Add TriggerSecretDetectionFalsePositiveDetectionWorkflowWorker with no-op implementation - Add comprehensive specs to validate trigger conditions and worker invocation - Follow existing SAST FP workflow pattern for consistency - Add comprehensive specs for Secret Scanning FP detection trigger - Add parameterized tests for secret_detection report type with various severity levels - Test that dismissed and resolved vulnerabilities do not trigger the workflow - Test project-level setting duo_secret_detection_fp_detection_enabled - Test user permission checks for duo_workflow ability - Ensure consistency with existing SAST FP detection test patterns - Refs: https://gitlab.com/gitlab-org/gitlab/-/issues/577436 Changelog: added EE: true --- ee/app/models/ee/vulnerability.rb | 2 - ee/app/workers/all_queues.yml | 3 + ...alse_positive_detection_workflow_worker.rb | 15 ++++ ee/spec/models/ee/vulnerability_spec.rb | 70 +++++++++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 ee/app/workers/vulnerabilities/trigger_secret_detection_false_positive_detection_workflow_worker.rb diff --git a/ee/app/models/ee/vulnerability.rb b/ee/app/models/ee/vulnerability.rb index fbdb6fdb5589ce..5d3236887c09ff 100644 --- a/ee/app/models/ee/vulnerability.rb +++ b/ee/app/models/ee/vulnerability.rb @@ -399,8 +399,6 @@ def trigger_false_positive_detection end end - private - def high_or_critical_severity? severity.in?(%w[critical high]) end diff --git a/ee/app/workers/all_queues.yml b/ee/app/workers/all_queues.yml index 73f03bdec9f998..8897657bb5dfb0 100644 --- a/ee/app/workers/all_queues.yml +++ b/ee/app/workers/all_queues.yml @@ -4800,6 +4800,9 @@ - :name: vulnerabilities_trigger_false_positive_detection_workflow :worker_name: Vulnerabilities::TriggerFalsePositiveDetectionWorkflowWorker :feature_category: :vulnerability_management +- :name: vulnerabilities_trigger_secret_detection_false_positive_detection_workflow + :worker_name: Vulnerabilities::TriggerSecretDetectionFalsePositiveDetectionWorkflowWorker + :feature_category: :vulnerability_management :has_external_dependencies: false :urgency: :throttled :resource_boundary: :unknown diff --git a/ee/app/workers/vulnerabilities/trigger_secret_detection_false_positive_detection_workflow_worker.rb b/ee/app/workers/vulnerabilities/trigger_secret_detection_false_positive_detection_workflow_worker.rb new file mode 100644 index 00000000000000..fd8d39cba7da5c --- /dev/null +++ b/ee/app/workers/vulnerabilities/trigger_secret_detection_false_positive_detection_workflow_worker.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Vulnerabilities + class TriggerSecretDetectionFalsePositiveDetectionWorkflowWorker + include ApplicationWorker + + feature_category :vulnerability_management + urgency :low + + def perform(vulnerability_id) + # no-op implementation + # This worker will be implemented as part of the Secret Scanning FP detection workflow + end + end +end diff --git a/ee/spec/models/ee/vulnerability_spec.rb b/ee/spec/models/ee/vulnerability_spec.rb index a709fc30364ca8..31e1b6c36ae84d 100644 --- a/ee/spec/models/ee/vulnerability_spec.rb +++ b/ee/spec/models/ee/vulnerability_spec.rb @@ -1625,6 +1625,76 @@ end end end + + context 'when secret detection false positive detection is enabled' do + using RSpec::Parameterized::TableSyntax + + where(:report_type, :severity, :duo_secret_detection_fp_detection_enabled, :state, :should_trigger) do + :secret_detection | :critical | true | :detected | true + :secret_detection | :high | true | :detected | true + :secret_detection | :medium | true | :detected | false + :secret_detection | :low | true | :detected | false + :secret_detection | :info | true | :detected | false + :secret_detection | :unknown | true | :detected | false + :secret_detection | :high | false | :detected | false + :secret_detection | :high | true | :dismissed | false + :secret_detection | :high | true | :resolved | false + :dast | :high | true | :detected | false + end + + with_them do + before do + project.update!(duo_secret_detection_fp_detection_enabled: duo_secret_detection_fp_detection_enabled) + allow(Ability).to receive(:allowed?).with(project.first_owner, :duo_workflow, project).and_return(true) + end + + it 'triggers or does not trigger secret detection false positive detection workflow based on conditions' do + if should_trigger + expect_next_instance_of(::Vulnerability) do |instance| + expect(instance).to receive(:run_after_commit_or_now).and_yield + end + expect(::Vulnerabilities::TriggerSecretDetectionFalsePositiveDetectionWorkflowWorker) + .to receive(:perform_async).with(anything) + else + expect(::Vulnerabilities::TriggerSecretDetectionFalsePositiveDetectionWorkflowWorker) + .not_to receive(:perform_async) + end + + create(:vulnerability, report_type, severity, state, author: user, project: project) + end + end + + context 'when project first_owner does not have duo_workflow permission' do + before do + project.update!(duo_secret_detection_fp_detection_enabled: true) + allow(Ability).to receive(:allowed?).with(project.first_owner, :duo_workflow, project).and_return(false) + end + + it 'does not trigger secret detection false positive detection workflow' do + expect(::Vulnerabilities::TriggerSecretDetectionFalsePositiveDetectionWorkflowWorker) + .not_to receive(:perform_async) + + create(:vulnerability, :secret_detection, :critical, author: user, project: project) + end + end + + context 'when project first_owner has duo_workflow permission' do + before do + project.update!(duo_secret_detection_fp_detection_enabled: true) + allow(Ability).to receive(:allowed?).with(project.first_owner, :duo_workflow, project).and_return(true) + end + + it 'triggers secret detection false positive detection workflow for high severity secret detection vulnerability' do + expect_next_instance_of(::Vulnerability) do |instance| + expect(instance).to receive(:run_after_commit_or_now).and_yield + end + expect(::Vulnerabilities::TriggerSecretDetectionFalsePositiveDetectionWorkflowWorker) + .to receive(:perform_async).with(anything) + + create(:vulnerability, :secret_detection, :high, author: user, project: project) + end + end + end end context 'when updating an existing vulnerability' do -- GitLab From d800735a3bfb8af5ecf3a288887bf3bea7f072ce Mon Sep 17 00:00:00 2001 From: SAM FIGUEROA Date: Wed, 17 Dec 2025 17:22:56 +0100 Subject: [PATCH 2/2] Add FF trigger for secret FP detection --- .../duo_secret_detection_false_positive.yml | 8 +++++++ ee/app/models/ee/vulnerability.rb | 24 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 config/feature_flags/wip/duo_secret_detection_false_positive.yml diff --git a/config/feature_flags/wip/duo_secret_detection_false_positive.yml b/config/feature_flags/wip/duo_secret_detection_false_positive.yml new file mode 100644 index 00000000000000..1ccdcdc857f351 --- /dev/null +++ b/config/feature_flags/wip/duo_secret_detection_false_positive.yml @@ -0,0 +1,8 @@ +--- +name: duo_secret_detection_false_positive +description: Enable Duo false positive detection for secret detection vulnerabilities +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/216844 +milestone: '18.8' +group: group::threat insights +type: wip +default_enabled: false diff --git a/ee/app/models/ee/vulnerability.rb b/ee/app/models/ee/vulnerability.rb index 5d3236887c09ff..00885608aa538f 100644 --- a/ee/app/models/ee/vulnerability.rb +++ b/ee/app/models/ee/vulnerability.rb @@ -387,8 +387,19 @@ def self.es_type def trigger_false_positive_detection return unless ::Feature.enabled?(:enable_vulnerability_fp_detection, group) - return unless sast? return unless high_or_critical_severity? + return if resolved? || dismissed? + + if sast? + trigger_sast_false_positive_detection + elsif secret_detection? + trigger_secret_detection_false_positive_detection + end + end + + private + + def trigger_sast_false_positive_detection return unless project.duo_sast_fp_detection_enabled user = project.first_owner || author @@ -399,6 +410,17 @@ def trigger_false_positive_detection end end + def trigger_secret_detection_false_positive_detection + return unless ::Feature.enabled?(:duo_secret_detection_false_positive, project) + + user = project.first_owner || author + return unless Ability.allowed?(user, :duo_workflow, project) + + run_after_commit_or_now do + ::Vulnerabilities::TriggerSecretDetectionFalsePositiveDetectionWorkflowWorker.perform_async(id) + end + end + def high_or_critical_severity? severity.in?(%w[critical high]) end -- GitLab