mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-06-09 01:35:18 +02:00
policy: chassis fan-out — _as variants on the remaining 6 writers (MR-722) (#103)
PR #102 wired apply_schema_as. This PR completes the chassis-side coverage so every public mutating engine entry point hits the same Omnigraph::enforce(action, scope, actor) gate regardless of transport: - mutate_as → enforce(Change, Branch(branch), actor) - load_as → enforce(Change, Branch(branch), actor) - ingest_as → enforce(Change, Branch(branch), actor); also threads actor through the implicit branch_create_from_as so fresh-branch ingest correctly hits BranchCreate too - branch_create_as → enforce(BranchCreate, TargetBranch(name), actor) - branch_create_from_as → enforce(BranchCreate, BranchTransition { source, target }, actor) - branch_delete_as → enforce(BranchDelete, TargetBranch(name), actor) - branch_merge_as → enforce(BranchMerge, BranchTransition { source, target }, actor) Three new _as variants for branch ops (create, create_from, delete) that had no actor surface before; existing actor-less variants delegate with actor=None so the no-policy path is a strict no-op. HTTP handlers updated to thread the resolved actor into the new _as variants for branch_create and branch_delete (was previously dropped). 14 new SDK chassis tests (one allow + one deny pair per wired writer); the existing 4 apply_schema_as tests stay. All 18 pass. docs/user/policy.md updated to describe engine-wide enforcement and the coarse-vs-fine layer split (engine = action gate, query layer per-row = MR-725 future). AGENTS.md capability matrix updated to match. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
9973683261
commit
da42beec41
8 changed files with 437 additions and 32 deletions
|
|
@ -11,9 +11,7 @@ OmniGraph integrates AWS Cedar (`cedar-policy = 4.9`) for ABAC.
|
|||
5. `branch_create`
|
||||
6. `branch_delete`
|
||||
7. `branch_merge`
|
||||
8. `run_publish`
|
||||
9. `run_abort`
|
||||
10. `admin` — reserved
|
||||
8. `admin` — reserved for policy-management surfaces (hot reload, audit log, approvals). No call site today; see MR-724 for the reservation rationale.
|
||||
|
||||
## Scope kinds
|
||||
|
||||
|
|
@ -39,9 +37,43 @@ Each rule must use exactly one of `branch_scope` or `target_branch_scope`.
|
|||
- `omnigraph policy test` — run cases in `policy.tests.yaml`, exit 1 on any expectation mismatch.
|
||||
- `omnigraph policy explain --actor … --action … [--branch …] [--target-branch …]` — show decision and matched rule.
|
||||
|
||||
## Server enforcement
|
||||
## Enforcement
|
||||
|
||||
Every mutating endpoint calls `authorize_request()` *before* the handler runs; decisions are logged with actor / action / branch / outcome / matched rule.
|
||||
Policy is a property of the **engine**, not the transport. Every mutating
|
||||
write — `mutate_as`, `load_as`, `ingest_as`, `apply_schema_as`,
|
||||
`branch_create_as`, `branch_create_from_as`, `branch_delete_as`,
|
||||
`branch_merge_as` — calls `Omnigraph::enforce(action, scope, actor)` at
|
||||
the head of the method. The gate fires identically whether the call
|
||||
originates from the HTTP server, the CLI, or an embedded SDK consumer.
|
||||
When no `PolicyChecker` is installed (the dev/embedded default) the gate
|
||||
is a strict no-op; when one is installed and the call site forgets to
|
||||
thread an actor through, the gate fails closed rather than silently
|
||||
bypassing.
|
||||
|
||||
Server-side, `authorize_request()` still runs at the HTTP boundary —
|
||||
that's where actor identity is resolved from the bearer token and where
|
||||
admission control / per-actor rate limits live. Engine-layer enforcement
|
||||
is the **defense in depth** layer: it catches CLI direct-engine writes,
|
||||
embedded SDK consumers, and any future transport that hasn't (or won't)
|
||||
re-implement HTTP's authorize_request. Both layers consult the same
|
||||
Cedar policy via the same `PolicyChecker` trait, so decisions cannot
|
||||
disagree.
|
||||
|
||||
## Coarse vs. fine enforcement
|
||||
|
||||
There are two enforcement points, each with non-overlapping
|
||||
responsibilities:
|
||||
|
||||
| Layer | Question it answers | Where it fires |
|
||||
|---|---|---|
|
||||
| **Engine-layer (coarse)** | Can this actor invoke this action against this branch / branch-transition? | `Omnigraph::enforce(action, scope, actor)` at the head of every `_as` writer; one Cedar decision per call. |
|
||||
| **Query-layer (fine)** | For the rows / types this action actually touches, which can the actor see or modify? | Per-row predicates pushed into DataFusion at plan time. **Not yet implemented — see MR-725.** |
|
||||
|
||||
The engine-layer gate keeps `ResourceScope` deliberately at branch
|
||||
granularity (`Graph`, `Branch`, `TargetBranch`, `BranchTransition`).
|
||||
Per-type and per-row authority is the query-layer's job; conflating them
|
||||
in `ResourceScope` would create two places per-type policy could be
|
||||
evaluated and a drift surface between them.
|
||||
|
||||
## Actor identity (signed-claim-only)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue