Fix compliance framework policy sync causing stale approval rules

What does this MR do and why?

Fixes race conditions in compliance framework policy sync that cause stale or missing ApprovalMergeRequestRule records to persist on open merge requests after rapid compliance framework changes.

Race conditions

  • Deduplication drops critical events: The policy sync worker deduplicates on (project, policy), discarding event data. When rapid framework changes produce competing events, the "removed" or "re-link" event is silently lost — producing orphaned or missing rules. Fix: ignore event data entirely and query current DB state to decide link vs. unlink.
  • Default branch changes can re-create deleted rules: Default branch changes trigger MergeRequests::Refresh::ApprovalWorker which iterates all project-level approval rules and upserts MR rules, running outside the policy sync flow. It can re-create rules that were just deleted by an unlink.
  • Concurrent INSERT during delete window: MergeRequests::Refresh::ApprovalWorker can load rules into memory before an unlink starts, then insert MR rules after the delete completes — the new rows are invisible to the deletion operation.
  • Default branch change blindly syncs inapplicable policies: Default branch change events sync all linked policies without checking scope applicability, perpetuating orphaned rules when the compliance framework handler was deduplicated away.

Database queries

#synchronize_approval_rules_from_target_project

-- https://console.postgres.ai/gitlab/gitlab-production-main/sessions/50814/commands/150678
SELECT
	"approval_project_rules".*
FROM
	"approval_project_rules"
WHERE
	"approval_project_rules"."project_id" = 80934902
	AND "approval_project_rules"."rule_type" = 2
	AND ("approval_project_rules"."approval_policy_rule_id" IN (
			SELECT
				"approval_policy_rule_project_links"."approval_policy_rule_id"
			FROM
				"approval_policy_rule_project_links"
			WHERE
				"approval_policy_rule_project_links"."project_id" = 80934902)
			OR "approval_project_rules"."approval_policy_rule_id" IS NULL);

References

Code references

Root cause (before this MR):

How to set up and validate locally

Prerequisites

  1. Create a new top-level group and a contained project
  2. On the project-level, create the develop branch and protect it
  3. On the group-level, navigate to Secure > Compliance center > Frameworks and create the SOC2 and HIPAA frameworks
  4. On the group-level, navigate to Secure > Policies and create the following merge request approval policies, substituting <FRAMEWORK_ID> respectively:
approval_policy:
  - name: SOC2
    enabled: true
    policy_scope:
      compliance_frameworks:
        - id: <FRAMEWORK_ID>
    actions:
      - type: require_approval
        approvals_required: 1
        role_approvers:
          - owner
    rules:
      - type: any_merge_request
        branch_type: protected
        commits: any
approval_policy:
  - name: HIPAA
    enabled: true
    policy_scope:
      compliance_frameworks:
        - id: <FRAMEWORK_ID>
    actions:
      - type: require_approval
        approvals_required: 1
        role_approvers:
          - owner
    rules:
      - type: any_merge_request
        branch_type: protected
        commits: any
  1. Open a new merge request on the project
  2. On the group-level or project-level, navigate to Secure > Compliance center > Frameworks and assign one of the two frameworks to the project
  3. Verify the merge request has only the HIPAA approval rule
  4. Swap frameworks via the compliance dashboard
  5. Change the project's default branch to increase Sidekiq contention
  6. Swap back both frameworks
  7. Reload the MR: it may show both rules (stale orphan) or zero rules (missing re-link).

Note: Since this is non-deterministic, you can use this reproduction script to attempt to trigger the race condition.

Verifying the fix

  1. Enable the feature flag:

    Feature.enable(:scoped_compliance_framework_policy_sync)
  2. Repeat the steps above and verify that stale rules no longer persist.

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 Dominic Bauer

Merge request reports

Loading