Support report_artifacts in external agent workload definitions

Summary

Add artifacts_reports support so external agents can declare security report artifacts (e.g. gl-sast-report.json) in their flow definition. The CI pipeline produced by the workload will then upload them as proper report artifacts, enabling the MR security widget to display findings.

Example

A complete external agent flow definition with report_artifacts:

injectGatewayToken: true
image: my-scanner:latest
commands:
  - export ANTHROPIC_AUTH_TOKEN=$AI_...EN
  - export ANTHROPIC_CUSTOM_HEADERS="$AI_FLOW_AI_GATEWAY_HEADERS"
  - export ANTHROPIC_BASE_URL="https://cloud.gitlab.com/ai/v1/proxy/anthropic"
  - echo "Running security scan on project"
  - my-scanner --project-dir . --output /tmp/scan-report.json
  - cp /tmp/scan-report.json gl-sast-report.json
report_artifacts:
  sast:
    - gl-sast-report.json

This produces a workload CI job equivalent to:

my-agent-job:
  image: my-scanner:latest
  stage: build
  script:
    - export ANTHROPIC_AUTH_TOKEN=$AI_...EN
    - export ANTHROPIC_CUSTOM_HEADERS="$AI_FLOW_AI_GATEWAY_HEADERS"
    - export ANTHROPIC_BASE_URL="https://cloud.gitlab.com/ai/v1/proxy/anthropic"
    - echo "Running security scan on project"
    - my-scanner --project-dir . --output /tmp/scan-report.json
    - cp /tmp/scan-report.json gl-sast-report.json
  artifacts:
    reports:
      sast:
        - gl-sast-report.json

The report_artifacts keys map directly to CI/CD report types. Common report types:

Key Report type Example file
sast SAST gl-sast-report.json
dependency_scanning Dependency Scanning gl-dependency-scanning-report.json
secret_detection Secret Detection gl-secret-detection-report.json
container_scanning Container Scanning gl-container-scanning-report.json

Validation approach

Validation happens at two layers, each with a clear purpose:

  1. JSON schema (third_party_flow_v1.json) — validates at catalog seeding time. Catches obviously wrong definitions (wrong types, empty arrays, oversized paths) before they are stored and ever run. Constraints: maxProperties: 20, minItems: 1, maxItems: 20, minLength: 1, maxLength: 255.

  2. CI pipeline config parser (Gitlab::Ci::Config::Entry::Reports) — validates at workload execution time when the job YAML is processed by Ci::CreatePipelineService. This is the authoritative validation layer — it enforces allowed report type keys, value formats, and all CI-specific constraints. Invalid entries cause a loud pipeline creation failure with a clear error message (e.g. reports config contains unknown keys: evil_report), which is preferable to silently dropping misconfigured entries.

RunService#execute_workload intentionally applies only a type guard (is_a?(Hash)) and passes the value through to WorkloadDefinition, delegating all content validation to CI's existing parser. This avoids duplicating validation logic and ensures agent authors get clear error feedback on misconfiguration.

Changes

lib/ci/workloads/workload_definition.rb

  • Add artifacts_reports attribute
  • Emit artifacts: { reports: ... } in the CI job hash when present
  • Works alongside existing artifacts_paths — both can be set independently or together

ee/app/services/ai/flow_triggers/run_service.rb

  • Wire execute_workload to read report_artifacts from the external agent flow definition and pass it to WorkloadDefinition with a type guard

app/validators/json_schemas/ai_catalog/third_party_flow_v1.json

  • Add report_artifacts as an allowed property in the third-party flow JSON schema

Tests

  • WorkloadDefinition: specs for artifacts_reports alone, combined with artifacts_paths, empty hash, and absence
  • RunService: specs for valid forwarding, non-Hash rejection, and absent report_artifacts
  • Epic: &22756
  • Issue: #605554 #605465
  • Foundational flow equivalent (DAP path): commit 5a2a1527 (StartWorkflowService / FoundationalFlow#security_report_artifacts)
Edited by Mher Tolpin

Merge request reports

Loading
Loading