Ingest BLSA default-branch scans that finish after a newer push
What does this MR do and why?
Fixes lost business logic security scan findings when someone pushes to the default branch while a scan is running.
- The bug: a default-branch scan only counted as one if its commit was still the default-branch HEAD when it finished. A push during a long scan made that check fail. The findings were then dropped without a log line.
- The fix: when the HEAD check fails, look at which branch the scan was dispatched for (the workload job's
DUO_WORKFLOW_SOURCE_BRANCHvariable). If it was the default branch, the scan still counts. This matches regular pipelines:Ci::Pipeline#default_branch?checks the ref, not the SHA. - Logging: every workload pipeline that fails the HEAD check now logs the decision with a reason.
Part of the BLSA split of !246889. Targets master directly; it doesn't depend on !257196 (merged). Tracker: https://gitlab.com/gitlab-org/gitlab/-/work_items/630266
Verified: in a sandbox, a scan where main moved mid-run still had all 4 findings ingested into the vulnerability report.
Behavior
All rows assume a duo_workflow workload pipeline and the agentic_analyzer_security_ingestion flag on, unless stated otherwise.
| Case | Before | After |
|---|---|---|
| Default-branch scan, no push during the scan | Ingested | Ingested (no log) |
| Default-branch scan, push during the scan | Dropped, no log | Ingested, logs default_branch_moved_since_dispatch |
| Scan dispatched for another branch | Not a default-branch scan | Same, logs not_dispatched_for_default_branch |
| Older workload with no dispatch branch variable | Not a default-branch scan | Same, logs dispatch_branch_unknown |
| Flag off | Not a default-branch scan | Same, no log |
| Non-workload pipeline | Uses Ci::Pipeline#default_branch? only |
Same, no log |
"Counts as a default-branch scan" drives three things, not just ingestion:
Security::Ingestion.ingest_pipeline?(vulnerability report ingestion).ProjectTrackedContexts::FindOrCreateService.from_pipeline(binds to the default-branch tracked context).- The pipeline-completion hook in
EE::Ci::Pipeline(analyzer status and scan profile status workers).
Review focus
- Dispatch-intent source:
dispatched_for_default_branch?readsDUO_WORKFLOW_SOURCE_BRANCHfrom the first build'syaml_variables.StartWorkflowService#resolve_source_branchsets it server-side, with the same fallback asWorkloadBranchService(blank or missing branch means the default branch). - Queries: the fallback runs only when the flag is on and the SHA is not HEAD. That includes every feature-branch workload pipeline. It costs two reads (first build, then its job definition), memoized per request.
Backward compatibility / impact
- No schema change and no new flag. Everything stays behind
agentic_analyzer_security_ingestion. - Workloads without the variable (older pipelines) behave as before: not a default-branch scan.
- New
infolog line:Agentic analyzer default-branch scan check. It can appear once per pipeline in each worker that checks it.
Design decisions
- A job variable is the record of dispatch intent. It needs no migration. The cost is an implicit contract with
StartWorkflowService. A dedicated column would be more explicit. - A default branch renamed mid-scan drops the scan (logged). The variable holds the old name. A regular pipeline on the old ref behaves the same.
Known limitations
- Dispatch race (not introduced here).
WorkloadBranchServiceandresolve_source_branchresolve the source branch separately. If the requested branch is deleted between the two calls, the variable says "default branch" but the ref came from the deleted branch. Possible follow-up: pass the resolved ref throughStartWorkflowService. - An older SHA can be ingested last. A pushed-over scan that finishes after a newer default-branch pipeline takes the latest-pipeline slot for ingestion. Regular default-branch pipelines already behave this way on master.
Files in this MR (4)
- Logic:
ee/app/services/security/agentic_analyzer.rb(dispatch_source_branch,log_default_branch_scan) - Comment only:
ee/app/services/security/project_tracked_contexts/find_or_create_service.rb - Specs:
ee/spec/services/security/agentic_analyzer_spec.rb(moved-since-dispatch, other branch, flag off, other source, non-workload) - Specs:
ee/spec/services/security/ingestion_spec.rb(ingest_pipeline?for a moved default branch)
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.