Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- **Compliance cost model verified — SOC 2 readiness is ~$15–17K first-year, not $20–50K.** The compliance-readiness tracker's cost table is filled from real quotes (2026-08-07 compliance-automation platform conversation): ~$12K/yr platform covering both SOC 2 and ISO 42001, ~$3K Type I, ~$4–5K Type II, pen test and ISO 42001 bundled at no increment. Cost is no longer the gating variable — the trigger remains the first enterprise contract requiring certification. The three-horizon map's P5 profile carries the same economics. Numbers rounded and vendor-neutral in the public tree; attributed quote record internal. Docs only — no product impact. (#454)

### Added
- **Decision-sink port delivered: cpex-ocsf-audit now records denials off the cpex#166 audit seam.** The WS-A / P1 step the guinea-pig report left open is implemented: with no `hooks:` listed the plugin auto-attaches as a cpex `AuditHandler` (same registration contract as the upstream audit-logger — hook-listed instances stay post-hook observers and never double-emit) and consumes the executor's finalized `DecisionLog` at every pipeline verdict. The mapping the passive stream could never produce: Deny → `action_id` 2 / `disposition` Blocked with the violation at `status_code`/`status_detail` (a fail-closed panic arrives as `plugin_panic`, distinguishable by code), Allow-after-modification → Modified, plain Allow → Allowed; the ordered per-plugin steps (full vocabulary incl. `deny_ignored` — flagged flat so "every suppressed transform-deny" is one SIEM query — and `aborted`, distinct from error), invocation span, entry taint, content hashes, and the seam's `(epoch, stream_id, stream_seq, emission_seq)` completeness/ordering stamps ride under `unmapped.cpex.*` inside the hashed bytes, so decision facts are tamper-evident in the attestation chain. Non-CMF dispatches and zero-plugin invocations emit honest records (activity Unknown / empty steps). 11 new tests (32 total, green against seam head `386710a`); follow-up tracked: `on_effect` lifecycle events want a richer class than 6003. (#457)
- **Guinea-pig port verified: cpex-ocsf-audit runs clean against the cpex#166 audit seam.** Delivers the commitment made on the cpex PR thread (2026-08-14): the OCSF audit plugin built and ran its full suite (21/21 tests, `cargo check --all-targets` clean) against `feat/audit-seam` @ `386710a` — the post-hardening head — with zero source changes, confirming the seam's "all changes are opt-in" claim for a real out-of-tree consumer. `integrations/cpex-ocsf-audit/SEAM-PORT-RESULTS.md` records scope (the `AuditHandler`/`DecisionLog` sink port with the `DenyIgnored`/`Aborted` mapping remains the tracked WS-A/P1 next step), findings for upstream (cpex-core gains `futures` + `sha2` transitive deps; the 1.96 MSRV pin fails fast), and repro steps; the committed `Cargo.lock` pins the exact resolution used. Docs/test evidence only — no product impact. (#456)
- **Full agent test suite now runs in CI on `agent/**` changes.** The Ada Evals workflow ran only the static citation gate (deliberately no ADK install), so the other ~150 agent tests ran nowhere — how a test sat red on `main` for weeks after #235 and how the ADK 0.4→2.7 drift stayed invisible until #452. New `agent-tests` job installs from the exact-pinned `agent/requirements.txt` on Python 3.13 and runs the whole suite; separate job keeps the citation gate fast, the existing path filter keeps main CI untouched for non-agent changes, and it is deliberately not a required check (path-filtered required checks block merges when skipped). CI only — no product impact. (#453)

Expand Down
24 changes: 24 additions & 0 deletions integrations/cpex-ocsf-audit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,30 @@ open OCSF/WS4 gaps self-documenting in the wire output.

## Wiring (APL)

**Audit-only sink mode (recommended on cpex with the audit seam, PR #166):** omit
`hooks:` entirely. The plugin then auto-attaches as a **decision-audit sink**
(`Plugin::as_audit_handler`) and fires at every pipeline verdict — **denials
included** — with the executor's `DecisionLog`: verdict → `action_id`/`disposition`
(Denied/Blocked with the violation at `status_code`/`status_detail`, Modified,
Allowed), and the ordered per-plugin steps (incl. `deny_ignored` / `aborted`),
span, entry taint, content hashes and the `(epoch, stream_id, stream_seq,
emission_seq)` stream stamps under `unmapped.cpex.*`, inside the hashed bytes.

```yaml
plugins:
- name: ocsf-audit
kind: audit/ocsf
# no `hooks:` -> decision-audit sink mode (sees denials)
config:
destination: stderr
chain: true
```

**Post-hook observer mode (legacy; pre-seam cpex):** list the CMF POST hooks to
observe. This path sees allowed traffic only — it structurally cannot record a
denial — and a hook-listed instance deliberately does **not** also attach as a
sink, so one invocation never emits twice.

```yaml
routes:
- tool: get_compensation
Expand Down
34 changes: 25 additions & 9 deletions integrations/cpex-ocsf-audit/SEAM-PORT-RESULTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,31 @@ The PR's claim that "all changes are opt-in; no behavior changes without
explicit configuration" holds for a real out-of-tree consumer, not just the
in-tree `audit-logger`.

**Not yet exercised (next step of the port):** registering as a
decision-audit sink (`AuditHandler` / `DecisionLog`) and mapping the
finalized decision vocabulary — `Allowed` / `ModifiedPayload` /
`ModifiedExtensions` / `DenyIgnored` / `Aborted` / `Error`, terminal
verdicts, `plugin_panic` coding, and the `(epoch, stream_seq, emission_seq)`
stamps — into OCSF records (deny/modify records, action_id 2/4). That is the
WS-A / P1 work item already tracked in `src/lib.rs`; the vocabulary review
on the PR thread (2026-08-18) confirmed the contract carries everything the
mapping needs.
**Not yet exercised at the time of the first run (delivered later the same
day — see below):** registering as a decision-audit sink (`AuditHandler` /
`DecisionLog`) and mapping the finalized decision vocabulary — `Allowed` /
`ModifiedPayload` / `ModifiedExtensions` / `DenyIgnored` / `Aborted` /
`Error`, terminal verdicts, `plugin_panic` coding, and the
`(epoch, stream_seq, emission_seq)` stamps — into OCSF records (deny/modify
records, action_id 2/4).

## Addendum (2026-08-18, later): the decision-sink port is implemented

The WS-A / P1 step above landed the same day: with no `hooks:` listed the
plugin now auto-attaches as an `AuditHandler` (mirroring the upstream
audit-logger's registration contract) and consumes the full `DecisionLog`
at every verdict. Verdict → `security_control` (Denied/Blocked with the
violation surfaced at `status_code`/`status_detail` — so `plugin_panic`
arrives distinguishable by code; Allow-after-modification → Modified;
plain Allow → Allowed); steps, span, entry taint, content hashes and the
stream stamps ride under `unmapped.cpex.*` **inside the hashed bytes**, so
the decision facts are tamper-evident in the attestation chain. 11 new
tests (32 total, all green against the same seam head `386710a`) cover the
registration contract, every verdict mapping, the `deny_ignored` and
`aborted` renderings, zero-step and non-CMF dispatches, and that the
stream stamps are bound into the fingerprint. Remaining follow-up:
`AuditHandler::on_effect` (effect-lifecycle events want a richer OCSF
class than 6003 — e.g. Authentication for a token mint).

## Observations for upstream (the "anything that doesn't match intent" list)

Expand Down
Loading
Loading