refactor(settings): adopt environment-only runtime secret flow

This commit is contained in:
2026-03-30 19:55:06 +02:00
parent fed7aa5b61
commit a19d2cbae0
19 changed files with 757 additions and 172 deletions
@@ -7,6 +7,23 @@ type RuntimeAwareSystemSettings = {
anonymizationSeed?: string | null;
};
export const RUNTIME_SECRET_FIELDS = [
"azureOpenAiApiKey",
"azureDalleApiKey",
"geminiApiKey",
"smtpPassword",
"anonymizationSeed",
] as const;
export type RuntimeSecretField = (typeof RUNTIME_SECRET_FIELDS)[number];
export type RuntimeSecretStatus = {
configured: boolean;
activeSource: "environment" | "database" | "none";
hasStoredValue: boolean;
envVarNames: string[];
};
function readEnvOverride(...names: string[]): string | null {
for (const name of names) {
const value = process.env[name]?.trim();
@@ -26,16 +43,92 @@ function resolvePrimaryAiApiKey(provider: string | null | undefined): string | n
return readEnvOverride("OPENAI_API_KEY", "AZURE_OPENAI_API_KEY");
}
function getPrimaryAiEnvVarNames(provider: string | null | undefined): string[] {
if (provider === "azure") {
return ["AZURE_OPENAI_API_KEY", "OPENAI_API_KEY"];
}
return ["OPENAI_API_KEY", "AZURE_OPENAI_API_KEY"];
}
function resolveSecretEnvOverride(
field: RuntimeSecretField,
provider: string | null | undefined,
): string | null {
if (field === "azureOpenAiApiKey") {
return resolvePrimaryAiApiKey(provider);
}
if (field === "azureDalleApiKey") {
return readEnvOverride("AZURE_DALLE_API_KEY");
}
if (field === "geminiApiKey") {
return readEnvOverride("GEMINI_API_KEY");
}
if (field === "smtpPassword") {
return readEnvOverride("SMTP_PASSWORD");
}
return readEnvOverride("ANONYMIZATION_SEED");
}
function getSecretEnvVarNames(
field: RuntimeSecretField,
provider: string | null | undefined,
): string[] {
if (field === "azureOpenAiApiKey") {
return getPrimaryAiEnvVarNames(provider);
}
if (field === "azureDalleApiKey") {
return ["AZURE_DALLE_API_KEY"];
}
if (field === "geminiApiKey") {
return ["GEMINI_API_KEY"];
}
if (field === "smtpPassword") {
return ["SMTP_PASSWORD"];
}
return ["ANONYMIZATION_SEED"];
}
export function getRuntimeSecretStatuses(
settings: RuntimeAwareSystemSettings | null | undefined,
): Record<RuntimeSecretField, RuntimeSecretStatus> {
const provider = settings?.aiProvider;
return Object.fromEntries(
RUNTIME_SECRET_FIELDS.map((field) => {
const envValue = resolveSecretEnvOverride(field, provider);
const storedValue = settings?.[field]?.trim() || null;
const activeSource = envValue
? "environment"
: storedValue
? "database"
: "none";
return [
field,
{
configured: !!(envValue || storedValue),
activeSource,
hasStoredValue: !!storedValue,
envVarNames: getSecretEnvVarNames(field, provider),
} satisfies RuntimeSecretStatus,
];
}),
) as Record<RuntimeSecretField, RuntimeSecretStatus>;
}
export function resolveSystemSettingsRuntime<T extends RuntimeAwareSystemSettings>(
settings: T | null | undefined,
): T & Required<Pick<RuntimeAwareSystemSettings, "azureOpenAiApiKey" | "azureDalleApiKey" | "geminiApiKey" | "smtpPassword" | "anonymizationSeed">> {
const resolved = { ...(settings ?? {}) } as T & Required<Pick<RuntimeAwareSystemSettings, "azureOpenAiApiKey" | "azureDalleApiKey" | "geminiApiKey" | "smtpPassword" | "anonymizationSeed">>;
resolved.azureOpenAiApiKey = resolvePrimaryAiApiKey(resolved.aiProvider) ?? settings?.azureOpenAiApiKey ?? null;
resolved.azureDalleApiKey = readEnvOverride("AZURE_DALLE_API_KEY") ?? settings?.azureDalleApiKey ?? null;
resolved.geminiApiKey = readEnvOverride("GEMINI_API_KEY") ?? settings?.geminiApiKey ?? null;
resolved.smtpPassword = readEnvOverride("SMTP_PASSWORD") ?? settings?.smtpPassword ?? null;
resolved.anonymizationSeed = readEnvOverride("ANONYMIZATION_SEED") ?? settings?.anonymizationSeed ?? null;
resolved.azureOpenAiApiKey = resolveSecretEnvOverride("azureOpenAiApiKey", resolved.aiProvider) ?? settings?.azureOpenAiApiKey ?? null;
resolved.azureDalleApiKey = resolveSecretEnvOverride("azureDalleApiKey", resolved.aiProvider) ?? settings?.azureDalleApiKey ?? null;
resolved.geminiApiKey = resolveSecretEnvOverride("geminiApiKey", resolved.aiProvider) ?? settings?.geminiApiKey ?? null;
resolved.smtpPassword = resolveSecretEnvOverride("smtpPassword", resolved.aiProvider) ?? settings?.smtpPassword ?? null;
resolved.anonymizationSeed = resolveSecretEnvOverride("anonymizationSeed", resolved.aiProvider) ?? settings?.anonymizationSeed ?? null;
return resolved;
}