Skip to main content

The hand-offs: extract, govern, evaluate, expose

Objective

Explain the hand-off at each seam of the pipeline (extraction to Git, Git to signed bundle, bundle to PDP, PDP to MCP query) and author the allow rules for the policy the fabric enforces.

Concept

An architect's job is the seams, not the boxes. Each hand-off is where a bad assumption causes an outage or a leak, so name what crosses each one.

Seam 1: application code to Rego in Git (Zift)

Zift's two-pass scan finds authorization scattered across handlers and middleware and zift extract rewrites it as a single default-deny Rego policy. In the lab, three embedded checks became three parts of the policy:

  • a requireRole(...) middleware became the role_permissions map,
  • an inline if rec.owner_id == user.id guard became the ownership rule,
  • and a classification check on restricted records became the restricted path.

What crosses the seam is intent: the app stops deciding and starts asking. The externalization percentage Zift reports is how much of the app's authorization now lives in this file rather than in code.

Seam 2: Git to signed bundle (Writ)

The extracted policy is reviewed and merged like any code. On merge, Writ auto-builds it into a signed bundle and scopes it in the entity hierarchy (tenant, org, system, app). What crosses this seam is a chain of custody: reviewed in Git, built and signed by Writ, verifiable by the PDP before it loads. Writ then promotes the same signed bytes dev to staging to prod; rollback redeploys a prior commit_sha.

Seam 3: bundle to PDP (OPA / Enterprise OPA)

The PDP pulls the bundle, verifies the signature, and evaluates the policy at the PEP on every request. This is the only stage on the request path. What crosses the seam is a decision: input in, allow or deny out, under a latency budget (roughly sub-5ms to under 50ms depending on topology).

Seam 4: PDP to MCP query (Herald)

Herald exposes the same authorization query over MCP so callers, including AI agents, can ask "is this allowed?" and get a decision. Herald federates context from systems of record into input: in the lab, the HRIS employment_status and the ITSM change_ticket.status. What crosses this seam is context: the signals the policy needs but the caller does not hold. Herald fronts the query; the PDP still decides.

Hands-on lab

Now author the rules. Open ../lab/policy.rego and implement the TODO(learner) block: three allow if { ... } rules that OR together on top of default allow := false. Every rule requires an active employee (input.subject.employment_status == "active", the HRIS signal from seam 4).

  1. Role + tenancy — the role permits the action (input.action in role_permissions[input.subject.role], the map from seam 1), same org (input.subject.org == input.resource.org), resource below restricted (input.resource.classification in {"public", "internal"}).
  2. Ownership — action read or write and input.resource.owner_id == input.subject.id, regardless of org. No delete on this path.
  3. Restricted — like rule 1 but for input.resource.classification == "restricted", additionally requiring input.context.change_ticket.status == "approved" (the ITSM signal from seam 4).

Run until green:

git clone https://github.com/EnforceAuth/university-labs.git
cd university-labs
opa test courses/capstone-four-product-fabric -v

You move from FAIL: 3/11 to PASS: 11/11. The three deny tests that were already passing are your guardrail: if a rule you write lets an editor act across orgs, or lets a viewer delete, or lets a restricted read through without approval, a deny test flips to fail. That is the exact check a Writ promotion gate would run before signing a bundle. Keep iterating until opa test is green.

Check for understanding

  1. Name what crosses each of the four seams in one word (intent, custody, decision, context) and say which product owns each seam.
  2. Herald federates employment_status and change_ticket.status into input. Which rule in your policy depends on each, and what happens to the decision if Herald cannot reach the ITSM source and the status is absent?
  3. Your ownership rule must not grant delete. Which deny test enforces that, and why is delete kept role-gated instead of owner-grantable?