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:
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.scan_result_policies(akascan_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:
- !231013 (merged) — Foundation (this MR):
ApprovalPolicySourceadapter, feature flag,ApprovalRuleLikeintegration - !231014 (merged) — Service callers: Migrate ~10 services/libs from
scan_result_policy_readtoapproval_policy_source - !231015 — Project queries: Flag-aware
has_approval_policy_rules?andapproval_policy_rules_targeting_commitson Project - !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 actionsMR 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