[1.56.3] — 2026-05-19
fix(reliability): provider key detection rejects placeholder / too-short values, not only the empty string.
🐛 Fixes
- A placeholder
GEMINI_API_KEYin a parent.envwas reported "✓ set" AND mis-selected as the active provider over a validANTHROPIC_API_KEY.effectiveEnv()only rejectedundefined/'', so a 10-char placeholder counted as a real key: the onboarding banner showed GEMINI ✓ set,GET /api/status/providersreturnedactiveProvider: "gemini", and every live ⚡ eval would have silently failed against a dead key while a working 108-char Anthropic key was ignored. New pureisUsableKey()(env-config.mjs) treats a secret as configured only when it is ≥ 20 chars (no supported provider's key is shorter — GeminiAIza…≈ 39, Anthropicsk-ant-…≈ 100+, OpenAI ≥ 40, Qwen ≈ 35 — so a real key is never false-negatived) and not a known placeholder (your_*_here,changeme,placeholder,<…>, all-one-char, …). Applied uniformly tohasAnthropicKey()/hasGeminiKey()(anthropic.mjs),hasOpenAIKey()/hasQwenKey()(openai.mjs), and theGEMINI_API_KEY/ANTHROPIC_API_KEYrows ofGET /api/health— which also moved off rawprocess.envonto the same effective+plausible view, so the health page, the providers endpoint, and the OR-router now always agree.selectActiveProvider()is unchanged; it just receives a correctkeysConfigured.
🧪 Tests
- New CI-isolated suite
tests/key-detection-rejects-placeholder.test.mjs(5):isUsableKeyunit cases (empty/non-string, too-short incl. the 10-char repro, long-but-placeholder, realistic keys accepted) + an in-processcreateApp()reproduction of the exact reported scenario (10-charGEMINI_API_KEY+ realANTHROPIC_API_KEYin a temp parent.env, the 4 keys stripped fromprocess.env) assertinggeminiis NOT inkeysConfigured,activeProvider === "anthropic", and the/api/healthrows agree. Four existinganthropic/openaieffective-env layering tests had trivially-short stub keys (sk-x,AIzaTEST,sk-o, …) lengthened to realistic values — the layering contract they assert is unchanged; only the stubs had to clear the new floor. 821 → 826.