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

[Backend] Add Conservative / Standard / Proacti... (#622469 - closed) • Gal Katz • 19.4

How to set up and validate locally

  1. Enable the feature flags in the Rails console:

    Feature.enable(:triage_and_remediation_profile)
  2. List the presets. All three should be returned, each with five triggers, and configuration (the sbom_ingested effective config) should differ per preset:

    query {
      group(fullPath: "<GROUP_PATH>") {
        availableSecurityScanProfiles(type: TRIAGE_AND_REMEDIATION) {
          id
          name
          scanType
          gitlabRecommended
          triggers
          configuration
        }
      }
    }

    Expect id values of gid://gitlab/Security::ScanProfile/triage_and_remediation_conservative, ..._standard and ..._proactive, and configuration.auto_remediation of high/5, medium/10 and info/major respectively.

  3. 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
      }
    }
  4. 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
      }
    }
  5. Confirm the lean storage in the Rails console. Conservative stores four configuration rows out of five triggers; vulnerability_enrichment matches 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" }
  6. 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
  7. Re-run step 4 to confirm attaching is idempotent: no new profile, trigger or configuration rows.

  8. 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 }
      }
    }
  9. 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.

Merge request reports

Loading
Loading