Add the policy engine evaluation service and action dispatch

What does this MR do and why?

Adds Govern::PolicyEngine::EvaluateService, the one seam every settings trigger calls. It sends the context document to Gitlab::Glaz::GovernPolicyEngine#evaluate, records one Govern::PolicyEvaluation with its violations per decision, derives the verdict, and dispatches the matched actions.

An engine fault fails closed: the result is undecidable and the service dispatches nothing. A fault after the engine returns propagates instead, because a decision may already be recorded and its audit event written, so an undecidable result would hide it.

The verdict follows the proto. Any undecided policy makes the evaluation undecidable, any decision with a gating action denies, everything else allows. Dispatch goes through ActionCatalog, which names the executor an action runs on and whether it needs enforce mode. Callers name the trigger they evaluate; which actions a trigger accepts is the policy store's save-time check, so dispatch makes no second ruling.

It also adds the two value objects every enforcement point reads: SettingValidationRule for the target a policy authored, and SettingDrift for the setting a violation reports. They sit here rather than with the first consumer that needed them, so the write-back executor, the conflict check and the settings fence stay independent of one another.

Merge plan (nested = depends on parent, siblings = parallel)

Nothing calls the service yet. The workers of https://gitlab.com/gitlab-org/gitlab/-/work_items/630154 call it next. The code comes from the prototype in !259574, now with specs. No changelog entry, because security_policies_v2 defaults to off.

References

Screenshots or screen recordings

Backend-only change, no UI.

Before After

How to set up and validate locally

  1. Enable the experiment and point the engine at a running Policy Store:

    Feature.enable(:security_policies_v2)
    ApplicationSetting.current.update!(policy_store_experiment_enabled: true)
    ENV['GLAZ_POLICY_STORE_URL'] = 'http://localhost:9000'
  2. Create a policy with the project.after_create trigger through the Policy Store API, then evaluate a project against it:

    Govern::PolicyEngine::EvaluateService.new(
      subject: Project.first, actor: User.first, trigger: 'project.after_create'
    ).execute
  3. Inspect Govern::PolicyEvaluation.last and, for a matched log_audit_trail action, the newest audit event.

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
Loading