Add ApprovalPolicySource adapter to deprecate scan_result_policy_reads

What does this MR do and why?

Background

When an MR approval policy is created, its data are stored in two places:

  1. security_policies + approval_policy_rules — the source of truth, written when policies are synced from YAML. Contains the full policy definition (rules, actions, settings) in structured columns and JSONB content.
  2. scan_result_policies (aka scan_result_policy_reads) — a denormalized legacy read cache created for historical reasons. Extracts individual fields (license_states, fallback_behavior, role_approvers, etc.) into dedicated columns for faster reads.

Over time, every new policy feature required adding columns to both tables and keeping them in sync. This duplication causes:

  • Maintenance overhead: every new policy attribute needs a migration on scan_result_policies, a sync step, and tests for both paths.
  • Data consistency risks: if the sync drifts, the two tables disagree on what a policy says.

Solution

We should deprecate calling scan_result_policies and introduce an adapter layer (ApprovalPolicySource) that sits between the application code and the two data sources. Behind a feature flag, it transparently switches reads from the legacy scan_result_policies table to the canonical approval_policy_rules + security_policies tables. No caller needs to know which source is active — the adapter handles the routing.

Once the flag is fully rolled out and the legacy reads are removed, we can stop depending to scan_result_policies entirely and eventually drop the table.

This MR (part 1 of 4) builds the adapter and wires it into the model layer. Subsequent MRs migrate service callers, project-level queries, and violation FK handling:

  1. !231013 (merged) — Foundation (this MR): ApprovalPolicySource adapter, feature flag, ApprovalRuleLike integration
  2. !231014 (merged) — Service callers: Migrate ~10 services/libs from scan_result_policy_read to approval_policy_source
  3. !231015 — Project queries: Flag-aware has_approval_policy_rules? and approval_policy_rules_targeting_commits on Project
  4. !231016 — Violation FK handling: Flag-gated violation create/delete using approval_policy_rule_id

References

Screenshots or screen recordings

Before After

How to set up and validate locally

# Enable the feature flag
Feature.enable(:deprecate_scan_result_policies)

# The adapter should now read from ApprovalPolicyRule instead of ScanResultPolicyRead
rule = ApprovalMergeRequestRule.last
source = rule.approval_policy_source
source.policy_name("fallback") # reads from security_policy.name
source.fail_open?              # reads from security_policy.approval_policy.fallback_behavior
source.role_approvers          # reads from security_policy actions

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.

Related to #510281

Edited by Sashi Kumar Kumaresan

Merge request reports

Loading