feat(ap2): official-toolchain fixtures + interop + kid-binding fix (AK-1 tail)#106
Conversation
…T1/AC1/AC6/T9) Closes the AK-1 DoD tail: the VC verify pipeline was merged but backed only by synthetic fixtures, so the approved AP2 deck phrase was not yet earned. This slice produces official-toolchain interop evidence. T1/AC1 — official reference fixtures: - The google-agentic-commerce/AP2 reference repo (pinned e1ea56d, the same commit our spec-pin already targets) ships NO pre-signed sample mandate VCs, only models/schemas/tests that mint at runtime. So the honest "official sample" is one minted with the reference SD-JWT issuer. - tests/fixtures/ap2/generate.py drives ap2.sdk.sdjwt.sd_jwt.create (ES256, RFC 9901) over the genuine ap2.models IntentMandate/CartMandate bodies with a deterministic issuer key, and vendors intent/cart VC envelopes + the issuer DID document + meta + PROVENANCE.md (source URL, commit SHA, retrieval date). AC1 interop finding (real, fixed): the reference issuer emits a BARE JOSE kid (e.g. `issuer-key-1`), but the verifier required a DID-fragment-qualified VM id. Different namespaces — every reference mandate failed AP2_KEY_RESOLUTION_FAILED. Fixed: kid now also matches the VM-id fragment / `<did>#<kid>`, WITHOUT weakening the cross-issuer-confusion guard (candidate keys still come only from the issuer's own DID document). Regression tests cover bare-kid match + non-match. AC6 — interop CI: .github/workflows/ap2-interop.yml (workflow_dispatch + weekly schedule, ubuntu-latest, SHA-pinned actions). interop-checked-in always verifies the committed reference-minted fixtures; interop-fresh regenerates them from the reference SDK and round-trips — guarded by a single documented skip when the upstream toolchain is unavailable (the sole permitted skip in this epic). T7 — Python parity gap: documented (not half-implemented) in the Python README with an explicit "do not represent Python as verifying" guardrail + follow-up TODO, per T7's allowance. T9 — honesty docs: ap2-vc.ts spec-pin notes the vendored fixtures; the main README AP2 honesty note now states official-fixture-backed verification (TS-side) and what it does NOT cover (Python verify, mandate issuing). Gates: eslint src 0 errors, tsc --noEmit clean, full suite 555 pass / 0 skip, coverage on src/ap2-vc.ts 87.8% stmts / 86.2% branch (≥80/70), open-core boundary clean. Fixtures regenerate deterministically (issuer key byte-stable). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…eanup) The generator imports the external google-agentic-commerce/AP2 reference SDK, present only in the AC6 interop CI job / a local reference env. File-level pyright directive suppresses the expected unresolved-import + unused warnings (IDE noise only; not on build/test/lint path). Non-blocking CONCERNS from @qa gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 18 minutes and 29 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (12)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
FriendlyAI review unavailable — upstream errorThe review service returned an error, so no verdict was produced. This is a neutral result, not a block. If this PR needs to merge while review is unavailable, a maintainer can apply the |
There was a problem hiding this comment.
Code Review
This pull request integrates official-toolchain interop fixtures and tests for AP2 mandate verification, documenting the Python SDK's parity gap and updating the TypeScript verifier to resolve bare kid namespaces emitted by the reference issuer. Feedback on the changes suggests simplifying the fragmentOf helper function in src/ap2-vc.ts and replacing the legacy JSON.parse(JSON.stringify(...)) deep cloning pattern in the tests with the native structuredClone() API.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const fragmentOf = (id: string): string => { | ||
| const hash = id.indexOf('#'); | ||
| return hash >= 0 ? id.slice(hash + 1) : id; | ||
| }; |
There was a problem hiding this comment.
The fragmentOf helper function can be simplified by leveraging the behavior of String.prototype.slice() when passed 0 (which happens when indexOf('#') returns -1). This avoids the need for an explicit ternary check and local variable assignment, making the code more concise and readable.
const fragmentOf = (id: string): string => id.slice(id.indexOf('#') + 1);|
|
||
| describe('[INTEROP] AC2 - tampered real Cart Mandate fails closed', () => { | ||
| function tamper(mutate: (vc: Ap2MandateVc) => void): Ap2MandateVc { | ||
| const clone = JSON.parse(JSON.stringify(cartVc)) as Ap2MandateVc; |
There was a problem hiding this comment.
Instead of using the legacy JSON.parse(JSON.stringify(...)) pattern for deep cloning, you can use the native, standard structuredClone() API. It is cleaner, more performant, and preserves the type of cartVc without requiring an explicit type assertion.
| const clone = JSON.parse(JSON.stringify(cartVc)) as Ap2MandateVc; | |
| const clone = structuredClone(cartVc); |
AK-1 tail — AP2 official-toolchain fixtures + interop + kid-binding fix
Status
What this delivers
kidis rejected (no key-confusion path).Known gaps / skips (documented)
tests/scripts/verify-policy-wasm.test.ts(OPA WASM) surfaces red, it is out-of-scope and non-blocking.Independence
Independent of B1 wire-contract PRs — touches different files, no ordering dependency.
Resolves part of #103.