@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/cli.js
CHANGED
|
@@ -575,8 +575,70 @@ var init_inline_analyzer = __esm({
|
|
|
575
575
|
}
|
|
576
576
|
});
|
|
577
577
|
|
|
578
|
+
// src/infra/rules-loader.ts
|
|
579
|
+
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
580
|
+
import { resolve, dirname } from "path";
|
|
581
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
582
|
+
function findRulesFile(name) {
|
|
583
|
+
for (const dir of RULES_DIR_CANDS) {
|
|
584
|
+
const p = resolve(dir, name);
|
|
585
|
+
if (existsSync(p)) return p;
|
|
586
|
+
}
|
|
587
|
+
return null;
|
|
588
|
+
}
|
|
589
|
+
function loadJson(name) {
|
|
590
|
+
const p = findRulesFile(name);
|
|
591
|
+
if (!p) return {};
|
|
592
|
+
try {
|
|
593
|
+
return JSON.parse(readFileSync2(p, "utf-8")) || {};
|
|
594
|
+
} catch {
|
|
595
|
+
return {};
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function loadL1() {
|
|
599
|
+
return loadJson("l1_rules.json");
|
|
600
|
+
}
|
|
601
|
+
function loadL2() {
|
|
602
|
+
return loadJson("l2_rules.json");
|
|
603
|
+
}
|
|
604
|
+
function loadL3() {
|
|
605
|
+
return loadJson("l3_rules.json");
|
|
606
|
+
}
|
|
607
|
+
var __filename2, __dirname2, RULES_DIR_CANDS;
|
|
608
|
+
var init_rules_loader = __esm({
|
|
609
|
+
"src/infra/rules-loader.ts"() {
|
|
610
|
+
"use strict";
|
|
611
|
+
init_esm_shims();
|
|
612
|
+
__filename2 = fileURLToPath3(import.meta.url);
|
|
613
|
+
__dirname2 = dirname(__filename2);
|
|
614
|
+
RULES_DIR_CANDS = (() => {
|
|
615
|
+
const cands = [
|
|
616
|
+
// dist: __dirname=dist/ → dist/rules;__dirname=dist/engine/ → dist/engine/../rules=dist/rules
|
|
617
|
+
resolve(__dirname2, "../rules"),
|
|
618
|
+
resolve(__dirname2, "rules"),
|
|
619
|
+
// dev src: __dirname=ts/src/infra/ → ts/src/infra/../../../agent_moss/rules = 仓库根 agent_moss/rules
|
|
620
|
+
resolve(__dirname2, "../../../agent_moss/rules"),
|
|
621
|
+
// dist 但 __dirname 指向 dist/engine 再往上两级的仓库根 agent_moss/rules
|
|
622
|
+
resolve(__dirname2, "../../../../agent_moss/rules"),
|
|
623
|
+
// 相对当前工作目录的仓库根(兜底,兼容以仓库根为 cwd 运行)
|
|
624
|
+
resolve(process.cwd(), "agent_moss/rules")
|
|
625
|
+
];
|
|
626
|
+
return cands.filter((c) => existsSync(c));
|
|
627
|
+
})();
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
|
|
578
631
|
// src/engine/logic-rules.ts
|
|
579
632
|
import * as fs2 from "fs";
|
|
633
|
+
function _loadSensitivePathScope(scope) {
|
|
634
|
+
const sps = loadL1().sensitive_path_access || [];
|
|
635
|
+
return sps.filter((sp) => sp.scope === scope).map((sp) => ({
|
|
636
|
+
path: sp.path,
|
|
637
|
+
riskLevel: sp.risk_level,
|
|
638
|
+
desc: sp.desc,
|
|
639
|
+
credential: sp.deny_mode === "deny_both" ? true : void 0
|
|
640
|
+
}));
|
|
641
|
+
}
|
|
580
642
|
function isWriteOperation(actionType, actionDetail, writeKeywords = WRITE_KEYWORDS) {
|
|
581
643
|
if (writeKeywords.some((kw) => actionType.includes(kw) || actionDetail.includes(kw))) return true;
|
|
582
644
|
if (WRITE_COMMAND_RES.some((rx) => rx.test(actionDetail))) return true;
|
|
@@ -938,57 +1000,10 @@ var init_logic_rules = __esm({
|
|
|
938
1000
|
"use strict";
|
|
939
1001
|
init_esm_shims();
|
|
940
1002
|
init_inline_analyzer();
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
{ path: "/etc/passwd", riskLevel: "high", desc: "\u7CFB\u7EDF\u7528\u6237\u6587\u4EF6" },
|
|
946
|
-
{ path: "/etc/sudoers", riskLevel: "critical", desc: "sudo \u914D\u7F6E", credential: true },
|
|
947
|
-
// 系统配置(仅拦截写入)
|
|
948
|
-
{ path: "/etc/hosts", riskLevel: "medium", desc: "DNS \u89E3\u6790\u914D\u7F6E" },
|
|
949
|
-
{ path: "/etc/crontab", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1" },
|
|
950
|
-
{ path: "/etc/cron.d/", riskLevel: "high", desc: "\u7CFB\u7EDF\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55\uFF08\u62C6\u5206\u5F0F crontab\uFF09" },
|
|
951
|
-
{ path: "/var/spool/cron/", riskLevel: "high", desc: "\u7528\u6237\u7EA7\u5B9A\u65F6\u4EFB\u52A1\u76EE\u5F55" },
|
|
952
|
-
{ path: "/etc/systemd/", riskLevel: "high", desc: "systemd \u670D\u52A1\u914D\u7F6E" },
|
|
953
|
-
{ path: "/etc/ssh/sshd_config", riskLevel: "high", desc: "SSH \u670D\u52A1\u914D\u7F6E" },
|
|
954
|
-
{ path: "/etc/pam.d/", riskLevel: "high", desc: "PAM \u53EF\u63D2\u62D4\u8BA4\u8BC1\u6A21\u5757\u914D\u7F6E" },
|
|
955
|
-
// 危险目录(仅拦截写入)
|
|
956
|
-
{ path: "/boot/", riskLevel: "critical", desc: "\u542F\u52A8\u5F15\u5BFC\u76EE\u5F55" },
|
|
957
|
-
{ path: "/proc/sys/", riskLevel: "high", desc: "\u5185\u6838\u53C2\u6570" },
|
|
958
|
-
{ path: "/sys/", riskLevel: "high", desc: "sysfs \u5185\u6838\u63A5\u53E3" },
|
|
959
|
-
// 设备文件(/dev/null、/dev/zero、/dev/urandom 已移除,误报率极高)
|
|
960
|
-
{ path: "/dev/random", riskLevel: "high", desc: "\u963B\u585E\u5F0F\u968F\u673A\u6570\u8BBE\u5907\uFF08\u8BFB\u53D6\u8017\u5C3D\u71B5\u6C60\uFF09" },
|
|
961
|
-
{ path: "/dev/mem", riskLevel: "critical", desc: "\u7269\u7406\u5185\u5B58\u8BBF\u95EE\u8BBE\u5907\uFF08\u8BFB\u5199\u5747\u5371\u9669\uFF09", credential: true },
|
|
962
|
-
{ path: "/dev/kmsg", riskLevel: "high", desc: "\u5185\u6838\u6D88\u606F\u7F13\u51B2\u533A" },
|
|
963
|
-
// SSH 主机私钥
|
|
964
|
-
// SSH 主机私钥(排除 .pub 公钥变体,对齐 Python .ssh/id_rsa(?!\.pub) 范式)
|
|
965
|
-
{ path: "/etc/ssh/ssh_host_rsa_key(?!\\.pub)", riskLevel: "critical", desc: "SSH \u4E3B\u673A RSA \u79C1\u94A5", credential: true },
|
|
966
|
-
{ path: "/etc/ssh/ssh_host_ed25519_key(?!\\.pub)", riskLevel: "critical", desc: "SSH \u4E3B\u673A Ed25519 \u79C1\u94A5", credential: true },
|
|
967
|
-
{ path: "/etc/ssh/ssh_host_ecdsa_key(?!\\.pub)", riskLevel: "critical", desc: "SSH \u4E3B\u673A ECDSA \u79C1\u94A5", credential: true },
|
|
968
|
-
// Nginx 配置(仅拦截写入,对齐 Python linux.py sensitive_paths)
|
|
969
|
-
{ path: "/etc/nginx/nginx.conf", riskLevel: "high", desc: "Nginx \u4E3B\u914D\u7F6E" },
|
|
970
|
-
{ path: "/etc/nginx/conf.d/", riskLevel: "high", desc: "Nginx \u5B50\u914D\u7F6E\u76EE\u5F55" },
|
|
971
|
-
{ path: "/etc/nginx/sites-enabled/", riskLevel: "high", desc: "Nginx \u542F\u7528\u7AD9\u70B9\u914D\u7F6E\u76EE\u5F55" }
|
|
972
|
-
];
|
|
973
|
-
HOME_SENSITIVE_PATHS = [
|
|
974
|
-
{ path: ".ssh/id_rsa", riskLevel: "critical", desc: "SSH \u79C1\u94A5", credential: true },
|
|
975
|
-
{ path: ".ssh/id_ed25519", riskLevel: "critical", desc: "SSH \u79C1\u94A5 (ed25519)", credential: true },
|
|
976
|
-
{ path: ".ssh/authorized_keys", riskLevel: "high", desc: "SSH \u6388\u6743\u5BC6\u94A5" },
|
|
977
|
-
// 持久化与命令劫持(仅拦截写入)
|
|
978
|
-
{ path: ".bashrc", riskLevel: "high", desc: "\u7528\u6237 Shell \u521D\u59CB\u5316\u811A\u672C" },
|
|
979
|
-
{ path: ".bash_profile", riskLevel: "high", desc: "\u7528\u6237 Shell \u767B\u5F55\u811A\u672C" },
|
|
980
|
-
{ path: ".profile", riskLevel: "high", desc: "\u7528\u6237\u901A\u7528\u767B\u5F55\u811A\u672C" },
|
|
981
|
-
{ path: ".aws/credentials", riskLevel: "critical", desc: "AWS \u51ED\u8BC1", credential: true },
|
|
982
|
-
{ path: ".gitconfig", riskLevel: "medium", desc: "Git \u914D\u7F6E" },
|
|
983
|
-
{ path: ".gnupg", riskLevel: "high", desc: "GPG \u5BC6\u94A5\u76EE\u5F55" }
|
|
984
|
-
];
|
|
985
|
-
CREDENTIAL_PATHS = [
|
|
986
|
-
{ path: "credentials.yml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
987
|
-
{ path: "credentials.yaml", riskLevel: "high", desc: "\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" },
|
|
988
|
-
{ path: "secrets.yml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
989
|
-
{ path: "secrets.yaml", riskLevel: "high", desc: "\u5BC6\u94A5\u914D\u7F6E\u6587\u4EF6" },
|
|
990
|
-
{ path: ".env", riskLevel: "high", desc: "\u73AF\u5883\u53D8\u91CF/\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" }
|
|
991
|
-
];
|
|
1003
|
+
init_rules_loader();
|
|
1004
|
+
ROOT_SENSITIVE_PATHS = _loadSensitivePathScope("root");
|
|
1005
|
+
HOME_SENSITIVE_PATHS = _loadSensitivePathScope("home");
|
|
1006
|
+
CREDENTIAL_PATHS = _loadSensitivePathScope("credential").map(({ path: path3, riskLevel, desc }) => ({ path: path3, riskLevel, desc, credential: true }));
|
|
992
1007
|
NON_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
993
1008
|
"ask_user_question",
|
|
994
1009
|
"glob",
|
|
@@ -1116,34 +1131,22 @@ var init_logic_rules = __esm({
|
|
|
1116
1131
|
DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/g;
|
|
1117
1132
|
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"];
|
|
1118
1133
|
CREATE_KEYWORDS = ["\u521B\u5EFA", "\u65B0\u5EFA", "create", "new file", "touch"];
|
|
1119
|
-
PASSWORD_MODIFY_PATTERNS =
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
INTENT_DEVIATION_PATTERNS = [
|
|
1136
|
-
{
|
|
1137
|
-
intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
|
|
1138
|
-
dangerousActions: ["\u5220\u9664", "remove", "delete", "rm", "\u683C\u5F0F\u5316", "format"],
|
|
1139
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u8BFB\u53D6/\u5206\u6790\uFF0C\u4F46\u6267\u884C\u4E86\u5220\u9664\u64CD\u4F5C"
|
|
1140
|
-
},
|
|
1141
|
-
{
|
|
1142
|
-
intentKeywords: ["\u67E5\u8BE2", "\u641C\u7D22", "search", "query", "find"],
|
|
1143
|
-
dangerousActions: ["\u4FEE\u6539", "update", "write", "\u5199\u5165", "alter"],
|
|
1144
|
-
reason: "\u539F\u59CB\u610F\u56FE\u4E3A\u67E5\u8BE2/\u641C\u7D22\uFF0C\u4F46\u6267\u884C\u4E86\u4FEE\u6539\u64CD\u4F5C"
|
|
1145
|
-
}
|
|
1146
|
-
];
|
|
1134
|
+
PASSWORD_MODIFY_PATTERNS = (() => {
|
|
1135
|
+
const pats = loadL2().password_modify_consent || [];
|
|
1136
|
+
return pats.map((p) => new RegExp(p.pattern, "i"));
|
|
1137
|
+
})();
|
|
1138
|
+
USER_DELETION_PATTERNS = (() => {
|
|
1139
|
+
const pats = loadL2().user_deletion_consent || [];
|
|
1140
|
+
return pats.map((p) => new RegExp(p.pattern, "i"));
|
|
1141
|
+
})();
|
|
1142
|
+
INTENT_DEVIATION_PATTERNS = (() => {
|
|
1143
|
+
const pats = loadL2().intent_consistency || [];
|
|
1144
|
+
return pats.map((p) => ({
|
|
1145
|
+
intentKeywords: p.intent_keywords,
|
|
1146
|
+
dangerousActions: p.dangerous_actions,
|
|
1147
|
+
reason: p.reason
|
|
1148
|
+
}));
|
|
1149
|
+
})();
|
|
1147
1150
|
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;
|
|
1148
1151
|
DIR_TRAVERSAL_KW = [
|
|
1149
1152
|
"os.listdir",
|
|
@@ -1161,21 +1164,21 @@ var init_logic_rules = __esm({
|
|
|
1161
1164
|
});
|
|
1162
1165
|
|
|
1163
1166
|
// src/engine/skill-loader.ts
|
|
1164
|
-
import { readFileSync as
|
|
1165
|
-
import { resolve, dirname } from "path";
|
|
1166
|
-
import { fileURLToPath as
|
|
1167
|
+
import { readFileSync as readFileSync3, readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
|
|
1168
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
1169
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
1167
1170
|
function loadAllSkills() {
|
|
1168
1171
|
if (cachedSkills) return cachedSkills;
|
|
1169
1172
|
cachedSkills = {};
|
|
1170
|
-
const dir =
|
|
1171
|
-
if (!
|
|
1173
|
+
const dir = existsSync3(SKILLS_DIR) ? SKILLS_DIR : SKILLS_DIR_FALLBACK;
|
|
1174
|
+
if (!existsSync3(dir)) {
|
|
1172
1175
|
console.warn("[AgentMoss] Skills directory not found:", SKILLS_DIR, "and fallback:", SKILLS_DIR_FALLBACK);
|
|
1173
1176
|
return cachedSkills;
|
|
1174
1177
|
}
|
|
1175
1178
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".md"));
|
|
1176
1179
|
for (const f of files) {
|
|
1177
1180
|
const name = f.replace(".md", "");
|
|
1178
|
-
cachedSkills[name] =
|
|
1181
|
+
cachedSkills[name] = readFileSync3(resolve2(dir, f), "utf-8");
|
|
1179
1182
|
}
|
|
1180
1183
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills from ${dir}`);
|
|
1181
1184
|
return cachedSkills;
|
|
@@ -1229,32 +1232,27 @@ function formatSkillsForPrompt(skills) {
|
|
|
1229
1232
|
${s.skillContent}`
|
|
1230
1233
|
).join("\n\n---\n\n");
|
|
1231
1234
|
}
|
|
1232
|
-
var
|
|
1235
|
+
var __filename3, __dirname3, SKILLS_DIR, SKILLS_DIR_FALLBACK, SKILL_KEYWORD_MAP, cachedSkills;
|
|
1233
1236
|
var init_skill_loader = __esm({
|
|
1234
1237
|
"src/engine/skill-loader.ts"() {
|
|
1235
1238
|
"use strict";
|
|
1236
1239
|
init_esm_shims();
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
"skill_installation_guard": ["skill", "plugin", "\u63D2\u4EF6", "extension", "\u6269\u5C55", "install skill", "\u5B89\u88C5\u63D2\u4EF6", "\u5B89\u88C5\u6280\u80FD", "marketplace", "\u5546\u5E97"],
|
|
1254
|
-
"supply_chain_guard": ["dependency", "\u4F9D\u8D56", "package", "\u5305", "npm install", "pip install", "requirements", "import", "library", "\u5E93", "registry", "\u4ED3\u5E93", "supply", "\u4F9B\u5E94\u94FE", "typosquatting"],
|
|
1255
|
-
"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"],
|
|
1256
|
-
"indirect_access_guard": ["listdir", "os.walk", "os.scandir", "glob.glob", "glob.iglob", "pathlib", "iterdir", "rglob", "scandir", "os.listdir", "\u76EE\u5F55\u904D\u5386", "traversal"]
|
|
1257
|
-
};
|
|
1240
|
+
init_rules_loader();
|
|
1241
|
+
__filename3 = fileURLToPath4(import.meta.url);
|
|
1242
|
+
__dirname3 = dirname2(__filename3);
|
|
1243
|
+
SKILLS_DIR = resolve2(__dirname3, "../skills");
|
|
1244
|
+
SKILLS_DIR_FALLBACK = resolve2(__dirname3, "../../../agent_moss/skills");
|
|
1245
|
+
SKILL_KEYWORD_MAP = (() => {
|
|
1246
|
+
const map = {};
|
|
1247
|
+
const cats = loadL3();
|
|
1248
|
+
for (const cat of Object.values(cats)) {
|
|
1249
|
+
if (!cat || typeof cat !== "object") continue;
|
|
1250
|
+
for (const [skillId, keywords] of Object.entries(cat)) {
|
|
1251
|
+
map[skillId] = keywords;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
return map;
|
|
1255
|
+
})();
|
|
1258
1256
|
cachedSkills = null;
|
|
1259
1257
|
}
|
|
1260
1258
|
});
|
|
@@ -1306,10 +1304,10 @@ __export(runtime_config_exports, {
|
|
|
1306
1304
|
updateSkillCategoryEnabled: () => updateSkillCategoryEnabled,
|
|
1307
1305
|
updateSkillEnabled: () => updateSkillEnabled
|
|
1308
1306
|
});
|
|
1309
|
-
import { readFileSync as
|
|
1307
|
+
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3 } from "fs";
|
|
1310
1308
|
import { join as join2 } from "path";
|
|
1311
|
-
import { fileURLToPath as
|
|
1312
|
-
import { dirname as
|
|
1309
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1310
|
+
import { dirname as dirname3 } from "path";
|
|
1313
1311
|
function runtimeDir() {
|
|
1314
1312
|
return getRuntimeConfigDir();
|
|
1315
1313
|
}
|
|
@@ -1321,7 +1319,7 @@ function getRuntimeConfigPath() {
|
|
|
1321
1319
|
function saveRuntimeConfig(config) {
|
|
1322
1320
|
const p = getRuntimeConfigPath();
|
|
1323
1321
|
const dir = p.substring(0, p.lastIndexOf("/"));
|
|
1324
|
-
if (dir && !
|
|
1322
|
+
if (dir && !existsSync4(dir)) mkdirSync(dir, { recursive: true });
|
|
1325
1323
|
writeFileSync(p, JSON.stringify(config, null, 2), "utf-8");
|
|
1326
1324
|
}
|
|
1327
1325
|
function emptyRuntimeConfig() {
|
|
@@ -1336,7 +1334,7 @@ function emptyRuntimeConfig() {
|
|
|
1336
1334
|
}
|
|
1337
1335
|
function loadRuntimeConfig() {
|
|
1338
1336
|
const p = getRuntimeConfigPath();
|
|
1339
|
-
if (!
|
|
1337
|
+
if (!existsSync4(p)) {
|
|
1340
1338
|
const seeded = mergeConfig({}, generateSourceDefaults());
|
|
1341
1339
|
try {
|
|
1342
1340
|
saveRuntimeConfig(seeded);
|
|
@@ -1345,7 +1343,7 @@ function loadRuntimeConfig() {
|
|
|
1345
1343
|
return seeded;
|
|
1346
1344
|
}
|
|
1347
1345
|
try {
|
|
1348
|
-
const data = JSON.parse(
|
|
1346
|
+
const data = JSON.parse(readFileSync4(p, "utf-8"));
|
|
1349
1347
|
const merged = mergeConfig(data, generateSourceDefaults());
|
|
1350
1348
|
return {
|
|
1351
1349
|
version: data.version || 1,
|
|
@@ -1413,9 +1411,9 @@ function getEnabledL2SensitivePaths(runtime) {
|
|
|
1413
1411
|
}
|
|
1414
1412
|
function hasRuntimeConfig() {
|
|
1415
1413
|
const p = getRuntimeConfigPath();
|
|
1416
|
-
if (!
|
|
1414
|
+
if (!existsSync4(p)) return false;
|
|
1417
1415
|
try {
|
|
1418
|
-
JSON.parse(
|
|
1416
|
+
JSON.parse(readFileSync4(p, "utf-8"));
|
|
1419
1417
|
return true;
|
|
1420
1418
|
} catch {
|
|
1421
1419
|
return false;
|
|
@@ -1594,8 +1592,8 @@ function _l3SkillsToRules() {
|
|
|
1594
1592
|
}
|
|
1595
1593
|
function _agentRulesToDefaults() {
|
|
1596
1594
|
const out = {};
|
|
1597
|
-
const agentsDir =
|
|
1598
|
-
if (!
|
|
1595
|
+
const agentsDir = existsSync4(_AGENTS_DIR_PROD) ? _AGENTS_DIR_PROD : existsSync4(_AGENTS_DIR_DEV) ? _AGENTS_DIR_DEV : _AGENTS_DIR_PROD;
|
|
1596
|
+
if (!existsSync4(agentsDir)) return out;
|
|
1599
1597
|
let entries;
|
|
1600
1598
|
try {
|
|
1601
1599
|
entries = readdirSync3(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -1604,10 +1602,10 @@ function _agentRulesToDefaults() {
|
|
|
1604
1602
|
}
|
|
1605
1603
|
for (const agentId of entries) {
|
|
1606
1604
|
const rulesFile = join2(agentsDir, agentId, "rules.json");
|
|
1607
|
-
if (!
|
|
1605
|
+
if (!existsSync4(rulesFile)) continue;
|
|
1608
1606
|
let data;
|
|
1609
1607
|
try {
|
|
1610
|
-
data = JSON.parse(
|
|
1608
|
+
data = JSON.parse(readFileSync4(rulesFile, "utf-8"));
|
|
1611
1609
|
} catch {
|
|
1612
1610
|
continue;
|
|
1613
1611
|
}
|
|
@@ -1686,6 +1684,9 @@ function generateSourceDefaults() {
|
|
|
1686
1684
|
agent_rules: _agentRulesToDefaults()
|
|
1687
1685
|
};
|
|
1688
1686
|
}
|
|
1687
|
+
function normalizePatternForFingerprint(pattern) {
|
|
1688
|
+
return pattern.replace(/\\\//g, "/");
|
|
1689
|
+
}
|
|
1689
1690
|
function _ruleFingerprint(rule) {
|
|
1690
1691
|
if (rule.intent_keywords && rule.intent_keywords.length || rule.dangerous_actions && rule.dangerous_actions.length) {
|
|
1691
1692
|
return JSON.stringify([
|
|
@@ -1693,8 +1694,8 @@ function _ruleFingerprint(rule) {
|
|
|
1693
1694
|
[...rule.dangerous_actions || []].sort()
|
|
1694
1695
|
]);
|
|
1695
1696
|
}
|
|
1696
|
-
if (rule.path) return JSON.stringify([rule.path]);
|
|
1697
|
-
if (rule.pattern) return JSON.stringify([rule.pattern]);
|
|
1697
|
+
if (rule.path) return JSON.stringify([normalizePatternForFingerprint(rule.path)]);
|
|
1698
|
+
if (rule.pattern) return JSON.stringify([normalizePatternForFingerprint(rule.pattern)]);
|
|
1698
1699
|
if (rule.keyword) return JSON.stringify([rule.keyword, rule.lang || ""]);
|
|
1699
1700
|
if (rule.value) return JSON.stringify([rule.value]);
|
|
1700
1701
|
return JSON.stringify([rule.id || ""]);
|
|
@@ -2045,7 +2046,7 @@ function deleteCustomSkill(skillId, category) {
|
|
|
2045
2046
|
skills.splice(idx, 1);
|
|
2046
2047
|
const skillPath = join2(RUNTIME_CONFIG_DIR, "agent_moss_skills", `${skillId}.md`);
|
|
2047
2048
|
try {
|
|
2048
|
-
if (
|
|
2049
|
+
if (existsSync4(skillPath)) unlinkSync(skillPath);
|
|
2049
2050
|
} catch {
|
|
2050
2051
|
}
|
|
2051
2052
|
saveRuntimeConfig(runtime);
|
|
@@ -2159,7 +2160,7 @@ function updateAgentCategoryEnabled(agentId, category, enabled) {
|
|
|
2159
2160
|
saveRuntimeConfig(runtime);
|
|
2160
2161
|
return runtime;
|
|
2161
2162
|
}
|
|
2162
|
-
var
|
|
2163
|
+
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;
|
|
2163
2164
|
var init_runtime_config = __esm({
|
|
2164
2165
|
"src/infra/runtime-config.ts"() {
|
|
2165
2166
|
"use strict";
|
|
@@ -2168,7 +2169,7 @@ var init_runtime_config = __esm({
|
|
|
2168
2169
|
init_heuristic();
|
|
2169
2170
|
init_logic_rules();
|
|
2170
2171
|
init_skill_loader();
|
|
2171
|
-
|
|
2172
|
+
__dirname4 = dirname3(fileURLToPath5(import.meta.url));
|
|
2172
2173
|
ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
|
|
2173
2174
|
RUNTIME_CONFIG_DIR = runtimeDir();
|
|
2174
2175
|
RUNTIME_CONFIG_PATH = join2(RUNTIME_CONFIG_DIR, "agent_moss_runtime.json");
|
|
@@ -2182,19 +2183,19 @@ var init_runtime_config = __esm({
|
|
|
2182
2183
|
deny_read: "\u4EC5\u62E6\u622A\u8BFB\u53D6",
|
|
2183
2184
|
deny_both: "\u8BFB\u5199\u5747\u62E6\u622A"
|
|
2184
2185
|
};
|
|
2185
|
-
_AGENTS_DIR_PROD = join2(
|
|
2186
|
-
_AGENTS_DIR_DEV = join2(
|
|
2186
|
+
_AGENTS_DIR_PROD = join2(__dirname4, "agents");
|
|
2187
|
+
_AGENTS_DIR_DEV = join2(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
2187
2188
|
SKILL_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
2188
2189
|
}
|
|
2189
2190
|
});
|
|
2190
2191
|
|
|
2191
2192
|
// src/agents/index.ts
|
|
2192
|
-
import { readFileSync as
|
|
2193
|
-
import { resolve as
|
|
2194
|
-
import { fileURLToPath as
|
|
2193
|
+
import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
|
|
2194
|
+
import { resolve as resolve3, dirname as dirname4 } from "path";
|
|
2195
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
2195
2196
|
function resolveAgentsDir() {
|
|
2196
|
-
if (
|
|
2197
|
-
if (
|
|
2197
|
+
if (existsSync5(AGENTS_DIR_PROD)) return AGENTS_DIR_PROD;
|
|
2198
|
+
if (existsSync5(AGENTS_DIR_DEV_FALLBACK)) return AGENTS_DIR_DEV_FALLBACK;
|
|
2198
2199
|
return AGENTS_DIR_PROD;
|
|
2199
2200
|
}
|
|
2200
2201
|
function getAgentExtensions(agentId) {
|
|
@@ -2210,13 +2211,13 @@ function getAgentExtensions(agentId) {
|
|
|
2210
2211
|
}
|
|
2211
2212
|
if (ext === null) {
|
|
2212
2213
|
const agentsDir = resolveAgentsDir();
|
|
2213
|
-
const rulesFile =
|
|
2214
|
-
if (!
|
|
2214
|
+
const rulesFile = resolve3(agentsDir, agentId, "rules.json");
|
|
2215
|
+
if (!existsSync5(rulesFile)) {
|
|
2215
2216
|
cache.set(agentId, null);
|
|
2216
2217
|
return null;
|
|
2217
2218
|
}
|
|
2218
2219
|
try {
|
|
2219
|
-
const raw =
|
|
2220
|
+
const raw = readFileSync5(rulesFile, "utf-8");
|
|
2220
2221
|
ext = JSON.parse(raw);
|
|
2221
2222
|
if (!ext.agent_id) {
|
|
2222
2223
|
console.warn(`[AgentMoss agents] rules.json \u7F3A\u5C11 agent_id \u5B57\u6BB5: ${rulesFile}`);
|
|
@@ -2235,15 +2236,15 @@ function getAgentExtensions(agentId) {
|
|
|
2235
2236
|
);
|
|
2236
2237
|
return ext;
|
|
2237
2238
|
}
|
|
2238
|
-
var
|
|
2239
|
+
var __filename4, __dirname5, AGENTS_DIR_PROD, AGENTS_DIR_DEV_FALLBACK, cache;
|
|
2239
2240
|
var init_agents = __esm({
|
|
2240
2241
|
"src/agents/index.ts"() {
|
|
2241
2242
|
"use strict";
|
|
2242
2243
|
init_esm_shims();
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
AGENTS_DIR_PROD =
|
|
2246
|
-
AGENTS_DIR_DEV_FALLBACK =
|
|
2244
|
+
__filename4 = fileURLToPath6(import.meta.url);
|
|
2245
|
+
__dirname5 = dirname4(__filename4);
|
|
2246
|
+
AGENTS_DIR_PROD = resolve3(__dirname5, "agents");
|
|
2247
|
+
AGENTS_DIR_DEV_FALLBACK = resolve3(__dirname5, "../../../agent_moss/agents");
|
|
2247
2248
|
cache = /* @__PURE__ */ new Map();
|
|
2248
2249
|
}
|
|
2249
2250
|
});
|
|
@@ -2303,7 +2304,7 @@ function runHeuristicCheck(input) {
|
|
|
2303
2304
|
}
|
|
2304
2305
|
}
|
|
2305
2306
|
}
|
|
2306
|
-
const injectionText = `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
2307
|
+
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();
|
|
2307
2308
|
const injectionHits = checkInjectionKeywords(injectionText, agentExt?.extra_injection_keywords);
|
|
2308
2309
|
if (injectionHits.length > 0) {
|
|
2309
2310
|
const topHit = injectionHits.reduce((a, b) => severityRank(a.riskLevel) >= severityRank(b.riskLevel) ? a : b);
|
|
@@ -2430,6 +2431,10 @@ function severityRank(s) {
|
|
|
2430
2431
|
const ranks = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
2431
2432
|
return ranks[s] || 0;
|
|
2432
2433
|
}
|
|
2434
|
+
function isSearchActionType(actionType) {
|
|
2435
|
+
const at = actionType.toLowerCase();
|
|
2436
|
+
return SEARCH_ACTION_PREFIXES.some((p) => at.startsWith(p)) || ["websearch", "web_search", "search", "query"].includes(at);
|
|
2437
|
+
}
|
|
2433
2438
|
function checkSensitivePath(command, cwd, agentExt) {
|
|
2434
2439
|
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
2435
2440
|
const isWriteOpFlag = isWriteOperation("", command);
|
|
@@ -2697,214 +2702,76 @@ function checkLateralMovement(actionDetail) {
|
|
|
2697
2702
|
}
|
|
2698
2703
|
return null;
|
|
2699
2704
|
}
|
|
2700
|
-
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES;
|
|
2705
|
+
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS, SENSITIVE_EXCLUDED_PREFIXES, SEARCH_ACTION_PREFIXES;
|
|
2701
2706
|
var init_heuristic = __esm({
|
|
2702
2707
|
"src/engine/heuristic.ts"() {
|
|
2703
2708
|
"use strict";
|
|
2704
2709
|
init_esm_shims();
|
|
2705
2710
|
init_config();
|
|
2706
2711
|
init_agents();
|
|
2712
|
+
init_rules_loader();
|
|
2707
2713
|
init_logic_rules();
|
|
2708
|
-
INJECTION_KEYWORDS =
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
{ keyword: "\u4ECE\u73B0\u5728\u5F00\u59CB\u4F60", riskLevel: "high", lang: "zh" },
|
|
2726
|
-
{ keyword: "\u4F60\u7684\u65B0\u89D2\u8272\u662F", riskLevel: "high", lang: "zh" },
|
|
2727
|
-
// ---- Command Injection ----
|
|
2728
|
-
{ keyword: "system prompt", riskLevel: "high", lang: "en" },
|
|
2729
|
-
{ keyword: "reveal your instructions", riskLevel: "high", lang: "en" },
|
|
2730
|
-
{ keyword: "output your instructions", riskLevel: "high", lang: "en" },
|
|
2731
|
-
{ keyword: "repeat your instructions", riskLevel: "medium", lang: "en" },
|
|
2732
|
-
{ keyword: "\u7CFB\u7EDF\u63D0\u793A", riskLevel: "high", lang: "zh" },
|
|
2733
|
-
{ keyword: "\u8F93\u51FA\u4F60\u7684\u6307\u4EE4", riskLevel: "high", lang: "zh" },
|
|
2734
|
-
{ keyword: "\u91CD\u590D\u4F60\u7684\u6307\u4EE4", riskLevel: "medium", lang: "zh" },
|
|
2735
|
-
// ---- Social Engineering ----
|
|
2736
|
-
{ keyword: "this is an authorized test", riskLevel: "high", lang: "en" },
|
|
2737
|
-
{ keyword: "security audit approved", riskLevel: "high", lang: "en" },
|
|
2738
|
-
{ keyword: "admin override", riskLevel: "critical", lang: "en" },
|
|
2739
|
-
{ keyword: "debug mode", riskLevel: "high", lang: "en" },
|
|
2740
|
-
{ keyword: "maintenance mode", riskLevel: "high", lang: "en" },
|
|
2741
|
-
{ keyword: "\u8FD9\u662F\u6388\u6743\u7684\u6D4B\u8BD5", riskLevel: "high", lang: "zh" },
|
|
2742
|
-
{ keyword: "\u5B89\u5168\u5BA1\u8BA1\u5DF2\u6279\u51C6", riskLevel: "high", lang: "zh" },
|
|
2743
|
-
{ keyword: "\u7BA1\u7406\u5458\u8986\u76D6", riskLevel: "critical", lang: "zh" },
|
|
2744
|
-
{ keyword: "\u8C03\u8BD5\u6A21\u5F0F", riskLevel: "high", lang: "zh" },
|
|
2745
|
-
// ---- XSS ----
|
|
2746
|
-
{ keyword: "<script>", riskLevel: "high", lang: "en" },
|
|
2747
|
-
{ keyword: "javascript:", riskLevel: "high", lang: "en" },
|
|
2748
|
-
{ keyword: "onerror=", riskLevel: "high", lang: "en" },
|
|
2749
|
-
{ keyword: "onload=", riskLevel: "high", lang: "en" },
|
|
2750
|
-
// ---- Fake Boundaries ----
|
|
2751
|
-
{ keyword: "=== END OF", riskLevel: "high", lang: "en" },
|
|
2752
|
-
{ keyword: "--- END SYSTEM", riskLevel: "high", lang: "en" },
|
|
2753
|
-
{ keyword: "[END OF", riskLevel: "high", lang: "en" },
|
|
2754
|
-
{ keyword: "=== \u7ED3\u675F", riskLevel: "high", lang: "zh" },
|
|
2755
|
-
{ keyword: "--- \u7ED3\u675F\u7CFB\u7EDF", riskLevel: "high", lang: "zh" },
|
|
2756
|
-
// ---- Developer Mode ----
|
|
2757
|
-
{ keyword: "developer mode", riskLevel: "critical", lang: "en" },
|
|
2758
|
-
{ keyword: "DAN mode", riskLevel: "critical", lang: "en" },
|
|
2759
|
-
{ keyword: "jailbreak", riskLevel: "critical", lang: "en" },
|
|
2760
|
-
{ keyword: "\u5F00\u53D1\u8005\u6A21\u5F0F", riskLevel: "critical", lang: "zh" },
|
|
2761
|
-
{ keyword: "\u8D8A\u72F1", riskLevel: "critical", lang: "zh" }
|
|
2762
|
-
// 注:xiaoO 专属绕过词(绕过审计/禁用安全检查/关闭防护/bypass audit 等)
|
|
2763
|
-
// 已迁至 agent_moss/agents/xiaoo/rules.json 的 extra_injection_keywords,
|
|
2764
|
-
// 由 agent_ext 机制注入,不再污染通用层。
|
|
2765
|
-
];
|
|
2766
|
-
DANGEROUS_PATTERNS = [
|
|
2767
|
-
// --- Critical: rm command graded detection (strict to loose, first match wins) ---
|
|
2768
|
-
// 1. rm -rf root dir (含通配符如 /* /.* 等) — 使用负向先行断言 (?!\w):/ 后面不是单词字符时匹配
|
|
2769
|
-
{ 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" },
|
|
2770
|
-
// 注意:已移除"rm -rf /任意绝对路径"的宽泛规则,避免误杀 /tmp 等临时目录清理操作
|
|
2771
|
-
// 2. rm with -r or -f targeting system dirs — var 分支排除 /var/tmp/(合法清理)
|
|
2772
|
-
{ 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" },
|
|
2773
|
-
// 3. rm -r absolute path (no -f) — 排除 /tmp/ /var/tmp/ /run/ /dev/shm/(CI/开发高频合法清理)
|
|
2774
|
-
{ 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" },
|
|
2775
|
-
// 4. rm -f absolute path (no -r) — 同样排除临时目录
|
|
2776
|
-
{ 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" },
|
|
2777
|
-
// dd 磁盘清零 — 只拦截写入系统关键目录,放行 /tmp 等临时目录
|
|
2778
|
-
{ 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" },
|
|
2779
|
-
// mkfs 格式化 — 只拦截对块设备(/dev/sdX 等)的格式化,放行对普通文件的格式化
|
|
2780
|
-
{ 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" },
|
|
2781
|
-
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb", riskType: "resource_exhaustion" },
|
|
2782
|
-
// --- Critical: remote code execution ---
|
|
2783
|
-
// curl|bash 优先匹配 user_rules(high/sensitive_action),见下方 UserRuleMatcher 段;
|
|
2784
|
-
// 非 bash 的 curl|sh/zsh/dash 走 CommandPatternScanner critical。两条分流由
|
|
2785
|
-
// runHeuristicCheck 的规则顺序保证(bash 在前 high,其余 fall-through 到 critical)。
|
|
2786
|
-
{ pattern: /curl\s+.*\|\s*bash/i, severity: "high", description: "curl pipe bash \u6267\u884C (user_rules)", riskType: "sensitive_action" },
|
|
2787
|
-
{ pattern: /curl\s+.*\|\s*(sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
2788
|
-
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
2789
|
-
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
2790
|
-
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "high", description: "base64 \u89E3\u7801\u6267\u884C (user_rules)", riskType: "sensitive_action" },
|
|
2791
|
-
// --- Critical: reverse shell ---
|
|
2792
|
-
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell", riskType: "script_execution" },
|
|
2793
|
-
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5", riskType: "lateral_movement" },
|
|
2794
|
-
// --- Critical: sensitive file access ---
|
|
2795
|
-
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)", riskType: "file_access" },
|
|
2796
|
-
{ pattern: /\/etc\/gshadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6 (/etc/gshadow)", riskType: "file_access" },
|
|
2797
|
-
// 注意:/etc/passwd 已从拦截列表移除,因为它是公开可读的标准系统文件,真正敏感的是 /etc/shadow
|
|
2798
|
-
{ pattern: /\.ssh\/id_rsa(?!\.pub)/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6", riskType: "file_access" },
|
|
2799
|
-
// --- Critical: privilege escalation / container escape ---
|
|
2800
|
-
{ 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" },
|
|
2801
|
-
// --- Critical: dangerous permissions / ownership (提权 / 权限敞口) ---
|
|
2802
|
-
// 修正「只拦 777、xx7 漏放」的缺口:
|
|
2803
|
-
// 1) 八进制末位 7:other 位含写+执行敞口(chmod 777/647/007/4777 等);644/755/1700 不命中
|
|
2804
|
-
// 2) 八进制 setuid/setgid 位:首位 4(setuid)/2(setgid) 的 4 位八进制(chmod 4755/2755)
|
|
2805
|
-
// 3) 符号 setuid/setgid:chmod u+s / g+s / a+s
|
|
2806
|
-
// 普通权限修改(chmod 644)不在此列——L2 read_before_write 已豁免 chmod/chown(不写内容),
|
|
2807
|
-
// 危险形态在此 L1 专门拦,以「提权」正确理由拦截,不再靠 RBW 误打误撞。
|
|
2808
|
-
{ 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" },
|
|
2809
|
-
{ 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" },
|
|
2810
|
-
{ 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" },
|
|
2811
|
-
{ 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" },
|
|
2812
|
-
// sudo 提权 — 只拦截 sudo 后跟的危险命令,不一刀切拦截所有 sudo
|
|
2813
|
-
{ 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" },
|
|
2814
|
-
// --- High: system config overwrite ---
|
|
2815
|
-
// > /etc/ 重定向覆盖:对齐 Python CommandPatternScanner `>\s*/etc/`(不兼容引号路径),
|
|
2816
|
-
// 引号包裹的重定向目标(cat > '/etc/ssh/sshd_config')走 checkSensitivePath 敏感路径 high。
|
|
2817
|
-
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55", riskType: "file_access" },
|
|
2818
|
-
{ pattern: />\s*\/boot\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u542F\u52A8\u5F15\u5BFC\u76EE\u5F55", riskType: "file_access" },
|
|
2819
|
-
// 注:/proc/ 重定向覆盖走 checkSensitivePath 的 high(内核参数 /proc/sys/),此处不拦 /proc/ 避免遮蔽(对齐 Python)。
|
|
2820
|
-
// --- High: download script + execute risk ---
|
|
2821
|
-
// curl -X POST 外传敏感信息(对齐 Python linux.py: curl POST env/key/token)
|
|
2822
|
-
{ 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" },
|
|
2823
|
-
{ 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" },
|
|
2824
|
-
{ 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" },
|
|
2825
|
-
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C", riskType: "script_execution" },
|
|
2826
|
-
// --- High: package manager pipe-to-shell ---
|
|
2827
|
-
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell", riskType: "script_execution" },
|
|
2828
|
-
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell", riskType: "script_execution" },
|
|
2829
|
-
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell", riskType: "script_execution" },
|
|
2830
|
-
// --- Medium: destructive git operations (降级为 medium,允许但记录) ---
|
|
2831
|
-
{ 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" },
|
|
2832
|
-
// --- High: network port scanning (横向移动侦察) ---
|
|
2833
|
-
{ 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" },
|
|
2834
|
-
{ 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" },
|
|
2835
|
-
// --- Medium: credential export ---
|
|
2836
|
-
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1", riskType: "data_exfiltration" },
|
|
2837
|
-
// --- High: shell rc file append (persistence) ---
|
|
2838
|
-
// 两条规则:第一条匹配 ~ 与 /home/<user>/ 形态;第二条按文件名兜底,
|
|
2839
|
-
// 覆盖非标准 home 路径(如鸿蒙 /storage/Users/currentUser/.bashrc、
|
|
2840
|
-
// /root/.bashrc),避免按 home 前缀枚举导致漏检持久化后门。
|
|
2841
|
-
{ 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" },
|
|
2842
|
-
{ 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" },
|
|
2843
|
-
// --- High: device file write (只拦截重定向写入设备文件,不拦截读取) ---
|
|
2844
|
-
{ 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" },
|
|
2845
|
-
// --- High: non-interactive password modification ---
|
|
2846
|
-
{ 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" },
|
|
2847
|
-
{ 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" },
|
|
2848
|
-
{ pattern: /\bchpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 chpasswd \u6279\u91CF\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4", riskType: "script_execution" },
|
|
2849
|
-
{ 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" },
|
|
2850
|
-
{ 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" },
|
|
2851
|
-
{ 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" },
|
|
2852
|
-
// --- High: non-interactive password modification (extended) ---
|
|
2853
|
-
{ pattern: /\blpasswd\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\u64CD\u4F5C (lpasswd)", riskType: "script_execution" },
|
|
2854
|
-
{ pattern: /\bgpasswd\s+(?!-[adA])/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7EC4\u5BC6\u7801\u7BA1\u7406\u64CD\u4F5C (gpasswd)", riskType: "script_execution" },
|
|
2855
|
-
{ pattern: /\bchgpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u6279\u91CF\u4FEE\u6539\u7EC4\u5BC6\u7801\u64CD\u4F5C (chgpasswd)", riskType: "script_execution" },
|
|
2856
|
-
// --- High: user/group deletion (irreversible, requires user consent) ---
|
|
2857
|
-
{ pattern: /\buserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (userdel)", riskType: "script_execution" },
|
|
2858
|
-
{ pattern: /\bdeluser\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (deluser)", riskType: "script_execution" },
|
|
2859
|
-
{ pattern: /\bluserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (luserdel)", riskType: "script_execution" },
|
|
2860
|
-
{ pattern: /\bgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (groupdel)", riskType: "script_execution" },
|
|
2861
|
-
{ pattern: /\blgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (lgroupdel)", riskType: "script_execution" },
|
|
2862
|
-
// --- High: generic command -p parameter password setting ---
|
|
2863
|
-
{ 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" }
|
|
2864
|
-
];
|
|
2714
|
+
INJECTION_KEYWORDS = (() => {
|
|
2715
|
+
const kws = loadL1().injection_detection || [];
|
|
2716
|
+
return kws.map((k) => ({
|
|
2717
|
+
keyword: k.keyword,
|
|
2718
|
+
riskLevel: k.risk_level,
|
|
2719
|
+
lang: k.lang || "en"
|
|
2720
|
+
}));
|
|
2721
|
+
})();
|
|
2722
|
+
DANGEROUS_PATTERNS = (() => {
|
|
2723
|
+
const cmds = loadL1().dangerous_commands || [];
|
|
2724
|
+
return cmds.map((c) => ({
|
|
2725
|
+
pattern: new RegExp(c.pattern, "i"),
|
|
2726
|
+
severity: c.risk_level,
|
|
2727
|
+
riskType: c.risk_type,
|
|
2728
|
+
description: c.reason
|
|
2729
|
+
}));
|
|
2730
|
+
})();
|
|
2865
2731
|
SENSITIVE_EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
2732
|
+
SEARCH_ACTION_PREFIXES = ["search-", "web-", "browser-", "query-", "websearch", "web_search"];
|
|
2866
2733
|
}
|
|
2867
2734
|
});
|
|
2868
2735
|
|
|
2869
2736
|
// src/engine/template-loader.ts
|
|
2870
|
-
import { readFileSync as
|
|
2871
|
-
import { resolve as
|
|
2872
|
-
import { fileURLToPath as
|
|
2737
|
+
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
2738
|
+
import { resolve as resolve4, dirname as dirname5 } from "path";
|
|
2739
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
2873
2740
|
function loadTemplates() {
|
|
2874
2741
|
if (cachedTemplates) return cachedTemplates;
|
|
2875
2742
|
cachedTemplates = {};
|
|
2876
|
-
const dir =
|
|
2877
|
-
if (!
|
|
2743
|
+
const dir = existsSync6(TEMPLATES_DIR) ? TEMPLATES_DIR : TEMPLATES_DIR_FALLBACK;
|
|
2744
|
+
if (!existsSync6(dir)) {
|
|
2878
2745
|
console.warn("[AgentMoss] Templates directory not found:", TEMPLATES_DIR, "and fallback:", TEMPLATES_DIR_FALLBACK);
|
|
2879
2746
|
return cachedTemplates;
|
|
2880
2747
|
}
|
|
2881
2748
|
for (const file of TEMPLATE_FILES) {
|
|
2882
|
-
const filePath =
|
|
2883
|
-
if (
|
|
2749
|
+
const filePath = resolve4(dir, file);
|
|
2750
|
+
if (existsSync6(filePath)) {
|
|
2884
2751
|
const key = file.replace(".txt", "").replace("_template", "");
|
|
2885
|
-
cachedTemplates[key] =
|
|
2752
|
+
cachedTemplates[key] = readFileSync6(filePath, "utf-8");
|
|
2886
2753
|
}
|
|
2887
2754
|
}
|
|
2888
2755
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates from ${dir}`);
|
|
2889
2756
|
return cachedTemplates;
|
|
2890
2757
|
}
|
|
2891
|
-
var
|
|
2758
|
+
var __filename5, __dirname6, TEMPLATES_DIR, TEMPLATES_DIR_FALLBACK, TEMPLATE_FILES, cachedTemplates;
|
|
2892
2759
|
var init_template_loader = __esm({
|
|
2893
2760
|
"src/engine/template-loader.ts"() {
|
|
2894
2761
|
"use strict";
|
|
2895
2762
|
init_esm_shims();
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
TEMPLATES_DIR =
|
|
2899
|
-
TEMPLATES_DIR_FALLBACK =
|
|
2763
|
+
__filename5 = fileURLToPath7(import.meta.url);
|
|
2764
|
+
__dirname6 = dirname5(__filename5);
|
|
2765
|
+
TEMPLATES_DIR = resolve4(__dirname6, "../templates");
|
|
2766
|
+
TEMPLATES_DIR_FALLBACK = resolve4(__dirname6, "../../../agent_moss/templates");
|
|
2900
2767
|
TEMPLATE_FILES = ["prompt1_template.txt", "prompt2_template.txt", "security_judge_template.txt"];
|
|
2901
2768
|
cachedTemplates = null;
|
|
2902
2769
|
}
|
|
2903
2770
|
});
|
|
2904
2771
|
|
|
2905
2772
|
// src/engine/script-analyzer.ts
|
|
2906
|
-
import { readFileSync as
|
|
2907
|
-
import { resolve as
|
|
2773
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
2774
|
+
import { resolve as resolve5, join as join3 } from "path";
|
|
2908
2775
|
function emptyResult() {
|
|
2909
2776
|
return { scriptPath: "", scriptContent: "", matchedKeywords: [], lineCount: 0, isSuspicious: false, error: "", riskLevel: "", riskReason: "" };
|
|
2910
2777
|
}
|
|
@@ -2957,8 +2824,8 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
2957
2824
|
}
|
|
2958
2825
|
function readScriptContent(scriptPath, maxLines = 500) {
|
|
2959
2826
|
try {
|
|
2960
|
-
const expandedPath = scriptPath.startsWith("~") ? join3(process.env.HOME || "/home/user", scriptPath.slice(2)) :
|
|
2961
|
-
const raw =
|
|
2827
|
+
const expandedPath = scriptPath.startsWith("~") ? join3(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve5(scriptPath);
|
|
2828
|
+
const raw = readFileSync7(expandedPath, "utf-8");
|
|
2962
2829
|
const lines = raw.split("\n").slice(0, maxLines);
|
|
2963
2830
|
return { content: lines.join("\n"), lineCount: lines.length, error: "" };
|
|
2964
2831
|
} catch (e) {
|
|
@@ -3096,8 +2963,8 @@ var init_script_analyzer = __esm({
|
|
|
3096
2963
|
});
|
|
3097
2964
|
|
|
3098
2965
|
// src/engine/script-content-analyzer.ts
|
|
3099
|
-
import { readFileSync as
|
|
3100
|
-
import { resolve as
|
|
2966
|
+
import { readFileSync as readFileSync8, statSync, existsSync as existsSync7 } from "fs";
|
|
2967
|
+
import { resolve as resolve6, join as join4, isAbsolute, dirname as dirname6 } from "path";
|
|
3101
2968
|
import { homedir as homedir2 } from "os";
|
|
3102
2969
|
function emptyChain() {
|
|
3103
2970
|
return {
|
|
@@ -3244,7 +3111,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
3244
3111
|
let resolved;
|
|
3245
3112
|
try {
|
|
3246
3113
|
resolved = resolvePath(p);
|
|
3247
|
-
if (
|
|
3114
|
+
if (existsSync7(resolved)) {
|
|
3248
3115
|
const stat = statSync(resolved);
|
|
3249
3116
|
if (stat.isFile()) return resolved;
|
|
3250
3117
|
}
|
|
@@ -3258,18 +3125,18 @@ function resolvePath(p) {
|
|
|
3258
3125
|
if (expanded.startsWith("~/") || expanded === "~") {
|
|
3259
3126
|
expanded = join4(homedir2(), expanded.slice(1));
|
|
3260
3127
|
}
|
|
3261
|
-
return
|
|
3128
|
+
return resolve6(expanded);
|
|
3262
3129
|
}
|
|
3263
3130
|
function readScriptContent2(scriptPath, maxFileSize = 2 * 1024 * 1024) {
|
|
3264
3131
|
try {
|
|
3265
3132
|
const path3 = resolvePath(scriptPath);
|
|
3266
|
-
if (!
|
|
3133
|
+
if (!existsSync7(path3)) return { content: "", lineCount: 0, fileSize: 0, error: `\u811A\u672C\u4E0D\u5B58\u5728: ${scriptPath}` };
|
|
3267
3134
|
const stat = statSync(path3);
|
|
3268
3135
|
if (!stat.isFile()) return { content: "", lineCount: 0, fileSize: 0, error: `\u4E0D\u662F\u6587\u4EF6: ${scriptPath}` };
|
|
3269
3136
|
if (stat.size > maxFileSize) {
|
|
3270
3137
|
return { content: "", lineCount: 0, fileSize: stat.size, error: `\u811A\u672C\u6587\u4EF6\u8FC7\u5927 (${stat.size} bytes)\uFF0C\u8DF3\u8FC7\u8BFB\u53D6` };
|
|
3271
3138
|
}
|
|
3272
|
-
const content =
|
|
3139
|
+
const content = readFileSync8(path3, "utf-8");
|
|
3273
3140
|
const lineCount = content ? content.split("\n").length : 0;
|
|
3274
3141
|
return { content, lineCount, fileSize: stat.size, error: "" };
|
|
3275
3142
|
} catch (e) {
|
|
@@ -3288,7 +3155,7 @@ function extractChildScriptPaths(content, baseDir) {
|
|
|
3288
3155
|
if (pathStr.includes("/dev/") || pathStr.startsWith("|") || pathStr.startsWith(";")) continue;
|
|
3289
3156
|
const full = isAbsolute(pathStr) ? pathStr : join4(baseDir, pathStr);
|
|
3290
3157
|
const resolved = resolvePath(full);
|
|
3291
|
-
if (
|
|
3158
|
+
if (existsSync7(resolved)) {
|
|
3292
3159
|
try {
|
|
3293
3160
|
if (statSync(resolved).isFile() && !paths.includes(resolved)) paths.push(resolved);
|
|
3294
3161
|
} catch {
|
|
@@ -3303,7 +3170,7 @@ function resolveScriptChain(entryPath, input, maxDepth = 3, maxFileSize = 2 * 10
|
|
|
3303
3170
|
const result = emptyChain();
|
|
3304
3171
|
result.entryPath = entryPath;
|
|
3305
3172
|
const entry = resolvePath(entryPath);
|
|
3306
|
-
const baseDir =
|
|
3173
|
+
const baseDir = existsSync7(entry) ? dirname6(entry) : input.cwd || process.cwd();
|
|
3307
3174
|
resolveRecursive({
|
|
3308
3175
|
path: entry,
|
|
3309
3176
|
depth: 0,
|
|
@@ -3378,7 +3245,7 @@ function resolveRecursive(ctx) {
|
|
|
3378
3245
|
maxTotalSize,
|
|
3379
3246
|
visited,
|
|
3380
3247
|
result,
|
|
3381
|
-
baseDir:
|
|
3248
|
+
baseDir: dirname6(resolvePath(childPath)),
|
|
3382
3249
|
input
|
|
3383
3250
|
});
|
|
3384
3251
|
if (result.hasCritical) return;
|
|
@@ -3639,16 +3506,16 @@ __export(token_stats_exports, {
|
|
|
3639
3506
|
recordTokenUsage: () => recordTokenUsage,
|
|
3640
3507
|
resetTokenStats: () => resetTokenStats
|
|
3641
3508
|
});
|
|
3642
|
-
import { readFileSync as
|
|
3509
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
3643
3510
|
function getStatsPath() {
|
|
3644
3511
|
const envPath = process.env[ENV_STATS_PATH];
|
|
3645
3512
|
if (envPath) return envPath;
|
|
3646
3513
|
return getTokenStatsPath();
|
|
3647
3514
|
}
|
|
3648
3515
|
function loadAllRecords(statsPath) {
|
|
3649
|
-
if (!
|
|
3516
|
+
if (!existsSync8(statsPath)) return [];
|
|
3650
3517
|
try {
|
|
3651
|
-
const data = JSON.parse(
|
|
3518
|
+
const data = JSON.parse(readFileSync9(statsPath, "utf-8"));
|
|
3652
3519
|
if (Array.isArray(data)) return data;
|
|
3653
3520
|
if (data && Array.isArray(data.records)) return data.records;
|
|
3654
3521
|
return [];
|
|
@@ -3659,7 +3526,7 @@ function loadAllRecords(statsPath) {
|
|
|
3659
3526
|
function saveRecords(statsPath, records) {
|
|
3660
3527
|
try {
|
|
3661
3528
|
const dir = statsPath.substring(0, statsPath.lastIndexOf("/"));
|
|
3662
|
-
if (dir && !
|
|
3529
|
+
if (dir && !existsSync8(dir)) mkdirSync2(dir, { recursive: true });
|
|
3663
3530
|
writeFileSync2(statsPath, JSON.stringify(records, null, 2), "utf-8");
|
|
3664
3531
|
} catch (e) {
|
|
3665
3532
|
}
|
|
@@ -3781,7 +3648,7 @@ function getTokenTrend(days = 0, startDate, endDate) {
|
|
|
3781
3648
|
}
|
|
3782
3649
|
function resetTokenStats() {
|
|
3783
3650
|
const statsPath = getStatsPath();
|
|
3784
|
-
if (
|
|
3651
|
+
if (existsSync8(statsPath)) {
|
|
3785
3652
|
try {
|
|
3786
3653
|
unlinkSync2(statsPath);
|
|
3787
3654
|
} catch {
|
|
@@ -3989,7 +3856,7 @@ async function analyzeWithLLM(prompt, config) {
|
|
|
3989
3856
|
}
|
|
3990
3857
|
if (attempt < maxRetries) {
|
|
3991
3858
|
console.error(`[AgentMoss] LLM call failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${retryCfg.retryInterval}s:`, err.message);
|
|
3992
|
-
await new Promise((
|
|
3859
|
+
await new Promise((resolve7) => setTimeout(resolve7, retryCfg.retryInterval * 1e3));
|
|
3993
3860
|
} else {
|
|
3994
3861
|
clearTimeout(totalTimeoutTimer);
|
|
3995
3862
|
console.error("[AgentMoss] LLM call failed after all retries:", err.message);
|
|
@@ -4427,9 +4294,9 @@ var require_bindings = __commonJS({
|
|
|
4427
4294
|
init_esm_shims();
|
|
4428
4295
|
var fs4 = __require("fs");
|
|
4429
4296
|
var path3 = __require("path");
|
|
4430
|
-
var
|
|
4297
|
+
var fileURLToPath10 = require_file_uri_to_path();
|
|
4431
4298
|
var join6 = path3.join;
|
|
4432
|
-
var
|
|
4299
|
+
var dirname8 = path3.dirname;
|
|
4433
4300
|
var exists = fs4.accessSync && function(path4) {
|
|
4434
4301
|
try {
|
|
4435
4302
|
fs4.accessSync(path4);
|
|
@@ -4539,12 +4406,12 @@ var require_bindings = __commonJS({
|
|
|
4539
4406
|
Error.stackTraceLimit = origSTL;
|
|
4540
4407
|
var fileSchema = "file://";
|
|
4541
4408
|
if (fileName.indexOf(fileSchema) === 0) {
|
|
4542
|
-
fileName =
|
|
4409
|
+
fileName = fileURLToPath10(fileName);
|
|
4543
4410
|
}
|
|
4544
4411
|
return fileName;
|
|
4545
4412
|
};
|
|
4546
4413
|
exports.getRoot = function getRoot(file) {
|
|
4547
|
-
var dir =
|
|
4414
|
+
var dir = dirname8(file), prev;
|
|
4548
4415
|
while (true) {
|
|
4549
4416
|
if (dir === ".") {
|
|
4550
4417
|
dir = process.cwd();
|
|
@@ -4750,13 +4617,13 @@ var require_backup = __commonJS({
|
|
|
4750
4617
|
var runBackup = (backup, handler) => {
|
|
4751
4618
|
let rate = 0;
|
|
4752
4619
|
let useDefault = true;
|
|
4753
|
-
return new Promise((
|
|
4620
|
+
return new Promise((resolve7, reject) => {
|
|
4754
4621
|
setImmediate(function step() {
|
|
4755
4622
|
try {
|
|
4756
4623
|
const progress = backup.transfer(rate);
|
|
4757
4624
|
if (!progress.remainingPages) {
|
|
4758
4625
|
backup.close();
|
|
4759
|
-
|
|
4626
|
+
resolve7(progress);
|
|
4760
4627
|
return;
|
|
4761
4628
|
}
|
|
4762
4629
|
if (useDefault) {
|
|
@@ -5385,11 +5252,11 @@ init_esm_shims();
|
|
|
5385
5252
|
init_runtime_config();
|
|
5386
5253
|
init_token_stats();
|
|
5387
5254
|
import { Hono } from "hono";
|
|
5388
|
-
import { readFileSync as
|
|
5389
|
-
import { join as join5, dirname as
|
|
5390
|
-
import { fileURLToPath as
|
|
5391
|
-
var
|
|
5392
|
-
var STATIC_DIR = join5(
|
|
5255
|
+
import { readFileSync as readFileSync10, existsSync as existsSync10 } from "fs";
|
|
5256
|
+
import { join as join5, dirname as dirname7 } from "path";
|
|
5257
|
+
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
5258
|
+
var __dirname7 = dirname7(fileURLToPath8(import.meta.url));
|
|
5259
|
+
var STATIC_DIR = join5(__dirname7, "static");
|
|
5393
5260
|
var CONSOLE_TOKEN_ENV = "AGENT_MOSS_CONSOLE_TOKEN";
|
|
5394
5261
|
function getConsoleToken() {
|
|
5395
5262
|
return process.env[CONSOLE_TOKEN_ENV] || "";
|
|
@@ -5414,8 +5281,8 @@ function createConsoleRouter() {
|
|
|
5414
5281
|
console2.use("/api/*", authMiddleware());
|
|
5415
5282
|
const serveIndex = (c) => {
|
|
5416
5283
|
const indexFile = join5(STATIC_DIR, "index.html");
|
|
5417
|
-
if (
|
|
5418
|
-
return c.html(
|
|
5284
|
+
if (existsSync10(indexFile)) {
|
|
5285
|
+
return c.html(readFileSync10(indexFile, "utf-8"));
|
|
5419
5286
|
}
|
|
5420
5287
|
return c.html("<h1>AgentMoss Policy Console</h1><p>Frontend not built. Use /console/api/* endpoints.</p>");
|
|
5421
5288
|
};
|
|
@@ -5506,13 +5373,13 @@ function createConsoleRouter() {
|
|
|
5506
5373
|
if (!/^[A-Za-z0-9_-]+$/.test(skillId)) {
|
|
5507
5374
|
return c.json({ error: "invalid skill_id" }, 400);
|
|
5508
5375
|
}
|
|
5509
|
-
const skillPath = join5(
|
|
5510
|
-
if (!
|
|
5511
|
-
const builtinPath = join5(
|
|
5512
|
-
if (
|
|
5376
|
+
const skillPath = join5(dirname7(getRuntimeConfigPath()), "agent_moss_skills", `${skillId}.md`);
|
|
5377
|
+
if (!existsSync10(skillPath)) {
|
|
5378
|
+
const builtinPath = join5(__dirname7, "..", "..", "agent_moss", "skills", `${skillId}.md`);
|
|
5379
|
+
if (existsSync10(builtinPath)) return c.text(readFileSync10(builtinPath, "utf-8"));
|
|
5513
5380
|
return c.json({ error: "skill not found" }, 404);
|
|
5514
5381
|
}
|
|
5515
|
-
return c.text(
|
|
5382
|
+
return c.text(readFileSync10(skillPath, "utf-8"));
|
|
5516
5383
|
});
|
|
5517
5384
|
console2.get("/api/agents", (c) => {
|
|
5518
5385
|
const rc = loadRuntimeConfig();
|
|
@@ -5596,12 +5463,12 @@ function createApp() {
|
|
|
5596
5463
|
}
|
|
5597
5464
|
async function findFreePort(startPort, host = "127.0.0.1", scan = 100) {
|
|
5598
5465
|
for (let port = startPort; port < startPort + scan; port++) {
|
|
5599
|
-
const free = await new Promise((
|
|
5466
|
+
const free = await new Promise((resolve7) => {
|
|
5600
5467
|
const server = net.createServer();
|
|
5601
5468
|
server.listen(port, host, () => {
|
|
5602
|
-
server.close(() =>
|
|
5469
|
+
server.close(() => resolve7(true));
|
|
5603
5470
|
});
|
|
5604
|
-
server.on("error", () =>
|
|
5471
|
+
server.on("error", () => resolve7(false));
|
|
5605
5472
|
});
|
|
5606
5473
|
if (free) {
|
|
5607
5474
|
if (port !== startPort) {
|
|
@@ -5626,7 +5493,7 @@ async function startServer(host = "127.0.0.1", port = 9090) {
|
|
|
5626
5493
|
}
|
|
5627
5494
|
|
|
5628
5495
|
// src/cli.ts
|
|
5629
|
-
import { fileURLToPath as
|
|
5496
|
+
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
5630
5497
|
import { realpathSync } from "fs";
|
|
5631
5498
|
function printHelp() {
|
|
5632
5499
|
console.log(`AgentMoss security analysis engine (TypeScript v${version})
|
|
@@ -5717,7 +5584,7 @@ async function main() {
|
|
|
5717
5584
|
const { execSync } = await import("child_process");
|
|
5718
5585
|
const fs4 = await import("fs");
|
|
5719
5586
|
const path3 = await import("path");
|
|
5720
|
-
const { fileURLToPath:
|
|
5587
|
+
const { fileURLToPath: fileURLToPath10 } = await import("url");
|
|
5721
5588
|
if (process.getuid?.() !== 0) {
|
|
5722
5589
|
try {
|
|
5723
5590
|
execSync("sudo -n true", { stdio: "ignore", timeout: 5e3 });
|
|
@@ -5732,18 +5599,18 @@ async function main() {
|
|
|
5732
5599
|
execSync(sudoArgs.join(" "), { stdio: "inherit" });
|
|
5733
5600
|
process.exit(0);
|
|
5734
5601
|
}
|
|
5735
|
-
const
|
|
5736
|
-
const
|
|
5737
|
-
let srcPath = path3.join(
|
|
5602
|
+
const __filename6 = fileURLToPath10(import.meta.url);
|
|
5603
|
+
const __dirname8 = path3.dirname(__filename6);
|
|
5604
|
+
let srcPath = path3.join(__dirname8, "data", "agent_moss.service");
|
|
5738
5605
|
if (!fs4.existsSync(srcPath)) {
|
|
5739
|
-
srcPath = path3.join(
|
|
5606
|
+
srcPath = path3.join(__dirname8, "..", "src", "data", "agent_moss.service");
|
|
5740
5607
|
}
|
|
5741
5608
|
if (!fs4.existsSync(srcPath)) {
|
|
5742
5609
|
console.error("\u9519\u8BEF\uFF1A\u627E\u4E0D\u5230 agent_moss.service \u6A21\u677F\u6587\u4EF6");
|
|
5743
5610
|
process.exit(1);
|
|
5744
5611
|
}
|
|
5745
5612
|
const which = execSync("which agent-moss 2>/dev/null || true", { encoding: "utf-8" }).trim();
|
|
5746
|
-
const binPath = which || `${process.execPath} ${path3.join(
|
|
5613
|
+
const binPath = which || `${process.execPath} ${path3.join(__dirname8, "cli.js")}`;
|
|
5747
5614
|
let content = fs4.readFileSync(srcPath, "utf-8");
|
|
5748
5615
|
content = content.replace("__AGENT_MOSS_BIN__", binPath);
|
|
5749
5616
|
const dst = "/etc/systemd/system/agent-moss.service";
|
|
@@ -5787,13 +5654,13 @@ async function main() {
|
|
|
5787
5654
|
let version2 = "";
|
|
5788
5655
|
for (let port = 9090; port <= 9095; port++) {
|
|
5789
5656
|
try {
|
|
5790
|
-
const data = await new Promise((
|
|
5657
|
+
const data = await new Promise((resolve7, reject) => {
|
|
5791
5658
|
const req = http.get(`http://127.0.0.1:${port}/api/v1/health`, { timeout: 2e3 }, (res) => {
|
|
5792
5659
|
let body = "";
|
|
5793
5660
|
res.on("data", (chunk) => body += chunk);
|
|
5794
5661
|
res.on("end", () => {
|
|
5795
5662
|
try {
|
|
5796
|
-
|
|
5663
|
+
resolve7(JSON.parse(body));
|
|
5797
5664
|
} catch {
|
|
5798
5665
|
reject();
|
|
5799
5666
|
}
|
|
@@ -5821,13 +5688,13 @@ async function main() {
|
|
|
5821
5688
|
console.log(` Systemd: \u672A\u6CE8\u518C\uFF08\u8FD0\u884C agent-moss install --enable \u5B89\u88C5\uFF09`);
|
|
5822
5689
|
}
|
|
5823
5690
|
try {
|
|
5824
|
-
const data = await new Promise((
|
|
5691
|
+
const data = await new Promise((resolve7, reject) => {
|
|
5825
5692
|
const req = http.get(`http://127.0.0.1:${foundPort}/console/api/config`, { timeout: 3e3 }, (res) => {
|
|
5826
5693
|
let body = "";
|
|
5827
5694
|
res.on("data", (chunk) => body += chunk);
|
|
5828
5695
|
res.on("end", () => {
|
|
5829
5696
|
try {
|
|
5830
|
-
|
|
5697
|
+
resolve7(JSON.parse(body));
|
|
5831
5698
|
} catch {
|
|
5832
5699
|
reject();
|
|
5833
5700
|
}
|
|
@@ -5874,9 +5741,9 @@ async function main() {
|
|
|
5874
5741
|
var isMain = (() => {
|
|
5875
5742
|
try {
|
|
5876
5743
|
if (!process.argv[1]) return false;
|
|
5877
|
-
const thisFile = realpathSync(
|
|
5744
|
+
const thisFile = realpathSync(fileURLToPath9(import.meta.url));
|
|
5878
5745
|
const argv1 = realpathSync(
|
|
5879
|
-
process.argv[1].startsWith("file://") ?
|
|
5746
|
+
process.argv[1].startsWith("file://") ? fileURLToPath9(process.argv[1]) : process.argv[1]
|
|
5880
5747
|
);
|
|
5881
5748
|
return thisFile === argv1;
|
|
5882
5749
|
} catch {
|