Skip rule diffing for policy types without rules

What does this MR do and why?

Policy types without rules (pipeline execution and pipeline execution schedule) now always get an empty rules_diff in PolicyComparer. This stops Security::PersistSecurityPoliciesWorker from failing on policies that have a stray rules: key.

The JSON schemas for these two policy types don't set additionalProperties: false, so a policy YAML with a rules: key passes validation.

  • On create, Security::Policy.upsert_policy skips rules because supports_policy_rules? is false.
  • On every later update, PolicyComparer#compare_rules compares the YAML rules against no rules in the database. It reports them as created rules.
  • UpdateSecurityPoliciesService#create_new_rules then calls Security::Policy#upsert_rule. Security::PolicyRule.for_policy_type raises ArgumentError: unrecognized policy_type.

The worker fails. Changes to pipeline execution policies roll back, and the policy types persisted after them (vulnerability management, pipeline execution schedule, dependency firewall) are skipped. Every retry or resync fails again.

On GitLab.com this was the most common failure in security policy management Sidekiq jobs: about 13.4k failed jobs in 7 days, roughly half of all failures in that feature category. They came from a handful of projects.

The fix: compare_rules returns early when db_policy.supports_policy_rules? is false. Every consumer of rules_diff goes through this comparer, so one guard covers all of them (3 lines in ee/lib/security/security_orchestration_policies/policy_comparer.rb).

I did not tighten the JSON schemas. That would reject YAML that is accepted today.

Tests:

  • policy_comparer_spec.rb: a table-driven spec covers both policy types with a stray rules: key and expects an empty rules diff.
  • persist_policy_service_spec.rb: persists a pipeline execution policy with a stray rules: key, then updates it, and expects the update to succeed. Before the fix it raised the same ArgumentError as production.

No database changes, no feature flag (small fix to an error path), no UI or documentation changes.

References

No linked issue.

Screenshots or screen recordings

No UI changes. The before/after behavior is in the table below.

How to set up and validate locally

  1. Create a security policy project with .gitlab/security-policies/policy.yml containing a pipeline_execution_policy that has an extra rules: list, for example:
    rules:
      - type: pipeline
        branches: [main]
    Link the policy project to a project.
  2. Edit the policy, for example change description, and merge or commit the change. To sync right away, run this in the Rails console:
    Security::SyncScanPoliciesWorker.perform_async(<configuration_id>)
  3. Check log/sidekiq.log and the stored policy.
Before After
Security::PersistSecurityPoliciesWorker job_status is fail with ArgumentError: unrecognized policy_type Job succeeds
PolicyUpdatedEvent rules_diff Not published, the job fails first Empty
Security::Policy description Keeps the old description Shows the new description

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.

Merge request reports

Loading
Loading