feat(cli): add cards and auth domains + signed-request header support#704
feat(cli): add cards and auth domains + signed-request header support#704ls-bolt[bot] wants to merge 2 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
@greptileai review |
Greptile SummaryThis PR adds
Confidence Score: 5/5Safe to merge — the new commands are well-isolated, all destructive operations have confirmation prompts, and the two previously flagged issues are both properly addressed in this revision. The signed-retry header plumbing is clean, the spending-limit parser uses a strict regex with InvalidArgumentError, and the test helper isolation fix prevents exitCode bleed between tests. The one remaining wrinkle — cards update checking the raw string instead of the parsed result for its empty-guard — would only manifest with intentionally degenerate whitespace input and the API would reject the empty body anyway. cli/src/commands/cards.ts — the update guard uses the raw flag string rather than the parseList result.
|
| Filename | Overview |
|---|---|
| cli/src/commands/cards.ts | New cards command; --limit NaN guard is present; cards update guard uses raw options.fundingSources (undefined check) rather than the parsed result, allowing whitespace-only input to bypass validation and send an empty PATCH body. |
| cli/src/commands/auth.ts | New auth command; spending-limit parsing uses regex + InvalidArgumentError (previous NaN→null issue addressed); JSON passkey fields parsed with error propagation; confirmation prompts on all destructive operations. |
| cli/src/client.ts | Adds optional headers parameter to get/post/patch/delete; header merging correctly skips undefined values and happens after auth/content-type headers are set. |
| cli/src/signed.ts | New helper adds --wallet-signature / --request-id options and builds the header map; undefined values are filtered by the client layer. |
| cli/test/helpers.ts | Saves/restores env vars and process.exitCode in finally block, preventing test-to-test contamination. |
| cli/test/auth.test.ts | New tests covering all auth sub-commands including spending-limit rejection, signed-retry header forwarding, and empty-filter guard for delegated-keys list. |
| cli/test/cards.test.ts | Tests cover list, create, update (freeze, signed headers, no-arg rejection, CLOSED+funding-sources rejection), and reveal. |
| cli/src/index.ts | Registers new cards and auth commands alongside existing ones; straightforward addition. |
| cli/README.md | Documents cards and auth commands with examples; includes multi-leg signed-retry note and panEmbedUrl caution. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant CLI
participant GridClient
participant GridAPI
Note over User,GridAPI: First leg — unsigned call
User->>CLI: grid cards update Card:1 --state CLOSED
CLI->>GridClient: patch("/cards/Card:1", body)
GridClient->>GridAPI: PATCH /cards/Card:1
GridAPI-->>GridClient: "202 { payloadToSign, requestId }"
GridClient-->>CLI: ApiResponse(202)
CLI-->>User: prints challenge JSON
Note over User,GridAPI: Out-of-band signing
User->>User: sign payloadToSign via embedded-wallet-sign.js
Note over User,GridAPI: Second leg — signed retry
User->>CLI: grid cards update Card:1 --state CLOSED --wallet-signature stamp --request-id req-1
CLI->>GridClient: patch("/cards/Card:1", body, headers)
GridClient->>GridAPI: PATCH /cards/Card:1 + Grid-Wallet-Signature + Request-Id
GridAPI-->>GridClient: "200 { card }"
GridClient-->>CLI: ApiResponse(200)
CLI-->>User: prints updated card JSON
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User
participant CLI
participant GridClient
participant GridAPI
Note over User,GridAPI: First leg — unsigned call
User->>CLI: grid cards update Card:1 --state CLOSED
CLI->>GridClient: patch("/cards/Card:1", body)
GridClient->>GridAPI: PATCH /cards/Card:1
GridAPI-->>GridClient: "202 { payloadToSign, requestId }"
GridClient-->>CLI: ApiResponse(202)
CLI-->>User: prints challenge JSON
Note over User,GridAPI: Out-of-band signing
User->>User: sign payloadToSign via embedded-wallet-sign.js
Note over User,GridAPI: Second leg — signed retry
User->>CLI: grid cards update Card:1 --state CLOSED --wallet-signature stamp --request-id req-1
CLI->>GridClient: patch("/cards/Card:1", body, headers)
GridClient->>GridAPI: PATCH /cards/Card:1 + Grid-Wallet-Signature + Request-Id
GridAPI-->>GridClient: "200 { card }"
GridClient-->>CLI: ApiResponse(200)
CLI-->>User: prints updated card JSON
Reviews (3): Last reviewed commit: "feat(cli): add cards and auth domains + ..." | Re-trigger Greptile
848b62b to
fc569a6
Compare
d8e8758 to
102281f
Compare
Revision — addressed Greptile + Faraday review
|
|
@greptileai review |
fc569a6 to
da61871
Compare
102281f to
d573b9f
Compare
|
@greptileai review |
New cards commands (list/get/create/update/reveal) and auth commands (credentials, delegated-keys, sessions). Extend GridClient so get/post/patch/ delete accept optional headers, and expose --wallet-signature/--request-id on the signed-retry operations (the CLI forwards a caller-supplied Turnkey stamp; it does not compute one). vitest boundary tests cover both domains.
d573b9f to
876fe21
Compare
da61871 to
b0aab72
Compare

Summary
Adds the cards and auth domains to the Grid CLI, plus signed-request header support so the signed-retry flows are usable. Stacked on #702/#703.
cards (
grid cards …)list,get,create,update(freeze/unfreeze/replace-sources/close),reveal(prints the short-livedpanEmbedUrl). Nodelete— closing isupdate --state CLOSED.auth (
grid auth …)credentials—list,create,challenge(OTP resend / passkey re-challenge),verify,revokedelegated-keys—list,get,create(with repeatable--spending-limit CUR:amount),revokesessions—list,refresh,revokeSigned-request support
Many auth operations and
cards updateuse Grid's signed-retry flow (first call returns202+payloadToSign; the retry carries aGrid-Wallet-Signature+Request-Id). This PR:GridClientsoget/post/patch/deleteaccept optional headers;--wallet-signature/--request-idon the signed operations.The CLI forwards a caller-supplied stamp — it does not compute the Turnkey/HPKE signature itself (compute it with
scripts/embedded-wallet-sign.jsor your own tooling). Passkey create/verify likewise accept the WebAuthn--attestation/--assertionas JSON you produce client-side.Note on structure
The plan proposed cards and auth as two separate stacked PRs. They share the new
client.tsheader plumbing (andauthdepends on it) and both touchindex.ts, so I've kept them in one PR to avoid a fragile cross-branch split. Say the word if you'd prefer them separated.Test plan
cd cli && npm run build— clean strict compile.npm test— 53 boundary tests (19 new for cards + auth), asserting each command's method/path/query/body/headers.Known follow-up
configure --client-secret) — not done here.