import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync, } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, test } from "vitest"; import { WorkspaceSecretStore } from "../src/workspaces/secret-store.js"; const roots: string[] = []; function fixture() { const root = mkdtempSync(join(tmpdir(), "thoth-workspace-secret-store-")); const runtimeRoot = mkdtempSync(join(tmpdir(), "thoth-workspace-secret-runtime-")); roots.push(root, runtimeRoot); return { root, runtimeRoot, store: new WorkspaceSecretStore({ root, runtimeRoot, installationId: "installation-test", }), }; } afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); describe("WorkspaceSecretStore", () => { test("persists ciphertext and exposes status without exposing plaintext", () => { const { root, store } = fixture(); const secret = "correct horse battery staple"; store.put("psd-clinical", "dwh.password", secret); expect(store.has("psd-clinical", "dwh.password")).toBe(true); expect(store.configured("psd-clinical")).toEqual(["dwh.password"]); const vault = readFileSync(join(root, "vault.json"), "utf8"); expect(vault).not.toContain(secret); expect(statSync(join(root, "vault.json")).mode & 0o777).toBe(0o600); expect(statSync(join(root, "master.key")).mode & 0o777).toBe(0o600); }); test("blind replacement changes the materialized value and forget removes it", () => { const { store } = fixture(); store.put("psd-clinical", "dwh.password", "old-value"); store.put("psd-clinical", "dwh.password", "new-value"); const lease = store.materialize("psd-clinical", ["dwh.password"]); const path = lease.files.get("dwh.password"); expect(path).toBeDefined(); expect(readFileSync(path!, "utf8")).toBe("new-value"); expect(statSync(path!).mode & 0o777).toBe(0o400); lease.release(); expect(existsSync(path!)).toBe(false); store.forget("psd-clinical", "dwh.password"); expect(store.has("psd-clinical", "dwh.password")).toBe(false); }); test("materializes only requested secrets and cleans the whole lease directory", () => { const { runtimeRoot, store } = fixture(); store.putMany("psd-clinical", { "dwh.password": "warehouse-password", "evidence.api_key": "evidence-key", }); const lease = store.materialize("psd-clinical", ["evidence.api_key"]); expect([...lease.files.keys()]).toEqual(["evidence.api_key"]); expect(readFileSync(lease.files.get("evidence.api_key")!, "utf8")).toBe("evidence-key"); expect(statSync(runtimeRoot).mode & 0o777).toBe(0o700); const directory = join(lease.files.get("evidence.api_key")!, ".."); lease.release(); expect(existsSync(directory)).toBe(false); }); test("fails closed with a sanitized error when the encrypted vault is tampered", () => { const { root, store } = fixture(); const secret = "must-never-appear-in-errors"; store.put("psd-clinical", "dwh.password", secret); const path = join(root, "vault.json"); const document = JSON.parse(readFileSync(path, "utf8")) as { entries: Record; }; const record = Object.values(document.entries)[0]!; record.ciphertext = Buffer.from("tampered").toString("base64"); writeFileSync(path, JSON.stringify(document), { mode: 0o600 }); expect(() => store.materialize("psd-clinical", ["dwh.password"])) .toThrow("Workspace secret store is unavailable."); try { store.materialize("psd-clinical", ["dwh.password"]); } catch (error) { expect(String(error)).not.toContain(secret); } }); test("rejects invalid identifiers and oversized values", () => { const { store } = fixture(); expect(() => store.put("../workspace", "dwh.password", "secret")).toThrow(); expect(() => store.put("psd-clinical", "../password", "secret")).toThrow(); expect(() => store.put("psd-clinical", "dwh.password", "x".repeat(65_537))).toThrow(); }); });