Re-evaluate approval policies on vulnerability triage
Problem
Issue #560563 (closed) (the "target-branch triage" gap): when a vulnerability is triaged (dismissed / resolved) through the Vulnerability Report, the merge request approval policy is not re-evaluated. The merge request stays blocked until a new pipeline runs.
This is most visible when a CVE database update introduces findings on the default/target branch: those findings can only be triaged in the Vulnerability Report (not the MR security widget), so the policy never re-evaluates and the MR stays blocked despite everything being triaged.
Root cause
Only the MR-security-widget path (Security::Findings::DismissService) schedules SyncFindingsToApprovalRulesWorker. The vulnerability-level services (Vulnerabilities::DismissService, Vulnerabilities::BulkDismissService, and the Vulnerabilities::BaseStateTransitionService subclasses such as ResolveService) change vulnerability state but never trigger policy re-evaluation.
Change
- Add a shared concern
Security::ScanResultPolicies::SyncOnVulnerabilityStateChangethat schedulesSyncFindingsToApprovalRulesWorkerfor the project'slatest_ingested_security_pipeline(nil-guarded). - Include it in
Vulnerabilities::DismissService,Vulnerabilities::BaseStateTransitionService(coversResolveService, Confirm, RevertToDetected), andVulnerabilities::BulkDismissService(per project, inside the existingafter_commit). - Performance: the worker deduplicates on
pipeline_id(until_executing, including_scheduled: true), so bulk triage within a project collapses to a single re-evaluation.
Testing
- Specs added for dismiss, resolve, and bulk-dismiss asserting the worker is scheduled with the project's pipeline id, plus a nil-pipeline guard case.
dismiss_service_spec+resolve_service_spec+confirm_service_spec+revert_to_detected_service_specpass locally (no regression from the base-class change). The bulk-dismiss example runs under:elasticin CI.
Known limitation / follow-up
Resolution of target-branch MRs flows through SyncFindingsToApprovalRulesService#merge_requests_targeting_pipeline_ref, which is gated on pipeline.latest?. latest_ingested_security_pipeline is normally the latest default-branch pipeline, so this resolves in the common case; relaxing that guard (mirroring the source-branch handling in !240937 (closed)) is a separate follow-up.
References
- Related to #560563 (closed)
- Part of a series of fixes for that issue, alongside !240608 (closed) and !240937 (closed)