Skip to content

feat(policy): enforce a run's policy bundle per-run (allowlist + approval) - #120

Merged
prashar32 merged 1 commit into
mainfrom
feat/per-run-policy-enforcement
Jun 13, 2026
Merged

feat(policy): enforce a run's policy bundle per-run (allowlist + approval)#120
prashar32 merged 1 commit into
mainfrom
feat/per-run-policy-enforcement

Conversation

@prashar32

Copy link
Copy Markdown
Owner

Closes the seam the policy-bundle work (#28) left open: a run created under a bundle (policyRef) is now governed by that bundle — not just its budget.

What's enforced per-run

  • Tool allowlist — the MCP gateway enforces the run's bundle toolAllowlist for its tools/calls: a tool outside it is blocked, even if the global allowlist would allow it. An empty bundle allowlist falls back to the global one.
  • Approval rules — the bundle's approvalPolicy applies to that run on top of the global fail-safe gating. A bundle can add a requirement (e.g. name a normally read-only tool) but never silently drop the fail-closed gating of side-effecting tools.
  • The run's policyRef is persisted (migration 00006runs.policy_ref), so enforcement survives a daemon restart and applies even when the MCP gateway resolves a run by its run-id header.

How

  • policyRef threaded through RunRecord → runs manager (Create/View/record/reload) → POST /v1/runs.
  • approval.Gate.RequestUnder(ctx, req, policy) evaluates a supplied policy instead of the gate default; Request delegates to it.
  • The MCP gateway resolves the run's bundle from the store and applies its allowlist + approval policy.

Tests

  • Per-run allowlist: a bundle restricts a run's tools while the global allowlist is allow-all; a no-bundle run still uses global.
  • A bundle rule gates an otherwise read-only tool (proving RequestUnder with the bundle policy).
  • policyRef persists and is restored across a restart (Create → store → GetOrCreate).

go vet clean; full suite green. docs/POLICY.md gains a Per-run enforcement section.

Also fixes a CHANGELOG artifact from an earlier merge: a duplicated ## [0.6.0] header, with the post-release Ollama entry moved to [Unreleased] (it shipped after the v0.6.0 tag).

…oval)

A run created under a bundle (policyRef) is now governed by that bundle, not just
its budget — closing the seam the policy-bundle work left open.

- Persist policyRef on the run (migration 00006 adds runs.policy_ref; threaded
  through RunRecord, the runs manager, View/record, and reload — so it survives a
  restart and the MCP gateway sees it even for a reused run-id).
- MCP gateway: the run's bundle allowlist governs its tools/call (a tool outside it
  is blocked even if the global allowlist would allow it; empty bundle allowlist
  falls back to global). The bundle's approval rules apply on top of the global
  fail-safe gating — a bundle can ADD a requirement (e.g. naming a normally
  read-only tool) but never silently drop the fail-closed gating of side effects.
- approval.Gate.RequestUnder(ctx, req, policy) evaluates a supplied policy instead
  of the gate's default; Request delegates to it.

Tests: per-run allowlist (a bundle restricts a run while the global allowlist is
allow-all; a no-bundle run still uses global), a bundle rule gating an otherwise
read-only tool, and policyRef persist+reload across a restart. docs/POLICY.md gains
a "Per-run enforcement" section. Also collapses a duplicated [0.6.0] CHANGELOG
header left by an earlier merge and moves the post-release Ollama entry to
[Unreleased] where it belongs.
@prashar32
prashar32 merged commit 5e3513a into main Jun 13, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant