From 1a182e53fe921d5d4696bd11a6d806a640cdc5a3 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Tue, 13 Oct 2026 22:17:27 -0400 Subject: [PATCH] downloads: serve Nook delta files the Sparkle updater fetches The v0.10.0 publish stopped at the enclosure check: the appcast names Nook17-9.delta / Nook17-10.delta, and the proxy 400'd both with 'Invalid file format' while the TheNook DMG passed. Sparkle names delta files after the app bundle, not the DMG, so the prefix allowlist needs 'Nook' alongside 'TheNook'. Both deltas sat in S3 the whole time; the appcast was never published and the live one still serves 0.9.0. Adds a static source-audit regression test in the repo's downloads.test pattern; proven red against the unfixed allowlist. Tests: bun test src/routes/api/downloads/filename.test.ts NOOK-337 Co-Authored-By: glm-5.3-flash --- src/routes/api/downloads/[filename].ts | 7 +++-- src/routes/api/downloads/filename.test.ts | 38 +++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/routes/api/downloads/filename.test.ts diff --git a/src/routes/api/downloads/[filename].ts b/src/routes/api/downloads/[filename].ts index 0bd28d1..dd77cd0 100644 --- a/src/routes/api/downloads/[filename].ts +++ b/src/routes/api/downloads/[filename].ts @@ -8,7 +8,10 @@ import { env } from "~/env/server"; * * Handles: * - Full DMG files: /api/downloads/Gaze-0.2.2.dmg, /api/downloads/InputHalo-0.1.0.dmg - * - Delta updates: /api/downloads/Gaze3-2.delta, /api/downloads/InputHalo3-2.delta + * - Delta updates: /api/downloads/Gaze3-2.delta, /api/downloads/Nook17-9.delta + * + * The Nook delta files are named after the app bundle ("Nook"), not the DMG + * ("TheNook"), so both prefixes must be allowed (NOOK-337). * * URL: https://freno.me/api/downloads/[filename] */ @@ -24,7 +27,7 @@ export async function GET(event: APIEvent) { }); } - const validPrefixes = ["Gaze", "InputHalo", "TheNook"]; + const validPrefixes = ["Gaze", "InputHalo", "TheNook", "Nook"]; const isValidPrefix = validPrefixes.some((prefix) => filename.startsWith(prefix)); if ( !isValidPrefix || diff --git a/src/routes/api/downloads/filename.test.ts b/src/routes/api/downloads/filename.test.ts new file mode 100644 index 0000000..79d5544 --- /dev/null +++ b/src/routes/api/downloads/filename.test.ts @@ -0,0 +1,38 @@ +/** + * Regression test for the downloads proxy filename allowlist (NOOK-337). + * + * The v0.10.0 publish failed its CI enclosure check because Sparkle names + * delta files after the app bundle ("Nook17-9.delta") while the DMG is named + * "TheNook-*.dmg" — and "Nook" was missing from the allowlist, so every Nook + * delta request 400'd with "Invalid file format" while the DMG passed. + * + * The route hits S3 and cannot be unit-tested under bun:test, so this is a + * STATIC SOURCE AUDIT — the same pattern the downloads.test.ts regressions + * use. + */ +import { describe, it, expect } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +const SOURCE = readFileSync( + join(import.meta.dir, "[filename].ts"), + "utf8" +); + +describe("Downloads proxy filename allowlist (NOOK-337)", () => { + it("allows the Nook app-bundle prefix used by Sparkle delta names", () => { + expect(SOURCE).toContain('"Nook"'); + }); + + it("still allows every previously served prefix", () => { + for (const prefix of ["Gaze", "InputHalo", "TheNook"]) { + expect(SOURCE).toContain(`"${prefix}"`); + } + }); + + it("still serves the extensions Sparkle fetches", () => { + for (const ext of [".dmg", ".delta", ".zip"]) { + expect(SOURCE).toContain(`"${ext}"`); + } + }); +});