Skip to content

Bring draft-02 implementation (PR #8) onto master - #9

Merged
sunilp merged 16 commits into
masterfrom
fix/test-counts
Oct 10, 2026
Merged

sunilp merged 16 commits into
masterfrom
fix/test-counts

Conversation

@sunilp

@sunilp sunilp commented Oct 10, 2026

Copy link
Copy Markdown
Owner

PR #8 was stacked on fix/test-counts and merged there after #7 had already merged to master, so master is missing the draft-02 work. This carries it over unchanged. Same tests as #8: 323 Python, 80 Rust, 26 cross-language conformance passing locally. CI cannot run while the Actions billing lock is in place.

sunilp added 16 commits October 10, 2026 15:48
V3, V4 and V5 now have one implementation that works on structured link
values. Both encodings will parse into it. Also adds TokenError.wire_code,
which always returns the aip_-prefixed code the draft uses.
Each link is a JWS signed by the key the previous link named in cnf, and
carries the SHA-256 of the previous link. Delegator identity is therefore
authenticated, unlike the Biscuit encoding. Verification runs V1 here and
V3 to V5 on the shared chain model.
Adds detect_format so bindings can pick a verifier. CompactToken is kept
and marked deprecated.
Any prefix of a valid chain also verifies and carries wider authority, so a
relying party that needs attenuation to hold against downstream holders must
check proof of possession against the leaf link's cnf key. leaf_holder_key()
exposes it. verify now raises only TokenError for non-string tokens and bad
root keys, and cnf jwk x must be strict base64url.
The regex attenuation walk is gone; V3, V4 and V5 now run in
chain_model.verify_links for both encodings. Domains are encoded as facts
only, since a Datalog check would reject every request that names no
domain, and are checked structurally.
An empty tools or domains list meant different things by encoding: Biscuit
wrote no facts, so it inherited the parent value, while JWT denied every
domain. It is now malformed in both encodings, at verify_links and at mint
time. Biscuit links() also rejects repeated single-valued facts, and forged
block tests cover domain widening, extended expiry and max_depth in a
delegation block.
The spec says base64url; Python decoded standard base64, so roughly
half of spec-conformant signatures failed. Standard base64 is still
accepted for documents written by earlier releases. Rust (hex) is
unchanged and tracked in the draft's implementation status section.
Bindings now pick a verifier by token format. The proxy applies V2 root
binding and the deployment audit to JWT chains the same way it does to
Biscuit chains.
The same forged-delegation cases run through Biscuit and JWT, so the two
encodings cannot drift apart while their own tests keep passing.
A review of draft-prakash-aip-02 found that CompactToken.verify never read the JWT header, so a plain EdDSA JWT with typ JWT or no typ, signed by the root key, was accepted by the MCP middleware. Section 5.1.4 limits legacy acceptance to typ aip+jwt. Verify now rejects any other typ as token_malformed before decoding.
A review of draft-prakash-aip-02 found that links() turned a missing identity fact on block 0 into an empty issuer, and a missing delegator or delegate on a delegation block into an empty or null party, with nothing rejecting it. Table 1 makes issuer required for all links and delegate required for delegation links, so a block missing a required fact is now token_malformed, checked next to the duplicate-fact rejection.
Bump version to 0.6.0 (pyproject and aip_core.__version__), add the 0.6.0 changelog entry, add a JWT chain README example with the truncation and proof-of-possession warning, and refresh the test count.
Implement draft-02: JWT chain encoding, shared chain model, 0.6.0 prep
@sunilp
sunilp merged commit 69695e6 into master Oct 10, 2026
0 of 2 checks passed
@coderabbitai

coderabbitai Bot commented Oct 10, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 59bb117e-a2c6-4bf3-81bd-b39e457e75a9

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

1 participant