Repository navigation
refimpl: add first-stage Rust AGT Guardian - #187
Arham-Begani wants to merge 8 commits into
Conversation
Signed-off-by: Arham Begani <arhambegani2@gmail.com>
|
I completed an independent substantive review of the first-stage Rust Guardian against the ACS v0.1.0 schemas and existing TypeScript AGT behavior. I checked handshake/method declaration and dispatch, failure handling, AGT→ACS verdict mapping, session/hash-chain handling, Rust↔TS parity coverage, and the documented limitations around duplicate request_id, wire chain_hash, signatures, ASK/ask_details, and DEFER. |
Signed-off-by: Arham Begani <123586002+Arham-Begani@users.noreply.github.com>
Signed-off-by: Arham Begani <123586002+Arham-Begani@users.noreply.github.com>
|
I read this stage against the TypeScript Guardian it ports, concentrating on the session store, since that is where both implementations hold state a policy decision actually reads. The chain behaviour is faithful and worth saying before the finding. The 1,024 retained-session cap matches
The window is real because The cause looks structural rather than local. This store keeps recency in Smaller, same file. The eviction line reports the cap but not what it causes. Upstream's message reads "A further step on this session starts a new chain at seq 1, which the Inspector renders as a chain break", and its doc gives the reason: the eviction and the chain break it causes are otherwise two unexplained facts in two different places. Upstream reports eviction twice over, and the second report is Neither |
Signed-off-by: Arham Begani <123586002+Arham-Begani@users.noreply.github.com>
Signed-off-by: Arham Begani <123586002+Arham-Begani@users.noreply.github.com>
Signed-off-by: Arham Begani <123586002+Arham-Begani@users.noreply.github.com>
|
Thanks for the review. I addressed the session-store finding.
I also added the requested regression coverage using 1,025 sessions, verified the recreated session retains the propagated labels and restarts at I additionally moved the Rust↔TypeScript live parity comparison into CI. All current checks, including Rust tests, clippy, formatting, TypeScript tests, and the live parity test, are passing. Would appreciate a final review when you get a chance. |
|
That is the right shape. Routing The The regression test pins it at the right place: against the previous commit it fails on Since you asked for a final pass, one more parity observation, explicitly not a request for changes. The TypeScript store wraps its eviction reporter in a try/catch, and its own comment says why: a reporter that throws would surface as a Guardian failure on whichever unrelated step happened to overflow the cap, and a Guardian-side failure under the default posture runs the tool ungoverned, so a broken reporter must not cause the thing the cap exists to prevent. The bare I would not hold the PR for it. The direction is fail-closed rather than fail-open, since a poisoned lock sends Nothing else from me, and the finding is closed. One thing worth saying plainly so you are not waiting on the wrong signal: I am not a code owner here and this is a comment rather than a review, so it does not move the merge. That still needs one of the names in CODEOWNERS. |
Signed-off-by: Arham Begani <123586002+Arham-Begani@users.noreply.github.com>
rocklambros
left a comment
There was a problem hiding this comment.
@Arham-Begani, the session-store fix holds up. replace_labels now goes through ensure_session, and the 1,025-session test passes in CI. I also read eb609e44, which landed just after Mayur's last comment, and the eviction warning can't panic anymore. Most of what I have left is small, but three things need to change before this merges.
-
The Guardian runs whatever
opait finds.policy.rs:18-33falls back toopaon PATH and only checks thatopa versionexits 0. The TS Guardian runs the OPA binary pinned inagt/bun.lockby sha512.manifest.yaml:11-14already records an OPA loader quirk that dropsdata.jsonand answers allow for everything, so a developer with a different Homebrewopacan end up with an allow-all Guardian and nothing would notice. Please parse theopa versionoutput and refuse to start unless it says0.70.0. In the same spirit, the CI job installs OPA withnpm install ... agent-control-specification-opa-linux-x64@0.3.1-beta.0, with no integrity check. You can movebun install --frozen-lockfileinreference-implementations/agtabove the Rust test step, setACS_OPA_PATHin the jobenv:to the binary underagt/node_modules/agent-control-specification-opa-linux-x64/bin/opa, and drop the npm step. -
The advertised deadline ties with the OPA deadline.
server.rs:129sends"default_ms": 5000, and the pinned SDK's OPA timeout is also 5s. The host starts its timer before OPA even spawns, so on a slow OPA the host gives up first, and with the default posture (main.rs:17,proceed) the tool runs. The README'sACS_OPA_TIMEOUT_MS=30000makes that gap 25 seconds. Please either advertise the OPA timeout plus about a second, or refuse to start when the OPA timeout isn't belowdefault_ms, and add a unit test. The TS Guardian has the same pair, so I'll file an issue for that side. -
The parity wording promises more than the nine cases check.
README.md:45says cross-language drift "fails the Reference implementation workflow", and the PR body says all five AGT verdict kinds are mapped. The nine cases use one session, valid ids, and one invalid payload. I compared a few inputs: a non-object argument gets different error text from each Guardian, and a handshake error hasdata.pointerin TS but nodatain Rust (server.rs:119). Aurn:uuid:session id or a space-separated timestamp gets allowed by TS and denied by Rust. Warn, escalate, andevaluation_failedaren't covered at all. Adding cases is the better fix, but it's also fine to narrow the wording to "nine cases" and list what isn't compared. Please also refresh the Testing section, since CI now runs 4 tests, not 3 plus 1.
These aren't blockers:
- Four
eprintln!calls are still left inserver.rs(lines 101, 247, 259, 386). Two of them run while a log mutex is held, so a failed stderr write can poison the lock and stop the audit logs with no message. Using the samelet _ = writeln!(io::stderr().lock(), ...)pattern you used insession.rsfixes all four. - The new
LICENSING.mdrow puts the Rust README under CC BY-SA, but the TS reference's READMEs fall under the Apache catch-all (LICENSING.md:55-57). Unless you meant that, it's simplest to drop the row. - Nothing will ever propose updates for the new
Cargo.lock(301 crates), because.github/dependabot.ymlonly coversgithub-actionsanduv. Please add acargoentry for/reference-implementations/agt-rust, copying the existing weekly schedule andcooldown: default-days: 7. It's a.github/change, so I'll approve that part. policy.rs:74uses the same regex text as the TS annotator, but Rust's\band\sare Unicode-aware, so a few inputs match differently. Please don't "fix" Rust to match TS on U+FEFF, because the TS side is the one that's wrong there. I'll handle that separately.
I'll re-run CI against current integration once you push, since the last run merged against 770f1e0.
Sync current integration, require the pinned OPA version, install its CI binary from the frozen AGT lockfile, and advertise the evaluator deadline plus delivery time. Add regressions, make audit logging non-panicking, correct licensing and parity claims, and enable Cargo dependency updates. AI-assisted-by: OpenAI Codex Signed-off-by: Arham Begani <123586002+Arham-Begani@users.noreply.github.com>
|
Review follow-up is pushed in 208698c, synchronized with integration at 8a45952.
All current checks pass, including Linux Rust tests, live Rust/TypeScript comparison, TypeScript checks, Python guards, strict documentation build, and zizmor. Local Rust results are 6 unit tests plus 1 HTTP integration test. The PR description records the separate Windows Python-suite limitations and links the successful Linux runs. This update was prepared with Codex assistance. The contributor personally reviewed the focused patch and full PR, certified the DCO, and explicitly authorized sign-offs on the new commit and six older follow-up commits. The metadata rewrite preserves every code tree; every PR commit now carries a human sign-off. The Unicode-aware Rust regex remains unchanged as requested. |
54fa594 to
208698c
Compare
|
@rocklambros Could you re-review A formal re-review request was attempted but GitHub rejected it for insufficient account permissions, so I am recording the request here. No review approval or merge is being inferred from the green checks. This follow-up was prepared with OpenAI Codex assistance. |
Summary
First stage of the Rust port for #88: a Rust AGT Guardian at
reference-implementations/agt-rust/using the existing AGT manifest and policy,mapping.yaml, and ACS v0.1.0 schemas. The existing TypeScript Claude Code and OpenCode shims can send requests to this server. No policy or schema copy is introduced.The modules separate HTTP/JSON-RPC dispatch, schema validation, SDK integration and egress annotation, verdict mapping, session state, and local audit logs.
Review updates
integration.ACS_OPA_TIMEOUT_MS=30000produces 31000 ms. Reject an unrepresentable deadline.Tested behavior and limits
The checked-in comparison covers nine cases against live Rust and TypeScript Guardians with the same policy: allow, deny, request and result redaction, egress denial, WebFetch allowance, invalid payload, an undispatched method, and handshake. Eight compare complete responses. The handshake compares everything except the intentionally different
timeout_config.default_ms, whose positive integer shape is still checked.This is evidence for those cases, not general parity. Non-object arguments, handshake validation error data, alternative UUID/timestamp formats, warn/escalate verdicts, and evaluation failures are not covered. The Rust SDK collapses absent
result_labelsand an empty array to the same vector; the Guardian conservatively retains labels for an empty vector. That IFC limitation remains documented.Validation of this update
cargo fmt --all -- --check: passed.cargo check --workspace --locked: passed.cargo clippy --workspace --all-targets --all-features --locked -- -D warnings: passed.ACS_OPA_PATH=<locked AGT OPA 0.70.0> ACS_OPA_TIMEOUT_MS=30000 cargo test --workspace --all-features --locked: 6 unit tests and 1 HTTP integration test passed. These include exact-version and deadline regression tests; the integration test checks the negotiated deadline.bun tests/compare-guardians.mjsagainst both live servers: all nine cases passed, with only the documented handshake deadline excluded from equality.bun run typecheckin the TypeScript reference: passed.uv run mkdocs build --strict: passed on Windows.The full Python guard suite does not pass on this Windows environment. A local harness outside the contribution shortens oversized test display IDs and selects Git Bash without changing test bodies or parameter values. It completed with 908 passed, 10 failed, 1 skipped. Failures involve Unix executable/shebang stubs, a missing
python3in test-provided shell environments, and Windows symlink privileges. An unadapted run also encounters Windows' environment-variable length limit. WSL cannot start because virtualization is disabled. These are local platform limitations. The subsequent upstream Linux CI passed on this update: Reference implementation (Rust formatting/check/clippy/tests/live comparison and TypeScript checks), Python guards and documentation build, and workflow security scan. Site deployment is skipped for the pull request.Remaining scope
The Rust host adapter, Inspector, and conformance runner are outside this stage. Only the two tool gates supported by the TypeScript reference are evaluated; no ACS-Core conformance claim is made.
AI assistance: Codex helped implement and test this update. The contributor personally reviewed the focused patch, certified the project's DCO, and authorized the human sign-off on the review-fix commit.
Part of #88.