From b8f57484a50efce72c1498a42f1e86dbbb6dff18 Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Sat, 24 Jan 2026 15:06:29 +0200 Subject: [PATCH] fix(web): implement atomic write for shared storage Add atomic write for the shared storage file to prevent race conditions. Write to a temp file with restricted permissions and atomically rename. Apply 600 permissions to the final storage file when possible --- packages/web/package.json | 1 + packages/web/server/lib/github-auth.js | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/web/package.json b/packages/web/package.json index 499dc3ef..4ee8ae21 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -25,6 +25,7 @@ "@fontsource/ibm-plex-mono": "^5.2.7", "@fontsource/ibm-plex-sans": "^5.1.1", "@ibm/plex": "^6.4.1", + "@octokit/rest": "^22.0.1", "@opencode-ai/sdk": "^1.1.19", "@radix-ui/react-collapsible": "^1.1.12", "@radix-ui/react-dialog": "^1.1.15", diff --git a/packages/web/server/lib/github-auth.js b/packages/web/server/lib/github-auth.js index c75b65c6..10131e55 100644 --- a/packages/web/server/lib/github-auth.js +++ b/packages/web/server/lib/github-auth.js @@ -43,7 +43,17 @@ function readJsonFile() { function writeJsonFile(payload) { ensureStorageDir(); - fs.writeFileSync(STORAGE_FILE, JSON.stringify(payload, null, 2), 'utf8'); + + // Atomic write so multiple OpenChamber instances can safely share the same file. + const tmpFile = `${STORAGE_FILE}.${process.pid}.${Date.now()}.tmp`; + fs.writeFileSync(tmpFile, JSON.stringify(payload, null, 2), 'utf8'); + try { + fs.chmodSync(tmpFile, 0o600); + } catch { + // best-effort + } + + fs.renameSync(tmpFile, STORAGE_FILE); try { fs.chmodSync(STORAGE_FILE, 0o600); } catch {