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.jsonThis 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.jsonThe 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:
-
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. -
CI pipeline config parser (
Gitlab::Ci::Config::Entry::Reports) — validates at workload execution time when the job YAML is processed byCi::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_reportsattribute - 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_workloadto readreport_artifactsfrom the external agent flow definition and pass it toWorkloadDefinitionwith a type guard
app/validators/json_schemas/ai_catalog/third_party_flow_v1.json
- Add
report_artifactsas an allowed property in the third-party flow JSON schema
Tests
- WorkloadDefinition: specs for
artifacts_reportsalone, combined withartifacts_paths, empty hash, and absence - RunService: specs for valid forwarding, non-Hash rejection, and absent
report_artifacts
Related
- Epic: &22756
- Issue: #605554 #605465
- Foundational flow equivalent (DAP path): commit 5a2a1527 (
StartWorkflowService/FoundationalFlow#security_report_artifacts)