diff --git a/apps/desktop/src/features/score/scoreStorage.bench.ts b/apps/desktop/src/features/score/scoreStorage.bench.ts new file mode 100644 index 000000000..d9b62d3c8 --- /dev/null +++ b/apps/desktop/src/features/score/scoreStorage.bench.ts @@ -0,0 +1,46 @@ +import { bench, describe } from "vitest"; + +/** Documented. */ +function validateOld(response: unknown[]) { + if (Array.isArray(response) && response.every((byte) => typeof byte === "number")) { + return Uint8Array.from(response as number[]); + } + throw new Error("invalid"); +} + +/** Documented. */ +function validateNew(response: unknown[]) { + if (Array.isArray(response)) { + const len = response.length; + const arr = new Uint8Array(len); + let isValid = true; + for (let i = 0; i < len; i++) { + const byte = response[i]; + if (typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255) { + isValid = false; + break; + } + arr[i] = byte; + } + if (isValid) { + return arr; + } + } + throw new Error("invalid"); +} + +describe("PDF byte array processing", () => { + const size = 5_000_000; + const payload = new Array(size); + for (let i = 0; i < size; i++) { + payload[i] = i % 256; + } + + bench("legacy Array.from and every", () => { + validateOld(payload); + }); + + bench("single pass pre-allocated loop", () => { + validateNew(payload); + }); +}); diff --git a/apps/desktop/src/features/score/scoreStorage.test.ts b/apps/desktop/src/features/score/scoreStorage.test.ts index 0feec199e..af83b8312 100644 --- a/apps/desktop/src/features/score/scoreStorage.test.ts +++ b/apps/desktop/src/features/score/scoreStorage.test.ts @@ -7,6 +7,7 @@ type TauriWindow = Window & { }; const BRIDGE_UNAVAILABLE_MESSAGE = "Score PDFs are only available in the desktop app."; +const INVALID_RESPONSE_MESSAGE = "Invalid score bridge response"; describe("scoreStorage bridge resolution", () => { afterEach(() => { @@ -32,4 +33,35 @@ describe("scoreStorage bridge resolution", () => { BRIDGE_UNAVAILABLE_MESSAGE ); }); + + it("preserves exact bytes from a valid bridge array", async () => { + (window as TauriWindow).__TAURI_INVOKE__ = vi.fn().mockResolvedValue([0, 1, 255]); + + await expect(readScorePdf("project-1", "score-1")).resolves.toEqual( + new Uint8Array([0, 1, 255]) + ); + }); + + it("accepts an empty bridge array", async () => { + (window as TauriWindow).__TAURI_INVOKE__ = vi.fn().mockResolvedValue([]); + + await expect(readScorePdf("project-1", "score-1")).resolves.toEqual(new Uint8Array()); + }); + + it.each([ + ["NaN", Number.NaN], + ["Infinity", Number.POSITIVE_INFINITY], + ["negative", -1], + ["fractional", 1.5], + ["greater than 255", 256], + ["non-number", "1"] + ])("rejects a %s bridge byte", async (_label, invalidByte) => { + (window as TauriWindow).__TAURI_INVOKE__ = vi + .fn() + .mockResolvedValue([0, invalidByte, 255]); + + await expect(readScorePdf("project-1", "score-1")).rejects.toThrow( + INVALID_RESPONSE_MESSAGE + ); + }); }); diff --git a/apps/desktop/src/features/score/scoreStorage.ts b/apps/desktop/src/features/score/scoreStorage.ts index 492f12591..b77764671 100644 --- a/apps/desktop/src/features/score/scoreStorage.ts +++ b/apps/desktop/src/features/score/scoreStorage.ts @@ -91,8 +91,21 @@ export async function readScorePdf(projectId: string, scoreId: string): Promise< if (response instanceof ArrayBuffer) { return new Uint8Array(response); } - if (Array.isArray(response) && response.every((byte) => typeof byte === "number")) { - return Uint8Array.from(response as number[]); + if (Array.isArray(response)) { + const len = response.length; + const arr = new Uint8Array(len); + let isValid = true; + for (let i = 0; i < len; i++) { + const byte = response[i]; + if (typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255) { + isValid = false; + break; + } + arr[i] = byte; + } + if (isValid) { + return arr; + } } throw new Error(INVALID_RESPONSE_MESSAGE); diff --git a/services/analysis-engine/tests/test_supply_chain_policy.py b/services/analysis-engine/tests/test_supply_chain_policy.py index 1d8224c5a..6a0853944 100644 --- a/services/analysis-engine/tests/test_supply_chain_policy.py +++ b/services/analysis-engine/tests/test_supply_chain_policy.py @@ -1275,9 +1275,7 @@ def test_workflow_concurrency_cancels_only_superseded_pr_heads() -> None: workflow = (workflows_dir / workflow_name).read_text(encoding="utf-8") assert "concurrency:" in workflow, workflow_name assert "cancel-in-progress: false" in workflow, workflow_name - assert "contents: read" in workflow or "permissions: read-all" in workflow, ( - workflow_name - ) + assert "contents: read" in workflow or "permissions: read-all" in workflow, workflow_name assert "pull_request:" not in (workflows_dir / "release.yml").read_text(encoding="utf-8")