Skip to content

fix(link-legacy-key): validate response with Zod and add fetch timeout#2

Merged
matmilbury merged 2 commits into
mainfrom
fix/link-legacy-key-review-fixes
Apr 27, 2026
Merged

fix(link-legacy-key): validate response with Zod and add fetch timeout#2
matmilbury merged 2 commits into
mainfrom
fix/link-legacy-key-review-fixes

Conversation

@matmilbury
Copy link
Copy Markdown
Contributor

Summary

Addresses two issues from code review of #1:

  • Replace as LinkResult cast with Zod schema parsingres.json() returns external data from mcp-gateway. Casting with as bypasses runtime validation; if the response shape drifts, the code silently takes the wrong branch. Now uses LinkResultSchema.parse() which throws a clear error on malformed responses.
  • Add AbortSignal.timeout(10s) to the fetch call — Without a timeout, a misbehaving mcp-gateway (accepts TCP, never responds) hangs eterna login indefinitely. The 10s timeout ensures the CLI falls through to the existing warning path.

Also adds zod as a production dependency and creates src/auth/validation.ts for the schema (per CLAUDE.md: "Define schemas in validation.ts").

Test plan

  • Run eterna login with ETERNA_MCP_KEY set — verify link succeeds and prints "Legacy account linked"
  • Run eterna login with ETERNA_MCP_KEY set against a non-JSON-returning endpoint — verify Zod parse error is caught gracefully
  • Run eterna login with ETERNA_MCP_URL pointing to a blackhole (accepts TCP, never responds) — verify timeout after ~10s with warning message
  • npm run typecheck passes
  • npm run build passes

🤖 Generated with Claude Code

@matmilbury matmilbury changed the base branch from feature/legacy-key-migration to main April 27, 2026 08:53
@matmilbury matmilbury force-pushed the fix/link-legacy-key-review-fixes branch from cbe245b to 49ed3f9 Compare April 27, 2026 08:55
Replace `as LinkResult` cast on the mcp-gateway response with Zod schema
parsing to catch malformed responses at runtime instead of silently
proceeding with wrong data. Add AbortSignal.timeout(10s) to the fetch
call to prevent the login command from hanging indefinitely if
mcp-gateway accepts TCP but never responds.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matmilbury matmilbury force-pushed the fix/link-legacy-key-review-fixes branch from 49ed3f9 to ee8dd24 Compare April 27, 2026 08:56
@matmilbury
Copy link
Copy Markdown
Contributor Author

Code review

Found 1 issue:

  1. LinkResultSchema.parse() can throw an unhandled ZodError when the server returns an unexpected response shape. Every other failure path in linkLegacyKey (network error, HTTP 409, other HTTP errors) uses console.warn and returns cleanly — the function was designed to never throw. The .parse() call on line 38 is outside the try/catch block (which only wraps fetch), so a ZodError propagates to the caller in login.ts, where it is caught by the outer try/catch that calls stopSpinner(false, "Authentication failed") and sets process.exitCode = 1 — even though OAuth login already succeeded and tokens were saved. Wrap the parse in a try/catch consistent with the existing pattern, or use .safeParse() instead.

});
} catch {
console.warn(
"Warning: Could not reach mcp-gateway to link legacy key — your existing Bybit subaccount may not be preserved.",
);
return;
}
if (res.ok) {
const data = LinkResultSchema.parse(await res.json());
if (data.linked) {
console.log(
`✓ Legacy account linked — existing Bybit subaccount preserved`,
);

Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

Replace .parse() with .safeParse() so validation failures follow the
existing warn-and-return pattern instead of throwing an uncaught
ZodError that propagates to login.ts and reports 'Authentication failed'
despite a successful OAuth login.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@matmilbury matmilbury merged commit f64ac04 into main Apr 27, 2026
1 check passed
@matmilbury matmilbury deleted the fix/link-legacy-key-review-fixes branch April 27, 2026 09:26
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