static-permissions.test.ts
2701 bytes
1import { expect, test } from "bun:test";
2import { mkdtempSync, rmSync } from "node:fs";
3import { tmpdir } from "node:os";
4import { join } from "node:path";
5import { checkStaticPermission } from "../../src/pi/static-permissions";
6import type { PiPolicyEngineConfig } from "../../src/pi/config";
7
8test("explicit deny wins before external path handling", async () => {
9 const cwd = mkdtempSync(join(tmpdir(), "policy-engine-cwd-"));
10 try {
11 const decision = await checkStaticPermission(
12 "write",
13 { path: join(tmpdir(), "policy-engine-external-file") },
14 cwd,
15 { reviewer: { kind: "none" }, tools: { write: "deny" }, externalDirectories: [] },
16 );
17 expect(decision).toMatchObject({ decision: "deny" });
18 } finally {
19 rmSync(cwd, { recursive: true, force: true });
20 }
21});
22
23test("allows unconfigured tools and checks configured tools", async () => {
24 const config: PiPolicyEngineConfig = { reviewer: { kind: "none" }, tools: {}, externalDirectories: [] };
25 await expect(checkStaticPermission("my_extension_tool", {}, process.cwd(), config)).resolves.toMatchObject({
26 decision: "allow",
27 });
28 await expect(
29 checkStaticPermission("my_extension_tool", {}, process.cwd(), {
30 ...config,
31 tools: { my_extension_tool: "check" },
32 }),
33 ).resolves.toBeUndefined();
34});
35
36test("asks before changing a policy engine configuration", async () => {
37 const cwd = mkdtempSync(join(tmpdir(), "policy-engine-cwd-"));
38 try {
39 const config: PiPolicyEngineConfig = {
40 reviewer: { kind: "none" },
41 tools: { edit: "allow", write: "allow" },
42 externalDirectories: [],
43 };
44 for (const toolType of ["edit", "write"]) {
45 await expect(
46 checkStaticPermission(toolType, { path: ".pi/policy-engine.json" }, cwd, config),
47 ).resolves.toMatchObject({
48 decision: "ask",
49 });
50 }
51 } finally {
52 rmSync(cwd, { recursive: true, force: true });
53 }
54});
55
56test("allows external paths only inside configured directories", async () => {
57 const root = mkdtempSync(join(tmpdir(), "policy-engine-external-"));
58 const cwd = join(root, "cwd");
59 const external = join(root, "shared");
60 const nested = join(external, "nested", "file.txt");
61 const sibling = join(root, "shared-sibling", "file.txt");
62 try {
63 const config = { reviewer: { kind: "none" } as const, tools: {}, externalDirectories: [external] };
64 await expect(checkStaticPermission("read", { path: nested }, cwd, config)).resolves.toMatchObject({
65 decision: "allow",
66 });
67 await expect(checkStaticPermission("read", { path: sibling }, cwd, config)).resolves.toBeUndefined();
68 } finally {
69 rmSync(root, { recursive: true, force: true });
70 }
71});