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
7 changes: 4 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ env:
# The second host. praxis-proxy/policy PR #84 is Teryl's port of the
# same seam into the Praxis Policy Engine; the crate builds against it
# under `--no-default-features --features ppe`. That dependency is a
# git dep pinned by full SHA in Cargo.toml (PR #84 head `20798ae`, the
# rev PRAXIS-PORT-RESULTS.md was measured on), so there is nothing to
# clone here — Cargo fetches it, and --locked holds it to the lock.
# git dep pinned by full SHA in Cargo.toml (the PR #84 head the crate
# was last re-verified on; PRAXIS-PORT-RESULTS.md records each bump),
# so there is nothing to clone here: Cargo fetches it, and --locked
# holds it to the lock.
# Both hosts build in this one job because the cpex path dependency
# has to resolve even when the `cpex` feature is off.

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- **The validator declares its Python floor.** `scripts/aid_emit1_validator.py` requires 3.10+ for `zip(..., strict=True)` (which the repo's ruff B905 rule mandates, so it isn't going away) and said so nowhere — an outside verifier hit it as an opaque `TypeError` deep in a chain check. Now a docstring line and a startup version gate with a message that names the requirement.
- **Corrected two question citations in the WS4 #172 evidence-contract mapping.** `docs/cosai-ws4-ocsf-mapping/evidence-contract-ocsf-mapping.md` is linked from a CoSAI thread that now has named reviewers, and two of its citations did not survive a check against the issue text as filed. (1) The header claimed the document as the **Q14/Q15** deliverable, but WS4 #172 Q15 asks for the false-positive profile of normal agent behaviour and what cross-run correlation requires operationally — detection-side material the document explicitly defers in its own scope note. Header retitled to Q14 alone, and the scope note now says plainly that Q15 is out of scope and unclaimed, matching what the CHANGELOG entry for #493 already said. (2) The schema gap register cited **Q16** for cross-boundary causal binding; Q16 is reachability minimisation versus patch hygiene (§9). The resource owner's record naming the causing tool call is the evidence complement of §5 (Q9–Q10), where a permitted party acts on the agent's behalf — re-cited accordingly. No mapping row, status, or OCSF claim changes. Docs only — no product impact.

### Changed
- **The OCSF audit plugin tracks PR #84 at `499ee91` and holds `base64` at 0.22 to match the PPE tree.** Teryl answered the two dependency findings on praxis-proxy/policy PR #84 on 2026-09-09: `sha2` is now a workspace dependency at `0.11` (`ef20d8f`), and `base64` stays at `0.22` across the tree because `jsonwebtoken` 11, which `identity-jwt` depends on, requires it, so `0.23` would put two majors in the build (verified against the PPE lock). The same head merges the #82 docs reorganisation, which moves the auditing guide to `docs/content/auditing.md`; nothing on the seam this crate consumes changed between `3e7734e` and `499ee91`. `integrations/cpex-ocsf-audit` moves its pin to that head and its `base64` requirement from `0.23` (a Renovate bump, #497) down to `0.22`, so the copy that lands under `reference/plugins/ocsf-audit` (`PRAXIS-INTREE-PLAN.md`) is a copy and the PPE build stays on one base64; a Renovate rule holds it there. Verified the way CI runs it, on toolchain 1.96.1 with a cpex sibling at `64c8eba`: warning-free `--locked` builds and 34 tests green on each host, `emit_sample` and `decision_sink_demo` byte-identical to the committed vectors, so the AID-EMIT-1 section 12 conformance vector is untouched. The in-tree plan drops `sha2` and `base64` from its list of workspace-table adds (only `p256` remains), records the `base64` answer as settled, and follows the auditing guide to its new path. He also repeated that the `plugin_settings:` load error predates #84 (praxis-proxy/policy #55), which `PRAXIS-PORT-RESULTS.md` observation 3 already records.

### Added
- **The in-tree port plan now sizes the `base64` version conflict, and answers the #84 review's version-spec claim before it reaches our PR.** `PRAXIS-INTREE-PLAN.md` listed `p256`, `sha2` and `base64` as three equal adds to PPE's `[workspace.dependencies]`. Read against the manifests at `3e7734e`, only `p256` is one: `sha2 = "0.11"` is already declared directly by four crates (`ppe-core`, `ppe-apl-runtime`, `builtins/plugins/delegator-oauth`, `builtins/session/valkey`) at the version this crate uses, which is the inconsistency praxis-bot flagged on PR #84 on 2026-09-09, and `base64` is a conflict rather than an add, since `identity-jwt`, `delegator-oauth` and `elicitation-ciba` each declare `0.22` directly while this crate is on `0.23`, a semver-incompatible major. The plan's default is now to pin this crate down to `0.22`: base64 is reached only through `Engine::encode` and `Engine::decode` on `general_purpose::STANDARD` in `src/sign.rs` and `src/emitter.rs`, an API unchanged across both versions, so the expected cost is the manifest line rather than a base64 upgrade across three builtins the port PR has no other reason to touch. Carrying both majors is the third option and the worst one; `deny.toml` sets `multiple-versions = "warn"`, so `make audit` would not fail, but the tree has one major today. The choice goes to the PR thread as an open question. The plan also records that the other half of the #84 review, a patch component on the version spec (`sha2 = "0.11.0"`), is not this tree's convention: the workspace table uses `tokio = "1"`, `thiserror = "2"` and `hashbrown = "0.17"` throughout. Docs only, no product impact.
- **In-tree port plan for the OCSF plugin into praxis-proxy/policy.** Teryl settled the two open decisions on 2026-09-08 after talking to Fred: the plugin lands under `reference/plugins/ocsf-audit` next to `audit-logger`, `publish = false` and not supported, and moves to `builtins/` after feedback; the source is this directory on `main` (v0.0.3, 34 tests, AID-EMIT-1 1.1.0), not cpex#128, and he will swap the link on praxis #12. `PRAXIS-INTREE-PLAN.md` records the decisions and everything PPE's own rules demand of the copy, read from `CONTRIBUTING.md`, `AGENTS.md`, the workspace lints, `clippy.toml`, `.markdownlint.yaml` and `deny.toml` at `3e7734e`: human-signed commits with no AI trailers, two-line SPDX headers, no history in comments (93 lines to restate), edition 2024, and a lint set that denies `unwrap_used`, `missing_assert_message` (159 sites), `print_stdout`, `missing_docs` and `doc_markdown`, with `allow-git = []` so `p256`, `sha2` and `base64` join `[workspace.dependencies]`. It sizes each pass, lists what is not carried (`run-demo.sh`, the measurement records, the lock), sets the acceptance bar (34 green, `emit_sample` byte-identical to the section 12 vector, zero mapping diff), and offers the history-preserving `git-filter-repo` import PPE documents in `docs/port-provenance.md` as the recommended landing. Gated on PR #84 merging; the earlier one-hour estimate becomes a day. Docs only, no product impact.
Expand Down
8 changes: 4 additions & 4 deletions integrations/cpex-ocsf-audit/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 17 additions & 5 deletions integrations/cpex-ocsf-audit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,27 @@ ppe = ["dep:praxis-policy-core"]
# Pin a rev rather than tracking `dev` for anything reproducible.
cpex-core = { path = "../../../cpex/crates/cpex-core", optional = true }

# The PR #84 head, `3e7734e`, which accepts the documented
# `engine_settings` audit keys at load (PRAXIS-PORT-RESULTS.md obs 1). A
# full SHA, not a branch: the PR is a draft and its branch will move.
# The PR #84 head, `499ee91` (2026-09-09): `3e7734e` accepted the
# documented `engine_settings` audit keys at load (PRAXIS-PORT-RESULTS.md
# obs 1), `ef20d8f` made `sha2` a workspace dependency, and the rest is
# the docs reorganisation (#82) merged in, with `docs/auditing.md` now at
# `docs/content/auditing.md`. Nothing on the seam this crate consumes
# changed between the two heads. A full SHA, not a branch: the PR is a
# draft and its branch will move.
# Bump deliberately, with the crate re-verified — the same rule as the
# cpex pin in .github/workflows/rust.yml.
praxis-policy-core = { git = "https://github.com/praxis-proxy/policy", rev = "3e7734ed46609e337d14262aaa6d152eb5757732", optional = true }
praxis-policy-core = { git = "https://github.com/praxis-proxy/policy", rev = "499ee91ff1e1102f3e38357450f3f9d4e213c602", optional = true }

async-trait = "0.1"
base64 = "0.23"
# 0.22, not the current 0.23: praxis-proxy/policy holds base64 at 0.22
# because `jsonwebtoken` 11 (identity-jwt) depends on it, and this crate
# is copied into that tree as `reference/plugins/ocsf-audit`
# (PRAXIS-INTREE-PLAN.md). Pinning down here keeps the copy a copy and the
# PPE build on one base64. Only `Engine::{encode,decode}` on
# `general_purpose::STANDARD` is used, identical across both majors;
# the conformance vectors are byte-identical either way. Hold it here
# until the in-tree copy lands or the PPE tree moves.
base64 = "0.22"
chrono = { version = "0.4", features = ["serde"] }
# ECDSA P-256 for the DSSE signer — same curve as the production JWKS
# (https://api.ai-identity.co/.well-known/ai-identity-public-keys.json).
Expand Down
87 changes: 44 additions & 43 deletions integrations/cpex-ocsf-audit/PRAXIS-INTREE-PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ Settled with Teryl on Slack, 2026-09-08, after he talked to Fred:

## PPE rules the copy must satisfy

Read from `praxis-proxy/policy` at `3e7734e`: `CONTRIBUTING.md`, `AGENTS.md`,
`Cargo.toml` (workspace lints), `clippy.toml`, `.markdownlint.yaml`,
`deny.toml`, `docs/port-provenance.md`.
Read from `praxis-proxy/policy` at `3e7734e`, dependencies re-read at
`499ee91`: `CONTRIBUTING.md`, `AGENTS.md`, `Cargo.toml` (workspace lints),
`clippy.toml`, `.markdownlint.yaml`, `deny.toml`, `docs/port-provenance.md`.
The auditing guide moved from `docs/auditing.md` to `docs/content/auditing.md`
when #84 took the #82 docs reorganisation (`a1e8621`, `499ee91`).

- **Commits.** Human-authored, `Signed-off-by` the human, no AI co-author or
session trailers (`AGENTS.md`, first paragraph). Same rule as this repo's
Expand Down Expand Up @@ -79,42 +81,41 @@ Read from `praxis-proxy/policy` at `3e7734e`: `CONTRIBUTING.md`, `AGENTS.md`,
bar as the library.
- **Dependencies.** `deny.toml` has `allow-git = []`: no git dependencies,
so the pinned `praxis-policy-core` git dep becomes
`praxis-policy-core = { workspace = true }`. Every third-party dependency
must already be in `[workspace.dependencies]`; `p256`, `sha2` and
`base64` are not there today and are added in the same PR, `p256` with
`ecdsa`, `pem`, `pkcs8`. `serde`, `serde_json`, `chrono`, `async-trait`,
`tracing` and `tokio` exist. All are Apache-2.0 OR MIT, inside the
`deny.toml` allow-list. `make audit` (`cargo deny check`) is a CI gate.

Two of the three are not clean adds, read from the manifests at
`3e7734e`. `sha2 = "0.11"` is already declared directly by four crates
(`ppe-core`, `ppe-apl-runtime`, `builtins/plugins/delegator-oauth`,
`builtins/session/valkey`) at the version this crate uses, the
inconsistency praxis-bot flagged on #84 on 2026-09-09; if Teryl lands the
workspace-dep half of that finding, the table entry arrives ahead of this
PR and the port matches it. `base64` is a version conflict rather than an
add: `identity-jwt`, `delegator-oauth` and `elicitation-ciba` each
declare `base64 = "0.22"` directly and this crate is on `0.23`, which is
semver-incompatible. `p256` is the only genuinely new dependency in the
tree.

Pinning this crate down to `0.22` is the cheaper resolution and the
plan's default. base64 is reached only through `Engine::encode` and
`Engine::decode` on `general_purpose::STANDARD` (`src/sign.rs`,
`src/emitter.rs`), an API unchanged across both versions, so the expected
cost is the manifest line, to be confirmed by the build rather than
assumed. Taking the tree to `0.23` instead makes this PR a base64 upgrade
across three builtins it has no other reason to touch. Carrying both is a
third option and a worse one: `deny.toml` sets `multiple-versions =
"warn"`, so `make audit` would not fail, but the tree has one major of
base64 today and this PR is not the reason to make it two.
`praxis-policy-core = { workspace = true }`. `serde`, `serde_json`,
`chrono`, `async-trait`, `tracing`, `tokio` and, since `ef20d8f`, `sha2`
are in `[workspace.dependencies]` and are taken with `{ workspace = true }`.
`p256` is the one genuinely new dependency in the tree and joins the
table in this PR with `ecdsa`, `pem`, `pkcs8`. All are Apache-2.0 OR MIT,
inside the `deny.toml` allow-list. `make audit` (`cargo deny check`) is a
CI gate.

How the other two resolved, read from the manifests at `499ee91`:

- `sha2`. praxis-bot flagged four crates each declaring `sha2 = "0.11"`
directly on #84 (2026-09-09). Teryl answered with `ef20d8f`, "make sha
0.11 a workspace dependency": `sha2 = "0.11"` is in the table and the
four crates take it from there. The port does the same and adds
nothing.
- `base64`. This crate was on `0.23`; `identity-jwt`, `delegator-oauth`
and `elicitation-ciba` declare `0.22` directly. Teryl settled it on the
same day: the tree stays on `0.22` because `jsonwebtoken` 11, which
`identity-jwt` depends on, requires base64 `0.22`, so `0.23` would put
two majors in the build (verified against the PPE lock: `jsonwebtoken
11.0.0` lists `base64 0.22.1`). This crate is pinned down to `0.22`
ahead of the port. The cost was the manifest line, confirmed by the
build: base64 is reached only through `Engine::encode` and
`Engine::decode` on `general_purpose::STANDARD` (`src/sign.rs`,
`src/emitter.rs`), 34 tests green on both hosts, `emit_sample` and
`decision_sink_demo` byte-identical. `base64` is not in the workspace
table at `499ee91`; the port declares `base64 = "0.22"` directly, the
way the three builtins do, unless Teryl prefers a table entry.

On the version spec itself, follow the table and not the bot. The #84
review also asks for a patch component (`sha2 = "0.11.0"`), but
`[workspace.dependencies]` at `3e7734e` uses major or major.minor
throughout: `tokio = "1"`, `thiserror = "2"`, `hashbrown = "0.17"`,
`serde_yaml = "0.9"`. Expect the same comment on this PR and answer it
the same way.
review also asked for a patch component (`sha2 = "0.11.0"`), and
`ef20d8f` wrote `sha2 = "0.11"`, matching the rest of
`[workspace.dependencies]`: `tokio = "1"`, `thiserror = "2"`,
`hashbrown = "0.17"`, `serde_yaml = "0.9"`. Expect the same comment on
this PR and answer it the same way.
- **Markdown.** 80-column prose, 120 in code blocks, tables exempt
(MD013); every fence declares a language (MD040); no bare URLs (MD034);
asterisk emphasis (MD049). Long prose lines today: `README.md` 89,
Expand All @@ -141,8 +142,8 @@ reference/plugins/ocsf-audit/

Workspace edits in the same PR: add the path to `members` and
`default-members` in the root `Cargo.toml` under the existing reference
comment; add the three dependencies to `[workspace.dependencies]`;
`docs/auditing.md` "PPE ships one, `audit-logger`" becomes two, with a
comment; add `p256` to `[workspace.dependencies]`;
`docs/content/auditing.md` "PPE ships one, `audit-logger`" becomes two, with a
`kind: audit/ocsf` YAML block after the `audit-logger` one; `README.md`
line 52 "two worked examples" becomes three. `kind` stays `audit/ocsf`.

Expand Down Expand Up @@ -232,10 +233,10 @@ reflow. Plan a day, verified against the acceptance list, not an hour.

## Open questions for the PR thread

- Whether `base64` enters `[workspace.dependencies]` at `0.22` with this
crate pinned down to match the three builtins, or at `0.23` with those
builtins bumped in the same PR. Pinning down is the plan's default;
Teryl's call.
- *(Settled 2026-09-09.)* `base64` stays at `0.22` in the tree, held there
by `jsonwebtoken` 11; this crate is pinned down to match. Still open is
only whether the port declares it directly, as the three builtins do, or
adds a workspace table entry.
- `doc-valid-idents` additions in `clippy.toml` for OCSF, DSSE, PAE, ECDSA,
AID-EMIT-1, or backticks throughout; Teryl's preference.
- Whether the praxis `demos` repository, which registers the reference
Expand Down
5 changes: 5 additions & 0 deletions integrations/cpex-ocsf-audit/PRAXIS-PORT-RESULTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ auditing", closes praxis#11), head `20798ae` — five commits on top of `main`
`rust-toolchain.toml` says 1.96.0, its MSRV)
**Baseline it is compared with:** the same crate on cpex `feat/audit-seam`
`64c8eba` (the CI pin), run the same day on the same toolchain.
**Re-verified 2026-09-09** against PR #84 head `499ee91` (`3e7734e` plus
`ef20d8f`, sha2 as a workspace dependency, and the docs reorganisation
from #82; no seam change), with this crate on base64 0.22: warning-free
`--locked` builds and 34 tests green on each host, `emit_sample` and
`decision_sink_demo` byte-identical to the committed vectors.

This is the re-run `PRAXIS-PORT-PLAN.md` describes: same crate, same protocol
as `SEAM-PORT-RESULTS.md`, retargeted at the praxis seam. The plan expected
Expand Down
7 changes: 4 additions & 3 deletions integrations/cpex-ocsf-audit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ record it emits is a real fail-closed deny on the host-named stream.
> policy dispatch, which refuses a hook-listed plugin that carries a
> `priority:`. The plugin host is `PolicyEngine`, with the same
> `register_factory` / `load_config` / `initialize` surface. The audit keys
> `docs/auditing.md` documents, `audit_stream_namespace` among them, load from
> the file as of PR #84 `3e7734e`, which fixed the allowlist gap reported as
> `PRAXIS-PORT-RESULTS.md` observation 1.
> `docs/content/auditing.md` documents, `audit_stream_namespace` among them,
> load from the file as of PR #84 `3e7734e`, which fixed the allowlist gap
> reported as `PRAXIS-PORT-RESULTS.md` observation 1. The crate pins the PR
> head at `499ee91` (2026-09-09), re-verified on both hosts.

**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
Expand Down
6 changes: 6 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
"matchUpdateTypes": ["minor", "patch"],
"groupName": "rust non-major"
},
{
"description": "cpex-ocsf-audit holds base64 at 0.22: praxis-proxy/policy is on 0.22 (jsonwebtoken 11 requires it) and the crate is copied into that tree; see the comment in its Cargo.toml",
"matchManagers": ["cargo"],
"matchPackageNames": ["base64"],
"allowedVersions": "<0.23"
},
{
"description": "Majors always ride solo so each gets its own review",
"matchUpdateTypes": ["major"],
Expand Down
Loading