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

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions