From ae343bfe1653b59c6302e1c0a6703bcee5b8ba9a Mon Sep 17 00:00:00 2001 From: Tommaso Casaburi Date: Sat, 19 Sep 2026 13:25:45 +0200 Subject: [PATCH] fix(jev): reject explicit null credential overrides --- scripts/jev/config.mjs | 8 ++++---- scripts/jev/tests/config.test.mjs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/scripts/jev/config.mjs b/scripts/jev/config.mjs index a5cad97..6726a59 100644 --- a/scripts/jev/config.mjs +++ b/scripts/jev/config.mjs @@ -39,8 +39,8 @@ function readSmallFile(file, code, optional = false) { } export function resolveJevSettings({ apiKey, model, env = process.env, home = os.homedir() } = {}) { - let key = apiKey ?? env.TYPESAFE_API_KEY; - let selectedModel = model ?? env.JEV_MODEL; + let key = apiKey === undefined ? env.TYPESAFE_API_KEY : apiKey; + let selectedModel = model === undefined ? env.JEV_MODEL : model; const keyFile = key === undefined ? env.TYPESAFE_API_KEY_FILE : undefined; let config = {}; // Explicit runtime credentials and model do not depend on this machine's config. @@ -66,11 +66,11 @@ export function resolveJevSettings({ apiKey, model, env = process.env, home = os fail("invalid_config"); } } - selectedModel ??= config.model; + if (selectedModel === undefined) selectedModel = config.model; if (typeof selectedModel !== "string" || !/^jev-\d+\.\d+\.\d+$/.test(selectedModel)) fail("pinned_model_required"); if (key === undefined) { - const file = keyFile ?? config.apiKeyFile; + const file = keyFile === undefined ? config.apiKeyFile : keyFile; if (file !== undefined) { if (typeof file !== "string" || !path.isAbsolute(file)) fail("invalid_api_key_file"); key = readSmallFile(file, "api_key_file_unreadable"); diff --git a/scripts/jev/tests/config.test.mjs b/scripts/jev/tests/config.test.mjs index cd8d5e5..5f3f141 100644 --- a/scripts/jev/tests/config.test.mjs +++ b/scripts/jev/tests/config.test.mjs @@ -56,6 +56,20 @@ test("explicit options then environment override local defaults; complete overri ); }); +test("explicit null settings are invalid and never select private defaults", (t) => { + const { home } = fixture(t); + for (const options of [{ apiKey: null }, { model: null }, { apiKey: null, model: null }]) { + assert.throws(() => resolveJevSettings({ env: {}, home, ...options })); + assert.throws(() => + resolveJevSettings({ + env: { TYPESAFE_API_KEY: "environment-key", JEV_MODEL: "jev-1.13.0" }, + home, + ...options, + }), + ); + } +}); + test("XDG and explicit config paths are honored without repository-relative credential discovery", (t) => { const { home, configFile } = fixture(t); const result = resolveJevSettings({