@kenhkl/agent-moss 0.11.4 → 0.12.0
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 +231 -364
- package/dist/cli.js.map +1 -1
- package/dist/engine/coordinator.js +196 -329
- package/dist/engine/coordinator.js.map +1 -1
- package/dist/rules/l1_rules.json +821 -0
- package/dist/rules/l2_rules.json +82 -0
- package/dist/rules/l3_rules.json +245 -0
- package/dist/server.js +217 -350
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -574,8 +574,70 @@ var init_inline_analyzer = __esm({
|
|
|
574
574
|
}
|
|
575
575
|
});
|
|
576
576
|
|
|
577
|
+
// src/infra/rules-loader.ts
|
|
578
|
+
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
579
|
+
import { resolve, dirname } from "path";
|
|
580
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
581
|
+
function findRulesFile(name) {
|
|
582
|
+
for (const dir of RULES_DIR_CANDS) {
|
|
583
|
+
const p = resolve(dir, name);
|
|
584
|
+
if (existsSync(p)) return p;
|
|
585
|
+
}
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
function loadJson(name) {
|
|
589
|
+
const p = findRulesFile(name);
|
|
590
|
+
if (!p) return {};
|
|
591
|
+
try {
|
|
592
|
+
return JSON.parse(readFileSync2(p, "utf-8")) || {};
|
|
593
|
+
} catch {
|
|
594
|
+
return {};
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
function loadL1() {
|
|
598
|
+
return loadJson("l1_rules.json");
|
|
599
|
+
}
|
|
600
|
+
function loadL2() {
|
|
601
|
+
return loadJson("l2_rules.json");
|
|
602
|
+
}
|
|
603
|
+
function loadL3() {
|
|
604
|
+
return loadJson("l3_rules.json");
|
|
605
|
+
}
|
|
606
|
+
var __filename2, __dirname2, RULES_DIR_CANDS;
|
|
607
|
+
var init_rules_loader = __esm({
|
|
608
|
+
"src/infra/rules-loader.ts"() {
|
|
609
|
+
"use strict";
|
|
610
|
+
init_esm_shims();
|
|
611
|
+
__filename2 = fileURLToPath3(import.meta.url);
|
|
612
|
+
__dirname2 = dirname(__filename2);
|
|
613
|
+
RULES_DIR_CANDS = (() => {
|
|
614
|
+
const cands = [
|
|
615
|
+
// dist: __dirname=dist/ → dist/rules;__dirname=dist/engine/ → dist/engine/../rules=dist/rules
|
|
616
|
+
resolve(__dirname2, "../rules"),
|
|
617
|
+
resolve(__dirname2, "rules"),
|
|
618
|
+
// dev src: __dirname=ts/src/infra/ → ts/src/infra/../../../agent_moss/rules = 仓库根 agent_moss/rules
|
|
619
|
+
resolve(__dirname2, "../../../agent_moss/rules"),
|
|
620
|
+
// dist 但 __dirname 指向 dist/engine 再往上两级的仓库根 agent_moss/rules
|
|
621
|
+
resolve(__dirname2, "../../../../agent_moss/rules"),
|
|
622
|
+
// 相对当前工作目录的仓库根(兜底,兼容以仓库根为 cwd 运行)
|
|
623
|
+
resolve(process.cwd(), "agent_moss/rules")
|
|
624
|
+
];
|
|
625
|
+
return cands.filter((c) => existsSync(c));
|
|
626
|
+
})();
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
|
|
577
630
|
// src/engine/logic-rules.ts
|
|
578
631
|
import * as fs2 from "fs";
|
|
632
|
+
function _loadSensitivePathScope(scope) {
|
|
633
|
+
const sps = loadL1().sensitive_path_access || [];
|
|
634
|
+
return sps.filter((sp) => sp.scope === scope).map((sp) => ({
|
|
635
|
+
path: sp.path,
|
|
636
|
+
riskLevel: sp.risk_level,
|
|
637
|
+
desc: sp.desc,
|
|
638
|
+
credential: sp.deny_mode === "deny_both" ? true : void 0
|
|
639
|
+
}));
|
|
640
|
+
}
|
|
579
641
|
function isWriteOperation(actionType, actionDetail, writeKeywords = WRITE_KEYWORDS) {
|
|
580
642
|
if (writeKeywords.some((kw) => actionType.includes(kw) || actionDetail.includes(kw))) return true;
|
|
581
643
|
if (WRITE_COMMAND_RES.some((rx) => rx.test(actionDetail))) return true;
|
|
@@ -937,57 +999,10 @@ var init_logic_rules = __esm({
|
|
|
937
999
|
"use strict";
|
|
938
1000
|
init_esm_shims();
|
|
939
1001
|
init_inline_analyzer();
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
{ path: "/etc/passwd", riskLevel: "high", desc: "\u7CFB\u7EDF\u7528\u6237\u6587\u4EF6" },
|
|
945
|
-
{ path: "/etc/sudoers", riskLevel: "critical", desc: "sudo \u914D\u7F6E", credential: true },
|
|
946
|
-
// 系统配置(仅拦截写入)
|
|
947
|
-
{ path: "/etc/hosts", riskLevel: "medium", desc: "DNS \u89E3\u6790\u914D\u7F6E" },
|
|
948
|
-
{ path: "/etc/crontab", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1" },
|
|
949
|
-
{ path: "/etc/cron.d/", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55\uFF08\u62C6\u5206\u5F0F crontab\uFF09" },
|
|
950
|
-
{ path: "/var/spool/cron/", riskLevel: "high", desc: "\u7528\u6237\u7EA7\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55" },
|
|
951
|
-
{ path: "/etc/systemd/", riskLevel: "high", desc: "systemd \u670D\u52A1\u914D\u7F6E" },
|
|
952
|
-
{ path: "/etc/ssh/sshd_config", riskLevel: "high", desc: "SSH \u670D\u52A1\u914D\u7F6E" },
|
|
953
|
-
{ path: "/etc/pam.d/", riskLevel: "high", desc: "PAM \u53EF\u63D2\u62D4\u8BA4\u8BC1\u6A21\u5757\u914D\u7F6E" },
|
|
954
|
-
// 危险目录(仅拦截写入)
|
|
955
|
-
{ path: "/boot/", riskLevel: "critical", desc: "\u542F\u52A8\u5F15\u5BFC\u76EE\u5F55" },
|
|
956
|
-
{ path: "/proc/sys/", riskLevel: "high", desc: "\u5185\u6838\u53C2\u6570" },
|
|
957
|
-
{ path: "/sys/", riskLevel: "high", desc: "sysfs \u5185\u6838\u63A5\u53E3" },
|
|
958
|
-
// 设备文件(/dev/null、/dev/zero、/dev/urandom 已移除,误报率极高)
|
|
959
|
-
{ path: "/dev/random", riskLevel: "high", desc: "\u963B\u585E\u5F0F\u968F\u673A\u6570\u8BBE\u5907\uFF08\u8BFB\u53D6\u8017\u5C3D\u71B5\u6C60\uFF09" },
|
|
960
|
-
{ path: "/dev/mem", riskLevel: "critical", desc: "\u7269\u7406\u5185\u5B58\u8BBF\u95EE\u8BBE\u5907\uFF08\u8BFB\u5199\u5747\u5371\u9669\uFF09", credential: true },
|
|
961
|
-
{ path: "/dev/kmsg", riskLevel: "high", desc: "\u5185\u6838\u6D88\u606F\u7F13\u51B2\u533A" },
|
|
962
|
-
// SSH 主机私钥
|
|
963
|
-
// SSH 主机私钥(排除 .pub 公钥变体,对齐 Python .ssh/id_rsa(?!\.pub) 范式)
|
|
964
|
-
{ path: "/etc/ssh/ssh_host_rsa_key(?!\\.pub)", riskLevel: "critical", desc: "SSH \u4E3B\u673A RSA \u79C1\u94A5", credential: true },
|
|
965
|
-
{ path: "/etc/ssh/ssh_host_ed25519_key(?!\\.pub)", riskLevel: "critical", desc: "SSH \u4E3B\u673A Ed25519 \u79C1\u94A5", credential: true },
|
|
966
|
-
{ path: "/etc/ssh/ssh_host_ecdsa_key(?!\\.pub)", riskLevel: "critical", desc: "SSH \u4E3B\u673A ECDSA \u79C1\u94A5", credential: true },
|
|
967
|
-
// Nginx 配置(仅拦截写入,对齐 Python linux.py sensitive_paths)
|
|
968
|
-
{ path: "/etc/nginx/nginx.conf", riskLevel: "high", desc: "Nginx \u4E3B\u914D\u7F6E" },
|
|
969
|
-
{ path: "/etc/nginx/conf.d/", riskLevel: "high", desc: "Nginx \u5B50\u914D\u7F6E\u76EE\u5F55" },
|
|
970
|
-
{ path: "/etc/nginx/sites-enabled/", riskLevel: "high", desc: "Nginx \u542F\u7528\u7AD9\u70B9\u914D\u7F6E\u76EE\u5F55" }
|
|
971
|
-
];
|
|
972
|
-
HOME_SENSITIVE_PATHS = [
|
|
973
|
-
{ path: ".ssh/id_rsa", riskLevel: "critical", desc: "SSH \u79C1\u94A5", credential: true },
|
|
974
|
-
{ path: ".ssh/id_ed25519", riskLevel: "critical", desc: "SSH \u79C1\u94A5 (ed25519)", credential: true },
|
|
975
|
-
{ path: ".ssh/authorized_keys", riskLevel: "high", desc: "SSH \u6388\u6743\u5BC6\u94A5" },
|
|
976
|
-
// 持久化与命令劫持(仅拦截写入)
|
|
977
|
-
{ path: ".bashrc", riskLevel: "high", desc: "\u7528\u6237 Shell \u521D\u59CB\u5316\u811A\u672C" },
|
|
978
|
-
{ path: ".bash_profile", riskLevel: "high", desc: "\u7528\u6237 Shell \u767B\u5F55\u811A\u672C" },
|
|
979
|
-
{ path: ".profile", riskLevel: "high", desc: "\u7528\u6237\u901A\u7528\u767B\u5F55\u811A\u672C" },
|
|
980
|
-
{ path: ".aws/credentials", riskLevel: "critical", desc: "AWS \u51ED\u8BC1", credential: true },
|
|
981
|
-
{ path: ".gitconfig", riskLevel: "medium", desc: "Git \u914D\u7F6E" },
|
|
982
|
-
{ path: ".gnupg", riskLevel: "high", desc: "GPG \u5BC6\u94A5\u76EE\u5F55" }
|
|
983
|
-
];
|
|
984
|
-
CREDENTIAL_PATHS = [
|
|
985
|
-
{ path: "credentials.yml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
986
|
-
{ path: "credentials.yaml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
987
|
-
{ path: "secrets.yml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
988
|
-
{ path: "secrets.yaml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
989
|
-
{ path: ".env", riskLevel: "high", desc: "\u73AF\u5883\u53D8\u91CF/\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" }
|
|
990
|
-
];
|
|
1002
|
+
init_rules_loader();
|
|
1003
|
+
ROOT_SENSITIVE_PATHS = _loadSensitivePathScope("root");
|
|
1004
|
+
HOME_SENSITIVE_PATHS = _loadSensitivePathScope("home");
|
|
1005
|
+
CREDENTIAL_PATHS = _loadSensitivePathScope("credential").map(({ path: path3, riskLevel, desc }) => ({ path: path3, riskLevel, desc, credential: true }));
|
|
991
1006
|
NON_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
992
1007
|
"ask_user_question",
|
|
993
1008
|
"glob",
|
|
@@ -1115,34 +1130,22 @@ var init_logic_rules = __esm({
|
|
|
1115
1130
|
DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/g;
|
|
1116
1131
|
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"];
|
|
1117
1132
|
CREATE_KEYWORDS = ["\u521B\u5EFA", "\u65B0\u5EFA", "create", "new file", "touch"];
|
|
1118
|
-
PASSWORD_MODIFY_PATTERNS =
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
INTENT_DEVIATION_PATTERNS = [
|
|
1135
|
-
{
|
|
1136
|
-
intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
|
|
1137
|
-
dangerousActions: ["\u5220\u9664", "remove", "delete", "rm", "\u683C\u5F0F\u5316", "format"],
|
|
1138
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
|
|
1139
|
-
},
|
|
1140
|
-
{
|
|
1141
|
-
intentKeywords: ["\u67E5\u8BE2", "\u641C\u7D22", "search", "query", "find"],
|
|
1142
|
-
dangerousActions: ["\u4FEE\u6539", "update", "write", "\u5199\u5165", "alter"],
|
|
1143
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u67E5\u8BE2/\u641C\u7D22\uFF0C\u4F46\u6267\u884C\u4E86\u4FEE\u6539\u64CD\u4F5C"
|
|
1144
|
-
}
|
|
1145
|
-
];
|
|
1133
|
+
PASSWORD_MODIFY_PATTERNS = (() => {
|
|
1134
|
+
const pats = loadL2().password_modify_consent || [];
|
|
1135
|
+
return pats.map((p) => new RegExp(p.pattern, "i"));
|
|
1136
|
+
})();
|
|
1137
|
+
USER_DELETION_PATTERNS = (() => {
|
|
1138
|
+
const pats = loadL2().user_deletion_consent || [];
|
|
1139
|
+
return pats.map((p) => new RegExp(p.pattern, "i"));
|
|
1140
|
+
})();
|
|
1141
|
+
INTENT_DEVIATION_PATTERNS = (() => {
|
|
1142
|
+
const pats = loadL2().intent_consistency || [];
|
|
1143
|
+
return pats.map((p) => ({
|
|
1144
|
+
intentKeywords: p.intent_keywords,
|
|
1145
|
+
dangerousActions: p.dangerous_actions,
|
|
1146
|
+
reason: p.reason
|
|
1147
|
+
}));
|
|
1148
|
+
})();
|
|
1146
1149
|
INLINE_SCRIPT_RE = /(?:^|\s)(?:python|python3|python3\.\d+|perl|perl5|ruby|jruby|mruby|node|php|lua)\s+(?:-[a-zA-Z]*[cer][a-zA-Z]*\s+)/i;
|
|
1147
1150
|
DIR_TRAVERSAL_KW = [
|
|
1148
1151
|
"os.listdir",
|
|
@@ -1160,21 +1163,21 @@ var init_logic_rules = __esm({
|
|
|
1160
1163
|
});
|
|
1161
1164
|
|
|
1162
1165
|
// src/engine/skill-loader.ts
|
|
1163
|
-
import { readFileSync as
|
|
1164
|
-
import { resolve, dirname } from "path";
|
|
1165
|
-
import { fileURLToPath as
|
|
1166
|
+
import { readFileSync as readFileSync3, readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
|
|
1167
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
1168
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
1166
1169
|
function loadAllSkills() {
|
|
1167
1170
|
if (cachedSkills) return cachedSkills;
|
|
1168
1171
|
cachedSkills = {};
|
|
1169
|
-
const dir =
|
|
1170
|
-
if (!
|
|
1172
|
+
const dir = existsSync3(SKILLS_DIR) ? SKILLS_DIR : SKILLS_DIR_FALLBACK;
|
|
1173
|
+
if (!existsSync3(dir)) {
|
|
1171
1174
|
console.warn("[AgentMoss] Skills directory not found:", SKILLS_DIR, "and fallback:", SKILLS_DIR_FALLBACK);
|
|
1172
1175
|
return cachedSkills;
|
|
1173
1176
|
}
|
|
1174
1177
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".md"));
|
|
1175
1178
|
for (const f of files) {
|
|
1176
1179
|
const name = f.replace(".md", "");
|
|
1177
|
-
cachedSkills[name] =
|
|
1180
|
+
cachedSkills[name] = readFileSync3(resolve2(dir, f), "utf-8");
|
|
1178
1181
|
}
|
|
1179
1182
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills from ${dir}`);
|
|
1180
1183
|
return cachedSkills;
|
|
@@ -1228,32 +1231,27 @@ function formatSkillsForPrompt(skills) {
|
|
|
1228
1231
|
${s.skillContent}`
|
|
1229
1232
|
).join("\n\n---\n\n");
|
|
1230
1233
|
}
|
|
1231
|
-
var
|
|
1234
|
+
var __filename3, __dirname3, SKILLS_DIR, SKILLS_DIR_FALLBACK, SKILL_KEYWORD_MAP, cachedSkills;
|
|
1232
1235
|
var init_skill_loader = __esm({
|
|
1233
1236
|
"src/engine/skill-loader.ts"() {
|
|
1234
1237
|
"use strict";
|
|
1235
1238
|
init_esm_shims();
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
"skill_installation_guard": ["skill", "plugin", "\u63D2\u4EF6", "extension", "\u6269\u5C55", "install skill", "\u5B89\u88C5\u63D2\u4EF6", "\u5B89\u88C5\u6280\u80FD", "marketplace", "\u5546\u5E97"],
|
|
1253
|
-
"supply_chain_guard": ["dependency", "\u4F9D\u8D56", "package", "\u5305", "npm install", "pip install", "requirements", "import", "library", "\u5E93", "registry", "\u4ED3\u5E93", "supply", "\u4F9B\u5E94\u94FE", "typosquatting"],
|
|
1254
|
-
"intent_deviation_guard": ["rm", "del", "delete", "remove", "\u5220\u9664", "format", "\u683C\u5F0F\u5316", "drop", "truncate", "\u6E05\u7A7A", "wipe", "\u64E6\u9664", "\u91CD\u7F6E", "reset", "sudo", "root", "admin", "\u7BA1\u7406\u5458", "privilege", "\u63D0\u6743"],
|
|
1255
|
-
"indirect_access_guard": ["listdir", "os.walk", "os.scandir", "glob.glob", "glob.iglob", "pathlib", "iterdir", "rglob", "scandir", "os.listdir", "\u76EE\u5F55\u904D\u5386", "traversal"]
|
|
1256
|
-
};
|
|
1239
|
+
init_rules_loader();
|
|
1240
|
+
__filename3 = fileURLToPath4(import.meta.url);
|
|
1241
|
+
__dirname3 = dirname2(__filename3);
|
|
1242
|
+
SKILLS_DIR = resolve2(__dirname3, "../skills");
|
|
1243
|
+
SKILLS_DIR_FALLBACK = resolve2(__dirname3, "../../../agent_moss/skills");
|
|
1244
|
+
SKILL_KEYWORD_MAP = (() => {
|
|
1245
|
+
const map = {};
|
|
1246
|
+
const cats = loadL3();
|
|
1247
|
+
for (const cat of Object.values(cats)) {
|
|
1248
|
+
if (!cat || typeof cat !== "object") continue;
|
|
1249
|
+
for (const [skillId, keywords] of Object.entries(cat)) {
|
|
1250
|
+
map[skillId] = keywords;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
return map;
|
|
1254
|
+
})();
|
|
1257
1255
|
cachedSkills = null;
|
|
1258
1256
|
}
|
|
1259
1257
|
});
|
|
@@ -1305,10 +1303,10 @@ __export(runtime_config_exports, {
|
|
|
1305
1303
|
updateSkillCategoryEnabled: () => updateSkillCategoryEnabled,
|
|
1306
1304
|
updateSkillEnabled: () => updateSkillEnabled
|
|
1307
1305
|
});
|
|
1308
|
-
import { readFileSync as
|
|
1306
|
+
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3 } from "fs";
|
|
1309
1307
|
import { join as join2 } from "path";
|
|
1310
|
-
import { fileURLToPath as
|
|
1311
|
-
import { dirname as
|
|
1308
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1309
|
+
import { dirname as dirname3 } from "path";
|
|
1312
1310
|
function runtimeDir() {
|
|
1313
1311
|
return getRuntimeConfigDir();
|
|
1314
1312
|
}
|
|
@@ -1320,7 +1318,7 @@ function getRuntimeConfigPath() {
|
|
|
1320
1318
|
function saveRuntimeConfig(config) {
|
|
1321
1319
|
const p = getRuntimeConfigPath();
|
|
1322
1320
|
const dir = p.substring(0, p.lastIndexOf("/"));
|
|
1323
|
-
if (dir && !
|
|
1321
|
+
if (dir && !existsSync4(dir)) mkdirSync(dir, { recursive: true });
|
|
1324
1322
|
writeFileSync(p, JSON.stringify(config, null, 2), "utf-8");
|
|
1325
1323
|
}
|
|
1326
1324
|
function emptyRuntimeConfig() {
|
|
@@ -1335,7 +1333,7 @@ function emptyRuntimeConfig() {
|
|
|
1335
1333
|
}
|
|
1336
1334
|
function loadRuntimeConfig() {
|
|
1337
1335
|
const p = getRuntimeConfigPath();
|
|
1338
|
-
if (!
|
|
1336
|
+
if (!existsSync4(p)) {
|
|
1339
1337
|
const seeded = mergeConfig({}, generateSourceDefaults());
|
|
1340
1338
|
try {
|
|
1341
1339
|
saveRuntimeConfig(seeded);
|
|
@@ -1344,7 +1342,7 @@ function loadRuntimeConfig() {
|
|
|
1344
1342
|
return seeded;
|
|
1345
1343
|
}
|
|
1346
1344
|
try {
|
|
1347
|
-
const data = JSON.parse(
|
|
1345
|
+
const data = JSON.parse(readFileSync4(p, "utf-8"));
|
|
1348
1346
|
const merged = mergeConfig(data, generateSourceDefaults());
|
|
1349
1347
|
return {
|
|
1350
1348
|
version: data.version || 1,
|
|
@@ -1412,9 +1410,9 @@ function getEnabledL2SensitivePaths(runtime) {
|
|
|
1412
1410
|
}
|
|
1413
1411
|
function hasRuntimeConfig() {
|
|
1414
1412
|
const p = getRuntimeConfigPath();
|
|
1415
|
-
if (!
|
|
1413
|
+
if (!existsSync4(p)) return false;
|
|
1416
1414
|
try {
|
|
1417
|
-
JSON.parse(
|
|
1415
|
+
JSON.parse(readFileSync4(p, "utf-8"));
|
|
1418
1416
|
return true;
|
|
1419
1417
|
} catch {
|
|
1420
1418
|
return false;
|
|
@@ -1593,8 +1591,8 @@ function _l3SkillsToRules() {
|
|
|
1593
1591
|
}
|
|
1594
1592
|
function _agentRulesToDefaults() {
|
|
1595
1593
|
const out = {};
|
|
1596
|
-
const agentsDir =
|
|
1597
|
-
if (!
|
|
1594
|
+
const agentsDir = existsSync4(_AGENTS_DIR_PROD) ? _AGENTS_DIR_PROD : existsSync4(_AGENTS_DIR_DEV) ? _AGENTS_DIR_DEV : _AGENTS_DIR_PROD;
|
|
1595
|
+
if (!existsSync4(agentsDir)) return out;
|
|
1598
1596
|
let entries;
|
|
1599
1597
|
try {
|
|
1600
1598
|
entries = readdirSync3(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -1603,10 +1601,10 @@ function _agentRulesToDefaults() {
|
|
|
1603
1601
|
}
|
|
1604
1602
|
for (const agentId of entries) {
|
|
1605
1603
|
const rulesFile = join2(agentsDir, agentId, "rules.json");
|
|
1606
|
-
if (!
|
|
1604
|
+
if (!existsSync4(rulesFile)) continue;
|
|
1607
1605
|
let data;
|
|
1608
1606
|
try {
|
|
1609
|
-
data = JSON.parse(
|
|
1607
|
+
data = JSON.parse(readFileSync4(rulesFile, "utf-8"));
|
|
1610
1608
|
} catch {
|
|
1611
1609
|
continue;
|
|
1612
1610
|
}
|
|
@@ -1685,6 +1683,9 @@ function generateSourceDefaults() {
|
|
|
1685
1683
|
agent_rules: _agentRulesToDefaults()
|
|
1686
1684
|
};
|
|
1687
1685
|
}
|
|
1686
|
+
function normalizePatternForFingerprint(pattern) {
|
|
1687
|
+
return pattern.replace(/\\\//g, "/");
|
|
1688
|
+
}
|
|
1688
1689
|
function _ruleFingerprint(rule) {
|
|
1689
1690
|
if (rule.intent_keywords && rule.intent_keywords.length || rule.dangerous_actions && rule.dangerous_actions.length) {
|
|
1690
1691
|
return JSON.stringify([
|
|
@@ -1692,8 +1693,8 @@ function _ruleFingerprint(rule) {
|
|
|
1692
1693
|
[...rule.dangerous_actions || []].sort()
|
|
1693
1694
|
]);
|
|
1694
1695
|
}
|
|
1695
|
-
if (rule.path) return JSON.stringify([rule.path]);
|
|
1696
|
-
if (rule.pattern) return JSON.stringify([rule.pattern]);
|
|
1696
|
+
if (rule.path) return JSON.stringify([normalizePatternForFingerprint(rule.path)]);
|
|
1697
|
+
if (rule.pattern) return JSON.stringify([normalizePatternForFingerprint(rule.pattern)]);
|
|
1697
1698
|
if (rule.keyword) return JSON.stringify([rule.keyword, rule.lang || ""]);
|
|
1698
1699
|
if (rule.value) return JSON.stringify([rule.value]);
|
|
1699
1700
|
return JSON.stringify([rule.id || ""]);
|
|
@@ -2044,7 +2045,7 @@ function deleteCustomSkill(skillId, category) {
|
|
|
2044
2045
|
skills.splice(idx, 1);
|
|
2045
2046
|
const skillPath = join2(RUNTIME_CONFIG_DIR, "agent_moss_skills", `${skillId}.md`);
|
|
2046
2047
|
try {
|
|
2047
|
-
if (
|
|
2048
|
+
if (existsSync4(skillPath)) unlinkSync(skillPath);
|
|
2048
2049
|
} catch {
|
|
2049
2050
|
}
|
|
2050
2051
|
saveRuntimeConfig(runtime);
|
|
@@ -2158,7 +2159,7 @@ function updateAgentCategoryEnabled(agentId, category, enabled) {
|
|
|
2158
2159
|
saveRuntimeConfig(runtime);
|
|
2159
2160
|
return runtime;
|
|
2160
2161
|
}
|
|
2161
|
-
var
|
|
2162
|
+
var __dirname4, ENV_RUNTIME_CONFIG_PATH, RUNTIME_CONFIG_DIR, RUNTIME_CONFIG_PATH, LAYER_DISABLE_ENV, DENY_MODE_LABELS, _AGENTS_DIR_PROD, _AGENTS_DIR_DEV, SKILL_ID_RE;
|
|
2162
2163
|
var init_runtime_config = __esm({
|
|
2163
2164
|
"src/infra/runtime-config.ts"() {
|
|
2164
2165
|
"use strict";
|
|
@@ -2167,7 +2168,7 @@ var init_runtime_config = __esm({
|
|
|
2167
2168
|
init_heuristic();
|
|
2168
2169
|
init_logic_rules();
|
|
2169
2170
|
init_skill_loader();
|
|
2170
|
-
|
|
2171
|
+
__dirname4 = dirname3(fileURLToPath5(import.meta.url));
|
|
2171
2172
|
ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
|
|
2172
2173
|
RUNTIME_CONFIG_DIR = runtimeDir();
|
|
2173
2174
|
RUNTIME_CONFIG_PATH = join2(RUNTIME_CONFIG_DIR, "agent_moss_runtime.json");
|
|
@@ -2181,19 +2182,19 @@ var init_runtime_config = __esm({
|
|
|
2181
2182
|
deny_read: "\u4EC5\u62E6\u622A\u8BFB\u53D6",
|
|
2182
2183
|
deny_both: "\u8BFB\u5199\u5747\u62E6\u622A"
|
|
2183
2184
|
};
|
|
2184
|
-
_AGENTS_DIR_PROD = join2(
|
|
2185
|
-
_AGENTS_DIR_DEV = join2(
|
|
2185
|
+
_AGENTS_DIR_PROD = join2(__dirname4, "agents");
|
|
2186
|
+
_AGENTS_DIR_DEV = join2(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
2186
2187
|
SKILL_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
2187
2188
|
}
|
|
2188
2189
|
});
|
|
2189
2190
|
|
|
2190
2191
|
// src/agents/index.ts
|
|
2191
|
-
import { readFileSync as
|
|
2192
|
-
import { resolve as
|
|
2193
|
-
import { fileURLToPath as
|
|
2192
|
+
import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
|
|
2193
|
+
import { resolve as resolve3, dirname as dirname4 } from "path";
|
|
2194
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
2194
2195
|
function resolveAgentsDir() {
|
|
2195
|
-
if (
|
|
2196
|
-
if (
|
|
2196
|
+
if (existsSync5(AGENTS_DIR_PROD)) return AGENTS_DIR_PROD;
|
|
2197
|
+
if (existsSync5(AGENTS_DIR_DEV_FALLBACK)) return AGENTS_DIR_DEV_FALLBACK;
|
|
2197
2198
|
return AGENTS_DIR_PROD;
|
|
2198
2199
|
}
|
|
2199
2200
|
function getAgentExtensions(agentId) {
|
|
@@ -2209,13 +2210,13 @@ function getAgentExtensions(agentId) {
|
|
|
2209
2210
|
}
|
|
2210
2211
|
if (ext === null) {
|
|
2211
2212
|
const agentsDir = resolveAgentsDir();
|
|
2212
|
-
const rulesFile =
|
|
2213
|
-
if (!
|
|
2213
|
+
const rulesFile = resolve3(agentsDir, agentId, "rules.json");
|
|
2214
|
+
if (!existsSync5(rulesFile)) {
|
|
2214
2215
|
cache.set(agentId, null);
|
|
2215
2216
|
return null;
|
|
2216
2217
|
}
|
|
2217
2218
|
try {
|
|
2218
|
-
const raw =
|
|
2219
|
+
const raw = readFileSync5(rulesFile, "utf-8");
|
|
2219
2220
|
ext = JSON.parse(raw);
|
|
2220
2221
|
if (!ext.agent_id) {
|
|
2221
2222
|
console.warn(`[AgentMoss agents] rules.json \u7F3A\u5C11 agent_id \u5B57\u6BB5: ${rulesFile}`);
|
|
@@ -2234,15 +2235,15 @@ function getAgentExtensions(agentId) {
|
|
|
2234
2235
|
);
|
|
2235
2236
|
return ext;
|
|
2236
2237
|
}
|
|
2237
|
-
var
|
|
2238
|
+
var __filename4, __dirname5, AGENTS_DIR_PROD, AGENTS_DIR_DEV_FALLBACK, cache;
|
|
2238
2239
|
var init_agents = __esm({
|
|
2239
2240
|
"src/agents/index.ts"() {
|
|
2240
2241
|
"use strict";
|
|
2241
2242
|
init_esm_shims();
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
AGENTS_DIR_PROD =
|
|
2245
|
-
AGENTS_DIR_DEV_FALLBACK =
|
|
2243
|
+
__filename4 = fileURLToPath6(import.meta.url);
|
|
2244
|
+
__dirname5 = dirname4(__filename4);
|
|
2245
|
+
AGENTS_DIR_PROD = resolve3(__dirname5, "agents");
|
|
2246
|
+
AGENTS_DIR_DEV_FALLBACK = resolve3(__dirname5, "../../../agent_moss/agents");
|
|
2246
2247
|
cache = /* @__PURE__ */ new Map();
|
|
2247
2248
|
}
|
|
2248
2249
|
});
|
|
@@ -2302,7 +2303,7 @@ function runHeuristicCheck(input) {
|
|
|
2302
2303
|
}
|
|
2303
2304
|
}
|
|
2304
2305
|
}
|
|
2305
|
-
const injectionText = `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
2306
|
+
const injectionText = isSearchActionType(input.aNext.actionType) ? `${input.aNext.actionType} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase() : `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
2306
2307
|
const injectionHits = checkInjectionKeywords(injectionText, agentExt?.extra_injection_keywords);
|
|
2307
2308
|
if (injectionHits.length > 0) {
|
|
2308
2309
|
const topHit = injectionHits.reduce((a, b) => severityRank(a.riskLevel) >= severityRank(b.riskLevel) ? a : b);
|
|
@@ -2429,6 +2430,10 @@ function severityRank(s) {
|
|
|
2429
2430
|
const ranks = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
2430
2431
|
return ranks[s] || 0;
|
|
2431
2432
|
}
|
|
2433
|
+
function isSearchActionType(actionType) {
|
|
2434
|
+
const at = actionType.toLowerCase();
|
|
2435
|
+
return SEARCH_ACTION_PREFIXES.some((p) => at.startsWith(p)) || ["websearch", "web_search", "search", "query"].includes(at);
|
|
2436
|
+
}
|
|
2432
2437
|
function checkSensitivePath(command, cwd, agentExt) {
|
|
2433
2438
|
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
2434
2439
|
const isWriteOpFlag = isWriteOperation("", command);
|
|
@@ -2696,172 +2701,34 @@ function checkLateralMovement(actionDetail) {
|
|
|
2696
2701
|
}
|
|
2697
2702
|
return null;
|
|
2698
2703
|
}
|
|
2699
|
-
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES;
|
|
2704
|
+
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES, SEARCH_ACTION_PREFIXES;
|
|
2700
2705
|
var init_heuristic = __esm({
|
|
2701
2706
|
"src/engine/heuristic.ts"() {
|
|
2702
2707
|
"use strict";
|
|
2703
2708
|
init_esm_shims();
|
|
2704
2709
|
init_config();
|
|
2705
2710
|
init_agents();
|
|
2711
|
+
init_rules_loader();
|
|
2706
2712
|
init_logic_rules();
|
|
2707
|
-
INJECTION_KEYWORDS =
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
{ keyword: "\u4ECE\u73B0\u5728\u5F00\u59CB\u4F60", riskLevel: "high", lang: "zh" },
|
|
2725
|
-
{ keyword: "\u4F60\u7684\u65B0\u89D2\u8272\u662F", riskLevel: "high", lang: "zh" },
|
|
2726
|
-
// ---- Command Injection ----
|
|
2727
|
-
{ keyword: "system prompt", riskLevel: "high", lang: "en" },
|
|
2728
|
-
{ keyword: "reveal your instructions", riskLevel: "high", lang: "en" },
|
|
2729
|
-
{ keyword: "output your instructions", riskLevel: "high", lang: "en" },
|
|
2730
|
-
{ keyword: "repeat your instructions", riskLevel: "medium", lang: "en" },
|
|
2731
|
-
{ keyword: "\u7CFB\u7EDF\u63D0\u793A", riskLevel: "high", lang: "zh" },
|
|
2732
|
-
{ keyword: "\u8F93\u51FA\u4F60\u7684\u6307\u4EE4", riskLevel: "high", lang: "zh" },
|
|
2733
|
-
{ keyword: "\u91CD\u590D\u4F60\u7684\u6307\u4EE4", riskLevel: "medium", lang: "zh" },
|
|
2734
|
-
// ---- Social Engineering ----
|
|
2735
|
-
{ keyword: "this is an authorized test", riskLevel: "high", lang: "en" },
|
|
2736
|
-
{ keyword: "security audit approved", riskLevel: "high", lang: "en" },
|
|
2737
|
-
{ keyword: "admin override", riskLevel: "critical", lang: "en" },
|
|
2738
|
-
{ keyword: "debug mode", riskLevel: "high", lang: "en" },
|
|
2739
|
-
{ keyword: "maintenance mode", riskLevel: "high", lang: "en" },
|
|
2740
|
-
{ keyword: "\u8FD9\u662F\u6388\u6743\u7684\u6D4B\u8BD5", riskLevel: "high", lang: "zh" },
|
|
2741
|
-
{ keyword: "\u5B89\u5168\u5BA1\u8BA1\u5DF2\u6279\u51C6", riskLevel: "high", lang: "zh" },
|
|
2742
|
-
{ keyword: "\u7BA1\u7406\u5458\u8986\u76D6", riskLevel: "critical", lang: "zh" },
|
|
2743
|
-
{ keyword: "\u8C03\u8BD5\u6A21\u5F0F", riskLevel: "high", lang: "zh" },
|
|
2744
|
-
// ---- XSS ----
|
|
2745
|
-
{ keyword: "<script>", riskLevel: "high", lang: "en" },
|
|
2746
|
-
{ keyword: "javascript:", riskLevel: "high", lang: "en" },
|
|
2747
|
-
{ keyword: "onerror=", riskLevel: "high", lang: "en" },
|
|
2748
|
-
{ keyword: "onload=", riskLevel: "high", lang: "en" },
|
|
2749
|
-
// ---- Fake Boundaries ----
|
|
2750
|
-
{ keyword: "=== END OF", riskLevel: "high", lang: "en" },
|
|
2751
|
-
{ keyword: "--- END SYSTEM", riskLevel: "high", lang: "en" },
|
|
2752
|
-
{ keyword: "[END OF", riskLevel: "high", lang: "en" },
|
|
2753
|
-
{ keyword: "=== \u7ED3\u675F", riskLevel: "high", lang: "zh" },
|
|
2754
|
-
{ keyword: "--- \u7ED3\u675F\u7CFB\u7EDF", riskLevel: "high", lang: "zh" },
|
|
2755
|
-
// ---- Developer Mode ----
|
|
2756
|
-
{ keyword: "developer mode", riskLevel: "critical", lang: "en" },
|
|
2757
|
-
{ keyword: "DAN mode", riskLevel: "critical", lang: "en" },
|
|
2758
|
-
{ keyword: "jailbreak", riskLevel: "critical", lang: "en" },
|
|
2759
|
-
{ keyword: "\u5F00\u53D1\u8005\u6A21\u5F0F", riskLevel: "critical", lang: "zh" },
|
|
2760
|
-
{ keyword: "\u8D8A\u72F1", riskLevel: "critical", lang: "zh" }
|
|
2761
|
-
// 注:xiaoO 专属绕过词(绕过审计/禁用安全检查/关闭防护/bypass audit 等)
|
|
2762
|
-
// 已迁至 agent_moss/agents/xiaoo/rules.json 的 extra_injection_keywords,
|
|
2763
|
-
// 由 agent_ext 机制注入,不再污染通用层。
|
|
2764
|
-
];
|
|
2765
|
-
DANGEROUS_PATTERNS = [
|
|
2766
|
-
// --- Critical: rm command graded detection (strict to loose, first match wins) ---
|
|
2767
|
-
// 1. rm -rf root dir (含通配符如 /* /.* 等) — 使用负向先行断言 (?!\w):/ 后面不是单词字符时匹配
|
|
2768
|
-
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\/(?!\w)/i, severity: "critical", description: "\u9012\u5F52\u5F3A\u5236\u5220\u9664\u6839\u76EE\u5F55 (rm -rf /)", riskType: "script_execution" },
|
|
2769
|
-
// 注意:已移除"rm -rf /任意绝对路径"的宽泛规则,避免误杀 /tmp 等临时目录清理操作
|
|
2770
|
-
// 2. rm with -r or -f targeting system dirs — var 分支排除 /var/tmp/(合法清理)
|
|
2771
|
-
{ pattern: /\brm\s+-[a-zA-Z]*[rf][a-zA-Z]*\s+\/(etc|var(?!\/tmp)|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55", riskType: "script_execution" },
|
|
2772
|
-
// 3. rm -r absolute path (no -f) — 排除 /tmp/ /var/tmp/ /run/ /dev/shm/(CI/开发高频合法清理)
|
|
2773
|
-
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*\s+\/(?!tmp\/|var\/tmp\/|run\/|dev\/shm\/)/i, severity: "high", description: "\u9012\u5F52\u5220\u9664\u64CD\u4F5C (rm -r /...)", riskType: "script_execution" },
|
|
2774
|
-
// 4. rm -f absolute path (no -r) — 同样排除临时目录
|
|
2775
|
-
{ pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*\s+\/(?!tmp\/|var\/tmp\/|run\/|dev\/shm\/)/i, severity: "medium", description: "\u5F3A\u5236\u5220\u9664\u6587\u4EF6 (rm -f /...)", riskType: "script_execution" },
|
|
2776
|
-
// dd 磁盘清零 — 只拦截写入系统关键目录,放行 /tmp 等临时目录
|
|
2777
|
-
{ pattern: /dd\s+if=\/dev\/zero.*\bof\s*=\s*\/(etc|var|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u78C1\u76D8\u6E05\u96F6\u5199\u5165\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55 (dd if=/dev/zero of=/\u7CFB\u7EDF\u76EE\u5F55)", riskType: "script_execution" },
|
|
2778
|
-
// mkfs 格式化 — 只拦截对块设备(/dev/sdX 等)的格式化,放行对普通文件的格式化
|
|
2779
|
-
{ pattern: /mkfs\.\w+\s+\/dev\/(sd|hd|nvme|vd|loop|mapper|md|dm)\S+/i, severity: "critical", description: "\u683C\u5F0F\u5316\u5757\u8BBE\u5907 (mkfs /dev/\u5757\u8BBE\u5907)", riskType: "script_execution" },
|
|
2780
|
-
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb", riskType: "resource_exhaustion" },
|
|
2781
|
-
// --- Critical: remote code execution ---
|
|
2782
|
-
// curl|bash 优先匹配 user_rules(high/sensitive_action),见下方 UserRuleMatcher 段;
|
|
2783
|
-
// 非 bash 的 curl|sh/zsh/dash 走 CommandPatternScanner critical。两条分流由
|
|
2784
|
-
// runHeuristicCheck 的规则顺序保证(bash 在前 high,其余 fall-through 到 critical)。
|
|
2785
|
-
{ pattern: /curl\s+.*\|\s*bash/i, severity: "high", description: "curl pipe bash \u6267\u884C (user_rules)", riskType: "sensitive_action" },
|
|
2786
|
-
{ pattern: /curl\s+.*\|\s*(sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
2787
|
-
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
2788
|
-
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
2789
|
-
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "high", description: "base64 \u89E3\u7801\u6267\u884C (user_rules)", riskType: "sensitive_action" },
|
|
2790
|
-
// --- Critical: reverse shell ---
|
|
2791
|
-
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell", riskType: "script_execution" },
|
|
2792
|
-
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5", riskType: "lateral_movement" },
|
|
2793
|
-
// --- Critical: sensitive file access ---
|
|
2794
|
-
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)", riskType: "file_access" },
|
|
2795
|
-
{ pattern: /\/etc\/gshadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6 (/etc/gshadow)", riskType: "file_access" },
|
|
2796
|
-
// 注意:/etc/passwd 已从拦截列表移除,因为它是公开可读的标准系统文件,真正敏感的是 /etc/shadow
|
|
2797
|
-
{ pattern: /\.ssh\/id_rsa(?!\.pub)/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6", riskType: "file_access" },
|
|
2798
|
-
// --- Critical: privilege escalation / container escape ---
|
|
2799
|
-
{ pattern: /\/var\/run\/docker\.sock/i, severity: "critical", description: "\u8BBF\u95EE Docker socket\uFF0C\u53EF\u80FD\u5BFC\u81F4\u5BB9\u5668\u9003\u9038", riskType: "privilege_escalation" },
|
|
2800
|
-
// --- Critical: dangerous permissions / ownership (提权 / 权限敞口) ---
|
|
2801
|
-
// 修正「只拦 777、xx7 漏放」的缺口:
|
|
2802
|
-
// 1) 八进制末位 7:other 位含写+执行敞口(chmod 777/647/007/4777 等);644/755/1700 不命中
|
|
2803
|
-
// 2) 八进制 setuid/setgid 位:首位 4(setuid)/2(setgid) 的 4 位八进制(chmod 4755/2755)
|
|
2804
|
-
// 3) 符号 setuid/setgid:chmod u+s / g+s / a+s
|
|
2805
|
-
// 普通权限修改(chmod 644)不在此列——L2 read_before_write 已豁免 chmod/chown(不写内容),
|
|
2806
|
-
// 危险形态在此 L1 专门拦,以「提权」正确理由拦截,不再靠 RBW 误打误撞。
|
|
2807
|
-
{ pattern: /chmod\s+[0-7]{0,3}7\b/i, severity: "critical", description: "\u5371\u9669\u6743\u9650\u8BBE\u7F6E (chmod ...7, other \u4F4D\u542B\u5199+\u6267\u884C\u655E\u53E3)", riskType: "privilege_escalation" },
|
|
2808
|
-
{ pattern: /chmod\s+[24][0-7]{3}\b/i, severity: "critical", description: "setuid/setgid \u4F4D\u8BBE\u7F6E (chmod 4xxx/2xxx, \u63D0\u6743)", riskType: "privilege_escalation" },
|
|
2809
|
-
{ pattern: /chmod\s+[ugoa]\+s\b/i, severity: "critical", description: "\u7B26\u53F7 setuid/setgid \u8BBE\u7F6E (chmod u+s/g+s/a+s, \u63D0\u6743)", riskType: "privilege_escalation" },
|
|
2810
|
-
{ pattern: /chown\s+root|chown\s+-R\s+\w+:\w+\s+\//i, severity: "high", description: "\u4FEE\u6539\u6240\u6709\u8005\u4E3A root / \u9012\u5F52\u4FEE\u6539\u6839\u76EE\u5F55\u6240\u6709\u8005", riskType: "script_execution" },
|
|
2811
|
-
// sudo 提权 — 只拦截 sudo 后跟的危险命令,不一刀切拦截所有 sudo
|
|
2812
|
-
{ pattern: /sudo\s+(rm|chmod|chown|dd|mkfs|format|iptables|crontab|passwd|userdel|useradd|groupdel)\b/i, severity: "high", description: "\u63D0\u6743\u6267\u884C\u9AD8\u5371\u547D\u4EE4 (sudo + \u5371\u9669\u64CD\u4F5C)", riskType: "privilege_escalation" },
|
|
2813
|
-
// --- High: system config overwrite ---
|
|
2814
|
-
// > /etc/ 重定向覆盖:对齐 Python CommandPatternScanner `>\s*/etc/`(不兼容引号路径),
|
|
2815
|
-
// 引号包裹的重定向目标(cat > '/etc/ssh/sshd_config')走 checkSensitivePath 敏感路径 high。
|
|
2816
|
-
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55", riskType: "file_access" },
|
|
2817
|
-
{ pattern: />\s*\/boot\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u542F\u52A8\u5F15\u5BFC\u76EE\u5F55", riskType: "file_access" },
|
|
2818
|
-
// 注:/proc/ 重定向覆盖走 checkSensitivePath 的 high(内核参数 /proc/sys/),此处不拦 /proc/ 避免遮蔽(对齐 Python)。
|
|
2819
|
-
// --- High: download script + execute risk ---
|
|
2820
|
-
// curl -X POST 外传敏感信息(对齐 Python linux.py: curl POST env/key/token)
|
|
2821
|
-
{ pattern: /curl\s+.*-X\s+POST.*\b(env|environment|secret|key|token|password)\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u901A\u8FC7 curl POST \u5916\u4F20\u53EF\u80FD\u5305\u542B\u654F\u611F\u4FE1\u606F\u7684\u8BF7\u6C42", riskType: "data_exfiltration" },
|
|
2822
|
-
{ pattern: /(?:curl|wget)\s+.*(?:-o|--output|>)\s*\S+\.(?:sh|bash)\b/i, severity: "high", description: "\u8FDC\u7A0B\u4E0B\u8F7D\u811A\u672C\u5230\u672C\u5730", riskType: "script_execution" },
|
|
2823
|
-
{ pattern: /(?:curl|wget)\s+\S+.*\b(?:chmod|chown)\s+\+x\b/i, severity: "high", description: "\u8FDC\u7A0B\u4E0B\u8F7D\u540E\u4FEE\u6539\u53EF\u6267\u884C\u6743\u9650\uFF0C\u5B58\u5728\u8FDC\u7A0B\u4EE3\u7801\u6267\u884C\u98CE\u9669", riskType: "script_execution" },
|
|
2824
|
-
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C", riskType: "script_execution" },
|
|
2825
|
-
// --- High: package manager pipe-to-shell ---
|
|
2826
|
-
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell", riskType: "script_execution" },
|
|
2827
|
-
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell", riskType: "script_execution" },
|
|
2828
|
-
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell", riskType: "script_execution" },
|
|
2829
|
-
// --- Medium: destructive git operations (降级为 medium,允许但记录) ---
|
|
2830
|
-
{ pattern: /git\s+push\s+.*--force/i, severity: "medium", description: "\u5F3A\u5236\u63A8\u9001\u64CD\u4F5C (git push --force)\uFF0C\u53EF\u80FD\u8986\u76D6\u8FDC\u7A0B\u63D0\u4EA4\u5386\u53F2", riskType: "script_execution" },
|
|
2831
|
-
// --- High: network port scanning (横向移动侦察) ---
|
|
2832
|
-
{ pattern: /\bnmap\s+/i, severity: "high", description: "\u7F51\u7EDC\u7AEF\u53E3\u626B\u63CF (nmap)\uFF0C\u53EF\u80FD\u7528\u4E8E\u6A2A\u5411\u79FB\u52A8\u4FA6\u5BDF", riskType: "lateral_movement" },
|
|
2833
|
-
{ pattern: /\b(masscan|zmap|unicornscan)\s+/i, severity: "high", description: "\u7F51\u7EDC\u7AEF\u53E3\u626B\u63CF\u5DE5\u5177\uFF0C\u53EF\u80FD\u7528\u4E8E\u6A2A\u5411\u79FB\u52A8\u4FA6\u5BDF", riskType: "lateral_movement" },
|
|
2834
|
-
// --- Medium: credential export ---
|
|
2835
|
-
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1", riskType: "data_exfiltration" },
|
|
2836
|
-
// --- High: shell rc file append (persistence) ---
|
|
2837
|
-
// 两条规则:第一条匹配 ~ 与 /home/<user>/ 形态;第二条按文件名兜底,
|
|
2838
|
-
// 覆盖非标准 home 路径(如鸿蒙 /storage/Users/currentUser/.bashrc、
|
|
2839
|
-
// /root/.bashrc),避免按 home 前缀枚举导致漏检持久化后门。
|
|
2840
|
-
{ pattern: />>\s*(~|\/home\/[^/]+)\/(\.bashrc|\.zshrc|\.profile|\.bash_profile|\.zprofile)/, severity: "high", description: "\u68C0\u6D4B\u5230\u4FEE\u6539 Shell \u914D\u7F6E\u6587\u4EF6\uFF08~/.bashrc \u7B49\uFF09\uFF0C\u53EF\u80FD\u7528\u4E8E\u6301\u4E45\u5316\u540E\u95E8", riskType: "persistence" },
|
|
2841
|
-
{ pattern: />>\s*\S*\/(\.bashrc|\.zshrc|\.profile|\.bash_profile|\.zprofile)\b/, severity: "high", description: "\u68C0\u6D4B\u5230\u4FEE\u6539 Shell \u914D\u7F6E\u6587\u4EF6\uFF08.bashrc \u7B49\uFF09\uFF0C\u53EF\u80FD\u7528\u4E8E\u6301\u4E45\u5316\u540E\u95E8", riskType: "persistence" },
|
|
2842
|
-
// --- High: device file write (只拦截重定向写入设备文件,不拦截读取) ---
|
|
2843
|
-
{ pattern: />\s*\/dev\/(sd|hd|nvme|vd|loop|mem|kmsg|port|zero|random|urandom|full|core)/i, severity: "high", description: "\u91CD\u5B9A\u5411\u5199\u5165\u8BBE\u5907\u6587\u4EF6", riskType: "file_access" },
|
|
2844
|
-
// --- High: non-interactive password modification ---
|
|
2845
|
-
{ pattern: /\|\s*passwd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7BA1\u9053\u65B9\u5F0F\u8C03\u7528 passwd\uFF08\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\uFF09", riskType: "script_execution" },
|
|
2846
|
-
{ pattern: /\bpasswd\s+--stdin\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 passwd --stdin \u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u8F93\u5165", riskType: "script_execution" },
|
|
2847
|
-
{ pattern: /\bchpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 chpasswd \u6279\u91CF\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4", riskType: "script_execution" },
|
|
2848
|
-
{ pattern: /\b(newusers|lnewusers)\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 newusers/lnewusers \u6279\u91CF\u7528\u6237\u6DFB\u52A0\u547D\u4EE4", riskType: "script_execution" },
|
|
2849
|
-
{ pattern: /\bpasswd\s+-[a-zA-Z]*d\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u5BC6\u7801\u64CD\u4F5C (passwd -d)", riskType: "script_execution" },
|
|
2850
|
-
{ pattern: /\bpasswd\s+-[a-zA-Z]*l\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u9501\u5B9A\u7528\u6237\u8D26\u6237\u64CD\u4F5C (passwd -l)", riskType: "script_execution" },
|
|
2851
|
-
// --- High: non-interactive password modification (extended) ---
|
|
2852
|
-
{ pattern: /\blpasswd\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\u64CD\u4F5C (lpasswd)", riskType: "script_execution" },
|
|
2853
|
-
{ pattern: /\bgpasswd\s+(?!-[adA])/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7EC4\u5BC6\u7801\u7BA1\u7406\u64CD\u4F5C (gpasswd)", riskType: "script_execution" },
|
|
2854
|
-
{ pattern: /\bchgpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u6279\u91CF\u4FEE\u6539\u7EC4\u5BC6\u7801\u64CD\u4F5C (chgpasswd)", riskType: "script_execution" },
|
|
2855
|
-
// --- High: user/group deletion (irreversible, requires user consent) ---
|
|
2856
|
-
{ pattern: /\buserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (userdel)", riskType: "script_execution" },
|
|
2857
|
-
{ pattern: /\bdeluser\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (deluser)", riskType: "script_execution" },
|
|
2858
|
-
{ pattern: /\bluserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (luserdel)", riskType: "script_execution" },
|
|
2859
|
-
{ pattern: /\bgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (groupdel)", riskType: "script_execution" },
|
|
2860
|
-
{ pattern: /\blgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (lgroupdel)", riskType: "script_execution" },
|
|
2861
|
-
// --- High: generic command -p parameter password setting ---
|
|
2862
|
-
{ pattern: /\b(useradd|luseradd|groupadd|usermod|lusermod|groupmod|lgroupmod)\b[^&|;]*?\s-p\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u901A\u8FC7 -p \u53C2\u6570\u8BBE\u7F6E\u6216\u4FEE\u6539\u5BC6\u7801 (useradd/usermod/groupmod)", riskType: "script_execution" }
|
|
2863
|
-
];
|
|
2713
|
+
INJECTION_KEYWORDS = (() => {
|
|
2714
|
+
const kws = loadL1().injection_detection || [];
|
|
2715
|
+
return kws.map((k) => ({
|
|
2716
|
+
keyword: k.keyword,
|
|
2717
|
+
riskLevel: k.risk_level,
|
|
2718
|
+
lang: k.lang || "en"
|
|
2719
|
+
}));
|
|
2720
|
+
})();
|
|
2721
|
+
DANGEROUS_PATTERNS = (() => {
|
|
2722
|
+
const cmds = loadL1().dangerous_commands || [];
|
|
2723
|
+
return cmds.map((c) => ({
|
|
2724
|
+
pattern: new RegExp(c.pattern, "i"),
|
|
2725
|
+
severity: c.risk_level,
|
|
2726
|
+
riskType: c.risk_type,
|
|
2727
|
+
description: c.reason
|
|
2728
|
+
}));
|
|
2729
|
+
})();
|
|
2864
2730
|
SENSITIVE_EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
2731
|
+
SEARCH_ACTION_PREFIXES = ["search-", "web-", "browser-", "query-", "websearch", "web_search"];
|
|
2865
2732
|
}
|
|
2866
2733
|
});
|
|
2867
2734
|
|
|
@@ -2874,16 +2741,16 @@ __export(token_stats_exports, {
|
|
|
2874
2741
|
recordTokenUsage: () => recordTokenUsage,
|
|
2875
2742
|
resetTokenStats: () => resetTokenStats
|
|
2876
2743
|
});
|
|
2877
|
-
import { readFileSync as
|
|
2744
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
2878
2745
|
function getStatsPath() {
|
|
2879
2746
|
const envPath = process.env[ENV_STATS_PATH];
|
|
2880
2747
|
if (envPath) return envPath;
|
|
2881
2748
|
return getTokenStatsPath();
|
|
2882
2749
|
}
|
|
2883
2750
|
function loadAllRecords(statsPath) {
|
|
2884
|
-
if (!
|
|
2751
|
+
if (!existsSync8(statsPath)) return [];
|
|
2885
2752
|
try {
|
|
2886
|
-
const data = JSON.parse(
|
|
2753
|
+
const data = JSON.parse(readFileSync9(statsPath, "utf-8"));
|
|
2887
2754
|
if (Array.isArray(data)) return data;
|
|
2888
2755
|
if (data && Array.isArray(data.records)) return data.records;
|
|
2889
2756
|
return [];
|
|
@@ -2894,7 +2761,7 @@ function loadAllRecords(statsPath) {
|
|
|
2894
2761
|
function saveRecords(statsPath, records) {
|
|
2895
2762
|
try {
|
|
2896
2763
|
const dir = statsPath.substring(0, statsPath.lastIndexOf("/"));
|
|
2897
|
-
if (dir && !
|
|
2764
|
+
if (dir && !existsSync8(dir)) mkdirSync2(dir, { recursive: true });
|
|
2898
2765
|
writeFileSync2(statsPath, JSON.stringify(records, null, 2), "utf-8");
|
|
2899
2766
|
} catch (e) {
|
|
2900
2767
|
}
|
|
@@ -3016,7 +2883,7 @@ function getTokenTrend(days = 0, startDate, endDate) {
|
|
|
3016
2883
|
}
|
|
3017
2884
|
function resetTokenStats() {
|
|
3018
2885
|
const statsPath = getStatsPath();
|
|
3019
|
-
if (
|
|
2886
|
+
if (existsSync8(statsPath)) {
|
|
3020
2887
|
try {
|
|
3021
2888
|
unlinkSync2(statsPath);
|
|
3022
2889
|
} catch {
|
|
@@ -3116,9 +2983,9 @@ var require_bindings = __commonJS({
|
|
|
3116
2983
|
init_esm_shims();
|
|
3117
2984
|
var fs4 = __require("fs");
|
|
3118
2985
|
var path3 = __require("path");
|
|
3119
|
-
var
|
|
2986
|
+
var fileURLToPath9 = require_file_uri_to_path();
|
|
3120
2987
|
var join6 = path3.join;
|
|
3121
|
-
var
|
|
2988
|
+
var dirname8 = path3.dirname;
|
|
3122
2989
|
var exists = fs4.accessSync && function(path4) {
|
|
3123
2990
|
try {
|
|
3124
2991
|
fs4.accessSync(path4);
|
|
@@ -3228,12 +3095,12 @@ var require_bindings = __commonJS({
|
|
|
3228
3095
|
Error.stackTraceLimit = origSTL;
|
|
3229
3096
|
var fileSchema = "file://";
|
|
3230
3097
|
if (fileName.indexOf(fileSchema) === 0) {
|
|
3231
|
-
fileName =
|
|
3098
|
+
fileName = fileURLToPath9(fileName);
|
|
3232
3099
|
}
|
|
3233
3100
|
return fileName;
|
|
3234
3101
|
};
|
|
3235
3102
|
exports.getRoot = function getRoot(file) {
|
|
3236
|
-
var dir =
|
|
3103
|
+
var dir = dirname8(file), prev;
|
|
3237
3104
|
while (true) {
|
|
3238
3105
|
if (dir === ".") {
|
|
3239
3106
|
dir = process.cwd();
|
|
@@ -3439,13 +3306,13 @@ var require_backup = __commonJS({
|
|
|
3439
3306
|
var runBackup = (backup, handler) => {
|
|
3440
3307
|
let rate = 0;
|
|
3441
3308
|
let useDefault = true;
|
|
3442
|
-
return new Promise((
|
|
3309
|
+
return new Promise((resolve7, reject) => {
|
|
3443
3310
|
setImmediate(function step() {
|
|
3444
3311
|
try {
|
|
3445
3312
|
const progress = backup.transfer(rate);
|
|
3446
3313
|
if (!progress.remainingPages) {
|
|
3447
3314
|
backup.close();
|
|
3448
|
-
|
|
3315
|
+
resolve7(progress);
|
|
3449
3316
|
return;
|
|
3450
3317
|
}
|
|
3451
3318
|
if (useDefault) {
|
|
@@ -3893,28 +3760,28 @@ init_skill_loader();
|
|
|
3893
3760
|
|
|
3894
3761
|
// src/engine/template-loader.ts
|
|
3895
3762
|
init_esm_shims();
|
|
3896
|
-
import { readFileSync as
|
|
3897
|
-
import { resolve as
|
|
3898
|
-
import { fileURLToPath as
|
|
3899
|
-
var
|
|
3900
|
-
var
|
|
3901
|
-
var TEMPLATES_DIR =
|
|
3902
|
-
var TEMPLATES_DIR_FALLBACK =
|
|
3763
|
+
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
3764
|
+
import { resolve as resolve4, dirname as dirname5 } from "path";
|
|
3765
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
3766
|
+
var __filename5 = fileURLToPath7(import.meta.url);
|
|
3767
|
+
var __dirname6 = dirname5(__filename5);
|
|
3768
|
+
var TEMPLATES_DIR = resolve4(__dirname6, "../templates");
|
|
3769
|
+
var TEMPLATES_DIR_FALLBACK = resolve4(__dirname6, "../../../agent_moss/templates");
|
|
3903
3770
|
var TEMPLATE_FILES = ["prompt1_template.txt", "prompt2_template.txt", "security_judge_template.txt"];
|
|
3904
3771
|
var cachedTemplates = null;
|
|
3905
3772
|
function loadTemplates() {
|
|
3906
3773
|
if (cachedTemplates) return cachedTemplates;
|
|
3907
3774
|
cachedTemplates = {};
|
|
3908
|
-
const dir =
|
|
3909
|
-
if (!
|
|
3775
|
+
const dir = existsSync6(TEMPLATES_DIR) ? TEMPLATES_DIR : TEMPLATES_DIR_FALLBACK;
|
|
3776
|
+
if (!existsSync6(dir)) {
|
|
3910
3777
|
console.warn("[AgentMoss] Templates directory not found:", TEMPLATES_DIR, "and fallback:", TEMPLATES_DIR_FALLBACK);
|
|
3911
3778
|
return cachedTemplates;
|
|
3912
3779
|
}
|
|
3913
3780
|
for (const file of TEMPLATE_FILES) {
|
|
3914
|
-
const filePath =
|
|
3915
|
-
if (
|
|
3781
|
+
const filePath = resolve4(dir, file);
|
|
3782
|
+
if (existsSync6(filePath)) {
|
|
3916
3783
|
const key = file.replace(".txt", "").replace("_template", "");
|
|
3917
|
-
cachedTemplates[key] =
|
|
3784
|
+
cachedTemplates[key] = readFileSync6(filePath, "utf-8");
|
|
3918
3785
|
}
|
|
3919
3786
|
}
|
|
3920
3787
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates from ${dir}`);
|
|
@@ -3923,8 +3790,8 @@ function loadTemplates() {
|
|
|
3923
3790
|
|
|
3924
3791
|
// src/engine/script-analyzer.ts
|
|
3925
3792
|
init_esm_shims();
|
|
3926
|
-
import { readFileSync as
|
|
3927
|
-
import { resolve as
|
|
3793
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
3794
|
+
import { resolve as resolve5, join as join3 } from "path";
|
|
3928
3795
|
var SUSPICIOUS_PATTERNS = [
|
|
3929
3796
|
// Network exfiltration (curl/wget POST in scripts is almost never legitimate)
|
|
3930
3797
|
{ name: "curl POST", pattern: /curl\s+(.*\s)?-X\s+POST/i },
|
|
@@ -4057,8 +3924,8 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
4057
3924
|
}
|
|
4058
3925
|
function readScriptContent(scriptPath, maxLines = 500) {
|
|
4059
3926
|
try {
|
|
4060
|
-
const expandedPath = scriptPath.startsWith("~") ? join3(process.env.HOME || "/home/user", scriptPath.slice(2)) :
|
|
4061
|
-
const raw =
|
|
3927
|
+
const expandedPath = scriptPath.startsWith("~") ? join3(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve5(scriptPath);
|
|
3928
|
+
const raw = readFileSync7(expandedPath, "utf-8");
|
|
4062
3929
|
const lines = raw.split("\n").slice(0, maxLines);
|
|
4063
3930
|
return { content: lines.join("\n"), lineCount: lines.length, error: "" };
|
|
4064
3931
|
} catch (e) {
|
|
@@ -4112,8 +3979,8 @@ ${result.scriptContent}
|
|
|
4112
3979
|
init_esm_shims();
|
|
4113
3980
|
init_heuristic();
|
|
4114
3981
|
init_logic_rules();
|
|
4115
|
-
import { readFileSync as
|
|
4116
|
-
import { resolve as
|
|
3982
|
+
import { readFileSync as readFileSync8, statSync, existsSync as existsSync7 } from "fs";
|
|
3983
|
+
import { resolve as resolve6, join as join4, isAbsolute, dirname as dirname6 } from "path";
|
|
4117
3984
|
import { homedir as homedir2 } from "os";
|
|
4118
3985
|
function emptyChain() {
|
|
4119
3986
|
return {
|
|
@@ -4342,7 +4209,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
4342
4209
|
let resolved;
|
|
4343
4210
|
try {
|
|
4344
4211
|
resolved = resolvePath(p);
|
|
4345
|
-
if (
|
|
4212
|
+
if (existsSync7(resolved)) {
|
|
4346
4213
|
const stat = statSync(resolved);
|
|
4347
4214
|
if (stat.isFile()) return resolved;
|
|
4348
4215
|
}
|
|
@@ -4356,18 +4223,18 @@ function resolvePath(p) {
|
|
|
4356
4223
|
if (expanded.startsWith("~/") || expanded === "~") {
|
|
4357
4224
|
expanded = join4(homedir2(), expanded.slice(1));
|
|
4358
4225
|
}
|
|
4359
|
-
return
|
|
4226
|
+
return resolve6(expanded);
|
|
4360
4227
|
}
|
|
4361
4228
|
function readScriptContent2(scriptPath, maxFileSize = 2 * 1024 * 1024) {
|
|
4362
4229
|
try {
|
|
4363
4230
|
const path3 = resolvePath(scriptPath);
|
|
4364
|
-
if (!
|
|
4231
|
+
if (!existsSync7(path3)) return { content: "", lineCount: 0, fileSize: 0, error: `\u811A\u672C\u4E0D\u5B58\u5728: ${scriptPath}` };
|
|
4365
4232
|
const stat = statSync(path3);
|
|
4366
4233
|
if (!stat.isFile()) return { content: "", lineCount: 0, fileSize: 0, error: `\u4E0D\u662F\u6587\u4EF6: ${scriptPath}` };
|
|
4367
4234
|
if (stat.size > maxFileSize) {
|
|
4368
4235
|
return { content: "", lineCount: 0, fileSize: stat.size, error: `\u811A\u672C\u6587\u4EF6\u8FC7\u5927 (${stat.size} bytes)\uFF0C\u8DF3\u8FC7\u8BFB\u53D6` };
|
|
4369
4236
|
}
|
|
4370
|
-
const content =
|
|
4237
|
+
const content = readFileSync8(path3, "utf-8");
|
|
4371
4238
|
const lineCount = content ? content.split("\n").length : 0;
|
|
4372
4239
|
return { content, lineCount, fileSize: stat.size, error: "" };
|
|
4373
4240
|
} catch (e) {
|
|
@@ -4386,7 +4253,7 @@ function extractChildScriptPaths(content, baseDir) {
|
|
|
4386
4253
|
if (pathStr.includes("/dev/") || pathStr.startsWith("|") || pathStr.startsWith(";")) continue;
|
|
4387
4254
|
const full = isAbsolute(pathStr) ? pathStr : join4(baseDir, pathStr);
|
|
4388
4255
|
const resolved = resolvePath(full);
|
|
4389
|
-
if (
|
|
4256
|
+
if (existsSync7(resolved)) {
|
|
4390
4257
|
try {
|
|
4391
4258
|
if (statSync(resolved).isFile() && !paths.includes(resolved)) paths.push(resolved);
|
|
4392
4259
|
} catch {
|
|
@@ -4401,7 +4268,7 @@ function resolveScriptChain(entryPath, input, maxDepth = 3, maxFileSize = 2 * 10
|
|
|
4401
4268
|
const result = emptyChain();
|
|
4402
4269
|
result.entryPath = entryPath;
|
|
4403
4270
|
const entry = resolvePath(entryPath);
|
|
4404
|
-
const baseDir =
|
|
4271
|
+
const baseDir = existsSync7(entry) ? dirname6(entry) : input.cwd || process.cwd();
|
|
4405
4272
|
resolveRecursive({
|
|
4406
4273
|
path: entry,
|
|
4407
4274
|
depth: 0,
|
|
@@ -4476,7 +4343,7 @@ function resolveRecursive(ctx) {
|
|
|
4476
4343
|
maxTotalSize,
|
|
4477
4344
|
visited,
|
|
4478
4345
|
result,
|
|
4479
|
-
baseDir:
|
|
4346
|
+
baseDir: dirname6(resolvePath(childPath)),
|
|
4480
4347
|
input
|
|
4481
4348
|
});
|
|
4482
4349
|
if (result.hasCritical) return;
|
|
@@ -4829,7 +4696,7 @@ async function analyzeWithLLM(prompt, config) {
|
|
|
4829
4696
|
}
|
|
4830
4697
|
if (attempt < maxRetries) {
|
|
4831
4698
|
console.error(`[AgentMoss] LLM call failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${retryCfg.retryInterval}s:`, err.message);
|
|
4832
|
-
await new Promise((
|
|
4699
|
+
await new Promise((resolve7) => setTimeout(resolve7, retryCfg.retryInterval * 1e3));
|
|
4833
4700
|
} else {
|
|
4834
4701
|
clearTimeout(totalTimeoutTimer);
|
|
4835
4702
|
console.error("[AgentMoss] LLM call failed after all retries:", err.message);
|
|
@@ -5342,11 +5209,11 @@ init_esm_shims();
|
|
|
5342
5209
|
init_runtime_config();
|
|
5343
5210
|
init_token_stats();
|
|
5344
5211
|
import { Hono } from "hono";
|
|
5345
|
-
import { readFileSync as
|
|
5346
|
-
import { join as join5, dirname as
|
|
5347
|
-
import { fileURLToPath as
|
|
5348
|
-
var
|
|
5349
|
-
var STATIC_DIR = join5(
|
|
5212
|
+
import { readFileSync as readFileSync10, existsSync as existsSync10 } from "fs";
|
|
5213
|
+
import { join as join5, dirname as dirname7 } from "path";
|
|
5214
|
+
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
5215
|
+
var __dirname7 = dirname7(fileURLToPath8(import.meta.url));
|
|
5216
|
+
var STATIC_DIR = join5(__dirname7, "static");
|
|
5350
5217
|
var CONSOLE_TOKEN_ENV = "AGENT_MOSS_CONSOLE_TOKEN";
|
|
5351
5218
|
function getConsoleToken() {
|
|
5352
5219
|
return process.env[CONSOLE_TOKEN_ENV] || "";
|
|
@@ -5371,8 +5238,8 @@ function createConsoleRouter() {
|
|
|
5371
5238
|
console2.use("/api/*", authMiddleware());
|
|
5372
5239
|
const serveIndex = (c) => {
|
|
5373
5240
|
const indexFile = join5(STATIC_DIR, "index.html");
|
|
5374
|
-
if (
|
|
5375
|
-
return c.html(
|
|
5241
|
+
if (existsSync10(indexFile)) {
|
|
5242
|
+
return c.html(readFileSync10(indexFile, "utf-8"));
|
|
5376
5243
|
}
|
|
5377
5244
|
return c.html("<h1>AgentMoss Policy Console</h1><p>Frontend not built. Use /console/api/* endpoints.</p>");
|
|
5378
5245
|
};
|
|
@@ -5463,13 +5330,13 @@ function createConsoleRouter() {
|
|
|
5463
5330
|
if (!/^[A-Za-z0-9_-]+$/.test(skillId)) {
|
|
5464
5331
|
return c.json({ error: "invalid skill_id" }, 400);
|
|
5465
5332
|
}
|
|
5466
|
-
const skillPath = join5(
|
|
5467
|
-
if (!
|
|
5468
|
-
const builtinPath = join5(
|
|
5469
|
-
if (
|
|
5333
|
+
const skillPath = join5(dirname7(getRuntimeConfigPath()), "agent_moss_skills", `${skillId}.md`);
|
|
5334
|
+
if (!existsSync10(skillPath)) {
|
|
5335
|
+
const builtinPath = join5(__dirname7, "..", "..", "agent_moss", "skills", `${skillId}.md`);
|
|
5336
|
+
if (existsSync10(builtinPath)) return c.text(readFileSync10(builtinPath, "utf-8"));
|
|
5470
5337
|
return c.json({ error: "skill not found" }, 404);
|
|
5471
5338
|
}
|
|
5472
|
-
return c.text(
|
|
5339
|
+
return c.text(readFileSync10(skillPath, "utf-8"));
|
|
5473
5340
|
});
|
|
5474
5341
|
console2.get("/api/agents", (c) => {
|
|
5475
5342
|
const rc = loadRuntimeConfig();
|
|
@@ -5553,12 +5420,12 @@ function createApp() {
|
|
|
5553
5420
|
}
|
|
5554
5421
|
async function findFreePort(startPort, host = "127.0.0.1", scan = 100) {
|
|
5555
5422
|
for (let port = startPort; port < startPort + scan; port++) {
|
|
5556
|
-
const free = await new Promise((
|
|
5423
|
+
const free = await new Promise((resolve7) => {
|
|
5557
5424
|
const server = net.createServer();
|
|
5558
5425
|
server.listen(port, host, () => {
|
|
5559
|
-
server.close(() =>
|
|
5426
|
+
server.close(() => resolve7(true));
|
|
5560
5427
|
});
|
|
5561
|
-
server.on("error", () =>
|
|
5428
|
+
server.on("error", () => resolve7(false));
|
|
5562
5429
|
});
|
|
5563
5430
|
if (free) {
|
|
5564
5431
|
if (port !== startPort) {
|