Skip to content

test(conformance): add offline-verifiable ACTION fixture bundles - #165

Merged
carloshvp merged 2 commits into
agentrust-io:mainfrom
miyannishar:test/action-offline-fixtures
Sep 13, 2026
Merged

test(conformance): add offline-verifiable ACTION fixture bundles#165
carloshvp merged 2 commits into
agentrust-io:mainfrom
miyannishar:test/action-offline-fixtures

Conversation

@miyannishar

Copy link
Copy Markdown
Contributor

What

Add self-contained, offline-verifiable fixture bundles for the delegation-linked action evidence cases under tests/fixtures/action/. Each bundle is a chain.json + dag.json + expected.json that a third party re-verifies with the shipped ca2a verify-dag --chain command 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 from tests/unit/test_committed_examples_verify.py (its _committed() helper is lifted into tests/committed_blobs.py so both suites share it), name the record file dag.json, and carry the verdict triple + trusted_root_issuer + optional at_time + reason code in expected.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 in tests/fixtures/action/README.md, pointing at the existing holder-proof note in tests/conformance/README.md).

Test plan

  • pytest passes
  • ruff check passes
  • mypy passes
  • Manual test performed (describe steps below if applicable)

Manual test steps:

pip install -e ".[dev]"
pytest tests/unit/ tests/conformance/ -q          # 602 passed, incl. the 5 bundle loader cases
python scripts/gen_action_fixtures.py --check       # bundles are byte-reproducible / in sync
ruff check src/ tests/ && ruff format --check src/ tests/
mypy src/ca2a_runtime/ src/ca2a_verify/
bandit -r src/ -c pyproject.toml
# and the shipped offline verifier, per bundle, e.g.:
ca2a verify-dag \
  --dag tests/fixtures/action/action-006-policy-denial/dag.json \
  --chain tests/fixtures/action/action-006-policy-denial/chain.json \
  --trusted-root-issuer <issuer-from-expected.json>

DCO sign-off

@miyannishar
miyannishar requested review from a team, carloshvp and zohebk8s as code owners September 13, 2026 13:36
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>
@miyannishar
miyannishar force-pushed the test/action-offline-fixtures branch from 1b90cf9 to 3f10932 Compare September 13, 2026 13:46

@carloshvp carloshvp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread tests/conformance/test_action_fixture_bundles.py Outdated
Comment thread scripts/gen_action_fixtures.py Outdated
…-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>
@miyannishar

Copy link
Copy Markdown
Contributor Author

Pushed 0b4ed20 addressing the review.

On the scope point: you're right that the loader never asserts authorization_decision/controller_outcome, so ACTION-001 changing controller_outcome to rejected would still pass. The fixtures README and the loader docstring now state explicitly that expected.json's verdict is the scenario's ACTION classification, not the offline verifier's output: the offline path observes only provenance_status (verified or a fail-closed code) and, for a denial, the recorded denial outcome. authorization_decision=allowed and every controller_outcome are not offline-observable, so they are documented as scenario labels and not asserted, and the controller-input limitation from the conformance README is kept explicit. No live holder-proof/controller/hardware execution is claimed.

The other two (fail on a missing committed blob; the advertised --check) are answered in their threads. Local suite still green (607 passed, 2 skipped); the hosted checks are the authoritative gate and await maintainer approval to run on this fork PR.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@carloshvp carloshvp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@carloshvp
carloshvp merged commit b9df502 into agentrust-io:main Sep 13, 2026
12 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(conformance): self-contained, offline-verifiable ACTION fixture bundles

3 participants