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_BRANCH variable). 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? reads DUO_WORKFLOW_SOURCE_BRANCH from the first build's yaml_variables. StartWorkflowService#resolve_source_branch sets it server-side, with the same fallback as WorkloadBranchService (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 info log 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). WorkloadBranchService and resolve_source_branch resolve 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 through StartWorkflowService.
  • 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.

Edited by Meir Benayoun

Merge request reports

Loading
Loading