@wrongstack/core 0.277.0 → 0.277.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/dist/index.js CHANGED
@@ -29606,19 +29606,51 @@ var LruCache = class {
29606
29606
  // src/security/permission-policy.ts
29607
29607
  init_safe_json();
29608
29608
  init_tool_subject();
29609
- var DESTRUCTIVE_BASH_PATTERNS = [
29610
- /\bgit\s+(?:clean\s+-[^\s]*[xdf]|reset\s+--hard)\b/i,
29611
- /\b(?:drop|truncate)\s+(?:table|database|schema)\b/i,
29612
- /\bdelete\s+from\b/i,
29613
- /\b(?:mkfs|format|diskpart|shutdown|reboot)\b/i,
29614
- /\bchmod\s+-R\s+777\b/i,
29615
- /\bchown\s+-R\b/i,
29616
- /\b(?:curl|wget)\b.*\|\s*(?:sh|bash|zsh|pwsh|powershell)\b/i,
29617
- /\b(?:powershell|pwsh)\b.*(?:-encodedcommand|-enc)\b/i,
29618
- /:\(\)\s*\{\s*:\|:&\s*}\s*;/
29609
+ var CATASTROPHIC_PATTERNS = [
29610
+ /\b(?:mkfs(?:\.[a-z0-9]+)?|mke2fs|newfs)\b/i,
29611
+ // make a filesystem — wipes a partition
29612
+ /\bformat\s+[A-Za-z]:/i,
29613
+ // format C: — wipes a Windows volume
29614
+ /\bdiskpart\b/i,
29615
+ // Windows partition editor
29616
+ /\bdd\b[^|]*\bof=(?:\/dev\/|\\\\[.?]\\)/i,
29617
+ // dd writing straight to a raw device
29618
+ />\s*\/dev\/(?:sd|hd|nvme|disk|mapper|vd)/i,
29619
+ // redirect into a raw block device
29620
+ /:\(\)\s*\{\s*:\|:&\s*\}\s*;/
29621
+ // classic fork bomb
29619
29622
  ];
29620
- var PROJECT_ESCAPE_PATTERN = /(?:^|[\s"'])\.\.(?:[\\/]|$)/;
29621
- var ABSOLUTE_PATH_PATTERN = /(?:^|[\s"'])(?:~[\\/]|\/[A-Za-z0-9_.-]|[A-Za-z]:[\\/])/;
29623
+ var CATASTROPHIC_POSIX_ROOTS = /* @__PURE__ */ new Set([
29624
+ "/etc",
29625
+ "/usr",
29626
+ "/bin",
29627
+ "/sbin",
29628
+ "/lib",
29629
+ "/lib64",
29630
+ "/var",
29631
+ "/boot",
29632
+ "/dev",
29633
+ "/sys",
29634
+ "/proc",
29635
+ "/opt",
29636
+ "/root",
29637
+ "/home",
29638
+ "/srv",
29639
+ "/run",
29640
+ "/system",
29641
+ "/library",
29642
+ "/applications",
29643
+ "/users"
29644
+ ]);
29645
+ var CATASTROPHIC_WIN_SUBDIRS = /* @__PURE__ */ new Set([
29646
+ "windows",
29647
+ "system32",
29648
+ "winnt",
29649
+ "program files",
29650
+ "program files (x86)",
29651
+ "programdata",
29652
+ "users"
29653
+ ]);
29622
29654
  var SHELL_OPERATORS = /* @__PURE__ */ new Set(["&&", "||", "|", ";", ">", ">>", "<", "2>", "2>>"]);
29623
29655
  function getInputString(input, key) {
29624
29656
  if (!input || typeof input !== "object") return void 0;
@@ -29635,20 +29667,21 @@ function pathLooksInsideProject(rawPath, projectRoot) {
29635
29667
  function tokenizeShell(command) {
29636
29668
  return command.match(/"[^"]*"|'[^']*'|\S+/g)?.map((token) => token.replace(/^['"]|['"]$/g, "")) ?? [];
29637
29669
  }
29638
- function pathTokenIsOutsideProject(token, projectRoot) {
29639
- if (!token || SHELL_OPERATORS.has(token) || token.startsWith("-")) return false;
29640
- if (token === "/" || token === "~" || token === "." || token === "..") return token !== ".";
29641
- if (token.includes("*")) return true;
29642
- if (token.startsWith("..") || token.includes("../") || token.includes("..\\")) return true;
29643
- if (path4.isAbsolute(token) || token.startsWith("~/")) return !pathLooksInsideProject(token, projectRoot);
29670
+ function isCatastrophicDeleteTarget(rawTarget) {
29671
+ const t2 = rawTarget.replace(/^['"]|['"]$/g, "").trim();
29672
+ if (!t2) return false;
29673
+ if (t2 === "*" || t2 === "." || t2 === "./" || t2 === ".\\" || t2 === "./*" || t2 === ".\\*") return true;
29674
+ const s = t2.replace(/[\\/]\*+$/, "").replace(/[\\/]+$/, "");
29675
+ if (s === "") return true;
29676
+ if (s === "~" || /^\$HOME$/i.test(s) || /^%USERPROFILE%$/i.test(s)) return true;
29677
+ if (/^[A-Za-z]:$/.test(s)) return true;
29678
+ const norm = s.toLowerCase().replace(/\\/g, "/");
29679
+ if (CATASTROPHIC_POSIX_ROOTS.has(norm)) return true;
29680
+ const win = norm.match(/^[a-z]:\/([^/]+)$/);
29681
+ if (win?.[1] && CATASTROPHIC_WIN_SUBDIRS.has(win[1])) return true;
29644
29682
  return false;
29645
29683
  }
29646
- function hasDangerousDeleteTarget(tokens, start, projectRoot) {
29647
- const targets = tokens.slice(start).filter((token) => !token.startsWith("-") && !SHELL_OPERATORS.has(token));
29648
- if (targets.length === 0) return true;
29649
- return targets.some((target) => pathTokenIsOutsideProject(target, projectRoot));
29650
- }
29651
- function hasDestructiveDelete(command, projectRoot) {
29684
+ function hasCatastrophicDelete(command) {
29652
29685
  const tokens = tokenizeShell(command);
29653
29686
  for (let i = 0; i < tokens.length; i++) {
29654
29687
  const token = tokens[i]?.toLowerCase();
@@ -29656,35 +29689,43 @@ function hasDestructiveDelete(command, projectRoot) {
29656
29689
  if (token === "rm") {
29657
29690
  const args = tokens.slice(i + 1);
29658
29691
  const recursiveOrForce = args.some(
29659
- (arg) => /^-[^-]*[rf]/i.test(arg) || arg === "--recursive" || arg === "--force"
29692
+ (arg) => /^-[^-]*[rf]/i.test(arg) || arg === "--recursive" || arg === "--force" || arg === "--no-preserve-root"
29660
29693
  );
29661
- if (recursiveOrForce && hasDangerousDeleteTarget(tokens, i + 1, projectRoot)) return true;
29694
+ if (!recursiveOrForce) continue;
29695
+ const targets = args.filter((arg) => !arg.startsWith("-") && !SHELL_OPERATORS.has(arg));
29696
+ if (targets.length === 0) return true;
29697
+ if (targets.some(isCatastrophicDeleteTarget)) return true;
29698
+ }
29699
+ if (token === "remove-item" || token === "ri") {
29700
+ const args = tokens.slice(i + 1);
29701
+ const recursive = args.some((arg) => {
29702
+ const a = arg.toLowerCase();
29703
+ return a === "-recurse" || a === "-force";
29704
+ });
29705
+ if (!recursive) continue;
29706
+ const targets = args.filter((arg) => !arg.startsWith("-") && !SHELL_OPERATORS.has(arg));
29707
+ if (targets.some(isCatastrophicDeleteTarget)) return true;
29662
29708
  }
29663
29709
  if (token === "rmdir" || token === "rd") {
29664
29710
  const args = tokens.slice(i + 1);
29665
29711
  const recursive = args.some((arg) => arg.toLowerCase() === "/s");
29666
- if (recursive && hasDangerousDeleteTarget(tokens, i + 1, projectRoot)) return true;
29712
+ if (!recursive) continue;
29713
+ const targets = args.filter((arg) => !arg.startsWith("-") && !arg.startsWith("/") && !SHELL_OPERATORS.has(arg));
29714
+ if (targets.some(isCatastrophicDeleteTarget)) return true;
29667
29715
  }
29668
29716
  if (token === "del" || token === "erase") {
29669
- if (hasDangerousDeleteTarget(tokens, i + 1, projectRoot)) return true;
29670
- }
29671
- if (token === "remove-item") {
29672
- const args = tokens.slice(i + 1).map((arg) => arg.toLowerCase());
29673
- const recursiveOrForce = args.includes("-recurse") || args.includes("-force");
29674
- if (recursiveOrForce && hasDangerousDeleteTarget(tokens, i + 1, projectRoot)) return true;
29717
+ const args = tokens.slice(i + 1);
29718
+ const targets = args.filter((arg) => !arg.startsWith("-") && !arg.startsWith("/") && !SHELL_OPERATORS.has(arg));
29719
+ if (targets.some(isCatastrophicDeleteTarget)) return true;
29675
29720
  }
29676
29721
  }
29677
29722
  return false;
29678
29723
  }
29679
- function isClearlyDestructiveBashCommand(command, projectRoot) {
29724
+ function isClearlyDestructiveBashCommand(command, _projectRoot) {
29680
29725
  const trimmed = command.trim();
29681
29726
  if (!trimmed) return false;
29682
- if (hasDestructiveDelete(trimmed, projectRoot)) return true;
29683
- if (DESTRUCTIVE_BASH_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
29684
- if (/\bcd\s+(?:\.\.|~|\/|[A-Za-z]:[\\/])/i.test(trimmed)) return true;
29685
- if (PROJECT_ESCAPE_PATTERN.test(trimmed)) return true;
29686
- const absolute = trimmed.match(ABSOLUTE_PATH_PATTERN)?.[0]?.trim().replace(/^['"]|['"]$/g, "");
29687
- if (absolute && !pathLooksInsideProject(absolute, projectRoot)) return true;
29727
+ if (hasCatastrophicDelete(trimmed)) return true;
29728
+ if (CATASTROPHIC_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
29688
29729
  return false;
29689
29730
  }
29690
29731