@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.
package/dist/cli.js CHANGED
@@ -412,6 +412,27 @@ var init_inline_analyzer = __esm({
412
412
 
413
413
  // src/engine/logic-rules.ts
414
414
  import * as fs2 from "fs";
415
+ function isWriteOperation(actionType, actionDetail, writeKeywords = WRITE_KEYWORDS) {
416
+ if (writeKeywords.some((kw) => actionType.includes(kw) || actionDetail.includes(kw))) return true;
417
+ if (WRITE_COMMAND_RES.some((rx) => rx.test(actionDetail))) return true;
418
+ if (/\bsed\s+-[a-zA-Z]*i/i.test(actionDetail)) return true;
419
+ if (actionDetail.includes(">")) {
420
+ const detailWithoutDevnull = actionDetail.replace(DEVNULL_REDIRECT_RE, "");
421
+ if (detailWithoutDevnull.includes(">")) {
422
+ const firstWord = actionDetail.trim().split(/\s+/)[0]?.toLowerCase() || "";
423
+ if (!READ_ONLY_COMMANDS.has(firstWord)) return true;
424
+ }
425
+ }
426
+ return false;
427
+ }
428
+ function matchDangerousAction(actionDetail, action) {
429
+ if (/[^\x00-\x7f]/.test(action)) {
430
+ return actionDetail.includes(action);
431
+ }
432
+ const escaped = action.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
433
+ const re = new RegExp(`(?<![-\\w])${escaped}\\b`, "i");
434
+ return re.test(actionDetail);
435
+ }
415
436
  function runLogicCheck(input) {
416
437
  const { actionHistory, aNext, cwd } = input;
417
438
  const actionDetail = aNext.actionDetail.toLowerCase();
@@ -426,7 +447,7 @@ function runLogicCheck(input) {
426
447
  const promptLower = input.promptSession.toLowerCase();
427
448
  for (const pattern of INTENT_DEVIATION_PATTERNS) {
428
449
  const intentMatched = pattern.intentKeywords.some((kw) => promptLower.includes(kw));
429
- const dangerousMatched = pattern.dangerousActions.some((kw) => actionDetail.includes(kw));
450
+ const dangerousMatched = pattern.dangerousActions.some((kw) => matchDangerousAction(actionDetail, kw));
430
451
  if (intentMatched && dangerousMatched) {
431
452
  return {
432
453
  allowed: false,
@@ -481,16 +502,7 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
481
502
  if (NON_WRITE_TOOL_PREFIXES.some((p) => actionType.startsWith(p))) return null;
482
503
  if (NON_WRITE_TOOLS.has(actionType)) return null;
483
504
  const isBashLike = actionType === "bash" || actionType === "executebash" || actionType === "terminal-executebash";
484
- let isWrite = isBashLike ? WRITE_KEYWORDS.some((kw) => actionType.includes(kw) || actionDetail.includes(kw)) : WRITE_KEYWORDS.some((kw) => actionType.includes(kw));
485
- if (!isWrite && actionDetail.includes(">")) {
486
- const detailWithoutDevnull = actionDetail.replace(/(?:2|&|1)?\s*>\s*\/dev\/null\b/g, "");
487
- if (detailWithoutDevnull.includes(">")) {
488
- const firstWord = actionDetail.split(/\s/)[0]?.toLowerCase() || "";
489
- if (!READ_ONLY_REDIR_CMDS.has(firstWord)) {
490
- isWrite = true;
491
- }
492
- }
493
- }
505
+ const isWrite = isBashLike ? isWriteOperation(actionType, actionDetail) : WRITE_KEYWORDS.some((kw) => actionType.includes(kw));
494
506
  if (!isWrite) return null;
495
507
  const targetPaths = extractFilePaths(actionDetail);
496
508
  if (targetPaths.length === 0) return null;
@@ -647,7 +659,7 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd) {
647
659
  violatedLayers: ["2"]
648
660
  };
649
661
  }
650
- 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;
662
+ 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;
651
663
  var init_logic_rules = __esm({
652
664
  "src/engine/logic-rules.ts"() {
653
665
  "use strict";
@@ -719,8 +731,105 @@ var init_logic_rules = __esm({
719
731
  "cat"
720
732
  ]);
721
733
  NON_WRITE_TOOL_PREFIXES = ["memory-", "skill-manager-", "mailbox-", "app-"];
722
- READ_ONLY_REDIR_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump"]);
723
734
  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"];
735
+ WRITE_COMMAND_RES = [
736
+ /\brm\b/,
737
+ /\bunlink\b/,
738
+ /\brmdir\b/,
739
+ /\bshred\b/,
740
+ /\bcp\b/,
741
+ /\bmv\b/,
742
+ /\binstall\b/,
743
+ /\btee\b/,
744
+ /\bdd\b/,
745
+ /\bmkfs\b/,
746
+ /\b(fdisk|parted|cfdisk|sfdisk)\b/,
747
+ /\bchmod\b/,
748
+ /\bchown\b/,
749
+ /\btruncate\b/
750
+ ];
751
+ READ_ONLY_COMMANDS = /* @__PURE__ */ new Set([
752
+ "cat",
753
+ "head",
754
+ "tail",
755
+ "less",
756
+ "more",
757
+ "grep",
758
+ "find",
759
+ "awk",
760
+ "sed",
761
+ "sort",
762
+ "uniq",
763
+ "wc",
764
+ "cut",
765
+ "strings",
766
+ "od",
767
+ "xxd",
768
+ "hexdump",
769
+ "tr",
770
+ "file",
771
+ "stat",
772
+ "du",
773
+ "df",
774
+ "ls",
775
+ "dir",
776
+ "tree",
777
+ "nl",
778
+ "tac",
779
+ "rev",
780
+ "lsblk",
781
+ "blockdev",
782
+ "smartctl",
783
+ "udevadm",
784
+ "dmidecode",
785
+ "lscpu",
786
+ "lspci",
787
+ "lsusb",
788
+ "lsmem",
789
+ "lsns",
790
+ "lsof",
791
+ "hwinfo",
792
+ "inxi",
793
+ "fdisk",
794
+ "parted",
795
+ "dmesg",
796
+ "journalctl",
797
+ "systemctl",
798
+ "hostnamectl",
799
+ "localectl",
800
+ "timedatectl",
801
+ "ps",
802
+ "top",
803
+ "free",
804
+ "vmstat",
805
+ "iostat",
806
+ "mpstat",
807
+ "pidof",
808
+ "pgrep",
809
+ "ip",
810
+ "ifconfig",
811
+ "route",
812
+ "ss",
813
+ "netstat",
814
+ "arp",
815
+ "ethtool",
816
+ "nmcli",
817
+ "uname",
818
+ "arch",
819
+ "nproc",
820
+ "getconf",
821
+ "getent",
822
+ "id",
823
+ "whoami",
824
+ "who",
825
+ "w",
826
+ "last",
827
+ "uptime",
828
+ "lsmod",
829
+ "modinfo",
830
+ "sysctl"
831
+ ]);
832
+ DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
724
833
  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"];
725
834
  CREATE_KEYWORDS = ["\u521B\u5EFA", "\u65B0\u5EFA", "create", "new file", "touch"];
726
835
  PASSWORD_MODIFY_PATTERNS = [
@@ -742,7 +851,7 @@ var init_logic_rules = __esm({
742
851
  INTENT_DEVIATION_PATTERNS = [
743
852
  {
744
853
  intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
745
- dangerousActions: ["\u5220\u9664", "remove", "delete", "rm ", "\u683C\u5F0F\u5316", "format"],
854
+ dangerousActions: ["\u5220\u9664", "remove", "delete", "rm", "\u683C\u5F0F\u5316", "format"],
746
855
  reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
747
856
  },
748
857
  {
@@ -1962,12 +2071,14 @@ function severityRank(s) {
1962
2071
  }
1963
2072
  function checkSensitivePath(command, cwd, agentExt) {
1964
2073
  const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
1965
- 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/];
1966
- const _DEVNULL_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/;
1967
- 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"]);
1968
- 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));
2074
+ const isWriteOpFlag = isWriteOperation("", command);
2075
+ const pathMatches = (text, path3) => {
2076
+ const escaped = path3.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2077
+ const re = path3.startsWith(".") || path3.startsWith("/") ? new RegExp(`(?:^|[\\s/\\\\'"])${escaped}\\b`, "i") : new RegExp(`\\b${escaped}\\b`, "i");
2078
+ return re.test(text);
2079
+ };
1969
2080
  for (const sp of ROOT_SENSITIVE_PATHS) {
1970
- if (command.includes(sp.path.toLowerCase())) {
2081
+ if (pathMatches(command, sp.path.toLowerCase())) {
1971
2082
  if (sp.path === "/dev/random") {
1972
2083
  if (isWriteOpFlag) {
1973
2084
  continue;
@@ -2021,7 +2132,7 @@ function checkSensitivePath(command, cwd, agentExt) {
2021
2132
  for (const sp of agentExt.extra_sensitive_paths) {
2022
2133
  const spPath = sp.path.toLowerCase();
2023
2134
  const expanded = `${expandedCwd}/${spPath}`;
2024
- if (command.includes(spPath) || command.includes(expanded.toLowerCase())) {
2135
+ if (pathMatches(command, spPath) || pathMatches(command, expanded.toLowerCase())) {
2025
2136
  const denyMode = sp.deny_mode || (sp.credential ? "deny_both" : sp.read_only ? "deny_read" : "deny_write");
2026
2137
  if (denyMode === "deny_read") {
2027
2138
  if (isWriteOpFlag) continue;