@poe-platform/safe-bash 0.1.424 → 0.1.426

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/README.md CHANGED
@@ -270,7 +270,7 @@ For SafeJS host integration, `makeSafeJsShellModule` exposes shell execution and
270
270
  | --- | --- |
271
271
  | `fs` | Required filesystem; no implicit host access. |
272
272
  | `cwd` | Initial virtual directory; defaults to `/`. |
273
- | `env` | Initial exported variables; defaults to an empty map, with `PWD` set from `cwd`. No host environment inheritance. Never pass host `process.env` or any secret-bearing object: everything in `env` is readable by executed scripts (`env`, `printenv`, `$VAR`), and on Cloudflare Workers with `nodejs_compat` `process.env` contains the Worker's secret bindings. The shell logs a warning when it detects this. |
273
+ | `env` | Initial exported variables; defaults to an empty map, with `PWD` set from `cwd`. No host environment inheritance. Never pass host `process.env` or any secret-bearing object: everything in `env` is readable by executed scripts (`env`, `printenv`, `$VAR`), and on Cloudflare Workers with `nodejs_compat` `process.env` contains the Worker's secret bindings. The shell warns only for the identical host `process.env` object, not copies, and does not filter values. |
274
274
  | `commands` | Existing `CommandRegistry`; defaults to an empty registry. |
275
275
  | `limits` | Resource limits listed below. |
276
276
 
@@ -289,7 +289,7 @@ provided. Pass an `AbortSignal` as `signal` to cancel. [Option types](src/shell/
289
289
  | `maxExpansionFields` | 10,000 |
290
290
  | `maxExpansionBytes` | 16 MiB |
291
291
  | `maxWallClockMs` | 30 seconds |
292
- | `maxCpuMs` | 30 seconds, checked at command and cooperative-yield checkpoints |
292
+ | `maxCpuMs` | 30 seconds elapsed including waits; checkpoint-enforced, not CPU accounting or preemptive enforcement. |
293
293
  | `pipeHighWaterMark` | 64 KiB |
294
294
 
295
295
  Always call `dispose()` when finished. Shell failures normally produce an exit
@@ -4109,6 +4109,7 @@ function filesystemCommands(maxDirectoryEntries) {
4109
4109
 
4110
4110
  // packages/safe-bash/src/commands/predicates.ts
4111
4111
  init_platform();
4112
+ var maxExpressionDepth = 256;
4112
4113
  async function metadata(context, path, link = false) {
4113
4114
  assertCommandRequirements(context, predicateRequirements, ["metadata"]);
4114
4115
  try {
@@ -4141,15 +4142,16 @@ function predicateCommands() {
4141
4142
  if (!/^[ \t]*[+-]?[0-9]+[ \t]*$/u.test(text)) throw new UsageError(`integer expression expected: '${text}'`);
4142
4143
  return BigInt(text.trim());
4143
4144
  };
4144
- const primary = () => {
4145
+ const primary = (depth) => {
4145
4146
  const token = args[offset++];
4146
4147
  if (token === void 0) throw new UsageError("argument expected");
4147
- if (token === "!" && !binary.has(args[offset] ?? "")) {
4148
- const inner = primary();
4149
- return async () => !await inner();
4150
- }
4151
- if (token === "(" && !binary.has(args[offset] ?? "")) {
4152
- const inner = disjunction();
4148
+ if ((token === "!" || token === "(") && !binary.has(args[offset] ?? "")) {
4149
+ if (depth >= maxExpressionDepth) throw new UsageError(`expression nesting exceeds ${maxExpressionDepth}`);
4150
+ if (token === "!") {
4151
+ const inner2 = primary(depth + 1);
4152
+ return async () => !await inner2();
4153
+ }
4154
+ const inner = disjunction(depth + 1);
4153
4155
  if (args[offset++] !== ")") throw new UsageError("missing ')'");
4154
4156
  return inner;
4155
4157
  }
@@ -4214,27 +4216,27 @@ function predicateCommands() {
4214
4216
  }
4215
4217
  return async () => token !== "";
4216
4218
  };
4217
- const conjunction = () => {
4218
- let predicate = primary();
4219
+ const conjunction = (depth) => {
4220
+ let predicate = primary(depth);
4219
4221
  while (args[offset] === "-a") {
4220
4222
  offset++;
4221
4223
  const left = predicate;
4222
- const right = primary();
4224
+ const right = primary(depth);
4223
4225
  predicate = async () => await left() && await right();
4224
4226
  }
4225
4227
  return predicate;
4226
4228
  };
4227
- const disjunction = () => {
4228
- let predicate = conjunction();
4229
+ const disjunction = (depth) => {
4230
+ let predicate = conjunction(depth);
4229
4231
  while (args[offset] === "-o") {
4230
4232
  offset++;
4231
4233
  const left = predicate;
4232
- const right = conjunction();
4234
+ const right = conjunction(depth);
4233
4235
  predicate = async () => await left() || await right();
4234
4236
  }
4235
4237
  return predicate;
4236
4238
  };
4237
- const evaluate = disjunction();
4239
+ const evaluate = disjunction(0);
4238
4240
  if (offset !== args.length) throw new UsageError(`unexpected argument '${args[offset]}'`);
4239
4241
  return { exitCode: await evaluate() ? 0 : 1 };
4240
4242
  })).map((command2) => ({ ...command2, filesystemRequirements: predicateRequirements }));
@@ -17941,7 +17943,7 @@ init_platform();
17941
17943
  // packages/safe-bash/src/commands/network/private-address.ts
17942
17944
  init_platform();
17943
17945
  function privateIPv4(first, second) {
17944
- return first === 10 || first === 127 || first === 0 || first === 169 && second === 254 || first === 192 && second === 168 || first === 172 && second >= 16 && second <= 31;
17946
+ return first === 10 || first === 127 || first === 0 || first === 169 && second === 254 || first === 192 && second === 168 || first === 172 && second >= 16 && second <= 31 || first === 100 && second >= 64 && second <= 127 || first === 198 && second >= 18 && second <= 19 || first >= 224;
17945
17947
  }
17946
17948
  function privateHostname(input3) {
17947
17949
  const hostname = input3.toLowerCase().replace(/\.$/u, "").replace(/^\[|\]$/gu, "");
@@ -17957,10 +17959,12 @@ function privateHostname(input3) {
17957
17959
  const mappedIPv4 = hextets.slice(0, 5).every((value2) => value2 === 0) && hextets[5] === 65535;
17958
17960
  const translatedIPv4 = hextets.slice(0, 4).every((value2) => value2 === 0) && hextets[4] === 65535 && hextets[5] === 0;
17959
17961
  const nat64IPv4 = hextets[0] === 100 && hextets[1] === 65435 && hextets.slice(2, 6).every((value2) => value2 === 0);
17960
- if (mappedIPv4 || translatedIPv4 || nat64IPv4) {
17962
+ const compatibleIPv4 = hextets.slice(0, 6).every((value2) => value2 === 0);
17963
+ if (mappedIPv4 || translatedIPv4 || nat64IPv4 || compatibleIPv4) {
17961
17964
  return privateIPv4(hextets[6] >>> 8, hextets[6] & 255);
17962
17965
  }
17963
- return (hextets[0] & 65024) === 64512 || (hextets[0] & 65472) === 65152;
17966
+ if (hextets[0] === 8194) return privateIPv4(hextets[1] >>> 8, hextets[1] & 255);
17967
+ return (hextets[0] & 65024) === 64512 || (hextets[0] & 65472) === 65152 || (hextets[0] & 65472) === 65216 || (hextets[0] & 65280) === 65280 || hextets[0] === 100 && hextets[1] === 65435 && hextets[2] === 1;
17964
17968
  }
17965
17969
  const parts2 = hostname.split(".");
17966
17970
  if (parts2.length !== 4 || parts2.some((part) => !part || Array.from(part).some((character) => character < "0" || character > "9"))) return false;
@@ -19144,7 +19148,7 @@ async function substitute(text, pattern, replacement, budget, global, occurrence
19144
19148
  }
19145
19149
 
19146
19150
  // packages/safe-bash/src/commands/text-programs/sed.ts
19147
- function parse(source, extended, separator) {
19151
+ function parse(source, extended, separator, maxProgramInstructions) {
19148
19152
  if (source.length > 1024 * 1024) throw new ProgramError("sed program exceeds 1 MiB");
19149
19153
  const result = [];
19150
19154
  const groups = [];
@@ -19240,6 +19244,7 @@ function parse(source, extended, separator) {
19240
19244
  continue;
19241
19245
  }
19242
19246
  if (offset === source.length) break;
19247
+ if (result.length >= maxProgramInstructions) throw new ProgramError("program instruction limit exceeded");
19243
19248
  const first = address();
19244
19249
  horizontal();
19245
19250
  let second;
@@ -19629,6 +19634,8 @@ async function execute(program, context, files, quiet, budget, separator, output
19629
19634
  }
19630
19635
  function sedCommand(options3 = {}) {
19631
19636
  const definition = command("sed", async (context) => {
19637
+ const maxProgramInstructions = options3.maxProgramInstructions === void 0 ? 1024 : options3.maxProgramInstructions;
19638
+ if (!Number.isSafeInteger(maxProgramInstructions) || maxProgramInstructions < 1) throw new ProgramError("maxProgramInstructions must be a positive safe integer");
19632
19639
  const budget = new Budget3(context, options3);
19633
19640
  const sources = [];
19634
19641
  const files = [];
@@ -19677,7 +19684,7 @@ function sedCommand(options3 = {}) {
19677
19684
  sources.push(byteString(files.shift()));
19678
19685
  }
19679
19686
  if (sources[0]?.startsWith("#n")) quiet = true;
19680
- const program = parse(sources.join("\n"), extended, separator);
19687
+ const program = parse(sources.join("\n"), extended, separator, maxProgramInstructions);
19681
19688
  const outputFiles = program.flatMap((instruction) => instruction.kind !== "r" && instruction.file !== void 0 ? [instruction.file] : []);
19682
19689
  await assertPathRequirements(context, sedRequirements, ["script-output"], outputFiles);
19683
19690
  if (inPlace !== void 0 || outputFiles.length) {