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.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"); }); it("rejects an unsupported version instead of interpreting it", () => { const root = mkdtempSync(join(tmpdir(), "hard-guard-loader-")); roots.push(root); const userPath = join(root, "hard-guards.jsonc"); writeFileSync( userPath, `{ "version": 2, "permission": { "*": "allow" } }`, ); const loader = new HardGuardPolicyLoader( userPath, join(root, "missing-fallback.jsonc"), ); expect(loader.loadGlobalConfig().permission).toEqual({ "*": "deny" }); expect(loader.getConfigIssues().join("\n")).toContain( "unsupported hard guard version", ); }); it("keeps the last good snapshot when the file turns invalid", () => { const root = mkdtempSync(join(tmpdir(), "hard-guard-loader-")); roots.push(root); const userPath = join(root, "hard-guards.jsonc"); writeFileSync( userPath, `{ "version": 1, "permission": { "*": "allow", "~/.ssh/**": "deny" } }`, ); const loader = new HardGuardPolicyLoader( userPath, join(root, "missing-fallback.jsonc"), ); const first = loader.loadGlobalConfig(); expect(first.permission).toEqual({ "*": "allow", "~/.ssh/**": "deny", }); // A corrupt edit must not weaken the boundary: the last valid snapshot // keeps applying while the file stays broken. writeFileSync(userPath, "{ not json"); const second = loader.loadGlobalConfig(); expect(second).toEqual(first); expect(loader.getConfigIssues().join("\n")).toContain("Failed to load"); }); it("restores the file's own rules once it becomes valid again", () => { const root = mkdtempSync(join(tmpdir(), "hard-guard-loader-")); roots.push(root); const userPath = join(root, "hard-guards.jsonc"); writeFileSync( userPath, `{ "version": 1, "permission": { "*": "allow", "~/.ssh/**": "deny" } }`, ); const loader = new HardGuardPolicyLoader( userPath, join(root, "missing-fallback.jsonc"), ); loader.loadGlobalConfig(); writeFileSync(userPath, "{ not json"); loader.loadGlobalConfig(); writeFileSync( userPath, `{ "version": 1, "permission": { "*": "allow", "~/.aws/**": "deny" } }`, ); const restored = loader.loadGlobalConfig(); expect(restored.permission).toEqual({ "*": "allow", "~/.aws/**": "deny", }); }); });