Skip to content

feat: passively audit own enforcement in PPE with audit plugin #11

Description

@terylt

Summary

PPE today cannot passively audit its own enforcement. Blocks, approval rejections, delegation failures, and injection-stops produce no audit record.

Goals

  1. Core owns decision emission; the plugin owns serialization. The executor emits one decision record per invocation — allow and deny and modify — that any audit sink consumes. The record exists whether or not an audit plugin is installed.
  2. Complete by construction. Fire on the verdict.
  3. Observation-only, enforced at the type level. A new AuditHook family and DecisionLog.
  4. Auto-attach, no per-hook YAML. The manager attaches any audit-kind plugin to the single verdict-emit path.
  5. Provenance without leakage. Records carry hashes + taint labels + spans, not raw payloads.
  6. Crash-safe effect auditing. Irreversible external actions (token mints, approval grants) are recorded write-ahead: begin_effect durably flushes intent before the act and fails closed; complete_effect records the outcome. Lifecycle prepared → confirmed | rejected | unknown; unknown is reconciled against the participant (IdP) via an idempotency key. Durability and audit granularity are the same mechanism.

Non-goals

  1. Not a general mediation kernel. v1 effect auditing is cooperative — a trusted plugin calls begin_effect before its I/O. The framework does not force an opaque plugin to do so. Structural (mediated) enforcement is scoped to builtins only
  2. Not a new correlation scheme. Adopt W3C trace context / OTel spans — do not mint a bespoke PPE id. Host-side trace-context propagation across hops is out of core.
  3. Route-scoped audit is deferred. Global-audit-everywhere covers the real need; per-route instances fork the attestation chain (own fingerprint head). Ship global; add scoping when a use case demands it.
  4. Not a durable sink by itself. stderr/tracing are not crash-durable. Core provides the write-ahead contract and a FileEffectLog; a production decision sink (fsync'd WAL or durable queue) is the operator's/consumer's responsibility.

Status

A completed version of this PR is available in the CPEX repo and could be ported over: contextforge-org/cpex#166
Discussion welcome on the goal/non-goal boundaries — especially (1) how far v2 mediation should reach and (5) whether any consumer needs route-scoped audit sooner than "on demand."

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions