@gotgenes/pi-permission-system 17.0.0 → 17.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/access-intent/access-path.ts +5 -5
- package/src/access-intent/bash/bash-path-resolver.ts +535 -0
- package/src/access-intent/bash/program.ts +21 -14
- package/src/access-intent/bash/token-classification.ts +24 -1
- package/src/canonicalize-path.ts +11 -5
- package/src/forwarded-permissions/permission-forwarder.ts +11 -1
- package/src/forwarding-manager.ts +7 -1
- package/src/handlers/before-agent-start.ts +1 -1
- package/src/handlers/gates/bash-path-extractor.ts +7 -5
- package/src/handlers/gates/external-directory.ts +7 -18
- package/src/handlers/gates/path.ts +3 -2
- package/src/handlers/gates/skill-read.ts +4 -2
- package/src/handlers/gates/tool-call-gate-pipeline.ts +20 -4
- package/src/handlers/gates/tool.ts +4 -2
- package/src/index.ts +12 -1
- package/src/input-normalizer.ts +9 -4
- package/src/path-normalizer.ts +100 -0
- package/src/path-utils.ts +39 -28
- package/src/permission-manager.ts +21 -7
- package/src/permission-session.ts +35 -2
- package/src/prompting-gateway.ts +3 -0
- package/src/rule.ts +8 -6
- package/src/skill-prompt-sanitizer.ts +8 -10
- package/src/subagent-context.ts +17 -9
- package/test/access-intent/access-path.test.ts +73 -24
- package/test/access-intent/bash/program.test.ts +131 -65
- package/test/access-intent/bash/token-classification.test.ts +75 -0
- package/test/bash-external-directory.test.ts +53 -1
- package/test/canonicalize-path.test.ts +34 -8
- package/test/forwarding-manager.test.ts +7 -1
- package/test/handlers/external-directory-symlink-acceptance.test.ts +23 -4
- package/test/handlers/gates/bash-command-metamorphic.test.ts +5 -1
- package/test/handlers/gates/bash-external-directory.test.ts +5 -1
- package/test/handlers/gates/bash-path.test.ts +6 -1
- package/test/handlers/gates/external-directory-policy.test.ts +26 -8
- package/test/handlers/gates/external-directory.test.ts +8 -1
- package/test/handlers/gates/path.test.ts +53 -14
- package/test/handlers/gates/skill-read.test.ts +26 -13
- package/test/handlers/gates/tool-call-gate-pipeline.test.ts +2 -1
- package/test/handlers/gates/tool.test.ts +13 -1
- package/test/helpers/gate-fixtures.ts +10 -0
- package/test/helpers/session-fixtures.ts +3 -0
- package/test/input-normalizer.test.ts +104 -39
- package/test/path-normalizer.test.ts +166 -0
- package/test/path-utils.test.ts +130 -51
- package/test/permission-forwarder.test.ts +1 -0
- package/test/permission-manager-unified.test.ts +40 -0
- package/test/permission-resolver.test.ts +12 -3
- package/test/permission-session.test.ts +41 -0
- package/test/pi-infrastructure-read.test.ts +27 -4
- package/test/prompting-gateway.test.ts +1 -0
- package/test/rule.test.ts +88 -42
- package/test/session-rules.test.ts +21 -4
- package/test/skill-prompt-sanitizer.test.ts +37 -16
- package/test/subagent-context.test.ts +77 -31
- package/test/synthesize.test.ts +13 -11
- package/src/access-intent/bash/cwd-projection.ts +0 -500
|
@@ -35,30 +35,37 @@ describe("AccessPath.forPath", () => {
|
|
|
35
35
|
realpathSync.mockImplementation((p: string) =>
|
|
36
36
|
p.startsWith("/tmp") ? `/private${p}` : p,
|
|
37
37
|
);
|
|
38
|
-
expect(
|
|
39
|
-
"/tmp/x",
|
|
40
|
-
|
|
41
|
-
]);
|
|
38
|
+
expect(
|
|
39
|
+
AccessPath.forPath("/tmp/x", { cwd, platform: "linux" }).matchValues(),
|
|
40
|
+
).toEqual(["/tmp/x", "/private/tmp/x"]);
|
|
42
41
|
});
|
|
43
42
|
|
|
44
43
|
test("deduplicates when the canonical form equals the lexical form", () => {
|
|
45
|
-
expect(
|
|
46
|
-
"/etc/hosts",
|
|
47
|
-
|
|
44
|
+
expect(
|
|
45
|
+
AccessPath.forPath("/etc/hosts", {
|
|
46
|
+
cwd,
|
|
47
|
+
platform: "linux",
|
|
48
|
+
}).matchValues(),
|
|
49
|
+
).toEqual(["/etc/hosts"]);
|
|
48
50
|
});
|
|
49
51
|
|
|
50
52
|
test("keeps the relative aliases for an in-cwd token without duplicating", () => {
|
|
51
|
-
expect(
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
expect(
|
|
54
|
+
AccessPath.forPath("src/foo.ts", {
|
|
55
|
+
cwd,
|
|
56
|
+
platform: "linux",
|
|
57
|
+
}).matchValues(),
|
|
58
|
+
).toEqual(["/projects/my-app/src/foo.ts", "src/foo.ts"]);
|
|
55
59
|
});
|
|
56
60
|
|
|
57
61
|
test("includes only the lexical aliases when canonical is empty", () => {
|
|
58
62
|
// Force canonicalizePath to return the original (no-op symlink resolution
|
|
59
63
|
// effectively means canonical === lexical, handled by dedup).
|
|
60
64
|
expect(
|
|
61
|
-
AccessPath.forPath("/etc/hosts", {
|
|
65
|
+
AccessPath.forPath("/etc/hosts", {
|
|
66
|
+
cwd,
|
|
67
|
+
platform: "linux",
|
|
68
|
+
}).matchValues(),
|
|
62
69
|
).not.toHaveLength(0);
|
|
63
70
|
});
|
|
64
71
|
|
|
@@ -68,6 +75,7 @@ describe("AccessPath.forPath", () => {
|
|
|
68
75
|
AccessPath.forPath("foo.ts", {
|
|
69
76
|
cwd,
|
|
70
77
|
resolveBase: "/projects/my-app/sub",
|
|
78
|
+
platform: "linux",
|
|
71
79
|
}).matchValues(),
|
|
72
80
|
).toEqual(["/projects/my-app/sub/foo.ts", "sub/foo.ts", "foo.ts"]);
|
|
73
81
|
});
|
|
@@ -80,6 +88,7 @@ describe("AccessPath.forPath", () => {
|
|
|
80
88
|
AccessPath.forPath("foo.ts", {
|
|
81
89
|
cwd,
|
|
82
90
|
resolveBase: "/projects/my-app/sub",
|
|
91
|
+
platform: "linux",
|
|
83
92
|
}).matchValues(),
|
|
84
93
|
).toEqual([
|
|
85
94
|
"/projects/my-app/sub/foo.ts",
|
|
@@ -90,24 +99,59 @@ describe("AccessPath.forPath", () => {
|
|
|
90
99
|
});
|
|
91
100
|
});
|
|
92
101
|
|
|
102
|
+
describe("platform option", () => {
|
|
103
|
+
test("win32: builds lexical/match/boundary values with win32 rules", () => {
|
|
104
|
+
const ap = AccessPath.forPath("src\\foo.ts", {
|
|
105
|
+
cwd: "C:\\Projects\\App",
|
|
106
|
+
platform: "win32",
|
|
107
|
+
});
|
|
108
|
+
expect(ap.value()).toBe("c:\\projects\\app\\src\\foo.ts");
|
|
109
|
+
expect(ap.boundaryValue()).toBe("c:\\projects\\app\\src\\foo.ts");
|
|
110
|
+
expect(ap.matchValues()).toEqual([
|
|
111
|
+
"c:\\projects\\app\\src\\foo.ts",
|
|
112
|
+
"src\\foo.ts",
|
|
113
|
+
]);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("win32: lowercases the symlink-resolved boundary value", () => {
|
|
117
|
+
realpathSync.mockImplementation((p: string) =>
|
|
118
|
+
p === "c:\\projects\\app\\link" ? "C:\\Real\\App" : p,
|
|
119
|
+
);
|
|
120
|
+
expect(
|
|
121
|
+
AccessPath.forPath("link", {
|
|
122
|
+
cwd: "C:\\Projects\\App",
|
|
123
|
+
platform: "win32",
|
|
124
|
+
}).boundaryValue(),
|
|
125
|
+
).toBe("c:\\real\\app");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
93
129
|
describe("boundaryValue()", () => {
|
|
94
130
|
test("returns the canonical (symlink-resolved) form", () => {
|
|
95
131
|
realpathSync.mockImplementation((p: string) =>
|
|
96
132
|
p.startsWith("/tmp") ? `/private${p}` : p,
|
|
97
133
|
);
|
|
98
|
-
expect(
|
|
99
|
-
"/
|
|
100
|
-
|
|
134
|
+
expect(
|
|
135
|
+
AccessPath.forPath("/tmp/x", {
|
|
136
|
+
cwd,
|
|
137
|
+
platform: "linux",
|
|
138
|
+
}).boundaryValue(),
|
|
139
|
+
).toBe("/private/tmp/x");
|
|
101
140
|
});
|
|
102
141
|
|
|
103
142
|
test("returns the lexical form when path has no symlinks", () => {
|
|
104
|
-
expect(
|
|
105
|
-
"/etc/hosts",
|
|
106
|
-
|
|
143
|
+
expect(
|
|
144
|
+
AccessPath.forPath("/etc/hosts", {
|
|
145
|
+
cwd,
|
|
146
|
+
platform: "linux",
|
|
147
|
+
}).boundaryValue(),
|
|
148
|
+
).toBe("/etc/hosts");
|
|
107
149
|
});
|
|
108
150
|
|
|
109
151
|
test("returns empty string for empty input", () => {
|
|
110
|
-
expect(
|
|
152
|
+
expect(
|
|
153
|
+
AccessPath.forPath("", { cwd, platform: "linux" }).boundaryValue(),
|
|
154
|
+
).toBe("");
|
|
111
155
|
});
|
|
112
156
|
});
|
|
113
157
|
|
|
@@ -117,14 +161,16 @@ describe("AccessPath.forPath", () => {
|
|
|
117
161
|
p.startsWith("/tmp") ? `/private${p}` : p,
|
|
118
162
|
);
|
|
119
163
|
// Even when the path resolves to a different canonical, value() stays lexical.
|
|
120
|
-
expect(
|
|
164
|
+
expect(
|
|
165
|
+
AccessPath.forPath("/tmp/x", { cwd, platform: "linux" }).value(),
|
|
166
|
+
).toBe("/tmp/x");
|
|
121
167
|
});
|
|
122
168
|
|
|
123
169
|
test("normalizes the path against cwd", () => {
|
|
124
170
|
// A relative path becomes an absolute lexical value.
|
|
125
|
-
expect(
|
|
126
|
-
"
|
|
127
|
-
);
|
|
171
|
+
expect(
|
|
172
|
+
AccessPath.forPath("src/foo.ts", { cwd, platform: "linux" }).value(),
|
|
173
|
+
).toBe("/projects/my-app/src/foo.ts");
|
|
128
174
|
});
|
|
129
175
|
|
|
130
176
|
test("normalizes a relative path against an explicit resolveBase", () => {
|
|
@@ -132,12 +178,15 @@ describe("AccessPath.forPath", () => {
|
|
|
132
178
|
AccessPath.forPath("foo.ts", {
|
|
133
179
|
cwd,
|
|
134
180
|
resolveBase: "/projects/my-app/sub",
|
|
181
|
+
platform: "linux",
|
|
135
182
|
}).value(),
|
|
136
183
|
).toBe("/projects/my-app/sub/foo.ts");
|
|
137
184
|
});
|
|
138
185
|
|
|
139
186
|
test("returns empty string for empty input", () => {
|
|
140
|
-
expect(AccessPath.forPath("", { cwd }).value()).toBe(
|
|
187
|
+
expect(AccessPath.forPath("", { cwd, platform: "linux" }).value()).toBe(
|
|
188
|
+
"",
|
|
189
|
+
);
|
|
141
190
|
});
|
|
142
191
|
});
|
|
143
192
|
});
|