Recognize agentic analyzer workload pipelines for security ingestion
Summary
Teach the security ingestion layer to recognize Duo AI external agent workload pipelines as default-branch scans, so their security findings are promoted into the Vulnerability Report.
Problem
Workload pipelines run on synthetic refs (refs/workloads/<hash>) with source: :duo_workflow. pipeline.default_branch? checks ref == project.default_branch, so it returns false for workload pipelines even when their SHA matches the default branch HEAD. The security ingestion gate rejects them and findings never reach the Vulnerability Report.
Solution
Add default_branch_security_scan? to EE::Ci::Pipeline — a dedicated predicate that extends default_branch? for security ingestion. For regular pipelines it delegates to default_branch?. For duo_workflow workload pipelines, it checks SHA equality with the default branch HEAD (feature-flag gated).
Replace pipeline.default_branch? with pipeline.default_branch_security_scan? in the security ingestion path.
Changes
ee/app/models/ee/ci/pipeline.rb(+19 lines) —default_branch_security_scan?method, memoized withSafeRequestStoreee/app/services/security/ingestion.rb(1 line change) — usedefault_branch_security_scan?ee/app/services/security/project_tracked_contexts/find_or_create_service.rb(+3 lines) — usedefault_branch_security_scan?, bind workload context to default branch name instead of synthetic ref- Feature flag —
agentic_analyzer_security_ingestion(WIP, off by default). Rollout: #606048
How to test
Prerequisites
- GDK with rails-web, rails-background-jobs, and a CI runner
- !245049 (merged) applied (adds
artifacts_reportstoWorkloadDefinition) - An external agent seeded with
report_artifacts: { sast: [gl-sast-report.json] } - A project with a flow trigger configured for pipeline events
Steps
-
Enable the feature flag in the GDK rails console (
bundle exec rails console):Feature.enable(:agentic_analyzer_security_ingestion) -
Merge an MR into
mainon the test project. This triggers the external agent via the flow trigger. -
Wait for the workload pipeline to complete:
Project.find(<id>).all_pipelines.where(source: :duo_workflow).order(id: :desc).first.status -
Verify the new method works:
pipeline = Project.find(<id>).all_pipelines.where(source: :duo_workflow).order(id: :desc).first pipeline.default_branch? # => false (synthetic ref) pipeline.default_branch_security_scan? # => true (SHA matches) Security::Ingestion.ingest_pipeline?(pipeline) # => true -
Verify findings were ingested:
Vulnerability.where(project: Project.find(<id>)).each do |v| puts "#{v.severity} - #{v.title} (present_on_default_branch: #{v.present_on_default_branch})" endExpected: vulnerabilities with
present_on_default_branch: true. -
Disable the flag and repeat — workload pipeline should be rejected by
ingest_pipeline?.
Related
- Issue: #605465 / #603669
- Rollout: #606048
- Part 1 (workload report packaging): !245049 (merged)
- Epic: &22756