test(conformance): add offline-verifiable ACTION fixture bundles - #165
Conversation
Serialize a representative set of delegation-linked action evidence cases to disk as self-contained chain.json + dag.json + expected.json bundles under tests/fixtures/action/, re-verified through the shipped `ca2a verify-dag --chain` command against the committed blobs. Until now every ACTION case was built in memory, so the offline-verification claim was never exercised end to end from files. Adds a seeded, byte-reproducible generator (scripts/gen_action_fixtures.py, with a --check staleness mode), a loader test that reads the committed blobs, and lifts the committed-blob helper into tests/committed_blobs.py so the existing example test and the new loader test share it. The bundles cover the offline provenance, authorization-denial, and validity-window axes; they do not exercise holder-proof authorization replay, which is not offline-replayable evidence. Idea credit: @Ahmedibrahim222 (agentrust-io#36). Refs agentrust-io#164. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Nishar <nishar@dayos.com>
1b90cf9 to
3f10932
Compare
carloshvp
left a comment
There was a problem hiding this comment.
Reviewed exact head 3f10932. Requesting changes on two reproducible fixture-validation gaps below.
Independent isolated macOS/Python 3.13 validation: full suite 623 passed, 2 skipped; Ruff, mypy, Bandit and whitespace checks passed. I also invoked the installed ca2a CLI separately against all five committed bundles: the happy path and recorded denial succeed, while the parent-link, escalation and expiry cases fail with their documented codes. A separately tampered chain signature fails with INVALID_CREDENTIAL. The commit is signed off and merges cleanly against fetched main. These positives do not cover the missing-artifact and check-mode failures.
One scope clarification as well: ACTION-001's CLI output establishes verified/cross-checked provenance and leaf scope; it does not report an allowed action or an accepted controller outcome. Changing expected.json's controller_outcome to rejected leaves the loader passing, because that field is never asserted. Please distinguish scenario labels from observed offline verdicts in the fixture documentation; the existing controller-input limitation should remain explicit. No live holder-proof or controller/hardware execution was validated.
The hosted check rollup currently contains only the maintainer gate; the local suite is independent evidence, not a replacement for hosted repository checks.
…-check, clarify verdict labels Responds to @carloshvp's review of PR agentrust-io#165: - Loader failed open on a missing committed blob. Add tests/committed_blobs.git_source_available() and, when git is available, assert each REQUIRED_BUNDLES blob is present at HEAD (a missing artifact now fails instead of skipping). Skips remain only when git/the source archive is unavailable. Pin the bundle set so dropping or adding a whole directory is a deliberate, test-visible change rather than silent coverage loss. - Restore the advertised --check mode in scripts/gen_action_fixtures.py: it now compares generated bytes to disk without writing and exits nonzero for any stale or missing file, instead of always rewriting and returning 0. - Distinguish scenario labels from observed offline verdicts in the fixtures README and the loader docstring: expected.json's `verdict` is the scenario's ACTION classification, while the offline CLI only observes provenance and, for a denial, the recorded denial outcome. authorization_decision=allowed and controller_outcome are not offline-observable and are not asserted; the controller-input limitation stays explicit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Nishar <nishar@dayos.com>
|
Pushed 0b4ed20 addressing the review. On the scope point: you're right that the loader never asserts The other two (fail on a missing committed blob; the advertised |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
carloshvp
left a comment
There was a problem hiding this comment.
Re-reviewed exact head 0b4ed20. Both requested changes are addressed.
The loader now requires every pinned bundle's committed blobs when Git is available, and the required directory set cannot silently shrink. The check mode compares without rewriting and returns failure for stale/missing files. Documentation now clearly separates scenario authorization/controller labels from what the offline verifier observes.
Independent isolated macOS/Python 3.13 validation: full suite 623 passed, 2 skipped; Ruff and mypy passed. Eighteen additional adversarial checks passed: each of the three blob types missing from each of five bundles fails rather than skips, and clean/stale/missing check-mode cases preserve all input files while returning the appropriate status. Current hosted Python matrix checks also pass. Merge simulation is clean and both commits have DCO sign-offs.
Approving this exact head and resolving my two addressed threads. No live holder-proof, controller action, or hardware outcome is inferred from the fixture labels.
What
Add self-contained, offline-verifiable fixture bundles for the delegation-linked action evidence cases under
tests/fixtures/action/. Each bundle is achain.json+dag.json+expected.jsonthat a third party re-verifies with the shippedca2a verify-dag --chaincommand against the committed blobs, plus a seeded generator (scripts/gen_action_fixtures.py) and a loader test.Why
Every ACTION case (ACTION-001..016) is currently built in memory inside
tests/conformance/test_profile_conformance.py, so cA2A's offline-verifiable-provenance claim is never exercised end to end from serialized files. These bundles close that gap, following @imran-siddique's direction on #164: they reuse the committed-blob pattern fromtests/unit/test_committed_examples_verify.py(its_committed()helper is lifted intotests/committed_blobs.pyso both suites share it), name the record filedag.json, and carry the verdict triple +trusted_root_issuer+ optionalat_time+ reason code inexpected.json.Idea proposed by @Ahmedibrahim222 in #36. Closes #164.
The five bundles cover distinct offline verdicts: verified happy path (ACTION-001), parent-hash mismatch (ACTION-002,
PROVENANCE_LINK_BROKEN), recorded authorization denial (ACTION-005/006), scope escalation (ACTION-010,SCOPE_ESCALATION), and an expired validity window replayed with--at-time(ACTION-012,CREDENTIAL_EXPIRED).Security impact
None to the runtime, verifier, or any trust boundary: this is additive test fixtures, a generator, and a loader test. No
src/code changes. The bundles are honest about scope — the offline path covers provenance, the DAG, the chain↔record cross-check, and recorded denial outcomes, but not the holder-proof authorization-replay axis, which is not offline-replayable evidence (documented intests/fixtures/action/README.md, pointing at the existing holder-proof note intests/conformance/README.md).Test plan
pytestpassesruff checkpassesmypypassesManual test steps:
DCO sign-off