Add triage and remediation presets values
What does this MR do and why?
Introduces three GitLab-provided Triage and Remediation scan profile presets - Conservative, Standard and Proactive.
This builds on the preceding MR, which made a scan profile's identity its preset_key rather than its scan_type, so a single scan type can offer several default presets.
Standard is set as Configuration::DEFAULTS[:triage_and_remediation], making it the effective baseline. Each preset declares its full intended values rather than a hand-written diff, and the existing Security::ScanProfiles::Configuration.strip_defaults computes what actually gets stored for each. Standard therefore persists zero configuration rows, and Conservative and Proactive persist only their diff from it; reads reconstruct the full values through Configuration.effective_for. Declaring full values keeps the constants readable against the product table while storage stays lean.
Standard is the baseline and stores nothing:
| Trigger | Conservative | Standard | Proactive |
|---|---|---|---|
vulnerability_enrichment |
run_mode: auto |
run_mode: auto |
run_mode: auto |
sast_vulnerability_resolution |
high, manual |
medium, auto |
info, auto |
sast_false_positive |
high, manual |
medium, auto |
info, auto |
secret_detection_false_positive |
run_mode: manual |
run_mode: auto |
run_mode: auto |
sbom_ingested |
high, minor, 5 MRs |
medium, minor, 10 MRs |
info, major, 10 MRs |
Security::ScanProfiles::FindOrCreateService now persists a trigger together with its configuration, which it previously did not do at all.
Gated by the triage_and_remediation_profile WIP flag, disabled by default, at three namespace-scoped sites: the group profile list, attaching a preset, and creating a custom profile of this scan type.
The values used here are based on the table in this comment.
Changelog: added
EE: true
Related issue
[Backend] Add Conservative / Standard / Proacti... (#622469 - closed) • Gal Katz • 19.4
How to set up and validate locally
-
Enable the feature flags in the Rails console:
Feature.enable(:triage_and_remediation_profile) -
List the presets. All three should be returned, each with five triggers, and
configuration(thesbom_ingestedeffective config) should differ per preset:query { group(fullPath: "<GROUP_PATH>") { availableSecurityScanProfiles(type: TRIAGE_AND_REMEDIATION) { id name scanType gitlabRecommended triggers configuration } } }Expect
idvalues ofgid://gitlab/Security::ScanProfile/triage_and_remediation_conservative,..._standardand..._proactive, andconfiguration.auto_remediationofhigh/5,medium/10andinfo/majorrespectively. -
Resolve a single preset by its virtual Global ID:
query { securityScanProfile(id: "gid://gitlab/Security::ScanProfile/triage_and_remediation_proactive") { id name scanType triggers configuration } } -
Attach a preset to a project. This is the call that persists it:
mutation { securityScanProfileAttach(input: { securityScanProfileId: "gid://gitlab/Security::ScanProfile/triage_and_remediation_conservative" projectIds: ["gid://gitlab/Project/<PROJECT_ID>"] }) { errors } } -
Confirm the lean storage in the Rails console. Conservative stores four configuration rows out of five triggers;
vulnerability_enrichmentmatches the baseline so it stores none:namespace = Group.find_by_full_path('<GROUP_PATH>') profile = Security::ScanProfile.by_namespace(namespace) .by_name('Triage and Remediation (Conservative)').first profile.scan_profile_triggers.count # => 5 profile.configurations.count # => 4 profile.scan_profile_triggers.includes(:configuration).each do |trigger| puts "#{trigger.trigger_type}: #{trigger.configuration&.configuration.inspect}" end # sbom_ingested: {"auto_remediation"=>{"severity_level"=>"high", "open_merge_requests_limit"=>5}} # sast_false_positive: {"run_mode"=>"manual", "severity_level"=>"high"} # sast_vulnerability_resolution: {"run_mode"=>"manual", "severity_level"=>"high"} # secret_detection_false_positive: {"run_mode"=>"manual"} # vulnerability_enrichment: nil # Defaults are merged back in on read: profile.effective_configuration_for('sast_vulnerability_resolution') # => { severity_level: "high", run_mode: "manual" } profile.effective_configuration_for('vulnerability_enrichment') # => { run_mode: "auto" } -
Attach Standard and confirm it persists five triggers and zero configuration rows, while still reading back the full baseline:
Security::ScanProfiles::FindOrCreateService.execute( namespace: namespace, identifier: 'triage_and_remediation_standard' ).payload[:scan_profile].then do |standard| puts standard.scan_profile_triggers.count # => 5 puts standard.configurations.count # => 0 puts standard.effective_configuration_for('sbom_ingested').inspect # => {auto_remediation: {cooldown: 7, severity_level: "medium", upgrade_policy: "minor", open_merge_requests_limit: 10}} end -
Re-run step 4 to confirm attaching is idempotent: no new profile, trigger or configuration rows.
-
Confirm the flag gates creation of a custom profile of this scan type. With the flag disabled this returns a resource-not-available error:
Feature.disable(:triage_and_remediation_profile)mutation { securityScanProfileCreate(input: { namespaceId: "gid://gitlab/Group/<GROUP_ID>" scanType: TRIAGE_AND_REMEDIATION name: "My triage profile" description: "Custom triage profile" triggers: [{ triggerType: SBOM_INGESTED }] }) { errors scanProfile { id name } } } -
With the flag still disabled, re-run the list query from step 2. It should return an empty list, and attaching a preset (step 4) should fail.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.