@sjawhar/pi-legion-envoy 5.17.3 → 5.17.4
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/dist/legion.js +510 -47
- package/package.json +1 -1
package/dist/legion.js
CHANGED
|
@@ -33473,7 +33473,7 @@ import { logger } from "@oh-my-pi/pi-utils";
|
|
|
33473
33473
|
// package.json
|
|
33474
33474
|
var package_default = {
|
|
33475
33475
|
name: "@sjawhar/pi-legion-envoy",
|
|
33476
|
-
version: "5.17.
|
|
33476
|
+
version: "5.17.4",
|
|
33477
33477
|
type: "module",
|
|
33478
33478
|
omp: {
|
|
33479
33479
|
extensions: [
|
|
@@ -34776,6 +34776,8 @@ function createGoLegionTool(deps) {
|
|
|
34776
34776
|
import {
|
|
34777
34777
|
closeSync,
|
|
34778
34778
|
existsSync,
|
|
34779
|
+
lstatSync,
|
|
34780
|
+
opendirSync,
|
|
34779
34781
|
openSync,
|
|
34780
34782
|
readFileSync as readFileSync3,
|
|
34781
34783
|
readSync,
|
|
@@ -41435,9 +41437,15 @@ function isUnset(value) {
|
|
|
41435
41437
|
}
|
|
41436
41438
|
var NO_ELEMENTS = { kind: "literal", text: "", noElements: true };
|
|
41437
41439
|
function stored(value) {
|
|
41438
|
-
|
|
41439
|
-
|
|
41440
|
-
|
|
41440
|
+
const counted = value.map((piece) => {
|
|
41441
|
+
if (piece.unknownCount !== true)
|
|
41442
|
+
return piece;
|
|
41443
|
+
const { unknownCount: _, ...rest } = piece;
|
|
41444
|
+
return rest;
|
|
41445
|
+
});
|
|
41446
|
+
if (!counted.some((piece) => piece.noElements === true))
|
|
41447
|
+
return counted;
|
|
41448
|
+
return counted.map((piece) => piece.noElements === true ? literal2("") : piece);
|
|
41441
41449
|
}
|
|
41442
41450
|
var ANY_NAME = "\x00";
|
|
41443
41451
|
var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -41477,7 +41485,7 @@ function wrapRefusal(error48, site, label) {
|
|
|
41477
41485
|
}
|
|
41478
41486
|
var MAX_DEPTH = 8;
|
|
41479
41487
|
var MAX_WALK_STEPS = 1e5;
|
|
41480
|
-
var WALK_LIMIT = `the guard reached its walk limit of ${MAX_WALK_STEPS} nodes; run a smaller script`;
|
|
41488
|
+
var WALK_LIMIT = `the guard reached its walk limit of ${MAX_WALK_STEPS} steps (syntax nodes, pattern matching, and the destination entries a copy inspects); run a smaller script, or copy into a smaller destination`;
|
|
41481
41489
|
var MAX_ALTERNATIVES = 64;
|
|
41482
41490
|
var MAX_PATTERN_VALUE = 512;
|
|
41483
41491
|
var PATTERN_WORK_PER_STEP = 1024;
|
|
@@ -41500,6 +41508,10 @@ var FILE_COMMANDS = new Set([
|
|
|
41500
41508
|
"rm",
|
|
41501
41509
|
"unlink",
|
|
41502
41510
|
"mv",
|
|
41511
|
+
"cp",
|
|
41512
|
+
"dd",
|
|
41513
|
+
"install",
|
|
41514
|
+
"ln",
|
|
41503
41515
|
"shred",
|
|
41504
41516
|
"truncate",
|
|
41505
41517
|
"chmod",
|
|
@@ -41804,8 +41816,10 @@ function resolveArrayIndex(index, st, ctx) {
|
|
|
41804
41816
|
}
|
|
41805
41817
|
function parameter(name, quoted, st, ctx) {
|
|
41806
41818
|
if (name === "@" || name === "*") {
|
|
41807
|
-
if (st.positional === undefined)
|
|
41808
|
-
|
|
41819
|
+
if (st.positional === undefined) {
|
|
41820
|
+
const piece = unknown2(`\`$${name}\` (the positional parameters)`);
|
|
41821
|
+
return [[name === "*" && quoted ? piece : { ...piece, unknownCount: true }]];
|
|
41822
|
+
}
|
|
41809
41823
|
return elements(st.positional, name === "*" && quoted);
|
|
41810
41824
|
}
|
|
41811
41825
|
if (/^[0-9]+$/.test(name)) {
|
|
@@ -41880,11 +41894,14 @@ function parameterExpansion(part, quoted, st, ctx) {
|
|
|
41880
41894
|
if (part.index === "@" || part.index === "*") {
|
|
41881
41895
|
if (array2 !== undefined) {
|
|
41882
41896
|
const unknownElement = array2.get(UNKNOWN_ARRAY_INDEX);
|
|
41883
|
-
if (unknownElement !== undefined)
|
|
41884
|
-
|
|
41897
|
+
if (unknownElement !== undefined) {
|
|
41898
|
+
if (part.index === "*" && quoted)
|
|
41899
|
+
return [[...unknownElement]];
|
|
41900
|
+
return [unknownElement.map((piece) => ({ ...piece, unknownCount: true }))];
|
|
41901
|
+
}
|
|
41885
41902
|
return elements([...array2.values()], part.index === "*" && quoted);
|
|
41886
41903
|
}
|
|
41887
|
-
return parameter(name, quoted, st, ctx);
|
|
41904
|
+
return parameter(name, quoted, st, ctx).map((alt) => !(part.index === "*" && quoted) && alt.some((piece) => piece.kind === "unknown") ? alt.map((piece) => ({ ...piece, unknownCount: true })) : alt);
|
|
41888
41905
|
}
|
|
41889
41906
|
if (part.index !== undefined) {
|
|
41890
41907
|
const index = resolveArrayIndex(part.index, st, ctx);
|
|
@@ -42103,10 +42120,18 @@ function braceAlternatives(part) {
|
|
|
42103
42120
|
return [[{ kind: "glob", text: part.text }]];
|
|
42104
42121
|
return inner.split(",").map((alternative) => [literal2(alternative)]);
|
|
42105
42122
|
}
|
|
42123
|
+
function tildeAt(text) {
|
|
42124
|
+
if (text.startsWith("~"))
|
|
42125
|
+
return 0;
|
|
42126
|
+
const equals = text.indexOf("=");
|
|
42127
|
+
if (equals <= 0 || !IDENTIFIER.test(text.slice(0, equals)))
|
|
42128
|
+
return;
|
|
42129
|
+
return text.charAt(equals + 1) === "~" ? equals + 1 : undefined;
|
|
42130
|
+
}
|
|
42106
42131
|
function expandPart(part, first, st, ctx) {
|
|
42107
42132
|
switch (part.type) {
|
|
42108
42133
|
case "Literal":
|
|
42109
|
-
return [unquotedLiteral(part.text, first ?
|
|
42134
|
+
return [unquotedLiteral(part.text, first ? tildeAt(part.text) : undefined, st, ctx)];
|
|
42110
42135
|
case "SingleQuoted":
|
|
42111
42136
|
case "AnsiCQuoted":
|
|
42112
42137
|
return [[literal2(part.value)]];
|
|
@@ -42162,7 +42187,7 @@ function textLength(pieces) {
|
|
|
42162
42187
|
function expandWord(word, st, ctx) {
|
|
42163
42188
|
let alternatives = [[]];
|
|
42164
42189
|
if (word.parts === undefined)
|
|
42165
|
-
alternatives = [unquotedLiteral(word.text,
|
|
42190
|
+
alternatives = [unquotedLiteral(word.text, tildeAt(word.text), st, ctx)];
|
|
42166
42191
|
else {
|
|
42167
42192
|
word.parts.forEach((part, index) => {
|
|
42168
42193
|
alternatives = product(alternatives, expandPart(part, index === 0, st, ctx));
|
|
@@ -42188,6 +42213,9 @@ function args(words, st, ctx) {
|
|
|
42188
42213
|
if (exp.some((piece) => piece.kind === "glob")) {
|
|
42189
42214
|
return { text: word.text, exp, fields: "unknown" };
|
|
42190
42215
|
}
|
|
42216
|
+
if (exp.some((piece) => piece.unknownCount === true)) {
|
|
42217
|
+
return { text: word.text, exp, fields: "unknown" };
|
|
42218
|
+
}
|
|
42191
42219
|
if (unquoted && exp.some((piece) => piece.kind === "unknown" || /[ \t\n]/.test(piece.text))) {
|
|
42192
42220
|
return { text: word.text, exp, fields: "unknown" };
|
|
42193
42221
|
}
|
|
@@ -42227,6 +42255,9 @@ function mayBeOption(arg, matches) {
|
|
|
42227
42255
|
const { text, whole } = readableWord(arg);
|
|
42228
42256
|
if (whole)
|
|
42229
42257
|
return matches(text);
|
|
42258
|
+
return mayBeSomeOption(text);
|
|
42259
|
+
}
|
|
42260
|
+
function mayBeSomeOption(text) {
|
|
42230
42261
|
return text === "" || /^--?[a-zA-Z-]*$/.test(text);
|
|
42231
42262
|
}
|
|
42232
42263
|
function valueInWord(arg, count) {
|
|
@@ -42682,6 +42713,15 @@ function spendPatternWork(work, ctx) {
|
|
|
42682
42713
|
function outputChanged(before, after) {
|
|
42683
42714
|
return before !== undefined && (after === undefined || JSON.stringify(before) !== JSON.stringify(after));
|
|
42684
42715
|
}
|
|
42716
|
+
function loopValue(type, name, words) {
|
|
42717
|
+
const pids = words.every((word) => {
|
|
42718
|
+
const text = literalText(word.exp);
|
|
42719
|
+
return text === "" || word.exp.length > 0 && word.exp.every((piece) => piece.descendantPid);
|
|
42720
|
+
});
|
|
42721
|
+
if (pids)
|
|
42722
|
+
return [unknown2(`\`$${name}\`, a loop variable`, true)];
|
|
42723
|
+
return type === "For" && words.length === 1 && words[0]?.exp[0]?.kind === "literal" && words[0].exp[0].text !== "" && !words[0].exp[0].text.startsWith("-") && words[0]?.exp.some((piece) => piece.kind === "glob") ? words[0].exp : [unknown2(`\`$${name}\`, a loop variable`)];
|
|
42724
|
+
}
|
|
42685
42725
|
function walkNode(node, st, ctx, pipeIn) {
|
|
42686
42726
|
if (++ctx.steps.count > MAX_WALK_STEPS) {
|
|
42687
42727
|
const site = siteOf(node, st);
|
|
@@ -42805,11 +42845,7 @@ function walkNode(node, st, ctx, pipeIn) {
|
|
|
42805
42845
|
}
|
|
42806
42846
|
} else {
|
|
42807
42847
|
const body = clone2(st);
|
|
42808
|
-
|
|
42809
|
-
const text = literalText(word.exp);
|
|
42810
|
-
return text === "" || word.exp.length > 0 && word.exp.every((piece) => piece.descendantPid);
|
|
42811
|
-
});
|
|
42812
|
-
assignScalar(body, name, signalSafe ? [unknown2(`\`$${name}\`, a loop variable`, true)] : [unknown2(`\`$${name}\`, a loop variable`)]);
|
|
42848
|
+
assignScalar(body, name, loopValue(node.type, name, words));
|
|
42813
42849
|
if (node.type === "Select")
|
|
42814
42850
|
assignScalar(body, "REPLY", [unknown2("`$REPLY`, read from input")]);
|
|
42815
42851
|
uncertainly(ctx, () => walkList(node.body.commands, body, ctx));
|
|
@@ -43624,24 +43660,78 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43624
43660
|
return;
|
|
43625
43661
|
case "rm":
|
|
43626
43662
|
case "unlink":
|
|
43627
|
-
checkTargets(base, "delete", operands(rest, "").operands,
|
|
43663
|
+
checkTargets(base, "delete", operands(rest, "").operands, ACTS_ON_LINK, st, ctx, site);
|
|
43628
43664
|
return;
|
|
43629
43665
|
case "mv": {
|
|
43630
|
-
const found =
|
|
43631
|
-
|
|
43632
|
-
|
|
43633
|
-
|
|
43634
|
-
|
|
43635
|
-
|
|
43636
|
-
|
|
43637
|
-
|
|
43666
|
+
const found = writeArguments(rest, "tS", MV_OPTIONS);
|
|
43667
|
+
if (found.flags.has("--help") || found.flags.has("--version"))
|
|
43668
|
+
return;
|
|
43669
|
+
const targets = [...found.operands, ...writeDestinations(found, site)];
|
|
43670
|
+
checkTargets("mv", "move", targets, ACTS_ON_LINK, st, ctx, site);
|
|
43671
|
+
return;
|
|
43672
|
+
}
|
|
43673
|
+
case "cp": {
|
|
43674
|
+
const found = writeArguments(rest, "tS", CP_OPTIONS);
|
|
43675
|
+
if (found.flags.has("--help") || found.flags.has("--version"))
|
|
43676
|
+
return;
|
|
43677
|
+
const unlinks = found.flags.has("b") || found.flags.has("--backup") || found.flags.has("--remove-destination") || found.uncertain;
|
|
43678
|
+
const destinations = writeDestinations(found, site);
|
|
43679
|
+
checkTargets("cp", "overwrite", destinations, unlinks ? WRITES_EITHER : WRITES_THROUGH_LINK, st, ctx, site);
|
|
43680
|
+
checkCopyContents(found, destinations, st, ctx, site);
|
|
43681
|
+
return;
|
|
43682
|
+
}
|
|
43683
|
+
case "install": {
|
|
43684
|
+
const found = writeArguments(rest, "mogtS", INSTALL_OPTIONS);
|
|
43685
|
+
if (found.flags.has("--help") || found.flags.has("--version"))
|
|
43686
|
+
return;
|
|
43687
|
+
const directories = found.flags.has("d") || found.flags.has("--directory");
|
|
43688
|
+
checkTargets("install", directories ? "create or change the mode of" : "overwrite", directories ? found.operands : writeDestinations(found, site), WRITES_EITHER, st, ctx, site);
|
|
43689
|
+
return;
|
|
43690
|
+
}
|
|
43691
|
+
case "dd": {
|
|
43692
|
+
const targets = [];
|
|
43638
43693
|
for (const arg of rest) {
|
|
43639
|
-
const text =
|
|
43640
|
-
if (text
|
|
43641
|
-
|
|
43694
|
+
const { text, whole } = readableWord(arg);
|
|
43695
|
+
if (whole && longOption(text, ["--help", "--version"]) !== undefined)
|
|
43696
|
+
return;
|
|
43697
|
+
if (text.startsWith("of=")) {
|
|
43698
|
+
const carried = valueInWord(arg, 3);
|
|
43699
|
+
targets.push({
|
|
43700
|
+
text: arg.text,
|
|
43701
|
+
exp: carried ?? [unknown2("an `of=` operand the guard cannot read")]
|
|
43702
|
+
});
|
|
43703
|
+
continue;
|
|
43642
43704
|
}
|
|
43705
|
+
if (!whole && "of=".startsWith(text)) {
|
|
43706
|
+
targets.push({
|
|
43707
|
+
text: arg.text,
|
|
43708
|
+
exp: [unknown2("a `dd` operand the guard cannot read, which may name its `of=` file")]
|
|
43709
|
+
});
|
|
43710
|
+
}
|
|
43711
|
+
}
|
|
43712
|
+
checkTargets("dd", "write", targets, WRITES_THROUGH_LINK, st, ctx, site);
|
|
43713
|
+
return;
|
|
43714
|
+
}
|
|
43715
|
+
case "ln": {
|
|
43716
|
+
const found = writeArguments(rest, "St", LN_OPTIONS);
|
|
43717
|
+
if (found.flags.has("--help") || found.flags.has("--version"))
|
|
43718
|
+
return;
|
|
43719
|
+
const sole = found.operands[0];
|
|
43720
|
+
const single = found.operands.length === 1 && found.directory === undefined && !found.uncertain && sole !== undefined && readableWord(sole).whole;
|
|
43721
|
+
const destinations = single ? [{ text: ".", exp: [literal2(".")] }] : writeDestinations(found, site);
|
|
43722
|
+
checkTargets("ln", "overwrite", destinations, WRITES_EITHER, st, ctx, site);
|
|
43723
|
+
const symbolic = found.flags.has("s") || found.flags.has("--symbolic");
|
|
43724
|
+
if (!symbolic) {
|
|
43725
|
+
const sources = found.operands.filter((arg) => !destinations.includes(arg));
|
|
43726
|
+
checkTargets("ln", "hard-link", sources, LINKS_TO, st, ctx, site);
|
|
43643
43727
|
}
|
|
43644
|
-
|
|
43728
|
+
return;
|
|
43729
|
+
}
|
|
43730
|
+
case "sed": {
|
|
43731
|
+
const writes = sedWrites(rest);
|
|
43732
|
+
const program = writes.inferred ? "sed, whose option word the guard cannot read and which may be `-i`," : "sed -i";
|
|
43733
|
+
checkTargets(program, "rewrite in place", writes.replaced, WRITES_LINK, st, ctx, site);
|
|
43734
|
+
checkTargets(program, "rewrite in place", writes.followed, WRITES_EITHER, st, ctx, site);
|
|
43645
43735
|
return;
|
|
43646
43736
|
}
|
|
43647
43737
|
case "rsync": {
|
|
@@ -43663,9 +43753,9 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43663
43753
|
"--remote-option",
|
|
43664
43754
|
"--rsync-path",
|
|
43665
43755
|
"--temp-dir"
|
|
43666
|
-
]).operands.at(-1);
|
|
43756
|
+
]).operands.filter(passesAnArgument).at(-1);
|
|
43667
43757
|
if (destination !== undefined) {
|
|
43668
|
-
checkTargets("rsync", "synchronize and delete into", [destination],
|
|
43758
|
+
checkTargets("rsync", "synchronize and delete into", [destination], ACTS_THROUGH_LINK, st, ctx, site);
|
|
43669
43759
|
}
|
|
43670
43760
|
return;
|
|
43671
43761
|
}
|
|
@@ -43697,14 +43787,14 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43697
43787
|
targetDirectories.push(target);
|
|
43698
43788
|
}
|
|
43699
43789
|
}
|
|
43700
|
-
checkTargets(base, "extract and overwrite in", targetDirectories,
|
|
43790
|
+
checkTargets(base, "extract and overwrite in", targetDirectories, ACTS_THROUGH_LINK, st, ctx, site);
|
|
43701
43791
|
return;
|
|
43702
43792
|
}
|
|
43703
43793
|
case "shred":
|
|
43704
|
-
checkTargets("shred", "shred", operands(rest, "ns", ["--iterations", "--size", "--random-source"]).operands,
|
|
43794
|
+
checkTargets("shred", "shred", operands(rest, "ns", ["--iterations", "--size", "--random-source"]).operands, ACTS_ON_BOTH, st, ctx, site);
|
|
43705
43795
|
return;
|
|
43706
43796
|
case "truncate":
|
|
43707
|
-
checkTargets("truncate", "truncate", operands(rest, "sr", ["--size", "--reference"]).operands,
|
|
43797
|
+
checkTargets("truncate", "truncate", operands(rest, "sr", ["--size", "--reference"]).operands, ACTS_THROUGH_LINK, st, ctx, site);
|
|
43708
43798
|
return;
|
|
43709
43799
|
case "chmod":
|
|
43710
43800
|
case "chown":
|
|
@@ -43778,8 +43868,8 @@ function dispatch(invocation, outer, ctx) {
|
|
|
43778
43868
|
return false;
|
|
43779
43869
|
const { text, whole } = readableWord(word);
|
|
43780
43870
|
const compact = text.replace("-", "");
|
|
43781
|
-
const
|
|
43782
|
-
return whole ?
|
|
43871
|
+
const normalized = commands.map((command) => command.replace("-", ""));
|
|
43872
|
+
return whole ? completeName(compact, normalized) !== undefined : normalized.some((command) => command.startsWith(compact));
|
|
43783
43873
|
};
|
|
43784
43874
|
let killing;
|
|
43785
43875
|
for (const segment of segments) {
|
|
@@ -44023,11 +44113,50 @@ function nameAndValue(arg) {
|
|
|
44023
44113
|
}
|
|
44024
44114
|
return { name, value: undefined };
|
|
44025
44115
|
}
|
|
44026
|
-
|
|
44116
|
+
var ACTS_ON_LINK = {
|
|
44117
|
+
followed: false,
|
|
44118
|
+
unfollowed: true,
|
|
44119
|
+
overwrite: false
|
|
44120
|
+
};
|
|
44121
|
+
var ACTS_THROUGH_LINK = {
|
|
44122
|
+
followed: true,
|
|
44123
|
+
unfollowed: false,
|
|
44124
|
+
overwrite: false
|
|
44125
|
+
};
|
|
44126
|
+
var ACTS_ON_BOTH = {
|
|
44127
|
+
followed: true,
|
|
44128
|
+
unfollowed: true,
|
|
44129
|
+
overwrite: false
|
|
44130
|
+
};
|
|
44131
|
+
var WRITES_THROUGH_LINK = {
|
|
44132
|
+
followed: true,
|
|
44133
|
+
unfollowed: false,
|
|
44134
|
+
overwrite: true
|
|
44135
|
+
};
|
|
44136
|
+
var WRITES_LINK = {
|
|
44137
|
+
followed: false,
|
|
44138
|
+
unfollowed: true,
|
|
44139
|
+
overwrite: true
|
|
44140
|
+
};
|
|
44141
|
+
var WRITES_EITHER = {
|
|
44142
|
+
followed: true,
|
|
44143
|
+
unfollowed: true,
|
|
44144
|
+
overwrite: true
|
|
44145
|
+
};
|
|
44146
|
+
var LINKS_TO = {
|
|
44147
|
+
followed: true,
|
|
44148
|
+
unfollowed: false,
|
|
44149
|
+
overwrite: true
|
|
44150
|
+
};
|
|
44151
|
+
function checkTargets(program, verb, targets, reach, st, ctx, site) {
|
|
44027
44152
|
for (const target of targets) {
|
|
44028
|
-
|
|
44029
|
-
|
|
44030
|
-
|
|
44153
|
+
for (const follow of [true, false]) {
|
|
44154
|
+
if (!(follow ? reach.followed : reach.unfollowed))
|
|
44155
|
+
continue;
|
|
44156
|
+
const verdict = judgePath(target.exp, st, ctx, { follow, overwrite: reach.overwrite });
|
|
44157
|
+
if (!verdict.ok) {
|
|
44158
|
+
throw refusal(site, `${program} would ${verb} \`${target.text}\` (${verdict.resolution})`, ctx);
|
|
44159
|
+
}
|
|
44031
44160
|
}
|
|
44032
44161
|
const text = literalText(target.exp);
|
|
44033
44162
|
if (text !== undefined && (text.startsWith("/") || st.cwd !== undefined)) {
|
|
@@ -44035,6 +44164,339 @@ function checkTargets(program, verb, targets, follow, st, ctx, site) {
|
|
|
44035
44164
|
}
|
|
44036
44165
|
}
|
|
44037
44166
|
}
|
|
44167
|
+
function completeName(prefix, names) {
|
|
44168
|
+
if (names.includes(prefix))
|
|
44169
|
+
return prefix;
|
|
44170
|
+
const reachable = names.filter((name) => name.startsWith(prefix));
|
|
44171
|
+
return reachable.length === 1 ? reachable[0] : undefined;
|
|
44172
|
+
}
|
|
44173
|
+
function longOption(text, names) {
|
|
44174
|
+
return completeName(text.split("=", 1)[0], names);
|
|
44175
|
+
}
|
|
44176
|
+
var GNU_INFORMATION = { "--help": false, "--version": false };
|
|
44177
|
+
var MV_OPTIONS = {
|
|
44178
|
+
"--backup": false,
|
|
44179
|
+
"--context": false,
|
|
44180
|
+
"--debug": false,
|
|
44181
|
+
"--force": false,
|
|
44182
|
+
"--interactive": false,
|
|
44183
|
+
"--no-clobber": false,
|
|
44184
|
+
"--no-copy": false,
|
|
44185
|
+
"--no-target-directory": false,
|
|
44186
|
+
"--strip-trailing-slashes": false,
|
|
44187
|
+
"--suffix": true,
|
|
44188
|
+
"--target-directory": true,
|
|
44189
|
+
"--update": false,
|
|
44190
|
+
"--verbose": false,
|
|
44191
|
+
...GNU_INFORMATION
|
|
44192
|
+
};
|
|
44193
|
+
var CP_OPTIONS = {
|
|
44194
|
+
"--archive": false,
|
|
44195
|
+
"--attributes-only": false,
|
|
44196
|
+
"--backup": false,
|
|
44197
|
+
"--context": false,
|
|
44198
|
+
"--copy-contents": false,
|
|
44199
|
+
"--debug": false,
|
|
44200
|
+
"--dereference": false,
|
|
44201
|
+
"--force": false,
|
|
44202
|
+
"--interactive": false,
|
|
44203
|
+
"--link": false,
|
|
44204
|
+
"--no-clobber": false,
|
|
44205
|
+
"--no-dereference": false,
|
|
44206
|
+
"--no-preserve": true,
|
|
44207
|
+
"--no-target-directory": false,
|
|
44208
|
+
"--one-file-system": false,
|
|
44209
|
+
"--parents": false,
|
|
44210
|
+
"--preserve": false,
|
|
44211
|
+
"--recursive": false,
|
|
44212
|
+
"--reflink": false,
|
|
44213
|
+
"--remove-destination": false,
|
|
44214
|
+
"--sparse": true,
|
|
44215
|
+
"--strip-trailing-slashes": false,
|
|
44216
|
+
"--suffix": true,
|
|
44217
|
+
"--symbolic-link": false,
|
|
44218
|
+
"--target-directory": true,
|
|
44219
|
+
"--update": false,
|
|
44220
|
+
"--verbose": false,
|
|
44221
|
+
...GNU_INFORMATION
|
|
44222
|
+
};
|
|
44223
|
+
var INSTALL_OPTIONS = {
|
|
44224
|
+
"--backup": false,
|
|
44225
|
+
"--compare": false,
|
|
44226
|
+
"--context": false,
|
|
44227
|
+
"--debug": false,
|
|
44228
|
+
"--directory": false,
|
|
44229
|
+
"--group": true,
|
|
44230
|
+
"--mode": true,
|
|
44231
|
+
"--no-target-directory": false,
|
|
44232
|
+
"--owner": true,
|
|
44233
|
+
"--preserve-context": false,
|
|
44234
|
+
"--preserve-timestamps": false,
|
|
44235
|
+
"--strip": false,
|
|
44236
|
+
"--strip-program": true,
|
|
44237
|
+
"--suffix": true,
|
|
44238
|
+
"--target-directory": true,
|
|
44239
|
+
"--verbose": false,
|
|
44240
|
+
...GNU_INFORMATION
|
|
44241
|
+
};
|
|
44242
|
+
var LN_OPTIONS = {
|
|
44243
|
+
"--backup": false,
|
|
44244
|
+
"--directory": false,
|
|
44245
|
+
"--force": false,
|
|
44246
|
+
"--interactive": false,
|
|
44247
|
+
"--logical": false,
|
|
44248
|
+
"--no-dereference": false,
|
|
44249
|
+
"--no-target-directory": false,
|
|
44250
|
+
"--physical": false,
|
|
44251
|
+
"--relative": false,
|
|
44252
|
+
"--suffix": true,
|
|
44253
|
+
"--symbolic": false,
|
|
44254
|
+
"--target-directory": true,
|
|
44255
|
+
"--verbose": false,
|
|
44256
|
+
...GNU_INFORMATION
|
|
44257
|
+
};
|
|
44258
|
+
function passesAnArgument(arg) {
|
|
44259
|
+
return arg.fields !== "none";
|
|
44260
|
+
}
|
|
44261
|
+
function writeArguments(rest, valued, long) {
|
|
44262
|
+
const names = Object.keys(long);
|
|
44263
|
+
const operands2 = [];
|
|
44264
|
+
const flags = new Set;
|
|
44265
|
+
let directory;
|
|
44266
|
+
let uncertain;
|
|
44267
|
+
for (let i = 0;i < rest.length; i += 1) {
|
|
44268
|
+
const arg = rest[i];
|
|
44269
|
+
const { text, whole } = readableWord(arg);
|
|
44270
|
+
if (whole && text === "--") {
|
|
44271
|
+
operands2.push(...rest.slice(i + 1).filter(passesAnArgument));
|
|
44272
|
+
break;
|
|
44273
|
+
}
|
|
44274
|
+
if (!whole || !text.startsWith("-") || text === "-") {
|
|
44275
|
+
if (!whole && mayBeSomeOption(text))
|
|
44276
|
+
uncertain = arg;
|
|
44277
|
+
if (passesAnArgument(arg))
|
|
44278
|
+
operands2.push(arg);
|
|
44279
|
+
continue;
|
|
44280
|
+
}
|
|
44281
|
+
let takesValue = false;
|
|
44282
|
+
let offset;
|
|
44283
|
+
if (text.startsWith("--")) {
|
|
44284
|
+
const option = longOption(text, names);
|
|
44285
|
+
if (option === undefined)
|
|
44286
|
+
continue;
|
|
44287
|
+
flags.add(option);
|
|
44288
|
+
takesValue = long[option] === true && !text.includes("=");
|
|
44289
|
+
if (option === "--target-directory")
|
|
44290
|
+
offset = text.indexOf("=") + 1 || text.length;
|
|
44291
|
+
} else {
|
|
44292
|
+
for (let index = 1;index < text.length; index += 1) {
|
|
44293
|
+
const letter = text.charAt(index);
|
|
44294
|
+
flags.add(letter);
|
|
44295
|
+
if (!valued.includes(letter))
|
|
44296
|
+
continue;
|
|
44297
|
+
takesValue = index === text.length - 1;
|
|
44298
|
+
if (letter === "t")
|
|
44299
|
+
offset = index + 1;
|
|
44300
|
+
break;
|
|
44301
|
+
}
|
|
44302
|
+
}
|
|
44303
|
+
const next = takesValue ? rest[i + 1] : undefined;
|
|
44304
|
+
if (takesValue)
|
|
44305
|
+
i += 1;
|
|
44306
|
+
if (offset === undefined)
|
|
44307
|
+
continue;
|
|
44308
|
+
const value = valueInWord(arg, offset);
|
|
44309
|
+
directory = value === undefined ? next : { text: arg.text, exp: value };
|
|
44310
|
+
}
|
|
44311
|
+
return { operands: operands2, flags, directory, uncertain };
|
|
44312
|
+
}
|
|
44313
|
+
function writeDestinations(found, site) {
|
|
44314
|
+
if (found.operands.length > 1 && (found.flags.has("T") || found.flags.has("--no-target-directory"))) {
|
|
44315
|
+
return [found.operands.at(-1)];
|
|
44316
|
+
}
|
|
44317
|
+
if (found.directory !== undefined && !found.uncertain)
|
|
44318
|
+
return [found.directory];
|
|
44319
|
+
if (found.operands.length < 2 || found.uncertain) {
|
|
44320
|
+
const word = found.uncertain?.text ?? found.operands.at(-1)?.text ?? "missing destination";
|
|
44321
|
+
throw new Refusal(site.snippet, site.line, `the guard cannot read a write destination from \`${word}\`; put \`--\` before operands, or use \`-T\` to name the last operand as the destination`);
|
|
44322
|
+
}
|
|
44323
|
+
return [found.operands.at(-1)];
|
|
44324
|
+
}
|
|
44325
|
+
function checkCopyContents(found, destinations, st, ctx, site) {
|
|
44326
|
+
const recursive = found.uncertain || ["r", "R", "a", "--recursive", "--archive"].some((flag) => found.flags.has(flag));
|
|
44327
|
+
const direct = found.flags.has("T") || found.flags.has("--no-target-directory");
|
|
44328
|
+
for (const destination of destinations) {
|
|
44329
|
+
const text = literalText(destination.exp);
|
|
44330
|
+
if (text === undefined || !path4.isAbsolute(text) && st.cwd === undefined)
|
|
44331
|
+
continue;
|
|
44332
|
+
const dir = realExisting(path4.resolve(st.cwd ?? "/", text));
|
|
44333
|
+
if (!statSync(dir, { throwIfNoEntry: false })?.isDirectory())
|
|
44334
|
+
continue;
|
|
44335
|
+
for (const source of found.operands) {
|
|
44336
|
+
if (destinations.includes(source))
|
|
44337
|
+
continue;
|
|
44338
|
+
const name = literalText(source.exp);
|
|
44339
|
+
const from = name === undefined ? undefined : path4.resolve(st.cwd ?? "/", name);
|
|
44340
|
+
const knownTree = from !== undefined && statSync(from, { throwIfNoEntry: false })?.isDirectory();
|
|
44341
|
+
const root = direct || name === undefined ? dir : path4.join(dir, found.flags.has("--parents") ? name : path4.basename(name));
|
|
44342
|
+
const pending = [root];
|
|
44343
|
+
while (pending.length > 0) {
|
|
44344
|
+
const target = pending.pop();
|
|
44345
|
+
checkTargets("cp", "overwrite", [{ text: name === undefined ? source.text : target, exp: [literal2(target)] }], WRITES_THROUGH_LINK, st, ctx, site);
|
|
44346
|
+
if (!recursive && !(name === undefined && target === root))
|
|
44347
|
+
continue;
|
|
44348
|
+
if (!lstatSync(target, { throwIfNoEntry: false })?.isDirectory())
|
|
44349
|
+
continue;
|
|
44350
|
+
const entries = opendirSync(target);
|
|
44351
|
+
try {
|
|
44352
|
+
for (let entry = entries.readSync();entry !== null; entry = entries.readSync()) {
|
|
44353
|
+
if (++ctx.steps.count > MAX_WALK_STEPS) {
|
|
44354
|
+
throw new Refusal(site.snippet, site.line, WALK_LIMIT);
|
|
44355
|
+
}
|
|
44356
|
+
const child = path4.join(target, entry.name);
|
|
44357
|
+
if (knownTree && !existsSync(path4.join(from, path4.relative(root, child))))
|
|
44358
|
+
continue;
|
|
44359
|
+
pending.push(child);
|
|
44360
|
+
}
|
|
44361
|
+
} finally {
|
|
44362
|
+
entries.closeSync();
|
|
44363
|
+
}
|
|
44364
|
+
}
|
|
44365
|
+
}
|
|
44366
|
+
}
|
|
44367
|
+
}
|
|
44368
|
+
var SED_OPTIONS = {
|
|
44369
|
+
"--debug": false,
|
|
44370
|
+
"--expression": true,
|
|
44371
|
+
"--file": true,
|
|
44372
|
+
"--follow-symlinks": false,
|
|
44373
|
+
"--in-place": false,
|
|
44374
|
+
"--line-length": true,
|
|
44375
|
+
"--null-data": false,
|
|
44376
|
+
"--posix": false,
|
|
44377
|
+
"--quiet": false,
|
|
44378
|
+
"--regexp-extended": false,
|
|
44379
|
+
"--sandbox": false,
|
|
44380
|
+
"--separate": false,
|
|
44381
|
+
"--silent": false,
|
|
44382
|
+
"--unbuffered": false,
|
|
44383
|
+
...GNU_INFORMATION
|
|
44384
|
+
};
|
|
44385
|
+
function sedWrites(list) {
|
|
44386
|
+
const names = Object.keys(SED_OPTIONS);
|
|
44387
|
+
let inPlace = false;
|
|
44388
|
+
let follow = false;
|
|
44389
|
+
let expression = false;
|
|
44390
|
+
let splitOption = false;
|
|
44391
|
+
let ended = false;
|
|
44392
|
+
let reopened = false;
|
|
44393
|
+
let takesNext = false;
|
|
44394
|
+
const unread = [];
|
|
44395
|
+
const operands2 = [];
|
|
44396
|
+
for (let i = 0;i < list.length; i += 1) {
|
|
44397
|
+
const arg = list[i];
|
|
44398
|
+
const { text, whole } = readableWord(arg);
|
|
44399
|
+
const afterUnread = takesNext;
|
|
44400
|
+
takesNext = false;
|
|
44401
|
+
const several = arg.fields === "unknown";
|
|
44402
|
+
if (ended) {
|
|
44403
|
+
operands2.push({ arg, option: false, several });
|
|
44404
|
+
continue;
|
|
44405
|
+
}
|
|
44406
|
+
if (whole && text === "--") {
|
|
44407
|
+
if (reopened)
|
|
44408
|
+
operands2.push({ arg, option: false, several: false });
|
|
44409
|
+
if (afterUnread)
|
|
44410
|
+
reopened = true;
|
|
44411
|
+
else
|
|
44412
|
+
ended = true;
|
|
44413
|
+
continue;
|
|
44414
|
+
}
|
|
44415
|
+
if (several) {
|
|
44416
|
+
splitOption = true;
|
|
44417
|
+
takesNext = true;
|
|
44418
|
+
operands2.push({ arg, option: true, several });
|
|
44419
|
+
continue;
|
|
44420
|
+
}
|
|
44421
|
+
if (!text.startsWith("-") || whole && text === "-") {
|
|
44422
|
+
const option = !whole && text === "";
|
|
44423
|
+
if (option) {
|
|
44424
|
+
unread.push(arg);
|
|
44425
|
+
takesNext = true;
|
|
44426
|
+
}
|
|
44427
|
+
operands2.push({ arg, option, several });
|
|
44428
|
+
continue;
|
|
44429
|
+
}
|
|
44430
|
+
if (reopened)
|
|
44431
|
+
operands2.push({ arg, option: false, several });
|
|
44432
|
+
if (text.startsWith("--")) {
|
|
44433
|
+
const option = longOption(text, names);
|
|
44434
|
+
if (whole && !reopened && (option === "--help" || option === "--version")) {
|
|
44435
|
+
return { replaced: [], followed: [], inPlace: false, inferred: false };
|
|
44436
|
+
}
|
|
44437
|
+
if (option === "--in-place")
|
|
44438
|
+
inPlace = true;
|
|
44439
|
+
if (option === "--follow-symlinks")
|
|
44440
|
+
follow = true;
|
|
44441
|
+
if (option === "--expression" || option === "--file")
|
|
44442
|
+
expression = true;
|
|
44443
|
+
if (option === undefined && !whole)
|
|
44444
|
+
unread.push(arg);
|
|
44445
|
+
if ((option === undefined ? !whole : SED_OPTIONS[option]) && !text.includes("=")) {
|
|
44446
|
+
if (whole && !reopened)
|
|
44447
|
+
i += 1;
|
|
44448
|
+
else
|
|
44449
|
+
takesNext = true;
|
|
44450
|
+
}
|
|
44451
|
+
continue;
|
|
44452
|
+
}
|
|
44453
|
+
let settled = false;
|
|
44454
|
+
for (const [offset, letter] of [...text.slice(1)].entries()) {
|
|
44455
|
+
if (letter === "i") {
|
|
44456
|
+
inPlace = true;
|
|
44457
|
+
settled = true;
|
|
44458
|
+
break;
|
|
44459
|
+
}
|
|
44460
|
+
if ("efl".includes(letter)) {
|
|
44461
|
+
if (letter !== "l")
|
|
44462
|
+
expression = true;
|
|
44463
|
+
if (offset === text.length - 2) {
|
|
44464
|
+
if (whole && !reopened)
|
|
44465
|
+
i += 1;
|
|
44466
|
+
else
|
|
44467
|
+
takesNext = true;
|
|
44468
|
+
}
|
|
44469
|
+
settled = true;
|
|
44470
|
+
break;
|
|
44471
|
+
}
|
|
44472
|
+
}
|
|
44473
|
+
if (!settled && !whole) {
|
|
44474
|
+
unread.push(arg);
|
|
44475
|
+
takesNext = true;
|
|
44476
|
+
}
|
|
44477
|
+
}
|
|
44478
|
+
const unsettled = (settled) => settled ? 0 : 1;
|
|
44479
|
+
const replaced = [];
|
|
44480
|
+
const followed = [];
|
|
44481
|
+
let before = false;
|
|
44482
|
+
for (const operand of operands2) {
|
|
44483
|
+
const maybe = operand.option && !operand.several;
|
|
44484
|
+
const others = unread.length - (maybe ? 1 : 0);
|
|
44485
|
+
const needed = unsettled(inPlace || splitOption) + unsettled(expression || splitOption || operand.several || before);
|
|
44486
|
+
if (others >= needed + unsettled(follow || splitOption))
|
|
44487
|
+
followed.push(operand.arg);
|
|
44488
|
+
else if (others >= needed)
|
|
44489
|
+
replaced.push(operand.arg);
|
|
44490
|
+
if (!maybe)
|
|
44491
|
+
before = true;
|
|
44492
|
+
}
|
|
44493
|
+
return {
|
|
44494
|
+
replaced,
|
|
44495
|
+
followed,
|
|
44496
|
+
inPlace: inPlace || splitOption || unread.length > 0,
|
|
44497
|
+
inferred: !inPlace
|
|
44498
|
+
};
|
|
44499
|
+
}
|
|
44038
44500
|
function checkRecursiveMode(program, list, st, ctx, site) {
|
|
44039
44501
|
const flags = program === "chmod" ? "cfvR" : "cfvRhHLP";
|
|
44040
44502
|
const found = [];
|
|
@@ -44063,7 +44525,7 @@ function checkRecursiveMode(program, list, st, ctx, site) {
|
|
|
44063
44525
|
}
|
|
44064
44526
|
const verb = program === "chmod" ? "recursively change the mode of" : "recursively change the owner of";
|
|
44065
44527
|
if (recursive) {
|
|
44066
|
-
checkTargets(`${program} -R`, verb, reference ? found : found.slice(1),
|
|
44528
|
+
checkTargets(`${program} -R`, verb, reference ? found : found.slice(1), ACTS_THROUGH_LINK, st, ctx, site);
|
|
44067
44529
|
return;
|
|
44068
44530
|
}
|
|
44069
44531
|
for (const [index, arg] of found.entries()) {
|
|
@@ -44073,7 +44535,7 @@ function checkRecursiveMode(program, list, st, ctx, site) {
|
|
|
44073
44535
|
const targets = reference || arg.fields === "unknown" ? others : others.slice(1);
|
|
44074
44536
|
if (targets.length === 0)
|
|
44075
44537
|
continue;
|
|
44076
|
-
checkTargets(`${program} -R`, verb, targets,
|
|
44538
|
+
checkTargets(`${program} -R`, verb, targets, ACTS_THROUGH_LINK, st, ctx, site);
|
|
44077
44539
|
}
|
|
44078
44540
|
}
|
|
44079
44541
|
function checkFind(list, st, ctx, site) {
|
|
@@ -44119,8 +44581,9 @@ function checkFind(list, st, ctx, site) {
|
|
|
44119
44581
|
continue;
|
|
44120
44582
|
const inner = unwrap2(list.slice(i + index + 1, i + end), st, ctx, site);
|
|
44121
44583
|
const program = path4.basename(literalText(inner.argv[0]?.exp) ?? "");
|
|
44122
|
-
if (FILE_COMMANDS.has(program) || program === "xargs")
|
|
44584
|
+
if (FILE_COMMANDS.has(program) || program === "xargs" || program === "sed" && sedWrites(inner.argv.slice(1)).inPlace) {
|
|
44123
44585
|
action = `find ${word} ${program}`;
|
|
44586
|
+
}
|
|
44124
44587
|
if (SHELLS.has(program)) {
|
|
44125
44588
|
action = `find ${word} ${program}`;
|
|
44126
44589
|
shell = inner.argv;
|
|
@@ -44130,10 +44593,10 @@ function checkFind(list, st, ctx, site) {
|
|
|
44130
44593
|
if (rootsBeforePredicate === undefined)
|
|
44131
44594
|
return;
|
|
44132
44595
|
const under = rootsBeforePredicate.length > 0 ? rootsBeforePredicate : [{ text: ".", exp: [literal2(".")] }];
|
|
44133
|
-
checkTargets("find with a root the guard cannot read, which may be a predicate", "delete or change what it finds under", under,
|
|
44596
|
+
checkTargets("find with a root the guard cannot read, which may be a predicate", "delete or change what it finds under", under, ACTS_ON_LINK, st, ctx, site);
|
|
44134
44597
|
return;
|
|
44135
44598
|
}
|
|
44136
|
-
checkTargets(action, "delete or change what it finds under", targets,
|
|
44599
|
+
checkTargets(action, "delete or change what it finds under", targets, ACTS_ON_LINK, st, ctx, site);
|
|
44137
44600
|
if (shell === undefined)
|
|
44138
44601
|
return;
|
|
44139
44602
|
const found = targets.length === 1 ? targets[0]?.exp ?? [] : [unknown2("a path `find` found")];
|
|
@@ -44171,7 +44634,7 @@ function checkXargs(list, st, ctx, site) {
|
|
|
44171
44634
|
};
|
|
44172
44635
|
});
|
|
44173
44636
|
const program = path4.basename(literalText(argv[0]?.exp) ?? "");
|
|
44174
|
-
if (FILE_COMMANDS.has(program) || SIGNAL_COMMANDS.has(program)) {
|
|
44637
|
+
if (FILE_COMMANDS.has(program) || SIGNAL_COMMANDS.has(program) || program === "sed" && sedWrites(argv.slice(1)).inPlace) {
|
|
44175
44638
|
throw new Refusal(site.snippet, site.line, `\`xargs ${program}\` takes its targets from standard input, which the guard cannot see; name ` + `the paths or pids on the command line (or use \`find <dir> -delete\`) so it can check them`);
|
|
44176
44639
|
}
|
|
44177
44640
|
const overlay = new Map;
|