fix(auth): cloud connect --api-key no longer replaces the Polylane key - #104
Merged
Merged
Conversation
`polylane cloud connect --provider triggerdev --api-key <key>` (and the Render form) failed with "Not signed in" right after a successful `polylane auth login`: the parser folds global and command options into one record, so the provider key landed in the global `apiKey`, the loader took it as the Polylane key, and the resolver's raw-argv scan for `--api-key` confirmed it. The API rejected the Trigger.dev key with a 401. The command's declaration now decides ownership: `globalFlagsOf` strips every flag the command declares before the globals reach the loader, so the provider key stays in the command's args and the Polylane credential comes from the env var, the OAuth session, or the config file. The loader records which layer supplied `apiKey` (`apiKeySource`) and the resolver reads that instead of scanning `process.argv`, so a `--api-key` anywhere on the line no longer relabels an env key as a flag key. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
LGTM: Clean ownership split of command vs global flags fixes the --api-key collision; resolver is now argv-free, precedence preserved, tests thorough — one naming nit only.
- [nit] F1 src/commands/auth/login.ts:127 — Prompted API key labelled apiKeySource:'flag' — semantically misleading though functionally correct
Verdict submitted: approve at 2e872bc. The fix is well-scoped and correct — the option-table ownership split keeps the provider key out of the Polylane credential path, the resolver no longer scans argv, and precedence behavior is fully preserved with strong test coverage. Only finding is the F1 nit above.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A user who ran
polylane auth loginand thenpolylane cloud connect --provider triggerdev --api-key <key>sawError: Not signed inon 0.2.37, because the Trigger.dev key was sent to the API as their Polylane key. The connect command now keeps its own--api-keyfor the provider, and sign-in comes from the OAuth session,POLYLANE_API_KEY, or the config file as documented.Why: The parser folds global and command options into one record, so the provider key given to
cloud connect --api-keyfilled the globalapiKey, and the credential resolver's raw scan ofprocess.argvfor--api-keyconfirmed it as a flag-supplied Polylane key; the API answered 401. The Trigger.dev flag arrived in cli#101; Render's--api-keyconnect path had the same defect and is fixed here too.Where to look
--api-keyanywhere on the line cannot relabel an env key as a flag key.apiKeySourcealongsideapiKey, mirroring the precedence it already applies.cloud connect --provider triggerdev|render --api-key <key>with an OAuth session present and asserts the session is used.Feedback wanted: Is an option-table split (a command's declaration shadows the global) the least surprising rule, versus scoping the global
--api-keyto argv positions before the subcommand? The alternative would keeppolylane --api-key <polylane key> cloud connect --api-key <provider key>working; with this fix the last value wins the shared key and the Polylane one is dropped, so that shape needs the env var. A--provider-keyrename would remove the collision outright and is a follow-up, not this PR, since Render users have--api-keytoday.Risk: Every command's global-flag handling passes through the new split; a mistake would drop a legitimate global flag on commands whose options share a name, and today only
cloud connectandauth logindeclare--api-key. Rollback is a revert; no data or config format changes.Verified:
npm run typecheck,npm run lint,npm run test(534 tests, 111 suites, 0 failures; 524 on main); end-to-end dev run on both heads with an unreachable domain, see Validation.Decisions (3)
removeFirstNNonFlags) to keep track of where the subcommand ended, and would silently change meaning when a user types global flags after the subcommand, which the CLI accepts everywhere else.flags ?? env ?? file; recording which branch won is one field, and it makes the resolver a pure function ofConfig, which is what every caller (HTTP client, sockets, setup, status) already passes. The argv scan was the only thing in the auth path reading the raw command line.cloud connect --provider render --api-keyhas shipped for several releases; renaming it to--provider-keyis a separate compatibility decision. Noted as a follow-up.Validation (8 criteria)
POLYLANE_API_KEYglobalFlagsOfstubbed to identity on main's resolver: 4 of 5 fail (actual: 'api-key', expected: 'oauth';actual: 'tr_prod_sk_x', expected: 'sk_from_env')test/connect-api-key-collision.test.ts(2 cases)Not signed infrom the local gate)test/connect-api-key-collision.test.tsPOLYLANE_API_KEYstill authenticates connect, reported as sourceenvtest/connect-api-key-collision.test.ts; fails (actual: 'flag') with main's resolver restored, so the resolver change is load-bearingpolylane --api-key <polylane key> cloud liststill authenticates via the flagtest/connect-api-key-collision.test.ts;test/args.test.tsglobalFlagsOf (3 cases)apiKeySourcefor flag, env, config and nonetest/resolver.test.ts(6),test/loader.test.tscloud connect --provider triggerdev --api-key tr_prod_sk_x --verboseagainstinvalid.invalidwith a fake OAuth session sendsAuthorization: Bearer <redacted>; with no session it exits 3Not signed inbefore any request2e872bc(transcript in the agent report)006de1f: the same invocation sendsx-api-key: <redacted>on bothGET /v1/workspaces/planandPOST /v1/cloud_accounts, with and without the OAuth sessiongit checkout origin/main -- srcin the same worktreeFor agents
Reproduce the bug on main:
HOME=$(mktemp -d) npm run dev -- cloud connect --provider triggerdev --api-key tr_prod_sk_x --workspace ws_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --domain invalid.invalid --verbose --non-interactiveprints> x-api-key: <redacted>; on this branch it printsNot signed in(exit 3) and makes no request.src/generated/is produced bynpm run codegenand is not part of the diff. Known limit, not addressed:polylane --api-key <polylane key> cloud connect --api-key <provider key>resolves both to the same parsed key and the later one wins; usePOLYLANE_API_KEYfor that shape until a--provider-keyrename.🤖 Generated with Claude Code