Add configurable profile create mutation

What does this MR do and why?

Introduces ScanProfiles::Create mutation and ScanProfiles::CreateScanProfileService, a GQL write path to create a Security::ScanProfile together with its triggers and per-trigger configuration in a single atomic call.

The service creates the profile, its triggers, and one ScanProfiles::Configuration row per configured trigger inside a transaction. Per-scan-type configuration is typed via a oneOf input union and each trigger's configuration is attached through the existing FK. Also adds a new create_security_scan_profiles ability (for Security Manager, Maintainer, Owner, Admin) enforced by the mutation, a per-namespace cap of 20 profiles, and an allowed-trigger matrix per scan type.

Changelog: added
EE: true

[Backend] Add configuration write path (#605765 - closed) • Gal Katz

Query plan

Raw SQL
 SELECT COUNT(*)
 FROM "security_scan_profiles" 
 WHERE "security_scan_profiles"."namespace_id" = 9970
Plan

See details here

 Aggregate  (cost=3.36..3.37 rows=1 width=8) (actual time=1.777..1.778 rows=1 loops=1)
   Buffers: shared hit=3 read=6 dirtied=1
   WAL: records=1 fpi=1 bytes=6445
   I/O Timings: read=1.687 write=0.000
   ->  Index Only Scan using index_security_scan_profiles_namespace_scan_type_name on public.security_scan_profiles  (cost=0.28..3.35 rows=4 width=0) (actual time=1.238..1.770 rows=4 loops=1)
         Index Cond: (security_scan_profiles.namespace_id = 9970)
         Heap Fetches: 3
         Index Searches: 1
         Buffers: shared hit=3 read=6 dirtied=1
         WAL: records=1 fpi=1 bytes=6445
         I/O Timings: read=1.687 write=0.000
Settings: effective_cache_size = '338688MB', jit = 'off', work_mem = '100MB', random_page_cost = '1.5', seq_page_cost = '4'
Query ID: -2720531705532250424

How to set up and validate locally

  1. Enable the configurable_security_scan_profiles FF:

    Feature.enable(:configurable_security_scan_profiles)

  2. Choose a root group g.

  3. Use this mutation to create a profile with a typed configuration attached to its trigger:

mutation {
  securityScanProfileCreate(
    input: {
      namespaceId: "gid://gitlab/Group/<g.id>"
      scanType: DEPENDENCY_SCANNING_POST_PROCESSING
      name: "DS-PP"
      triggers: [
        {
          triggerType: SBOM_INGESTED
          configuration: {
            dependencyScanningPostProcessing: {
              autoRemediation: {
                enabled: true
                cooldown: 5
                severityLevel: HIGH
                upgradePolicy: MINOR
              }
            }
          }
        }
      ]
    }
  ) {
    scanProfile {
      id
      name
      scanType
      triggers
      configuration
    }
    errors
  }
}

Expect a persisted profile whose sbom_ingested trigger carries the configuration. Confirm:

Security::ScanProfile.last.scan_profile_triggers.map { |t| [t.trigger_type, t.configuration&.configuration] }
  1. Use these mutations to validate the error handling:

    a) No triggers → "A scan profile must have at least one trigger."
    mutation {
      securityScanProfileCreate(
        input: {
          namespaceId: "gid://gitlab/Group/<g.id>"
          scanType: SAST
          name: "x"
          triggers: []
        }
      ) {
        errors
      }
    }
    b) Trigger not allowed for scan type → "Trigger type is not allowed for sast scan profiles"
    mutation {
      securityScanProfileCreate(
        input: {
          namespaceId: "gid://gitlab/Group/1<g.id>"
          scanType: SAST
          name: "x"
          triggers: [{ triggerType: SBOM_INGESTED }]
        }
      ) {
        errors
      }
    }
    c) Config member does not match scan type → top-level ArgumentError
    mutation {
      securityScanProfileCreate(
        input: {
          namespaceId: "gid://gitlab/Group/<g.id>"
          scanType: SAST
          name: "x"
          triggers: [
            {
              triggerType: DEFAULT_BRANCH_PIPELINE
              configuration: {
                dependencyScanningPostProcessing: { autoRemediation: { enabled: true } }
              }
            }
          ]
        }
      ) {
        errors
      }
    }

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.

Edited by Gal Katz

Merge request reports

Loading