fix(site): centralize UUID generation and fix non-secure crash - #28285
Conversation
Add a generateUUID helper to site/src/utils/random.ts and route the uuid v4 and crypto.randomUUID call sites through it.
The uuid package's v4 compiles down to a crypto.randomUUID call in the production bundle, which is undefined in insecure contexts and throws "crypto.randomUUID is not a function" when Coder is served over plain HTTP (OSS-38). Derive the UUID from crypto.getRandomValues, which is available in insecure contexts, and only use crypto.randomUUID when it exists.
No longer imported after centralizing UUID generation on generateUUID. Also shorten the generateUUID doc comment.
|
i did review the pixel shots and they're fine so i approved them but i'm unsure how to get CI to pass, also i did reproduce that it stack traced before in an http context (accessing develop.sh instance via Coder Connect) and it doesn't anymore. |
|
(turns out this basically does what #27709 undid) |
|
|
||
| it("produces a valid UUID without crypto.randomUUID (insecure context)", () => { | ||
| const descriptor = Object.getOwnPropertyDescriptor(crypto, "randomUUID"); | ||
| Object.defineProperty(crypto, "randomUUID", { |
There was a problem hiding this comment.
can we use vi.stubGlobal in the unit tests instead?
There was a problem hiding this comment.
sure tbh claude did this
There was a problem hiding this comment.
oh yeah this is horrible haha my bad
There was a problem hiding this comment.
oh no worries! claude LOVES stubbing with Object.defineProperty, see it all the time
jeremyruppel
left a comment
There was a problem hiding this comment.
nice! thanks for finding and fixing this!
Fixes OSS-38:
crypto.randomUUID is not a functionwhen accessing Coder over plain HTTP.Root cause
crypto.randomUUIDis only defined in secure contexts (HTTPS or localhost). It isundefinedwhen Coder is served over plain HTTP. Theuuidpackage'sv4()short-circuits tocrypto.randomUUID()when it is truthy, and in the production bundle that path compiles down to a directcrypto.randomUUID()call, souuidv4()throws over HTTP. Observed crash (Template Builder, in theuseMemothat mints the telemetry session ID):The same
uuidv4()path backed the Terminal reconnection token and the Agent chat tab IDs / reconnection tokens, so those flows were affected too.Fix
Add a single
generateUUIDhelper insite/src/utils/random.tsthat derives the UUID fromcrypto.getRandomValues(the oneCryptomember available in insecure contexts) and only callscrypto.randomUUIDwhen it actually exists. Route all client-side UUID generation through it, so every call site is fixed at once and future ones stay safe.Changes
utils/random.ts— newgenerateUUID()helperTemplateBuilderPage.tsx— telemetry session ID/templates/new/builderTerminalPage.tsx— reconnection token/:username/:workspace/terminalAgentChatPageView.tsx— tab IDs + reconnection tokens/agents/:agentIduseChatDraftAttachments.ts— draft client IDs/agents/:agentIdTaskApps.stories.tsx— mock app IDs (Storybook)/tasks/:username/:taskIdWorkspaceSharingIndicator.stories.tsx— mock actor IDs (Storybook)/workspacesuuid/@types/uuiddirect depsuuidis still pinned via apnpm.overridesentry becausemermaid/streamdowndepend on it transitively.Tests
random.test.tscovers a valid UUID, uniqueness, and the insecure-context path (withcrypto.randomUUIDstubbed toundefined).TerminalPage.test.tsxnow mocks#/utils/randominstead of theuuidmodule.Validation
make fmt,biome check,tsc --noEmitcleanvitest rungreen:random.test.ts(6),TerminalPage.test.tsx(16),useChatDraftAttachments.test.ts(17), both changed stories (12)uuidv4()in Template Builder.This PR was generated by Coder Agents on behalf of @phorcys420.