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
@@ -118,6 +118,9 @@ describe("runtime config hardening", () => {
expect(result.hasApiKey).toBe(true);
expect(result.hasSmtpPassword).toBe(true);
expect(result.hasGeminiApiKey).toBe(true);
expect(result.runtimeSecrets.azureOpenAiApiKey.activeSource).toBe("environment");
expect(result.runtimeSecrets.smtpPassword.activeSource).toBe("environment");
expect(result.legacyStoredSecretFields).toEqual([]);
});
it("prefers environment API keys during AI connection tests", async () => {
@@ -150,4 +153,81 @@ describe("runtime config hardening", () => {
}),
);
});
it("does not persist incoming secret fields through updateSystemSettings", async () => {
const findUnique = vi.fn().mockResolvedValue(null);
const upsert = vi.fn().mockResolvedValue({});
const caller = createAdminCaller({
systemSettings: {
findUnique,
upsert,
},
});
const result = await caller.updateSystemSettings({
azureOpenAiApiKey: "sk-should-not-store",
smtpPassword: "smtp-should-not-store",
geminiApiKey: "gemini-should-not-store",
azureDalleApiKey: "dalle-should-not-store",
anonymizationSeed: "seed-should-not-store",
aiProvider: "openai",
azureOpenAiDeployment: "gpt-4o-mini",
});
expect(result).toEqual({
ok: true,
ignoredSecretFields: [
"azureOpenAiApiKey",
"smtpPassword",
"anonymizationSeed",
"azureDalleApiKey",
"geminiApiKey",
],
secretStorageMode: "environment-only",
});
expect(upsert).toHaveBeenCalledWith({
where: { id: "singleton" },
create: {
id: "singleton",
aiProvider: "openai",
azureOpenAiDeployment: "gpt-4o-mini",
},
update: {
aiProvider: "openai",
azureOpenAiDeployment: "gpt-4o-mini",
},
});
});
it("can clear legacy runtime secrets from database storage", async () => {
const findUnique = vi.fn().mockResolvedValue({
azureOpenAiApiKey: "db-key",
azureDalleApiKey: null,
geminiApiKey: "db-gemini",
smtpPassword: "db-smtp",
anonymizationSeed: null,
});
const update = vi.fn().mockResolvedValue({});
const caller = createAdminCaller({
systemSettings: {
findUnique,
update,
},
});
const result = await caller.clearStoredRuntimeSecrets();
expect(result).toEqual({
ok: true,
clearedFields: ["azureOpenAiApiKey", "geminiApiKey", "smtpPassword"],
});
expect(update).toHaveBeenCalledWith({
where: { id: "singleton" },
data: {
azureOpenAiApiKey: null,
geminiApiKey: null,
smtpPassword: null,
},
});
});
});