From a7721b66f7d2042b4ff32875bff29b09c2b43629 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Jul 2026 01:15:27 +0000 Subject: [PATCH 1/2] Initial plan From cf41969ede281d30b4eea665a25a80b3d2f43771 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Jul 2026 01:42:23 +0000 Subject: [PATCH 2/2] fix: use crypto.getRandomValues in randId and stub it in tests for determinism --- apps/web/src/core/utils/randId.test.ts | 49 +++++++++++++++----------- apps/web/src/core/utils/randId.ts | 6 ++-- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/apps/web/src/core/utils/randId.test.ts b/apps/web/src/core/utils/randId.test.ts index 7cf40e65b..bcce5bccc 100644 --- a/apps/web/src/core/utils/randId.test.ts +++ b/apps/web/src/core/utils/randId.test.ts @@ -1,44 +1,53 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { randId } from "./randId.ts"; describe("randId", () => { - beforeEach(() => { + afterEach(() => { vi.restoreAllMocks(); }); - it("returns a number", () => { - const result = randId(); - expect(typeof result).toBe("number"); - }); - it("returns an integer", () => { const result = randId(); + expect(typeof result).toBe("number"); expect(Number.isInteger(result)).toBe(true); }); - it("uses Math.random to generate the number", () => { - const mockRandom = vi.spyOn(Math, "random").mockReturnValue(0.5); + it("uses crypto.getRandomValues to generate the number", () => { + const mockGetRandomValues = vi + .spyOn(crypto, "getRandomValues") + .mockImplementation((array) => { + if (array instanceof Uint32Array) { + array[0] = 42; + } + return array; + }); + const result = randId(); - expect(mockRandom).toHaveBeenCalled(); - expect(result).toBe(Math.floor(0.5 * 1e9)); + expect(mockGetRandomValues).toHaveBeenCalled(); + expect(result).toBe(42); }); - it("returns a value between 0 and 1e9 (exclusive)", () => { + it("returns a value within the uint32 range", () => { const result = randId(); expect(result).toBeGreaterThanOrEqual(0); - expect(result).toBeLessThan(1e9); + expect(result).toBeLessThanOrEqual(0xffffffff); }); - it("returns different values on subsequent calls", () => { - vi.spyOn(Math, "random").mockRestore(); - - const results = new Set(); - - for (let i = 0; i < 100; i++) { + it("returns unique values across many calls", () => { + let counter = 0; + vi.spyOn(crypto, "getRandomValues").mockImplementation((array) => { + if (array instanceof Uint32Array) { + array[0] = counter++; + } + return array; + }); + + const results = new Set(); + for (let i = 0; i < 1000; i++) { results.add(randId()); } - expect(results.size).toBeGreaterThan(95); + expect(results.size).toBe(1000); }); }); diff --git a/apps/web/src/core/utils/randId.ts b/apps/web/src/core/utils/randId.ts index 2d2a5939b..3fae03dd3 100644 --- a/apps/web/src/core/utils/randId.ts +++ b/apps/web/src/core/utils/randId.ts @@ -1,3 +1,5 @@ -export const randId = () => { - return Math.floor(Math.random() * 1e9); +export const randId = (): number => { + const buf = new Uint32Array(1); + crypto.getRandomValues(buf); + return buf[0]; };