diff --git a/bin/cli/commands/setup.mjs b/bin/cli/commands/setup.mjs index 5415cdd70b..2dd589006c 100644 --- a/bin/cli/commands/setup.mjs +++ b/bin/cli/commands/setup.mjs @@ -24,9 +24,9 @@ function wantsProviderSetup(opts) { return opts.addProvider || Boolean(opts.provider) || Boolean(opts.apiKey); } -async function resolvePassword(opts, prompt, nonInteractive) { - if (opts.password) return opts.password; - if (process.env.INITIAL_PASSWORD) return process.env.INITIAL_PASSWORD; +async function resolvePassword(opts, prompt, nonInteractive, settings) { + if (opts.password !== undefined) return opts.password; + if (!settings.password && process.env.INITIAL_PASSWORD) return process.env.INITIAL_PASSWORD; if (nonInteractive) return ""; const answer = await prompt.ask("Set an admin password now? [y/N]", "N"); @@ -41,9 +41,9 @@ async function resolvePassword(opts, prompt, nonInteractive) { } async function setupPassword(db, opts, prompt, nonInteractive) { - const password = await resolvePassword(opts, prompt, nonInteractive); + const settings = getSettings(db); + const password = await resolvePassword(opts, prompt, nonInteractive, settings); if (!password) { - const settings = getSettings(db); if (!settings.password) { updateSettings(db, { requireLogin: false }); } diff --git a/tests/unit/cli-setup-command.test.ts b/tests/unit/cli-setup-command.test.ts index ae0c805a65..0f433a59c1 100644 --- a/tests/unit/cli-setup-command.test.ts +++ b/tests/unit/cli-setup-command.test.ts @@ -250,3 +250,32 @@ test("setup command prioritizes an explicit --password flag over INITIAL_PASSWOR process.env.INITIAL_PASSWORD = ORIGINAL_INITIAL_PASSWORD; } }); + +test("setup command does not replace an existing password from INITIAL_PASSWORD", async () => { + const ORIGINAL_INITIAL_PASSWORD = process.env.INITIAL_PASSWORD; + await withTempEnv(async (dataDir) => { + const { runSetupCommand } = await import("../../bin/cli/commands/setup.mjs"); + + await runSetupCommand({ nonInteractive: true, password: "existing-admin-secret" }); + + process.env.INITIAL_PASSWORD = "CHANGEME"; + const exitCode = await runSetupCommand({ nonInteractive: true }); + + assert.equal(exitCode, 0); + + const db = new Database(path.join(dataDir, "storage.sqlite")); + const passwordRow = db + .prepare("SELECT value FROM key_value WHERE namespace = 'settings' AND key = 'password'") + .get() as { value: string }; + db.close(); + + const storedHash = JSON.parse(passwordRow.value) as string; + assert.equal(await bcrypt.compare("existing-admin-secret", storedHash), true); + assert.equal(await bcrypt.compare("CHANGEME", storedHash), false); + }); + if (ORIGINAL_INITIAL_PASSWORD === undefined) { + delete process.env.INITIAL_PASSWORD; + } else { + process.env.INITIAL_PASSWORD = ORIGINAL_INITIAL_PASSWORD; + } +});