import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { HardGuardPolicyLoader } from "#src/hard-guard-loader"; const roots: string[] = []; afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); }); describe("HardGuardPolicyLoader", () => { it("loads only the global JSONC hard-guard file and preserves allow exceptions", () => { const root = mkdtempSync(join(tmpdir(), "hard-guard-loader-")); roots.push(root); const userPath = join(root, "hard-guards.jsonc"); mkdirSync(root, { recursive: true }); writeFileSync(userPath, `{ // Allow public examples, deny the rest of the credentials tree. "version": 1, "permission": { "*": "allow", "~/.ssh/**": "deny", "~/.ssh/*.example": "allow" } }`); const loader = new HardGuardPolicyLoader(userPath, join(root, "missing-fallback.jsonc")); const config = loader.loadGlobalConfig(); expect(config.permission).toEqual({ "*": "allow", "~/.ssh/**": "deny", "~/.ssh/*.example": "allow", }); expect(loader.loadProjectConfig()).toEqual({}); expect(loader.getConfigIssues()).toEqual([]); }); it("fails closed when neither the user file nor fallback is valid", () => { const root = mkdtempSync(join(tmpdir(), "hard-guard-loader-")); roots.push(root); const userPath = join(root, "hard-guards.jsonc"); writeFileSync(userPath, `{ "version": 1, "permission": { "*": "ask" } }`); const loader = new HardGuardPolicyLoader(userPath, join(root, "missing-fallback.jsonc")); expect(loader.loadGlobalConfig().permission).toEqual({ "*": "deny" }); expect(loader.getConfigIssues().join("\n")).toContain("allow or deny"); }); });