Skip to content

test(interop): add x402-exact intent + TS reference fixtures + matrix wiring#132

Closed
EfeDurmaz16 wants to merge 7 commits into
solana-foundation:mainfrom
EfeDurmaz16:pr/x402-harness-intent
Closed

test(interop): add x402-exact intent + TS reference fixtures + matrix wiring#132
EfeDurmaz16 wants to merge 7 commits into
solana-foundation:mainfrom
EfeDurmaz16:pr/x402-harness-intent

Conversation

@EfeDurmaz16

@EfeDurmaz16 EfeDurmaz16 commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds the x402-exact intent to the cross-language interop harness, with TypeScript reference client + server fixtures, base scenarios, and matrix wiring registering the Rust spine adapters from rust/crates/x402/src/bin/. Language adapters validate against the Rust spine through the same harness contract.

Scope

  • Intent contract types at harness/src/intents/x402-exact.ts with 5 scenarios (basic, network-mismatch, cross-route-replay, cross-server-portability, idempotent-resubmit)
  • TS reference adapters at harness/src/fixtures/typescript/exact-{client,server,shared}.ts
  • allowedPair helper made data-driven: walks the registered x402-exact adapters and accepts TS self-pair, Rust self-pair, same-language self-pairs, and Rust cross-spine pairs in either direction. New ports widen the matrix automatically with no test edits.
  • Rust adapter cargo --manifest-path corrected from ../../rust/Cargo.toml to ../rust/Cargo.toml after the tests/interop to harness rename
  • Env-var contract documented in harness/README.md

Files changed

  • Harness: harness/src/intents/x402-exact.ts, harness/src/fixtures/typescript/exact-{client,server,shared}.ts, harness/src/implementations.ts
  • Tests: harness/test/x402-exact.e2e.test.ts, harness/test/cross-server-scenarios.test.ts
  • Docs: harness/README.md

Security highlights

  • Canonical reject codes already declared in canonical-codes.ts (wrong_network, charge_request_mismatch, challenge_verification_failed, signature_consumed)
  • TS reference fixture uses a stub credential payload (challenge id + resource) and is restricted by allowedPair to its self-pair, so it cannot give false-positive coverage against canonical servers
  • The legacy MPP charge runner hard-skips the new intent so default pnpm test behaviour is unchanged

Test evidence

  • pnpm install: clean
  • pnpm exec vitest run test/intent-selection.test.ts test/canonical-json.test.ts test/x402-exact.e2e.test.ts test/cross-server-scenarios.test.ts test/process.test.ts: 3 files passed, 19 tests passed, 2 skipped (matrix gates inactive without RPC env)
  • With X402_INTEROP_MATRIX=1 plus dummy required envs: this branch alone (TS + Rust registered) enumerates 2 pairs; once the 6 language adapter PRs land, the same filter expands to 15 pairs
  • cargo build --manifest-path ../rust/Cargo.toml -p solana-x402 --bin interop_client from harness/: clean
  • Codex r8: 0 P1, confidence 4/5 (notes/codex-review/pr-132-r8.md)

Closes / supersedes

None.

Reviewer notes

…eferences (solana-foundation#122)

Per maintainer guidance in solana-foundation#122, this is a transversal cleanup PR:

Part A — remove internal kitchen references
- Drop M1/M2/M3 milestone framing from swift/README.md, swift/Examples/README.md
- Reword 'M1 baseline / M2-followup' coverage gate comments in python/pyproject.toml
  and .github/workflows/python.yml as plain coverage gate descriptions
- Remove 'M1 closure / L6 audit row' tag from lua/mpp/protocol/core/error_codes.lua

Part B — rename tests/interop to harness
- git mv tests/interop harness
- Update all path references repo-wide (.github/workflows/*, READMEs,
  .gitignore, docs, composer.json, .php-cs-fixer.dist.php, skill files)
- Fix relative paths inside the harness now that depth dropped by one
  (rust-client/Cargo.toml, php-server, ruby-server, go.mod replace lines,
  src/implementations.ts, test/compute-budget-caps.test.ts REPO_ROOT)
- Update Go module identifiers harness/{go-client,go-server} to match path
- Refresh internal comments/docs that still mentioned tests/interop

Part C — skill / README polish
- Skill references and intent docs now point at harness/* paths

Closes solana-foundation#122.
After renaming tests/interop/swift-client to harness/swift-client the
.package(path:) relative depth dropped by one; the previous '../../../swift'
resolved outside the repo. Surfaced by codex self-review.

Refs solana-foundation#122.
EfeDurmaz16 added a commit to EfeDurmaz16/mpp-sdk that referenced this pull request May 25, 2026
Cross-spine wiring on top of pr/transversal-cleanup (solana-foundation#131) and
pr/x402-harness-intent (solana-foundation#132). 0 new P1; ruby-x402-client and
ruby-x402-server adapters register cleanly with intents:
[x402-exact]. Matrix enumerates 9 pairs; allowedPair gate still
blocks ruby pairs from running, tracked as P2 follow-up.
Adds the canonical x402 `exact` intent to the cross-language interop
harness, plus TypeScript reference client and server fixtures and
matrix wiring that registers the Rust spine adapters already shipped
under `rust/crates/x402/src/bin/`. Language adapters can now target
the harness contract (X402_INTEROP_* env vars, ready/result JSON
shapes) to validate against the Rust spine cell.

The TS reference fixture carries a stub credential payload (challenge
id + resource) so the harness wiring, negative-code classification,
cross-server portability, and idempotent-resubmit flows can run
without a full Solana signer. Pair restriction in the matrix gates
TS↔TS and Rust↔Rust by default; full TS↔Rust on-chain settlement
parity lands with a follow-up SDK port.

The legacy MPP charge runner hard-skips the new intent so default
`pnpm test` behaviour is unchanged.
Three fixes so the x402-exact matrix actually executes once the
language adapter PRs (solana-foundation#124, solana-foundation#126, solana-foundation#127, solana-foundation#128, solana-foundation#129, solana-foundation#130) rebase on top
of this branch:

1. Pair filter is data-driven. Previously only ts-x402 self-pair and
   rust-x402 self-pair were accepted. Now the filter walks the
   registered adapters and accepts any pair where: both sides are the
   TS reference (stub-payload), both sides are the Rust spine, the two
   sides share a base language id (same-language self-pair, e.g.
   go-x402-client <-> go-x402-server), or one side is the Rust spine
   (cross-spine pair in either direction). TS reference is locked to
   its self-pair only because its stub payload would fail real
   signature verification on any other server.

2. rust-x402 cargo --manifest-path corrected from ../../rust/Cargo.toml
   to ../rust/Cargo.toml. The path was stale after the
   tests/interop -> harness rename; the existing rust (charge) entries
   already used the correct relative path, the x402 entries did not.

3. Pair selector docstring rewritten to spell out the data-driven
   matrix policy so future language ports don't need to touch the test.
…rver

The TS x402 fixture server gated its cross-server portability
rejection behind `issued.size > 0`, so a freshly started server (or
one that had not yet issued any 402 challenge) would accept any
challengeId from another server's credential and settle it. That
contradicts canonical Rust behavior, which rejects unknown
challengeIds with `challenge_verification_failed` from the very
first request.

Drop the `issued.size > 0` guard so the membership check fires
unconditionally. The happy-path flow (GET /protected -> 402 with
challengeId -> POST with challengeId) is unaffected because the
served challengeId is added to `issued` on the 402 path before
the client returns.

Codex r8 solana-foundation#132 P2: cross-server replay to a fresh TS server now
returns `challenge_verification_failed` immediately rather than
settling.
… key envs

The x402-exact-network-mismatch and x402-exact-cross-route-replay
scenarios were registered in src/intents/x402-exact.ts but never run
by any test (only the happy path was exercised in e2e.test.ts).
Add a TS-only negative-scenario suite that drives each one against
the TS reference server with hand-crafted credentials and asserts
the canonical reject code.

The network-mismatch scenario was previously a no-op even if invoked
because the scenario.network value flowed to both client and server.
The new test sends distinct networks: server advertises offers on
network A, credential claims network B, server emits wrong_network.

The TS reference fixture parsed X402_INTEROP_CLIENT_SECRET_KEY and
X402_INTEROP_FACILITATOR_SECRET_KEY as required envs but never read
them (stub credential, no on-chain signing). Drop the requirement
so the verifier surface can be exercised without standing up a
Surfpool RPC or funded keypair; the live matrix in
x402-exact.e2e.test.ts still requires them via the test guard.
Real-signing language adapters read their own keypair envs.
EfeDurmaz16 added a commit to EfeDurmaz16/mpp-sdk that referenced this pull request May 26, 2026
…irs + parity locks)

Add three-tier x402-exact test architecture on top of solana-foundation#132:

1. Wire compat (no RPC, default `pnpm test`):
   - `harness/test/x402-exact.compat.test.ts`
   - Drives every registered x402-exact adapter (gated by
     COMPAT_INCLUDE_IDS) against canonical fixtures and an attack
     suite. Catches wire-format drift before the live matrix runs.

2. Parity-lock fixtures (`harness/fixtures/x402-exact/`):
   - canonical-challenge.json — 402 envelope every client must parse.
   - canonical-payment-signature.json — credential every server must
     parse (accept or reject with a known token).
   - canonical-reject-tokens.json — union of high-level reject tokens
     and the invalid_exact_svm_payload_* family mirrored from
     rust/crates/x402/src/protocol/schemes/exact/verify.rs.
   - attack-scenarios.json — 9 tampered credential scenarios + replay.

3. Live full matrix (`harness/test/x402-exact.live.matrix.test.ts`):
   - Env-gated (X402_INTEROP_MATRIX=1 + funded keypair). Enumerates
     every allowedPair from the policy in implementations.ts and runs
     the happy path. Widens automatically as new adapters register.

Also expand `harness/test/x402-exact.e2e.test.ts` with an explicit
self-pair group so per-language regressions stand out in vitest output,
and update `harness/README.md` with the three-tier documentation and
extension recipe.
@EfeDurmaz16

Copy link
Copy Markdown
Collaborator Author

Folded into #134 (combined intent + matrix per maintainer preference for a single reviewable harness PR). Closing as superseded.

EfeDurmaz16 added a commit to EfeDurmaz16/mpp-sdk that referenced this pull request May 26, 2026
Cross-spine wiring on top of pr/transversal-cleanup (solana-foundation#131) and
pr/x402-harness-intent (solana-foundation#132). 0 new P1; ruby-x402-client and
ruby-x402-server adapters register cleanly with intents:
[x402-exact]. Matrix enumerates 9 pairs; allowedPair gate still
blocks ruby pairs from running, tracked as P2 follow-up.
EfeDurmaz16 added a commit to EfeDurmaz16/mpp-sdk that referenced this pull request May 26, 2026
…rver

The TS x402 fixture server gated its cross-server portability
rejection behind `issued.size > 0`, so a freshly started server (or
one that had not yet issued any 402 challenge) would accept any
challengeId from another server's credential and settle it. That
contradicts canonical Rust behavior, which rejects unknown
challengeIds with `challenge_verification_failed` from the very
first request.

Drop the `issued.size > 0` guard so the membership check fires
unconditionally. The happy-path flow (GET /protected -> 402 with
challengeId -> POST with challengeId) is unaffected because the
served challengeId is added to `issued` on the 402 path before
the client returns.

Codex r8 solana-foundation#132 P2: cross-server replay to a fresh TS server now
returns `challenge_verification_failed` immediately rather than
settling.
EfeDurmaz16 added a commit to EfeDurmaz16/mpp-sdk that referenced this pull request May 26, 2026
…irs + parity locks)

Add three-tier x402-exact test architecture on top of solana-foundation#132:

1. Wire compat (no RPC, default `pnpm test`):
   - `harness/test/x402-exact.compat.test.ts`
   - Drives every registered x402-exact adapter (gated by
     COMPAT_INCLUDE_IDS) against canonical fixtures and an attack
     suite. Catches wire-format drift before the live matrix runs.

2. Parity-lock fixtures (`harness/fixtures/x402-exact/`):
   - canonical-challenge.json — 402 envelope every client must parse.
   - canonical-payment-signature.json — credential every server must
     parse (accept or reject with a known token).
   - canonical-reject-tokens.json — union of high-level reject tokens
     and the invalid_exact_svm_payload_* family mirrored from
     rust/crates/x402/src/protocol/schemes/exact/verify.rs.
   - attack-scenarios.json — 9 tampered credential scenarios + replay.

3. Live full matrix (`harness/test/x402-exact.live.matrix.test.ts`):
   - Env-gated (X402_INTEROP_MATRIX=1 + funded keypair). Enumerates
     every allowedPair from the policy in implementations.ts and runs
     the happy path. Widens automatically as new adapters register.

Also expand `harness/test/x402-exact.e2e.test.ts` with an explicit
self-pair group so per-language regressions stand out in vitest output,
and update `harness/README.md` with the three-tier documentation and
extension recipe.
EfeDurmaz16 added a commit to EfeDurmaz16/mpp-sdk that referenced this pull request May 26, 2026
Cross-spine wiring on top of pr/transversal-cleanup (solana-foundation#131) and
pr/x402-harness-intent (solana-foundation#132). 0 new P1; ruby-x402-client and
ruby-x402-server adapters register cleanly with intents:
[x402-exact]. Matrix enumerates 9 pairs; allowedPair gate still
blocks ruby pairs from running, tracked as P2 follow-up.
EfeDurmaz16 added a commit to EfeDurmaz16/mpp-sdk that referenced this pull request May 26, 2026
…rver

The TS x402 fixture server gated its cross-server portability
rejection behind `issued.size > 0`, so a freshly started server (or
one that had not yet issued any 402 challenge) would accept any
challengeId from another server's credential and settle it. That
contradicts canonical Rust behavior, which rejects unknown
challengeIds with `challenge_verification_failed` from the very
first request.

Drop the `issued.size > 0` guard so the membership check fires
unconditionally. The happy-path flow (GET /protected -> 402 with
challengeId -> POST with challengeId) is unaffected because the
served challengeId is added to `issued` on the 402 path before
the client returns.

Codex r8 solana-foundation#132 P2: cross-server replay to a fresh TS server now
returns `challenge_verification_failed` immediately rather than
settling.
EfeDurmaz16 added a commit to EfeDurmaz16/mpp-sdk that referenced this pull request May 26, 2026
…irs + parity locks)

Add three-tier x402-exact test architecture on top of solana-foundation#132:

1. Wire compat (no RPC, default `pnpm test`):
   - `harness/test/x402-exact.compat.test.ts`
   - Drives every registered x402-exact adapter (gated by
     COMPAT_INCLUDE_IDS) against canonical fixtures and an attack
     suite. Catches wire-format drift before the live matrix runs.

2. Parity-lock fixtures (`harness/fixtures/x402-exact/`):
   - canonical-challenge.json — 402 envelope every client must parse.
   - canonical-payment-signature.json — credential every server must
     parse (accept or reject with a known token).
   - canonical-reject-tokens.json — union of high-level reject tokens
     and the invalid_exact_svm_payload_* family mirrored from
     rust/crates/x402/src/protocol/schemes/exact/verify.rs.
   - attack-scenarios.json — 9 tampered credential scenarios + replay.

3. Live full matrix (`harness/test/x402-exact.live.matrix.test.ts`):
   - Env-gated (X402_INTEROP_MATRIX=1 + funded keypair). Enumerates
     every allowedPair from the policy in implementations.ts and runs
     the happy path. Widens automatically as new adapters register.

Also expand `harness/test/x402-exact.e2e.test.ts` with an explicit
self-pair group so per-language regressions stand out in vitest output,
and update `harness/README.md` with the three-tier documentation and
extension recipe.
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