import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { DEFAULT_OPENAI_MODEL, SystemRole } from "@capakraken/shared"; import { createToolContext, executeTool } from "./assistant-tools-settings-test-helpers.js"; describe("assistant settings tools runtime settings", () => { beforeEach(() => { vi.clearAllMocks(); }); afterEach(() => { vi.unstubAllGlobals(); vi.unstubAllEnvs(); }); it("returns system settings with runtime secret flags through the real settings router path", async () => { vi.stubEnv("OPENAI_API_KEY", "env-openai-key"); vi.stubEnv("SMTP_PASSWORD", "env-smtp-password"); vi.stubEnv("GEMINI_API_KEY", "env-gemini-key"); const ctx = createToolContext({ systemSettings: { findUnique: vi.fn().mockResolvedValue({ aiProvider: "openai", azureOpenAiApiKey: null, smtpPassword: null, geminiApiKey: null, }), }, }); const result = await executeTool("get_system_settings", JSON.stringify({}), ctx); const parsed = JSON.parse(result.content) as { hasApiKey: boolean; hasSmtpPassword: boolean; hasGeminiApiKey: boolean; runtimeSecrets: { azureOpenAiApiKey: { activeSource: string }; smtpPassword: { activeSource: string }; }; legacyStoredSecretFields: string[]; }; expect(parsed.hasApiKey).toBe(true); expect(parsed.hasSmtpPassword).toBe(true); expect(parsed.hasGeminiApiKey).toBe(true); expect(parsed.runtimeSecrets.azureOpenAiApiKey.activeSource).toBe("environment"); expect(parsed.runtimeSecrets.smtpPassword.activeSource).toBe("environment"); expect(parsed.legacyStoredSecretFields).toEqual([]); }); it("updates system settings without persisting incoming secret fields", async () => { const findUnique = vi.fn().mockResolvedValue(null); const upsert = vi.fn().mockResolvedValue({}); const ctx = createToolContext({ systemSettings: { findUnique, upsert, }, }); const result = await executeTool( "update_system_settings", JSON.stringify({ 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: DEFAULT_OPENAI_MODEL, }), ctx, ); expect(JSON.parse(result.content)).toEqual({ ok: true, ignoredSecretFields: [ "azureOpenAiApiKey", "smtpPassword", "anonymizationSeed", "azureDalleApiKey", "geminiApiKey", ], secretStorageMode: "environment-only", }); expect(findUnique).toHaveBeenCalledWith({ where: { id: "singleton" } }); expect(upsert).toHaveBeenCalledWith({ where: { id: "singleton" }, create: { id: "singleton", aiProvider: "openai", azureOpenAiDeployment: DEFAULT_OPENAI_MODEL, }, update: { aiProvider: "openai", azureOpenAiDeployment: DEFAULT_OPENAI_MODEL, }, }); }); it("clears legacy runtime secrets through the real settings router path", async () => { const findUnique = vi.fn().mockResolvedValue({ azureOpenAiApiKey: "db-openai", azureDalleApiKey: null, geminiApiKey: "db-gemini", smtpPassword: null, anonymizationSeed: "db-seed", }); const update = vi.fn().mockResolvedValue({ id: "singleton" }); const auditCreate = vi.fn().mockResolvedValue(undefined); const ctx = createToolContext({ systemSettings: { findUnique, update, }, auditLog: { create: auditCreate, }, }); const result = await executeTool("clear_stored_runtime_secrets", "{}", ctx); expect(JSON.parse(result.content)).toEqual({ ok: true, clearedFields: ["azureOpenAiApiKey", "geminiApiKey", "anonymizationSeed"], }); expect(update).toHaveBeenCalledWith({ where: { id: "singleton" }, data: { azureOpenAiApiKey: null, geminiApiKey: null, anonymizationSeed: null, }, }); expect(auditCreate).toHaveBeenCalled(); }); it("rejects admin-only runtime settings tools for non-admin assistant users", async () => { const ctx = createToolContext( { systemSettings: { findUnique: vi.fn(), upsert: vi.fn(), update: vi.fn(), }, }, SystemRole.MANAGER, ); for (const [toolName, payload] of [ ["get_system_settings", {}], ["update_system_settings", { aiProvider: "openai" }], ["clear_stored_runtime_secrets", {}], ] as const) { const result = await executeTool(toolName, JSON.stringify(payload), ctx); expect(JSON.parse(result.content)).toEqual({ error: "You do not have permission to perform this action.", }); } }); });