Fix MCP crash when DB key exists without NEXUS_MASTER_KEY
KeyResolver now wraps getApiKey in try/catch and falls back to env instead of crashing startup. ProvidersStore.getApiKey returns undefined when the cipher is disabled rather than throwing. Server starts cleanly with env-only, and uses the encrypted DB key when the master key is present.
This commit is contained in:
@@ -133,12 +133,17 @@ export class ProvidersStore {
|
|||||||
this.db.prepare('DELETE FROM providers WHERE name = ?').run(name);
|
this.db.prepare('DELETE FROM providers WHERE name = ?').run(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the decrypted API key for a provider, or undefined. */
|
/**
|
||||||
|
* Return the decrypted API key for a provider, or undefined.
|
||||||
|
* Returns undefined (instead of throwing) when no master key is configured,
|
||||||
|
* so callers can gracefully fall back to env keys.
|
||||||
|
*/
|
||||||
getApiKey(name: string): string | undefined {
|
getApiKey(name: string): string | undefined {
|
||||||
const row = this.db.prepare('SELECT api_key_enc FROM providers WHERE name = ?').get(name) as
|
const row = this.db.prepare('SELECT api_key_enc FROM providers WHERE name = ?').get(name) as
|
||||||
| { api_key_enc: string | null }
|
| { api_key_enc: string | null }
|
||||||
| undefined;
|
| undefined;
|
||||||
if (!row?.api_key_enc) return undefined;
|
if (!row?.api_key_enc) return undefined;
|
||||||
|
if (!this.cipher.enabled) return undefined;
|
||||||
return this.cipher.decrypt(row.api_key_enc);
|
return this.cipher.decrypt(row.api_key_enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,18 @@ export class KeyResolver {
|
|||||||
resolve(providerName: string, defaultBaseUrl: string): ResolvedProvider {
|
resolve(providerName: string, defaultBaseUrl: string): ResolvedProvider {
|
||||||
const dbRow = this.store?.get(providerName);
|
const dbRow = this.store?.get(providerName);
|
||||||
const envKey = this.envKeyFor(providerName);
|
const envKey = this.envKeyFor(providerName);
|
||||||
const dbKey = this.store?.getApiKey(providerName);
|
// DB key may be unreadable (no master key / rotated key). Degrade gracefully:
|
||||||
|
// fall back to env instead of crashing startup.
|
||||||
|
let dbKey: string | undefined;
|
||||||
|
try {
|
||||||
|
dbKey = this.store?.getApiKey(providerName);
|
||||||
|
} catch (err) {
|
||||||
|
log.warn(
|
||||||
|
`could not read stored key for "${providerName}" (falling back to env)`,
|
||||||
|
err instanceof Error ? err.message : String(err)
|
||||||
|
);
|
||||||
|
dbKey = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const apiKey = envKey ?? dbKey;
|
const apiKey = envKey ?? dbKey;
|
||||||
const keySource: ResolvedProvider['keySource'] = envKey ? 'env' : dbKey ? 'db' : 'none';
|
const keySource: ResolvedProvider['keySource'] = envKey ? 'env' : dbKey ? 'db' : 'none';
|
||||||
|
|||||||
Reference in New Issue
Block a user