@gotgenes/pi-permission-system 33.0.4 → 33.0.5
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
CHANGED
|
@@ -5,6 +5,17 @@ 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
|
+
## [33.0.5](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v33.0.4...pi-permission-system-v33.0.5) (2026-09-20)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **pi-permission-system:** stop projecting an interpreter's inline script as a path ([f919704](https://github.com/gotgenes/pi-packages/commit/f919704d029d6cae6027f50ce89cc49d76f35358)), closes [#863](https://github.com/gotgenes/pi-packages/issues/863)
|
|
14
|
+
|
|
15
|
+
### Documentation
|
|
16
|
+
|
|
17
|
+
* **pi-permission-system:** record the interpreter script role in the roadmap and module tree ([630e29f](https://github.com/gotgenes/pi-packages/commit/630e29f2365fb1848a835078f5b28cb5462b0b94))
|
|
18
|
+
|
|
8
19
|
## [33.0.4](https://github.com/gotgenes/pi-packages/compare/pi-permission-system-v33.0.3...pi-permission-system-v33.0.4) (2026-09-20)
|
|
9
20
|
|
|
10
21
|
|
|
@@ -118,6 +118,7 @@ For allowlisted commands, all non-flag positional arguments are assumed to be pa
|
|
|
118
118
|
**This extension** extracts path candidates from all commands generically, then applies additional intelligence:
|
|
119
119
|
|
|
120
120
|
- A `PATTERN_FIRST_COMMANDS` map understands flag arity for `sed`, `awk`, `grep`, `rg`, and similar tools, distinguishing inline patterns/scripts from file arguments to avoid false positives.
|
|
121
|
+
The same table reads an interpreter's inline script (`node -e`, `bun --eval`, `python3 -c`, `perl -e`, `ruby -e`) as a script rather than an operand, while leaving a script *file* (`node build.js`) an operand.
|
|
121
122
|
- Redirect destinations (`> /path/to/file`) are extracted.
|
|
122
123
|
- Heredoc bodies, comments, and variable assignments are skipped.
|
|
123
124
|
|
package/package.json
CHANGED
|
@@ -36,10 +36,11 @@ export interface PathToken {
|
|
|
36
36
|
* {@link SKIP_SUBTREE_TYPES} check: `heredoc_body` is in both sets, and the
|
|
37
37
|
* host reading is the one that must win.
|
|
38
38
|
*
|
|
39
|
-
* For commands in `PATTERN_FIRST_COMMANDS`, uses position-based
|
|
40
|
-
* argument skipping to avoid collecting inline patterns/scripts
|
|
41
|
-
*
|
|
42
|
-
*
|
|
39
|
+
* For commands in `PATTERN_FIRST_COMMANDS`, uses position- and role-based
|
|
40
|
+
* argument skipping to avoid collecting inline patterns/scripts as path
|
|
41
|
+
* candidates — a leading pattern positional for a matching tool, a
|
|
42
|
+
* `script`-role flag's argument for an interpreter. For all other commands,
|
|
43
|
+
* collects all arguments generically.
|
|
43
44
|
*/
|
|
44
45
|
export function collectPathCandidateTokens(node: TSNode): PathToken[] {
|
|
45
46
|
if (node.type === "command") return collectCommandTokens(node);
|
|
@@ -499,19 +500,124 @@ const SD_CONFIG: PatternCommandConfig = {
|
|
|
499
500
|
};
|
|
500
501
|
|
|
501
502
|
/**
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
503
|
+
* An interpreter takes its inline script from a flag and never from a leading
|
|
504
|
+
* positional, so `patternPositionals: 0` — `node build.js /tmp/x` names two
|
|
505
|
+
* real operands and no script.
|
|
506
|
+
*
|
|
507
|
+
* Verified by execution on macOS, 2026-09-20, node v26.9.0: `node -e`,
|
|
508
|
+
* `node --eval`, `node --eval='…'`, `node -p '1+1'` — `2`, and
|
|
509
|
+
* `node --print '2+2'` — `4` all run their argument as the program.
|
|
510
|
+
* `node -p t.js` evaluates `t.js` as *source* rather than running the file
|
|
511
|
+
* (`[eval]:1 / t.js / ^`), so `-p` consumes its argument unconditionally.
|
|
512
|
+
*/
|
|
513
|
+
const NODE_CONFIG: PatternCommandConfig = {
|
|
514
|
+
flags: new Map<string, PatternFlagRole>([
|
|
515
|
+
["-e", "script"],
|
|
516
|
+
["--eval", "script"],
|
|
517
|
+
["-p", "script"],
|
|
518
|
+
["--print", "script"],
|
|
519
|
+
]),
|
|
520
|
+
patternPositionals: 0,
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* `bun` asserts the same four spellings as `node` and gets its own object
|
|
525
|
+
* rather than sharing one, because the table's rule is a shared *parser* and
|
|
526
|
+
* not a shared spelling — the two are different binaries (#823).
|
|
527
|
+
*
|
|
528
|
+
* Verified by execution, bun 1.4.2: `bun -e`, `bun --eval`, `bun -p '1+1'`
|
|
529
|
+
* — `2`, `bun --print '3+3'` — `6`; `bun -p` with no value errors
|
|
530
|
+
* `The argument '-p' requires a value but none was supplied.`, so it consumes
|
|
531
|
+
* unconditionally.
|
|
532
|
+
*/
|
|
533
|
+
const BUN_CONFIG: PatternCommandConfig = {
|
|
534
|
+
flags: new Map<string, PatternFlagRole>([
|
|
535
|
+
["-e", "script"],
|
|
536
|
+
["--eval", "script"],
|
|
537
|
+
["-p", "script"],
|
|
538
|
+
["--print", "script"],
|
|
539
|
+
]),
|
|
540
|
+
patternPositionals: 0,
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* `python` and `python3` share one object because they are the same
|
|
545
|
+
* interpreter family: every implementation either name reaches is a
|
|
546
|
+
* CPython-compatible front end where `-c` takes the following argument.
|
|
547
|
+
*
|
|
548
|
+
* Verified by execution, python3 3.14.7: `python3 -c 'print("PC-OK")'`, and
|
|
549
|
+
* `python3 -cu 'print("x")'` raises from `File "<string>", line 1` — the
|
|
550
|
+
* glued `u` is evaluated as the script, which is the getopt semantics the
|
|
551
|
+
* existing glued-value rule already models. No `python` binary exists on the
|
|
552
|
+
* authoring host, so its row rests on the family argument rather than a run.
|
|
553
|
+
*/
|
|
554
|
+
const PYTHON_CONFIG: PatternCommandConfig = {
|
|
555
|
+
flags: new Map<string, PatternFlagRole>([["-c", "script"]]),
|
|
556
|
+
patternPositionals: 0,
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Verified by execution, perl 5.34.1: `perl -e 'print "PE-OK\n"'` and
|
|
561
|
+
* `perl -E 'say "PE2-OK"'`; `perl -e` with nothing after it errors
|
|
562
|
+
* `No code specified for -e.`, so both consume unconditionally.
|
|
563
|
+
*
|
|
564
|
+
* `-p` and `-n` are deliberately absent. They take no argument of their own,
|
|
565
|
+
* and the cluster spelling that carries the script (`perl -pe 's|a|b|'`) is
|
|
566
|
+
* looked up as `-p` by the glued rule's `text.slice(0, 2)` — so listing `-p`
|
|
567
|
+
* would consume the following word on the *separated* spelling too and drop a
|
|
568
|
+
* real operand, the direction ADR 0009 forbids.
|
|
569
|
+
*/
|
|
570
|
+
const PERL_CONFIG: PatternCommandConfig = {
|
|
571
|
+
flags: new Map<string, PatternFlagRole>([
|
|
572
|
+
["-e", "script"],
|
|
573
|
+
["-E", "script"],
|
|
574
|
+
]),
|
|
575
|
+
patternPositionals: 0,
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Verified by execution, ruby 4.0.7: `ruby -e 'puts "RE-OK"'`.
|
|
580
|
+
*
|
|
581
|
+
* `-E` is deliberately **not** listed, though `perl` lists it: on `ruby` it is
|
|
582
|
+
* `--encoding`, not a script flag. `ruby -E utf-8 -e 'puts "RE2-OK"'` runs,
|
|
583
|
+
* proving `-E` consumed `utf-8` and left the script to `-e`. Leaving it
|
|
584
|
+
* unlisted over-surfaces `utf-8` as a token that names nothing, which the
|
|
585
|
+
* existence probe discards — the recoverable direction.
|
|
586
|
+
*/
|
|
587
|
+
const RUBY_CONFIG: PatternCommandConfig = {
|
|
588
|
+
flags: new Map<string, PatternFlagRole>([["-e", "script"]]),
|
|
589
|
+
patternPositionals: 0,
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Commands whose leading positional arguments are inline patterns/scripts
|
|
594
|
+
* rather than filesystem paths, and commands whose inline script arrives
|
|
595
|
+
* through a flag. The map stores per-command flag configuration so the walker
|
|
596
|
+
* can identify which arguments a flag consumes and which are positional.
|
|
597
|
+
*
|
|
598
|
+
* Two classes share the table because they share the question. A pattern-first
|
|
599
|
+
* *matching* tool (`sed`, `grep`, `rg`) leads with a pattern and skips one or
|
|
600
|
+
* two positionals; an **interpreter** (`node`, `bun`, `python`, `perl`,
|
|
601
|
+
* `ruby`) leads with nothing and skips none, so its script can only ever
|
|
602
|
+
* arrive through a `script`-role flag and a script *file* stays an operand
|
|
603
|
+
* (#863).
|
|
506
604
|
*
|
|
507
605
|
* Names share a configuration object only when they share a *parser*, which is
|
|
508
606
|
* narrower than being aliases: `egrep`/`fgrep` are the same binary as `grep`
|
|
509
607
|
* here, and `nawk` is one-true-awk like `awk` — but `gawk` has its own config,
|
|
510
608
|
* because it is the only one of the three that certainly means GNU awk and so
|
|
511
609
|
* the only one whose long options certainly consume (#823).
|
|
610
|
+
* `node` and `bun` split for the same reason from the other direction: they
|
|
611
|
+
* assert identical spellings and are different binaries.
|
|
512
612
|
*/
|
|
513
613
|
const PATTERN_FIRST_COMMANDS: ReadonlyMap<string, PatternCommandConfig> =
|
|
514
614
|
new Map([
|
|
615
|
+
["node", NODE_CONFIG],
|
|
616
|
+
["bun", BUN_CONFIG],
|
|
617
|
+
["python", PYTHON_CONFIG],
|
|
618
|
+
["python3", PYTHON_CONFIG],
|
|
619
|
+
["perl", PERL_CONFIG],
|
|
620
|
+
["ruby", RUBY_CONFIG],
|
|
515
621
|
["sed", SED_CONFIG],
|
|
516
622
|
["awk", AWK_CONFIG],
|
|
517
623
|
["gawk", GAWK_CONFIG],
|