From 65a808808f85a4e15e341c1a20dc574f20f9570b Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Wed, 4 Mar 2026 00:27:47 -0800 Subject: [PATCH] Fix electron-updater auth for private GitHub repos Use setFeedURL with private: true when a GitHub token is provided so electron-updater queries the GitHub API instead of the public Atom feed which rejects Bearer auth headers. Co-Authored-By: Claude Opus 4.6 --- apps/desktop/src/main.ts | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 157f3df9601d2c31b8a6af4b57a3455e433f0095..787ec3e04b751776055122d67a37d15ecfe36a3c 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -253,6 +253,28 @@ function resolveAppRoot(): string { return app.getAppPath(); } +/** Read the baked-in app-update.yml config (if applicable). */ +function readAppUpdateYml(): Record | null { + try { + // electron-updater reads from process.resourcesPath in packaged builds, + // or dev-app-update.yml via app.getAppPath() in dev. + const ymlPath = app.isPackaged + ? Path.join(process.resourcesPath, "app-update.yml") + : Path.join(app.getAppPath(), "dev-app-update.yml"); + const raw = FS.readFileSync(ymlPath, "utf-8"); + // The YAML is simple key-value pairs — avoid pulling in a YAML parser by + // doing a line-based parse (fields: provider, owner, repo, releaseType, …). + const entries: Record = {}; + for (const line of raw.split("\n")) { + const match = line.match(/^(\w+):\s*(.+)$/); + if (match?.[1] && match[2]) entries[match[1]] = match[2].trim(); + } + return entries.provider ? entries : null; + } catch { + return null; + } +} + function normalizeCommitHash(value: unknown): string | null { if (typeof value !== "string") { return null; @@ -687,10 +709,18 @@ function configureAutoUpdater(): void { process.env.GH_TOKEN?.trim() || ""; if (githubToken) { - autoUpdater.requestHeaders = { - ...autoUpdater.requestHeaders, - Authorization: `Bearer ${githubToken}`, - }; + // When a token is provided, re-configure the feed with `private: true` so + // electron-updater uses the GitHub API (api.github.com) instead of the + // public Atom feed (github.com/…/releases.atom) which rejects Bearer auth. + const appUpdateYml = readAppUpdateYml(); + if (appUpdateYml?.provider === "github") { + autoUpdater.setFeedURL({ + ...appUpdateYml, + provider: "github" as const, + private: true, + token: githubToken, + }); + } } autoUpdater.autoDownload = false; -- 2.54.0