Skip to content

feat(gateway): retire the provisioning wildcard — new keys get [operator], wallet claims SIWE-gated (item-5 L1) - #308

Open
LamaSu wants to merge 3 commits into
masterfrom
feat/auth-integrated
Open

feat(gateway): retire the provisioning wildcard — new keys get [operator], wallet claims SIWE-gated (item-5 L1)#308
LamaSu wants to merge 3 commits into
masterfrom
feat/auth-integrated

Conversation

@LamaSu

@LamaSu LamaSu commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Item 4 of the frictionless-Runtype remainder / item-5 L1. Integrates auth lane's feat/auth (was 33 commits behind) onto current master. Clean auto-merge; 11 auth tests pass (provision-scopes, provision-wallet-siwe with a real SIWE round-trip, admin-key-audit).

What it fixes

  • provision.ts mints scopes: ["operator"], never ["*"] (verified line 141). The stated item-4 gap closed for new keys.
  • Wallet provisioning is SIWE-gated: a bare walletAddress string is no longer trusted — caller must prove control via nonce→verify→session (bind-on-proof).
  • New GET /api/admin/keys/wildcard-audit (admin-gated) reports how many existing keys still hold *, so re-scoping is a decision with real numbers.

Money-path review (gateway, done — not assumed)

  • Onboarding is NOT broken: operator scope permits the registration writes. POST /api/capabilities has no scope rule (falls through, allowed for any authed key); /api/kernels grants operator|admin. Verified against scope-checker.ts.
  • operator is the money scope (escrow + fiat-ramp POST require operator|admin). So it is narrowed, not wildcard — but broader than the strict {fund,release,dispute} least-privilege the full item-5 targets. Honest caveat, not a blocker.
  • Existing ["*"] keys are unchanged (audit-only) and still hit the wildcard short-circuit. Re-scoping them is the operator's rollout call.

NOT merging on my own

This is a money-path auth change. Per the standing stipulation it needs a cross-family (sol) review before merge, and the operator's call on the narrowness tradeoff. Pushing + PR'ing so CI runs and review can happen; hold merge until sol signs off and CI is green.

🤖 gateway lane 0600b204 (integrating auth ab7b7c75's feat/auth)

LamaSu and others added 3 commits August 27, 2026 00:26
… #1099 piece 4)

GET /api/admin/keys/wildcard-audit gives an operator visibility into which
active API keys still carry scopes:["*"] (from before self-service
provisioning was narrowed) and how recently each was used, so migrating or
revoking them is an informed operator decision rather than something a code
change makes unilaterally -- some may back live integrations. Gated by
apiGate auth + scope-checker admin scope + an explicit PCC_KEY_ADMINS
allowlist that fails closed when unset. Read-only; revocation already exists
via DELETE /api/auth/keys/:keyId.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLJu9NPK6KmFrmTRvwawPC
…et claims (retire-the-wildcard #1099)

Every PCC key was minted with scopes:["*"], which scope-checker's wildcard
short-circuit lets bypass every scope check including the money path
(coord #615). This closes the provisioning half of that gap (scope-checker's
own escrow/fiat-ramp default-deny half already landed separately):

- POST /api/auth/provision now mints scopes:["operator"] instead of ["*"].
  That covers the documented self-service quick-start (register a kernel,
  submit evidence, build/negotiate a contract) without admin access or a
  money-path bypass.
- A bare walletAddress string in the request body is no longer trusted as
  proof of wallet control -- anyone could previously provision a live key
  against an address they don't own. The already-existing EIP-4361 (SIWE)
  nonce/verify machinery (auth/siwe-auth.ts) is now wired in: the caller
  must prove control via GET /api/auth/nonce -> sign -> POST
  /api/auth/verify, then provision using the verified session (bearer
  token or cookie). A claimed walletAddress that doesn't match the
  session's address is rejected with 401 wallet_not_verified.
- Fixes a missing `resolveSession` import that would have thrown at
  runtime, and fixes erc8004-identity-write.test.ts's wallet-path test,
  which asserted on an unprovable hardcoded address -- it now proves
  ownership through the real SIWE flow like provision-wallet-siwe.test.ts.

Deliberately NOT changed here: scope-checker's wildcard short-circuit
itself. Every key issued before this change still carries scopes:["*"],
and flipping the short-circuit off would immediately break all of them,
possibly including live integrations. That is a rollout/migration decision
for the operator, not something to make unilaterally -- see
routes/admin-key-audit.ts (piece 4) for the visibility to make that call,
and scope-checker-money-path.test.ts's "KNOWN GAP" test, which pins the
gap deliberately so it can't be mistaken for closed.

Scope note: this wires SIWE for wallet-bearing (machine/agent) operators
only. The human-with-no-wallet path (coord #1299 vs #1310, flagged by
gateway 0600b204) is a separate, still-open product decision and is
untouched here -- it decides who can hold money authority, which is the
operator's call, not a lane's.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XLJu9NPK6KmFrmTRvwawPC
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