From 668f79c0abdb333de7edcfefc1bf9cddc992dba6 Mon Sep 17 00:00:00 2001 From: Ngo Quoc Viet <123613986+NgoQuocViet2001@users.noreply.github.com> Date: Tue, 6 Oct 2026 06:21:27 +0700 Subject: [PATCH] fix: validate admin settings file target (#894) --- lib/admin/settings.ts | 7 ++++++- tests/unit/admin-settings.test.ts | 10 ++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/admin/settings.ts b/lib/admin/settings.ts index f2ecce40..7b168ef4 100644 --- a/lib/admin/settings.ts +++ b/lib/admin/settings.ts @@ -125,7 +125,12 @@ let writableCache: boolean | null = null export function isSettingsWritable(): boolean { if (writableCache !== null) return writableCache try { - const dir = path.dirname(getSettingsPath()) + const filePath = getSettingsPath() + if (fs.existsSync(filePath) && !fs.statSync(filePath).isFile()) { + writableCache = false + return writableCache + } + const dir = path.dirname(filePath) fs.mkdirSync(dir, { recursive: true }) fs.accessSync(dir, fs.constants.W_OK) writableCache = true diff --git a/tests/unit/admin-settings.test.ts b/tests/unit/admin-settings.test.ts index c9fe084f..c07e9808 100644 --- a/tests/unit/admin-settings.test.ts +++ b/tests/unit/admin-settings.test.ts @@ -154,9 +154,9 @@ describe("isSettingsWritable", () => { expect(isSettingsWritable()).toBe(true) }) - it("returns false for an unwritable path", () => { + it("returns false when the settings path is a directory", () => { _resetForTests() - process.env.SETTINGS_FILE = "/nonexistent-root-dir/settings.json" + process.env.SETTINGS_FILE = tmpDir expect(isSettingsWritable()).toBe(false) }) }) @@ -170,7 +170,9 @@ describe("settings file on disk", () => { version: 1, values: { TEST_ADMIN_VAR: "secret" }, }) - const mode = fs.statSync(filePath).mode & 0o777 - expect(mode).toBe(0o600) + if (process.platform !== "win32") { + const mode = fs.statSync(filePath).mode & 0o777 + expect(mode).toBe(0o600) + } }) })