@gotgenes/pi-permission-system 7.0.1 → 7.1.0
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/schemas/permissions.schema.json +2 -2
- package/src/path-utils.ts +13 -3
- package/tests/path-utils.test.ts +36 -0
- package/tests/pi-infrastructure-read.test.ts +106 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [7.1.0](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v7.0.1...pi-permission-system-v7.1.0) (2026-05-22)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* support glob patterns in piInfrastructureReadPaths ([#122](https://github.com/gotgenes/pi-packages/issues/122)) ([7ebce24](https://github.com/gotgenes/pi-packages/commit/7ebce24ff36f573c3165fdf49e4b470f68d79b69))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Documentation
|
|
17
|
+
|
|
18
|
+
* document piInfrastructureReadPaths glob support ([#122](https://github.com/gotgenes/pi-packages/issues/122)) ([94fa688](https://github.com/gotgenes/pi-packages/commit/94fa688f1c41a6cf1d7bb49a3934728741dd1001))
|
|
19
|
+
* fix misleading ** examples and clarify * matches all characters ([00563dc](https://github.com/gotgenes/pi-packages/commit/00563dc90e3e800e0fc1b0f3ad0a9ed8c78f86b7))
|
|
20
|
+
* plan glob support for piInfrastructureReadPaths ([#122](https://github.com/gotgenes/pi-packages/issues/122)) ([1450d8b](https://github.com/gotgenes/pi-packages/commit/1450d8b61529d54c21df49d364d8bbcc1c7e55ec))
|
|
21
|
+
|
|
8
22
|
## [7.0.1](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v7.0.0...pi-permission-system-v7.0.1) (2026-05-21)
|
|
9
23
|
|
|
10
24
|
|
package/package.json
CHANGED
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"default": false
|
|
31
31
|
},
|
|
32
32
|
"piInfrastructureReadPaths": {
|
|
33
|
-
"description": "Additional directories to auto-allow for reads as Pi infrastructure, bypassing the external_directory gate. Supports ~ expansion
|
|
34
|
-
"markdownDescription": "Additional directories to auto-allow for reads as Pi infrastructure, bypassing the `external_directory` gate.\n\nThe extension auto-discovers the global node_modules root (walks up from the extension's install path; falls back to `npm root -g` from a dev checkout), `agentDir`, `agentDir/git`, and project-local `.pi/npm/` and `.pi/git/`. Add entries here for edge cases where auto-discovery is insufficient (e.g. custom `npmCommand` pointing to pnpm).\n\nSupports
|
|
33
|
+
"description": "Additional directories to auto-allow for reads as Pi infrastructure, bypassing the external_directory gate. Supports ~ expansion and wildcard patterns (* and ?).",
|
|
34
|
+
"markdownDescription": "Additional directories to auto-allow for reads as Pi infrastructure, bypassing the `external_directory` gate.\n\nThe extension auto-discovers the global node_modules root (walks up from the extension's install path; falls back to `npm root -g` from a dev checkout), `agentDir`, `agentDir/git`, and project-local `.pi/npm/` and `.pi/git/`. Add entries here for edge cases where auto-discovery is insufficient (e.g. custom `npmCommand` pointing to pnpm).\n\nSupports `~`/`$HOME` expansion. Entries may be plain directory prefixes or wildcard patterns using `*` (matches any characters, including `/`) and `?` (matches exactly one character). `**` and `*` are equivalent — both cross directory boundaries.",
|
|
35
35
|
"type": "array",
|
|
36
36
|
"items": {
|
|
37
37
|
"type": "string",
|
package/src/path-utils.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { homedir } from "node:os";
|
|
|
2
2
|
import { join, normalize, resolve, sep } from "node:path";
|
|
3
3
|
|
|
4
4
|
import { getNonEmptyString, toRecord } from "./common";
|
|
5
|
+
import { expandHomePath } from "./expand-home";
|
|
6
|
+
import { wildcardMatch } from "./wildcard-matcher";
|
|
5
7
|
|
|
6
8
|
export function normalizePathForComparison(
|
|
7
9
|
pathValue: string,
|
|
@@ -111,6 +113,10 @@ export function isPathOutsideWorkingDirectory(
|
|
|
111
113
|
return !isPathWithinDirectory(normalizedPath, normalizedCwd);
|
|
112
114
|
}
|
|
113
115
|
|
|
116
|
+
function containsGlobChars(value: string): boolean {
|
|
117
|
+
return value.includes("*") || value.includes("?");
|
|
118
|
+
}
|
|
119
|
+
|
|
114
120
|
/**
|
|
115
121
|
* Returns true if the given tool + normalized path combination qualifies for
|
|
116
122
|
* automatic allow as a Pi infrastructure read.
|
|
@@ -121,7 +127,8 @@ export function isPathOutsideWorkingDirectory(
|
|
|
121
127
|
* OR within the project-local Pi package directories
|
|
122
128
|
* (`<cwd>/.pi/npm/` or `<cwd>/.pi/git/`).
|
|
123
129
|
*
|
|
124
|
-
* `infrastructureDirs`
|
|
130
|
+
* `infrastructureDirs` entries may be absolute paths or patterns containing
|
|
131
|
+
* `~`/`$HOME` (expanded at call time) or glob characters (`*`, `?`).
|
|
125
132
|
* Project-local paths are computed fresh from `cwd` on each call so they
|
|
126
133
|
* follow working-directory changes without a runtime rebuild.
|
|
127
134
|
*/
|
|
@@ -136,8 +143,11 @@ export function isPiInfrastructureRead(
|
|
|
136
143
|
}
|
|
137
144
|
|
|
138
145
|
for (const dir of infrastructureDirs) {
|
|
139
|
-
if (
|
|
140
|
-
return true;
|
|
146
|
+
if (containsGlobChars(dir)) {
|
|
147
|
+
if (wildcardMatch(dir, normalizedPath)) return true;
|
|
148
|
+
} else {
|
|
149
|
+
if (isPathWithinDirectory(normalizedPath, expandHomePath(dir)))
|
|
150
|
+
return true;
|
|
141
151
|
}
|
|
142
152
|
}
|
|
143
153
|
|
package/tests/path-utils.test.ts
CHANGED
|
@@ -290,4 +290,40 @@ describe("isPiInfrastructureRead", () => {
|
|
|
290
290
|
false,
|
|
291
291
|
);
|
|
292
292
|
});
|
|
293
|
+
|
|
294
|
+
// ── glob patterns ─────────────────────────────────────────────────
|
|
295
|
+
|
|
296
|
+
test("glob entry matches a versioned path", () => {
|
|
297
|
+
expect(
|
|
298
|
+
isPiInfrastructureRead(
|
|
299
|
+
"read",
|
|
300
|
+
"/opt/homebrew/Cellar/pi-coding-agent/0.74.0/libexec/lib/node_modules/@earendil-works/pi-coding-agent/SKILL.md",
|
|
301
|
+
["/opt/homebrew/**/@earendil-works/pi-coding-agent/**"],
|
|
302
|
+
cwd,
|
|
303
|
+
),
|
|
304
|
+
).toBe(true);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("glob entry does not match an unrelated path", () => {
|
|
308
|
+
expect(
|
|
309
|
+
isPiInfrastructureRead(
|
|
310
|
+
"read",
|
|
311
|
+
"/etc/passwd",
|
|
312
|
+
["/opt/homebrew/**/@earendil-works/pi-coding-agent/**"],
|
|
313
|
+
cwd,
|
|
314
|
+
),
|
|
315
|
+
).toBe(false);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test("plain entry with ~ expands to home dir for matching", () => {
|
|
319
|
+
// node:os is mocked: homedir() returns "/mock/home"
|
|
320
|
+
expect(
|
|
321
|
+
isPiInfrastructureRead(
|
|
322
|
+
"read",
|
|
323
|
+
"/mock/home/.pi/agent/config.json",
|
|
324
|
+
["~/.pi/agent"],
|
|
325
|
+
cwd,
|
|
326
|
+
),
|
|
327
|
+
).toBe(true);
|
|
328
|
+
});
|
|
293
329
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
1
2
|
import { join } from "node:path";
|
|
2
3
|
import { beforeEach, describe, expect, test, vi } from "vitest";
|
|
3
4
|
|
|
@@ -261,3 +262,108 @@ describe("isPiInfrastructureRead", () => {
|
|
|
261
262
|
).toBe(true);
|
|
262
263
|
});
|
|
263
264
|
});
|
|
265
|
+
|
|
266
|
+
// ── isPiInfrastructureRead — glob patterns ─────────────────────────────────
|
|
267
|
+
|
|
268
|
+
describe("isPiInfrastructureRead with glob patterns", () => {
|
|
269
|
+
test("glob entry matches a versioned nested path", () => {
|
|
270
|
+
expect(
|
|
271
|
+
isPiInfrastructureRead(
|
|
272
|
+
"read",
|
|
273
|
+
"/opt/homebrew/Cellar/pi-coding-agent/0.74.0/libexec/lib/node_modules/@earendil-works/pi-coding-agent/SKILL.md",
|
|
274
|
+
["/opt/homebrew/*/@earendil-works/pi-coding-agent/*"],
|
|
275
|
+
CWD,
|
|
276
|
+
),
|
|
277
|
+
).toBe(true);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("** behaves the same as * (matches across path separators)", () => {
|
|
281
|
+
expect(
|
|
282
|
+
isPiInfrastructureRead(
|
|
283
|
+
"read",
|
|
284
|
+
"/opt/homebrew/Cellar/pi-coding-agent/0.74.0/libexec/lib/node_modules/@earendil-works/pi-coding-agent/SKILL.md",
|
|
285
|
+
["/opt/homebrew/**/@earendil-works/pi-coding-agent/**"],
|
|
286
|
+
CWD,
|
|
287
|
+
),
|
|
288
|
+
).toBe(true);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test("glob entry does not match an unrelated path", () => {
|
|
292
|
+
expect(
|
|
293
|
+
isPiInfrastructureRead(
|
|
294
|
+
"read",
|
|
295
|
+
"/etc/passwd",
|
|
296
|
+
["/opt/homebrew/*/@earendil-works/pi-coding-agent/*"],
|
|
297
|
+
CWD,
|
|
298
|
+
),
|
|
299
|
+
).toBe(false);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
test("? matches exactly one character", () => {
|
|
303
|
+
expect(
|
|
304
|
+
isPiInfrastructureRead(
|
|
305
|
+
"read",
|
|
306
|
+
"/opt/homebrew/X/file.md",
|
|
307
|
+
["/opt/homebrew/?/file.md"],
|
|
308
|
+
CWD,
|
|
309
|
+
),
|
|
310
|
+
).toBe(true);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test("? does not match multiple characters", () => {
|
|
314
|
+
expect(
|
|
315
|
+
isPiInfrastructureRead(
|
|
316
|
+
"read",
|
|
317
|
+
"/opt/homebrew/abc/file.md",
|
|
318
|
+
["/opt/homebrew/?/file.md"],
|
|
319
|
+
CWD,
|
|
320
|
+
),
|
|
321
|
+
).toBe(false);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test("mixed array of plain dirs and glob patterns — both branches work", () => {
|
|
325
|
+
const dirs = [
|
|
326
|
+
"/home/user/.pi/agent",
|
|
327
|
+
"/opt/homebrew/*/@earendil-works/pi-coding-agent/*",
|
|
328
|
+
];
|
|
329
|
+
expect(
|
|
330
|
+
isPiInfrastructureRead(
|
|
331
|
+
"read",
|
|
332
|
+
"/home/user/.pi/agent/config.json",
|
|
333
|
+
dirs,
|
|
334
|
+
CWD,
|
|
335
|
+
),
|
|
336
|
+
).toBe(true);
|
|
337
|
+
expect(
|
|
338
|
+
isPiInfrastructureRead(
|
|
339
|
+
"read",
|
|
340
|
+
"/opt/homebrew/Cellar/pi-coding-agent/0.74.0/libexec/lib/node_modules/@earendil-works/pi-coding-agent/SKILL.md",
|
|
341
|
+
dirs,
|
|
342
|
+
CWD,
|
|
343
|
+
),
|
|
344
|
+
).toBe(true);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test("plain entry with ~ prefix matches after home expansion", () => {
|
|
348
|
+
const home = homedir();
|
|
349
|
+
expect(
|
|
350
|
+
isPiInfrastructureRead(
|
|
351
|
+
"read",
|
|
352
|
+
`${home}/.pi/agent/config.json`,
|
|
353
|
+
["~/.pi/agent"],
|
|
354
|
+
CWD,
|
|
355
|
+
),
|
|
356
|
+
).toBe(true);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
test("write tool with a glob-matching path is still rejected", () => {
|
|
360
|
+
expect(
|
|
361
|
+
isPiInfrastructureRead(
|
|
362
|
+
"write",
|
|
363
|
+
"/opt/homebrew/Cellar/pi-coding-agent/0.74.0/libexec/lib/node_modules/@earendil-works/pi-coding-agent/SKILL.md",
|
|
364
|
+
["/opt/homebrew/**/@earendil-works/pi-coding-agent/**"],
|
|
365
|
+
CWD,
|
|
366
|
+
),
|
|
367
|
+
).toBe(false);
|
|
368
|
+
});
|
|
369
|
+
});
|