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 @@ -18,6 +18,7 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- **The OCSF audit plugin refuses `signing: dsse` with `chain: false` instead of emitting unsigned records.** The signature covers the chained record, so with the chain off the chain wrapper returned before the signer ever ran and a config that promised signatures produced none. `integrations/cpex-ocsf-audit` now fails construction for the pair with an error naming the fix, pinned by a new test. The second round adds `#[serde(deny_unknown_fields)]` on the config, since every field has a default and a misspelled `authority_uid` was silently dropped (a test pins the rejection), and the canonicalizer now writes object keys without cloning them (37 tests on each host, vectors byte-identical). Found by the first review round on praxis-proxy/policy #171; the same guard is staged for the in-tree copy in `praxis-port/review/0003-review-171.patch`, with the `read_subject` capability for `panic_drive` (PPE only) and a reworded key-ordering note in SAMPLE-OUTPUT.md, which this crate also takes. `praxis-port/review/0004-review-173.patch` carries the two accepted findings on the #166 spike document (praxis #173): a stream gap is loss evidence rather than a verification failure, and digests of low-entropy content are keyed where the host provides a key; `0005-review-173-tail.patch` answers the second round: a dense sequence from 0 shows no leading or interior gap but cannot show a trailing loss, so tail completeness needs a trusted terminal sequence or checkpoint from the host. (#591)

### Changed
- **The AID-EMIT-1 validator reads stream stamps from `aid.stream` as well as `cpex.stream`.** Emitters that target the AI Identity platform and OCSF rather than a gateway write stream stamps under AI Identity's own vocabulary, `unmapped."aid.stream"`, proposed for AID-EMIT-1 as a 1.2.0 vocabulary profile; the CPEX host family keeps `unmapped."cpex.stream"`. `scripts/aid_emit1_validator.py` now looks up `aid.stream` first, then `cpex.stream`, so the density, head and ordering checks (`GAP-STREAM`, `W-STREAM-HEAD`, `E-STREAM-ORDER`) cover both. A record carrying both keys is read from `aid.stream` and warned as `W-STREAM-VOCAB`, since two sets of stamps let a SIEM and a verifier read different sequences. Records in the `cpex` vocabulary validate exactly as before. The validator's tests run against its synced copy in the platform repository.
- **The integrations page and CPEX plugin README link the upstream OCSF audit Epic.** They identify praxis-proxy/policy Epic #12 as tracking the Praxis Policy Engine reference-plugin work, and keep the status clear: the PPE port is prepared as patches in this repository, not described as merged upstream. (#599)
- **`capture-modes.md` is marked implemented, and records what the build decided where the spec was open.** Every item of section 10 is now built on the platform (AI-66). Section 7 records how redaction works:
- an item's `redact_after` comes from the rule matching the row that carries its digest, so responses can be redacted on a different clock from requests;
Expand Down
23 changes: 21 additions & 2 deletions scripts/aid_emit1_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@
must be dense per `(epoch, stream_id)` and start at 0 (a higher first
value is warned as `W-STREAM-HEAD`) — a gap is **surfaced as a
finding, never repaired** (warning by default, error with
``--strict-gaps``); a decrease is an ordering error.
``--strict-gaps``); a decrease is an ordering error. Stream stamps are
read from `unmapped."aid.stream"` (AI Identity's vocabulary), else
`unmapped."cpex.stream"` (the CPEX host family's); a record carrying
both is warned as `W-STREAM-VOCAB`.

Non-6003 records (e.g. proposed-class drafts using the same
`record_integrity` carrier) get the integrity/chain checks with the
Expand Down Expand Up @@ -78,6 +81,12 @@
DSSE_PAYLOAD_TYPE = b"application/vnd.ocsf.event+json"
HEX64 = re.compile(r"^[0-9a-f]{64}$")

# Where a record's stream stamps live, by vocabulary, in lookup order:
# "aid.stream" is AI Identity's own (emitters that target the platform and
# OCSF rather than a gateway), "cpex.stream" is the CPEX host family's. The
# member structure is identical; only the key differs.
STREAM_STAMP_KEYS = ("aid.stream", "cpex.stream")

# ---------------------------------------------------------------------------
# Canonicalization (§4)
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -496,7 +505,17 @@ def check_chains(
)
heads[chain] = (uid, fp)

stream = (ev.get("unmapped") or {}).get("cpex.stream")
unmapped = ev.get("unmapped")
unmapped = unmapped if isinstance(unmapped, dict) else {}
stamp_keys = [k for k in STREAM_STAMP_KEYS if isinstance(unmapped.get(k), dict)]
if len(stamp_keys) > 1:
out.warn(
"W-STREAM-VOCAB",
idx,
f"stream stamps in both {' and '.join(stamp_keys)}; read from {stamp_keys[0]}: "
"a conforming emitter uses one vocabulary",
)
stream = unmapped[stamp_keys[0]] if stamp_keys else None
if isinstance(stream, dict) and stream.get("stream_seq") is not None:
key = (chain, stream.get("epoch"), stream.get("stream_id"))
streams.setdefault(key, []).append((stream["stream_seq"], idx))
Expand Down
Loading