@kenhkl/agent-moss 0.10.3 → 0.10.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.
@@ -401,6 +401,27 @@ var init_inline_analyzer = __esm({
401
401
 
402
402
  // src/engine/logic-rules.ts
403
403
  import * as fs2 from "fs";
404
+ function isWriteOperation(actionType, actionDetail, writeKeywords = WRITE_KEYWORDS) {
405
+ if (writeKeywords.some((kw) => actionType.includes(kw) || actionDetail.includes(kw))) return true;
406
+ if (WRITE_COMMAND_RES.some((rx) => rx.test(actionDetail))) return true;
407
+ if (/\bsed\s+-[a-zA-Z]*i/i.test(actionDetail)) return true;
408
+ if (actionDetail.includes(">")) {
409
+ const detailWithoutDevnull = actionDetail.replace(DEVNULL_REDIRECT_RE, "");
410
+ if (detailWithoutDevnull.includes(">")) {
411
+ const firstWord = actionDetail.trim().split(/\s+/)[0]?.toLowerCase() || "";
412
+ if (!READ_ONLY_COMMANDS.has(firstWord)) return true;
413
+ }
414
+ }
415
+ return false;
416
+ }
417
+ function matchDangerousAction(actionDetail, action) {
418
+ if (/[^\x00-\x7f]/.test(action)) {
419
+ return actionDetail.includes(action);
420
+ }
421
+ const escaped = action.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
422
+ const re = new RegExp(`(?<![-\\w])${escaped}\\b`, "i");
423
+ return re.test(actionDetail);
424
+ }
404
425
  function runLogicCheck(input) {
405
426
  const { actionHistory, aNext, cwd } = input;
406
427
  const actionDetail = aNext.actionDetail.toLowerCase();
@@ -415,7 +436,7 @@ function runLogicCheck(input) {
415
436
  const promptLower = input.promptSession.toLowerCase();
416
437
  for (const pattern of INTENT_DEVIATION_PATTERNS) {
417
438
  const intentMatched = pattern.intentKeywords.some((kw) => promptLower.includes(kw));
418
- const dangerousMatched = pattern.dangerousActions.some((kw) => actionDetail.includes(kw));
439
+ const dangerousMatched = pattern.dangerousActions.some((kw) => matchDangerousAction(actionDetail, kw));
419
440
  if (intentMatched && dangerousMatched) {
420
441
  return {
421
442
  allowed: false,
@@ -470,16 +491,7 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
470
491
  if (NON_WRITE_TOOL_PREFIXES.some((p) => actionType.startsWith(p))) return null;
471
492
  if (NON_WRITE_TOOLS.has(actionType)) return null;
472
493
  const isBashLike = actionType === "bash" || actionType === "executebash" || actionType === "terminal-executebash";
473
- let isWrite = isBashLike ? WRITE_KEYWORDS.some((kw) => actionType.includes(kw) || actionDetail.includes(kw)) : WRITE_KEYWORDS.some((kw) => actionType.includes(kw));
474
- if (!isWrite && actionDetail.includes(">")) {
475
- const detailWithoutDevnull = actionDetail.replace(/(?:2|&|1)?\s*>\s*\/dev\/null\b/g, "");
476
- if (detailWithoutDevnull.includes(">")) {
477
- const firstWord = actionDetail.split(/\s/)[0]?.toLowerCase() || "";
478
- if (!READ_ONLY_REDIR_CMDS.has(firstWord)) {
479
- isWrite = true;
480
- }
481
- }
482
- }
494
+ const isWrite = isBashLike ? isWriteOperation(actionType, actionDetail) : WRITE_KEYWORDS.some((kw) => actionType.includes(kw));
483
495
  if (!isWrite) return null;
484
496
  const targetPaths = extractFilePaths(actionDetail);
485
497
  if (targetPaths.length === 0) return null;
@@ -636,7 +648,7 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd) {
636
648
  violatedLayers: ["2"]
637
649
  };
638
650
  }
639
- var ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, READ_ONLY_REDIR_CMDS, WRITE_KEYWORDS, READ_KEYWORDS, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW;
651
+ var ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, WRITE_KEYWORDS, WRITE_COMMAND_RES, READ_ONLY_COMMANDS, DEVNULL_REDIRECT_RE, READ_KEYWORDS, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW;
640
652
  var init_logic_rules = __esm({
641
653
  "src/engine/logic-rules.ts"() {
642
654
  "use strict";
@@ -708,8 +720,105 @@ var init_logic_rules = __esm({
708
720
  "cat"
709
721
  ]);
710
722
  NON_WRITE_TOOL_PREFIXES = ["memory-", "skill-manager-", "mailbox-", "app-"];
711
- READ_ONLY_REDIR_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump"]);
712
723
  WRITE_KEYWORDS = ["write", "\u5199\u5165", "save", "\u4FDD\u5B58", "modify", "\u4FEE\u6539", "update", "\u66F4\u65B0", "delete", "\u5220\u9664", "remove", "\u79FB\u9664", "create", "\u521B\u5EFA", "append", "\u8FFD\u52A0", "truncate", "\u622A\u65AD", "overwrite", "\u8986\u76D6", "replace", "\u66FF\u6362"];
724
+ WRITE_COMMAND_RES = [
725
+ /\brm\b/,
726
+ /\bunlink\b/,
727
+ /\brmdir\b/,
728
+ /\bshred\b/,
729
+ /\bcp\b/,
730
+ /\bmv\b/,
731
+ /\binstall\b/,
732
+ /\btee\b/,
733
+ /\bdd\b/,
734
+ /\bmkfs\b/,
735
+ /\b(fdisk|parted|cfdisk|sfdisk)\b/,
736
+ /\bchmod\b/,
737
+ /\bchown\b/,
738
+ /\btruncate\b/
739
+ ];
740
+ READ_ONLY_COMMANDS = /* @__PURE__ */ new Set([
741
+ "cat",
742
+ "head",
743
+ "tail",
744
+ "less",
745
+ "more",
746
+ "grep",
747
+ "find",
748
+ "awk",
749
+ "sed",
750
+ "sort",
751
+ "uniq",
752
+ "wc",
753
+ "cut",
754
+ "strings",
755
+ "od",
756
+ "xxd",
757
+ "hexdump",
758
+ "tr",
759
+ "file",
760
+ "stat",
761
+ "du",
762
+ "df",
763
+ "ls",
764
+ "dir",
765
+ "tree",
766
+ "nl",
767
+ "tac",
768
+ "rev",
769
+ "lsblk",
770
+ "blockdev",
771
+ "smartctl",
772
+ "udevadm",
773
+ "dmidecode",
774
+ "lscpu",
775
+ "lspci",
776
+ "lsusb",
777
+ "lsmem",
778
+ "lsns",
779
+ "lsof",
780
+ "hwinfo",
781
+ "inxi",
782
+ "fdisk",
783
+ "parted",
784
+ "dmesg",
785
+ "journalctl",
786
+ "systemctl",
787
+ "hostnamectl",
788
+ "localectl",
789
+ "timedatectl",
790
+ "ps",
791
+ "top",
792
+ "free",
793
+ "vmstat",
794
+ "iostat",
795
+ "mpstat",
796
+ "pidof",
797
+ "pgrep",
798
+ "ip",
799
+ "ifconfig",
800
+ "route",
801
+ "ss",
802
+ "netstat",
803
+ "arp",
804
+ "ethtool",
805
+ "nmcli",
806
+ "uname",
807
+ "arch",
808
+ "nproc",
809
+ "getconf",
810
+ "getent",
811
+ "id",
812
+ "whoami",
813
+ "who",
814
+ "w",
815
+ "last",
816
+ "uptime",
817
+ "lsmod",
818
+ "modinfo",
819
+ "sysctl"
820
+ ]);
821
+ DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
713
822
  READ_KEYWORDS = ["read", "\u8BFB\u53D6", "cat", "head", "tail", "less", "more", "view", "\u67E5\u770B", "open", "\u6253\u5F00", "load", "\u52A0\u8F7D", "grep", "search", "\u641C\u7D22", "find", "\u67E5\u627E"];
714
823
  CREATE_KEYWORDS = ["\u521B\u5EFA", "\u65B0\u5EFA", "create", "new file", "touch"];
715
824
  PASSWORD_MODIFY_PATTERNS = [
@@ -731,7 +840,7 @@ var init_logic_rules = __esm({
731
840
  INTENT_DEVIATION_PATTERNS = [
732
841
  {
733
842
  intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
734
- dangerousActions: ["\u5220\u9664", "remove", "delete", "rm ", "\u683C\u5F0F\u5316", "format"],
843
+ dangerousActions: ["\u5220\u9664", "remove", "delete", "rm", "\u683C\u5F0F\u5316", "format"],
735
844
  reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
736
845
  },
737
846
  {
@@ -1951,12 +2060,14 @@ function severityRank(s) {
1951
2060
  }
1952
2061
  function checkSensitivePath(command, cwd, agentExt) {
1953
2062
  const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
1954
- const _WRITE_CMD_RES = [/\brm\b/, /\bunlink\b/, /\brmdir\b/, /\bshred\b/, /\bcp\b/, /\bmv\b/, /\binstall\b/, /\btee\b/, /\bdd\b/, /\bmkfs\b/, /\b(fdisk|parted|cfdisk|sfdisk)\b/, /\bchmod\b/, /\bchown\b/, /\btruncate\b/];
1955
- const _DEVNULL_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
1956
- const _READONLY_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump", "tr", "file", "stat", "du", "df", "ls", "dir", "tree", "nl", "tac", "rev", "lsblk", "blockdev", "smartctl", "udevadm", "dmidecode", "lscpu", "lspci", "lsusb", "lsmem", "lsns", "lsof", "hwinfo", "inxi", "fdisk", "parted", "dmesg", "journalctl", "systemctl", "hostnamectl", "localectl", "timedatectl", "ps", "top", "free", "vmstat", "iostat", "mpstat", "pidof", "pgrep", "ip", "ifconfig", "route", "ss", "netstat", "arp", "ethtool", "nmcli", "uname", "arch", "nproc", "getconf", "getent", "id", "whoami", "who", "w", "last", "uptime", "lsmod", "modinfo", "sysctl"]);
1957
- const isWriteOpFlag = _WRITE_CMD_RES.some((rx) => rx.test(command)) || /\bsed\s+-[a-zA-Z]*i/.test(command) || command.includes(">") && !command.replace(_DEVNULL_RE, "").includes(">") || command.includes(">") && command.replace(_DEVNULL_RE, "").includes(">") && !_READONLY_CMDS.has(command.trim().split(/\s+/)[0]?.toLowerCase() || "") || WRITE_KEYWORDS.some((kw) => "".includes(kw) || command.includes(kw));
2063
+ const isWriteOpFlag = isWriteOperation("", command);
2064
+ const pathMatches = (text, path3) => {
2065
+ const escaped = path3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2066
+ const re = path3.startsWith(".") || path3.startsWith("/") ? new RegExp(`(?:^|[\\s/\\\\'"])${escaped}\\b`, "i") : new RegExp(`\\b${escaped}\\b`, "i");
2067
+ return re.test(text);
2068
+ };
1958
2069
  for (const sp of ROOT_SENSITIVE_PATHS) {
1959
- if (command.includes(sp.path.toLowerCase())) {
2070
+ if (pathMatches(command, sp.path.toLowerCase())) {
1960
2071
  if (sp.path === "/dev/random") {
1961
2072
  if (isWriteOpFlag) {
1962
2073
  continue;
@@ -2010,7 +2121,7 @@ function checkSensitivePath(command, cwd, agentExt) {
2010
2121
  for (const sp of agentExt.extra_sensitive_paths) {
2011
2122
  const spPath = sp.path.toLowerCase();
2012
2123
  const expanded = `${expandedCwd}/${spPath}`;
2013
- if (command.includes(spPath) || command.includes(expanded.toLowerCase())) {
2124
+ if (pathMatches(command, spPath) || pathMatches(command, expanded.toLowerCase())) {
2014
2125
  const denyMode = sp.deny_mode || (sp.credential ? "deny_both" : sp.read_only ? "deny_read" : "deny_write");
2015
2126
  if (denyMode === "deny_read") {
2016
2127
  if (isWriteOpFlag) continue;