Skip to content

fix(verify): preserve structural claim failure - #596

Draft
altrudev wants to merge 1 commit into
agentrust-io:mainfrom
altrudev:fix/verify-malformed-claims-592
Draft

fix(verify): preserve structural claim failure#596
altrudev wants to merge 1 commit into
agentrust-io:mainfrom
altrudev:fix/verify-malformed-claims-592

Conversation

@altrudev

@altrudev altrudev commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Maintainer ruling

Implements the ruling in #596 / #592: structural malformation wins.

If the TRACE Claim does not establish a valid structure, verify_trace_claim() now returns CLAIM_MALFORMED before signature or key-binding interpretation. This is deliberately scoped to the structural stage only; it does not establish any new precedence between signature failure and key-binding failure.

What

The schema stage is now a prerequisite boundary rather than a result that later stages may overwrite:

  • schema failure returns VerificationStatus.UNVERIFIED with CLAIM_MALFORMED;
  • no signature, confirmation-key, policy, catalog, freshness, audit-chain, or platform interpretation occurs for that malformed input;
  • details["malformed_field"] preserves the most specific malformed intermediate established by Pydantic, while details["schema_error"] retains the complete validation diagnostic;
  • existing post-schema verification ordering is unchanged.

This preserves the semantic distinction from the maintainer ruling: a malformed claim has an unevaluated signature, not an invalid signature.

Regression coverage

The former xfail reproducer is now a plain assertion matrix covering:

  • trace;
  • trace.cnf;
  • trace.cnf.jwk;
  • trace.cnf.jwk.x;
  • gateway;
  • gateway.audit_chain;
  • gateway.attestation_evidence.

Fourteen malformed-shape vectors assert CLAIM_MALFORMED, no verified fields, only the schema stage unverified, and the exact malformed intermediate. A separate mutation-oriented test replaces both crypto helpers with fail-fast sentinels and proves malformed structure cannot reach either signature or key-binding interpretation.

Current lineage

Reconstructed directly on current upstream main:

  • predecessor: d9fc737c2e964dc8e63b579382b4fb8b43a4df8a;
  • exact head: 141c5b2ee96c46213f53907260d61139db3f28a8;
  • one commit ahead / zero behind at reconstruction;
  • exactly two changed files: src/cmcp_verify/verify.py and tests/unit/test_verify_malformed_claim_shapes.py.

The four commits that landed after the original reproducer baseline changed OPAQUE/embodied-action code and workflow files; none overlaps these two files.

DDC review

  • Need ≠ Authority: PASS. The change implements the maintainer's explicit structural-precedence ruling and does not extend it.
  • Prerequisite ordering: PASS. Structure is established before any cryptographic interpretation.
  • Failure-path independence: PASS in targeted falsification. All 14 malformed locations resolve to their expected intermediate; removing the structural stop reaches signature and key-binding sentinels and is therefore caught.
  • Semantic containment: PASS. Signature-vs-key-binding precedence after successful schema validation is untouched.
  • Transition lineage: PASS. Candidate is reconstructed on the exact current predecessor with a two-file, one-commit delta.
  • Full repository executable gate: not claimed from this environment. The exact candidate could not be cloned into the available local runner, so repository-wide Ruff/mypy/pytest results are not asserted. No GitHub Actions result is being used as DDC evidence. The PR remains draft until that executable gate is independently satisfied.

No schema or wire-format change is proposed.

AI-assistance disclosure: ChatGPT assisted with source triage, maintainer-ruling translation, DDC falsification design, implementation drafting, exact-lineage reconstruction, and diff review. altrudev reviewed the bounded claim and remains responsible for the contribution.

@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

🟡 Contributor Check: MEDIUM

Check Result
Profile MEDIUM
Credential LOW
Overall MEDIUM

Automated check by AgenTrust Contributor Check.

@github-actions github-actions Bot added the needs-review:MEDIUM Contributor check flagged MEDIUM risk label Aug 30, 2026
@imran-siddique

imran-siddique commented Aug 31, 2026

Copy link
Copy Markdown
Member

Batch response for this cluster is here: agentrust-io/agent-manifest#357 (comment)

Short version: the finding class is real and welcome. Your CI had never run, held under first-time-contributor gating, until I released 36 runs across your PRs an hour ago, and five of your eight are now red. Please fix those, sequence trace-spec#258 against #252 which touch the same two files, and tell me the order you want them reviewed in.

Copy link
Copy Markdown
Contributor Author

I reconciled the released CI failure. The red step was ruff import formatting in the new test file, before the reproducer could execute; that is fixed at 4e2cce1.

Because this PR is explicitly a draft test-first reproducer, I also changed the current-head behavior at 99ba8a3 so only the known host-language escape (AttributeError / TypeError) is reported with pytest.xfail. If verify_trace_claim() returns normally, the original VerificationResult and schema assertions run unchanged. This keeps a known-current defect from making the whole draft CI red without weakening the desired invariant or silently choosing the still-open failure-precedence rule.

I am keeping #596 out of the review queue until the implementation/precedence decision is ready. Fresh CI is currently waiting on workflow approval; no green claim yet.

@imran-siddique

Copy link
Copy Markdown
Member

Thanks for splitting this the way you did. Asserting only the uncontested invariant and holding the precedence question for a maintainer is the right call, and it is the reason this is a useful reproducer rather than a change that quietly decides something.

The ruling: structural malformation wins.

If the claim structure is malformed, CLAIM_MALFORMED is the result, and a subsequent signature or key-binding failure must not overwrite it. Encode that as first-failure-wins for the structural stage specifically, not as a general ordering over all failure kinds.

The reason is not aesthetic. A signature verdict is a statement about a specific set of bytes. When the structure did not parse, the verifier never established what those bytes were, so whatever it computed is a verdict about something it could not identify. Reporting it as SIGNATURE_INVALID tells the caller the signature was checked and found bad. It was not checked. That is the same defect class I have been unpicking across the other repos: absence of evidence surfacing as a negative verdict rather than as "not established". A malformed record is not a record with a bad signature; it is a record whose signature is unevaluated.

The practical consequence is the one that matters to a caller: SIGNATURE_INVALID says do not trust this issuer, and CLAIM_MALFORMED says do not trust this input. Those route to different places, and collapsing the second into the first sends operators after the wrong party.

Two things I do want from the shape of it:

  1. Keep the malformed result carrying which intermediate failed to parse. Your matrix already covers trace, cnf, jwk, jwk.x, gateway, audit_chain and attestation_evidence; a caller debugging a producer needs to know which one, and a single flat CLAIM_MALFORMED throws that away.
  2. Do not extend the precedence rule past the structural stage on my say-so. Ordering between signature failure and key-binding failure is a separate question with its own arguments, and this PR does not need to answer it.

Once that is in, I am happy for the xfails on the escaping shapes to become plain assertions, since the escape itself is a bug we agree on.

Separately, on CI: the one thing still red is ruff rule I001 on the import block in the new test file, at head 99ba8a3. It reports as test (3.13, ubuntu-latest) but the failing step is Lint, so nothing in your matrix has executed yet. ruff check --fix on that file clears it.

@altrudev
altrudev force-pushed the fix/verify-malformed-claims-592 branch from 99ba8a3 to 141c5b2 Compare September 2, 2026 18:03
@altrudev altrudev changed the title test(verify): reproduce malformed TRACE Claim shape escapes fix(verify): preserve structural claim failure Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-review:MEDIUM Contributor check flagged MEDIUM risk

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants