Skip to content

Commit 52468f5

Browse files
TheodoreSpeaksclaude
authored andcommitted
fix(cli-auth): name minted keys by timestamp, not date
A second login on the same day failed with `A workspace API key named "CLI (2026-07-30)" already exists` — after the user had already approved in the browser, so the whole handoff was wasted and there was no way to complete it without renaming the existing key. Key names are unique per owner, so the name has to be unique per login. Now `CLI (2026-07-30 15:42:07Z)`: second precision, UTC so it is unambiguous in a shared workspace key list and sorts chronologically. The comment claiming a same-day collision was desirable (so logins would reuse one key) was wrong — nothing reuses the key, the mint just fails. A collision at second precision now means something genuinely unexpected, so it is still surfaced rather than retried under a suffixed name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EsThUPqZXjwuuyRjBbmVkj
1 parent 4fbf6b7 commit 52468f5

2 files changed

Lines changed: 19 additions & 7 deletions

File tree

apps/sim/app/api/cli/auth/poll/route.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ describe('POST /api/cli/auth/poll', () => {
9999
workspaceId: null,
100100
workspaceBound: false,
101101
})
102-
expect(mockGenerateCopilotApiKey).toHaveBeenCalledWith('user-1', expect.stringMatching(/^CLI /))
102+
// Second precision, not day: a date-only name made the second login of the
103+
// day fail after the user had already approved in the browser.
104+
expect(mockGenerateCopilotApiKey).toHaveBeenCalledWith(
105+
'user-1',
106+
expect.stringMatching(/^CLI \(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}Z\)$/)
107+
)
103108
expect(mockCompleteApproval).toHaveBeenCalledWith(REQUEST)
104109
expect(mockReleaseMint).not.toHaveBeenCalled()
105110
})

apps/sim/app/api/cli/auth/poll/route.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,25 @@ const POLL_RATE_LIMIT: TokenBucketConfig = {
2828
refillIntervalMs: 60_000,
2929
}
3030

31-
/** Keys are named for the day they were issued, matching what the CLI prints. */
31+
/**
32+
* Names a minted key for the instant it was issued, e.g. `CLI (2026-07-30
33+
* 15:42:07Z)`.
34+
*
35+
* Second precision, not day: key names are unique per owner, so a date-only
36+
* name made the second login of the day fail outright with "a key named …
37+
* already exists" — after the user had already approved in the browser. UTC so
38+
* the name is unambiguous in a shared workspace list and sorts chronologically.
39+
*/
3240
function cliKeyName(): string {
33-
return `CLI (${new Date().toISOString().slice(0, 10)})`
41+
return `CLI (${new Date().toISOString().slice(0, 19).replace('T', ' ')}Z)`
3442
}
3543

3644
/**
3745
* Mints from the key space the approval recorded.
3846
*
39-
* A name collision is reported as a conflict rather than retried under a
40-
* generated name: two logins on the same day from the same terminal should
41-
* reuse the existing key, and silently accumulating `CLI (date) (2)` rows
42-
* would hide that.
47+
* A name collision is still surfaced rather than retried under a suffixed name:
48+
* with second precision it means something genuinely unexpected, and silently
49+
* accumulating near-identical rows would hide it.
4350
*/
4451
async function mintForGrant(
4552
grant: ApprovalGrant

0 commit comments

Comments
 (0)