import { describe, expect, test } from "bun:test"; import { mkdtempSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { eq } from "drizzle-orm"; import { createApp } from "../src/app"; import { openDb } from "../src/db"; import { settings } from "../src/db/schema"; import { loadOrCreateKey } from "../src/lib/crypto"; async function authedApp() { const dir = mkdtempSync(join(tmpdir(), "helios-")); const db = openDb(dir); const app = createApp({ db, key: loadOrCreateKey(dir) }); const j = (b: unknown) => ({ method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(b) }); await app.request("/api/setup", j({ password: "hunter2hunter2" })); const cookie = (await app.request("/api/login", j({ password: "hunter2hunter2" }))).headers.get("set-cookie")!; return { app, db, cookie }; } describe("settings", () => { test("defaults, update, masked key, encrypted at rest", async () => { const { app, db, cookie } = await authedApp(); const h = { cookie }; let s = await (await app.request("/api/settings", { headers: h })).json(); expect(s).toEqual({ llmBaseUrl: "https://openrouter.ai/api/v1", llmModel: "anthropic/claude-sonnet-4.5", llmKeyMasked: null, }); const put = await app.request("/api/settings", { method: "PUT", headers: { ...h, "content-type": "application/json" }, body: JSON.stringify({ llmKey: "sk-or-v1-supersecret-abcd", llmModel: "meta-llama/llama-4" }), }); expect(put.status).toBe(204); s = await (await app.request("/api/settings", { headers: h })).json(); expect(s.llmKeyMasked).toBe("…abcd"); expect(s.llmModel).toBe("meta-llama/llama-4"); const raw = (await db.select().from(settings).where(eq(settings.key, "llm_key"))).at(0)!.value; expect(raw.startsWith("enc:")).toBe(true); expect(raw).not.toContain("supersecret"); }); test("rejects bad body", async () => { const { app, cookie } = await authedApp(); const r = await app.request("/api/settings", { method: "PUT", headers: { cookie, "content-type": "application/json" }, body: JSON.stringify({ llmBaseUrl: "not a url" }), }); expect(r.status).toBe(400); }); });