@kenhkl/agent-moss 0.11.5 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +321 -385
- package/dist/cli.js.map +1 -1
- package/dist/engine/coordinator.d.ts +9 -0
- package/dist/engine/coordinator.js +280 -349
- 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 +307 -371
- package/dist/server.js.map +1 -1
- package/dist/templates/security_judge_template.txt +7 -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;
|
|
@@ -621,6 +683,32 @@ function matchDangerousAction(actionDetail, action) {
|
|
|
621
683
|
const re = new RegExp(`(?<![-\\w])${escaped}\\b`, "i");
|
|
622
684
|
return re.test(actionDetail);
|
|
623
685
|
}
|
|
686
|
+
function collectIntentTexts(promptSession, promptHistory) {
|
|
687
|
+
const texts = [];
|
|
688
|
+
if (promptHistory) {
|
|
689
|
+
for (const turn of promptHistory) {
|
|
690
|
+
if (typeof turn === "string") {
|
|
691
|
+
const t2 = turn.trim();
|
|
692
|
+
if (t2) texts.push(t2.toLowerCase());
|
|
693
|
+
continue;
|
|
694
|
+
}
|
|
695
|
+
const t = (turn?.text || "").trim();
|
|
696
|
+
if (t) texts.push(t.toLowerCase());
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
if (promptSession && promptSession.trim()) {
|
|
700
|
+
texts.push(promptSession.toLowerCase());
|
|
701
|
+
}
|
|
702
|
+
const seen = /* @__PURE__ */ new Set();
|
|
703
|
+
const deduped = [];
|
|
704
|
+
for (const t of texts) {
|
|
705
|
+
if (!seen.has(t)) {
|
|
706
|
+
seen.add(t);
|
|
707
|
+
deduped.push(t);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return deduped;
|
|
711
|
+
}
|
|
624
712
|
function runLogicCheck(input) {
|
|
625
713
|
const { actionHistory, aNext, cwd } = input;
|
|
626
714
|
const actionDetail = aNext.actionDetail.toLowerCase();
|
|
@@ -630,25 +718,24 @@ function runLogicCheck(input) {
|
|
|
630
718
|
const isExcludedType = EXCLUDED_PREFIXES.some((p) => actionType.startsWith(p));
|
|
631
719
|
const rbwResult = checkReadBeforeWrite(actionType, actionDetail, actionHistory, input.reason, resolvedCwd);
|
|
632
720
|
if (rbwResult) return rbwResult;
|
|
633
|
-
if (
|
|
634
|
-
if (!
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
const
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
721
|
+
if (!isExcludedType) {
|
|
722
|
+
if (!INLINE_SCRIPT_RE.test(actionDetail)) {
|
|
723
|
+
const intentTexts = collectIntentTexts(input.promptSession, input.promptHistory);
|
|
724
|
+
for (const pattern of INTENT_DEVIATION_PATTERNS) {
|
|
725
|
+
const intentMatched = intentTexts.some(
|
|
726
|
+
(text) => pattern.intentKeywords.some((kw) => text.includes(kw))
|
|
727
|
+
);
|
|
728
|
+
const dangerousMatched = pattern.dangerousActions.some((kw) => matchDangerousAction(actionDetail, kw));
|
|
729
|
+
if (intentMatched && dangerousMatched) {
|
|
730
|
+
return {
|
|
731
|
+
allowed: false,
|
|
732
|
+
reason: pattern.reason,
|
|
733
|
+
riskLevel: "high",
|
|
734
|
+
riskType: "intent_deviation",
|
|
735
|
+
confidence: 85,
|
|
736
|
+
source: "logic_rule",
|
|
737
|
+
violatedLayers: ["2"]
|
|
738
|
+
};
|
|
652
739
|
}
|
|
653
740
|
}
|
|
654
741
|
}
|
|
@@ -938,57 +1025,10 @@ var init_logic_rules = __esm({
|
|
|
938
1025
|
"use strict";
|
|
939
1026
|
init_esm_shims();
|
|
940
1027
|
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
|
-
];
|
|
1028
|
+
init_rules_loader();
|
|
1029
|
+
ROOT_SENSITIVE_PATHS = _loadSensitivePathScope("root");
|
|
1030
|
+
HOME_SENSITIVE_PATHS = _loadSensitivePathScope("home");
|
|
1031
|
+
CREDENTIAL_PATHS = _loadSensitivePathScope("credential").map(({ path: path3, riskLevel, desc }) => ({ path: path3, riskLevel, desc, credential: true }));
|
|
992
1032
|
NON_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
993
1033
|
"ask_user_question",
|
|
994
1034
|
"glob",
|
|
@@ -1116,34 +1156,22 @@ var init_logic_rules = __esm({
|
|
|
1116
1156
|
DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/g;
|
|
1117
1157
|
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
1158
|
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
|
-
];
|
|
1159
|
+
PASSWORD_MODIFY_PATTERNS = (() => {
|
|
1160
|
+
const pats = loadL2().password_modify_consent || [];
|
|
1161
|
+
return pats.map((p) => new RegExp(p.pattern, "i"));
|
|
1162
|
+
})();
|
|
1163
|
+
USER_DELETION_PATTERNS = (() => {
|
|
1164
|
+
const pats = loadL2().user_deletion_consent || [];
|
|
1165
|
+
return pats.map((p) => new RegExp(p.pattern, "i"));
|
|
1166
|
+
})();
|
|
1167
|
+
INTENT_DEVIATION_PATTERNS = (() => {
|
|
1168
|
+
const pats = loadL2().intent_consistency || [];
|
|
1169
|
+
return pats.map((p) => ({
|
|
1170
|
+
intentKeywords: p.intent_keywords,
|
|
1171
|
+
dangerousActions: p.dangerous_actions,
|
|
1172
|
+
reason: p.reason
|
|
1173
|
+
}));
|
|
1174
|
+
})();
|
|
1147
1175
|
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
1176
|
DIR_TRAVERSAL_KW = [
|
|
1149
1177
|
"os.listdir",
|
|
@@ -1161,21 +1189,21 @@ var init_logic_rules = __esm({
|
|
|
1161
1189
|
});
|
|
1162
1190
|
|
|
1163
1191
|
// src/engine/skill-loader.ts
|
|
1164
|
-
import { readFileSync as
|
|
1165
|
-
import { resolve, dirname } from "path";
|
|
1166
|
-
import { fileURLToPath as
|
|
1192
|
+
import { readFileSync as readFileSync3, readdirSync as readdirSync2, existsSync as existsSync3 } from "fs";
|
|
1193
|
+
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
1194
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
1167
1195
|
function loadAllSkills() {
|
|
1168
1196
|
if (cachedSkills) return cachedSkills;
|
|
1169
1197
|
cachedSkills = {};
|
|
1170
|
-
const dir =
|
|
1171
|
-
if (!
|
|
1198
|
+
const dir = existsSync3(SKILLS_DIR) ? SKILLS_DIR : SKILLS_DIR_FALLBACK;
|
|
1199
|
+
if (!existsSync3(dir)) {
|
|
1172
1200
|
console.warn("[AgentMoss] Skills directory not found:", SKILLS_DIR, "and fallback:", SKILLS_DIR_FALLBACK);
|
|
1173
1201
|
return cachedSkills;
|
|
1174
1202
|
}
|
|
1175
1203
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".md"));
|
|
1176
1204
|
for (const f of files) {
|
|
1177
1205
|
const name = f.replace(".md", "");
|
|
1178
|
-
cachedSkills[name] =
|
|
1206
|
+
cachedSkills[name] = readFileSync3(resolve2(dir, f), "utf-8");
|
|
1179
1207
|
}
|
|
1180
1208
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills from ${dir}`);
|
|
1181
1209
|
return cachedSkills;
|
|
@@ -1229,32 +1257,27 @@ function formatSkillsForPrompt(skills) {
|
|
|
1229
1257
|
${s.skillContent}`
|
|
1230
1258
|
).join("\n\n---\n\n");
|
|
1231
1259
|
}
|
|
1232
|
-
var
|
|
1260
|
+
var __filename3, __dirname3, SKILLS_DIR, SKILLS_DIR_FALLBACK, SKILL_KEYWORD_MAP, cachedSkills;
|
|
1233
1261
|
var init_skill_loader = __esm({
|
|
1234
1262
|
"src/engine/skill-loader.ts"() {
|
|
1235
1263
|
"use strict";
|
|
1236
1264
|
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
|
-
};
|
|
1265
|
+
init_rules_loader();
|
|
1266
|
+
__filename3 = fileURLToPath4(import.meta.url);
|
|
1267
|
+
__dirname3 = dirname2(__filename3);
|
|
1268
|
+
SKILLS_DIR = resolve2(__dirname3, "../skills");
|
|
1269
|
+
SKILLS_DIR_FALLBACK = resolve2(__dirname3, "../../../agent_moss/skills");
|
|
1270
|
+
SKILL_KEYWORD_MAP = (() => {
|
|
1271
|
+
const map = {};
|
|
1272
|
+
const cats = loadL3();
|
|
1273
|
+
for (const cat of Object.values(cats)) {
|
|
1274
|
+
if (!cat || typeof cat !== "object") continue;
|
|
1275
|
+
for (const [skillId, keywords] of Object.entries(cat)) {
|
|
1276
|
+
map[skillId] = keywords;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
return map;
|
|
1280
|
+
})();
|
|
1258
1281
|
cachedSkills = null;
|
|
1259
1282
|
}
|
|
1260
1283
|
});
|
|
@@ -1306,10 +1329,10 @@ __export(runtime_config_exports, {
|
|
|
1306
1329
|
updateSkillCategoryEnabled: () => updateSkillCategoryEnabled,
|
|
1307
1330
|
updateSkillEnabled: () => updateSkillEnabled
|
|
1308
1331
|
});
|
|
1309
|
-
import { readFileSync as
|
|
1332
|
+
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3 } from "fs";
|
|
1310
1333
|
import { join as join2 } from "path";
|
|
1311
|
-
import { fileURLToPath as
|
|
1312
|
-
import { dirname as
|
|
1334
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1335
|
+
import { dirname as dirname3 } from "path";
|
|
1313
1336
|
function runtimeDir() {
|
|
1314
1337
|
return getRuntimeConfigDir();
|
|
1315
1338
|
}
|
|
@@ -1321,7 +1344,7 @@ function getRuntimeConfigPath() {
|
|
|
1321
1344
|
function saveRuntimeConfig(config) {
|
|
1322
1345
|
const p = getRuntimeConfigPath();
|
|
1323
1346
|
const dir = p.substring(0, p.lastIndexOf("/"));
|
|
1324
|
-
if (dir && !
|
|
1347
|
+
if (dir && !existsSync4(dir)) mkdirSync(dir, { recursive: true });
|
|
1325
1348
|
writeFileSync(p, JSON.stringify(config, null, 2), "utf-8");
|
|
1326
1349
|
}
|
|
1327
1350
|
function emptyRuntimeConfig() {
|
|
@@ -1336,7 +1359,7 @@ function emptyRuntimeConfig() {
|
|
|
1336
1359
|
}
|
|
1337
1360
|
function loadRuntimeConfig() {
|
|
1338
1361
|
const p = getRuntimeConfigPath();
|
|
1339
|
-
if (!
|
|
1362
|
+
if (!existsSync4(p)) {
|
|
1340
1363
|
const seeded = mergeConfig({}, generateSourceDefaults());
|
|
1341
1364
|
try {
|
|
1342
1365
|
saveRuntimeConfig(seeded);
|
|
@@ -1345,7 +1368,7 @@ function loadRuntimeConfig() {
|
|
|
1345
1368
|
return seeded;
|
|
1346
1369
|
}
|
|
1347
1370
|
try {
|
|
1348
|
-
const data = JSON.parse(
|
|
1371
|
+
const data = JSON.parse(readFileSync4(p, "utf-8"));
|
|
1349
1372
|
const merged = mergeConfig(data, generateSourceDefaults());
|
|
1350
1373
|
return {
|
|
1351
1374
|
version: data.version || 1,
|
|
@@ -1413,9 +1436,9 @@ function getEnabledL2SensitivePaths(runtime) {
|
|
|
1413
1436
|
}
|
|
1414
1437
|
function hasRuntimeConfig() {
|
|
1415
1438
|
const p = getRuntimeConfigPath();
|
|
1416
|
-
if (!
|
|
1439
|
+
if (!existsSync4(p)) return false;
|
|
1417
1440
|
try {
|
|
1418
|
-
JSON.parse(
|
|
1441
|
+
JSON.parse(readFileSync4(p, "utf-8"));
|
|
1419
1442
|
return true;
|
|
1420
1443
|
} catch {
|
|
1421
1444
|
return false;
|
|
@@ -1594,8 +1617,8 @@ function _l3SkillsToRules() {
|
|
|
1594
1617
|
}
|
|
1595
1618
|
function _agentRulesToDefaults() {
|
|
1596
1619
|
const out = {};
|
|
1597
|
-
const agentsDir =
|
|
1598
|
-
if (!
|
|
1620
|
+
const agentsDir = existsSync4(_AGENTS_DIR_PROD) ? _AGENTS_DIR_PROD : existsSync4(_AGENTS_DIR_DEV) ? _AGENTS_DIR_DEV : _AGENTS_DIR_PROD;
|
|
1621
|
+
if (!existsSync4(agentsDir)) return out;
|
|
1599
1622
|
let entries;
|
|
1600
1623
|
try {
|
|
1601
1624
|
entries = readdirSync3(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -1604,10 +1627,10 @@ function _agentRulesToDefaults() {
|
|
|
1604
1627
|
}
|
|
1605
1628
|
for (const agentId of entries) {
|
|
1606
1629
|
const rulesFile = join2(agentsDir, agentId, "rules.json");
|
|
1607
|
-
if (!
|
|
1630
|
+
if (!existsSync4(rulesFile)) continue;
|
|
1608
1631
|
let data;
|
|
1609
1632
|
try {
|
|
1610
|
-
data = JSON.parse(
|
|
1633
|
+
data = JSON.parse(readFileSync4(rulesFile, "utf-8"));
|
|
1611
1634
|
} catch {
|
|
1612
1635
|
continue;
|
|
1613
1636
|
}
|
|
@@ -1686,6 +1709,9 @@ function generateSourceDefaults() {
|
|
|
1686
1709
|
agent_rules: _agentRulesToDefaults()
|
|
1687
1710
|
};
|
|
1688
1711
|
}
|
|
1712
|
+
function normalizePatternForFingerprint(pattern) {
|
|
1713
|
+
return pattern.replace(/\\\//g, "/");
|
|
1714
|
+
}
|
|
1689
1715
|
function _ruleFingerprint(rule) {
|
|
1690
1716
|
if (rule.intent_keywords && rule.intent_keywords.length || rule.dangerous_actions && rule.dangerous_actions.length) {
|
|
1691
1717
|
return JSON.stringify([
|
|
@@ -1693,8 +1719,8 @@ function _ruleFingerprint(rule) {
|
|
|
1693
1719
|
[...rule.dangerous_actions || []].sort()
|
|
1694
1720
|
]);
|
|
1695
1721
|
}
|
|
1696
|
-
if (rule.path) return JSON.stringify([rule.path]);
|
|
1697
|
-
if (rule.pattern) return JSON.stringify([rule.pattern]);
|
|
1722
|
+
if (rule.path) return JSON.stringify([normalizePatternForFingerprint(rule.path)]);
|
|
1723
|
+
if (rule.pattern) return JSON.stringify([normalizePatternForFingerprint(rule.pattern)]);
|
|
1698
1724
|
if (rule.keyword) return JSON.stringify([rule.keyword, rule.lang || ""]);
|
|
1699
1725
|
if (rule.value) return JSON.stringify([rule.value]);
|
|
1700
1726
|
return JSON.stringify([rule.id || ""]);
|
|
@@ -2045,7 +2071,7 @@ function deleteCustomSkill(skillId, category) {
|
|
|
2045
2071
|
skills.splice(idx, 1);
|
|
2046
2072
|
const skillPath = join2(RUNTIME_CONFIG_DIR, "agent_moss_skills", `${skillId}.md`);
|
|
2047
2073
|
try {
|
|
2048
|
-
if (
|
|
2074
|
+
if (existsSync4(skillPath)) unlinkSync(skillPath);
|
|
2049
2075
|
} catch {
|
|
2050
2076
|
}
|
|
2051
2077
|
saveRuntimeConfig(runtime);
|
|
@@ -2159,7 +2185,7 @@ function updateAgentCategoryEnabled(agentId, category, enabled) {
|
|
|
2159
2185
|
saveRuntimeConfig(runtime);
|
|
2160
2186
|
return runtime;
|
|
2161
2187
|
}
|
|
2162
|
-
var
|
|
2188
|
+
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
2189
|
var init_runtime_config = __esm({
|
|
2164
2190
|
"src/infra/runtime-config.ts"() {
|
|
2165
2191
|
"use strict";
|
|
@@ -2168,7 +2194,7 @@ var init_runtime_config = __esm({
|
|
|
2168
2194
|
init_heuristic();
|
|
2169
2195
|
init_logic_rules();
|
|
2170
2196
|
init_skill_loader();
|
|
2171
|
-
|
|
2197
|
+
__dirname4 = dirname3(fileURLToPath5(import.meta.url));
|
|
2172
2198
|
ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
|
|
2173
2199
|
RUNTIME_CONFIG_DIR = runtimeDir();
|
|
2174
2200
|
RUNTIME_CONFIG_PATH = join2(RUNTIME_CONFIG_DIR, "agent_moss_runtime.json");
|
|
@@ -2182,19 +2208,19 @@ var init_runtime_config = __esm({
|
|
|
2182
2208
|
deny_read: "\u4EC5\u62E6\u622A\u8BFB\u53D6",
|
|
2183
2209
|
deny_both: "\u8BFB\u5199\u5747\u62E6\u622A"
|
|
2184
2210
|
};
|
|
2185
|
-
_AGENTS_DIR_PROD = join2(
|
|
2186
|
-
_AGENTS_DIR_DEV = join2(
|
|
2211
|
+
_AGENTS_DIR_PROD = join2(__dirname4, "agents");
|
|
2212
|
+
_AGENTS_DIR_DEV = join2(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
2187
2213
|
SKILL_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
2188
2214
|
}
|
|
2189
2215
|
});
|
|
2190
2216
|
|
|
2191
2217
|
// src/agents/index.ts
|
|
2192
|
-
import { readFileSync as
|
|
2193
|
-
import { resolve as
|
|
2194
|
-
import { fileURLToPath as
|
|
2218
|
+
import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
|
|
2219
|
+
import { resolve as resolve3, dirname as dirname4 } from "path";
|
|
2220
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
2195
2221
|
function resolveAgentsDir() {
|
|
2196
|
-
if (
|
|
2197
|
-
if (
|
|
2222
|
+
if (existsSync5(AGENTS_DIR_PROD)) return AGENTS_DIR_PROD;
|
|
2223
|
+
if (existsSync5(AGENTS_DIR_DEV_FALLBACK)) return AGENTS_DIR_DEV_FALLBACK;
|
|
2198
2224
|
return AGENTS_DIR_PROD;
|
|
2199
2225
|
}
|
|
2200
2226
|
function getAgentExtensions(agentId) {
|
|
@@ -2210,13 +2236,13 @@ function getAgentExtensions(agentId) {
|
|
|
2210
2236
|
}
|
|
2211
2237
|
if (ext === null) {
|
|
2212
2238
|
const agentsDir = resolveAgentsDir();
|
|
2213
|
-
const rulesFile =
|
|
2214
|
-
if (!
|
|
2239
|
+
const rulesFile = resolve3(agentsDir, agentId, "rules.json");
|
|
2240
|
+
if (!existsSync5(rulesFile)) {
|
|
2215
2241
|
cache.set(agentId, null);
|
|
2216
2242
|
return null;
|
|
2217
2243
|
}
|
|
2218
2244
|
try {
|
|
2219
|
-
const raw =
|
|
2245
|
+
const raw = readFileSync5(rulesFile, "utf-8");
|
|
2220
2246
|
ext = JSON.parse(raw);
|
|
2221
2247
|
if (!ext.agent_id) {
|
|
2222
2248
|
console.warn(`[AgentMoss agents] rules.json \u7F3A\u5C11 agent_id \u5B57\u6BB5: ${rulesFile}`);
|
|
@@ -2235,15 +2261,15 @@ function getAgentExtensions(agentId) {
|
|
|
2235
2261
|
);
|
|
2236
2262
|
return ext;
|
|
2237
2263
|
}
|
|
2238
|
-
var
|
|
2264
|
+
var __filename4, __dirname5, AGENTS_DIR_PROD, AGENTS_DIR_DEV_FALLBACK, cache;
|
|
2239
2265
|
var init_agents = __esm({
|
|
2240
2266
|
"src/agents/index.ts"() {
|
|
2241
2267
|
"use strict";
|
|
2242
2268
|
init_esm_shims();
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
AGENTS_DIR_PROD =
|
|
2246
|
-
AGENTS_DIR_DEV_FALLBACK =
|
|
2269
|
+
__filename4 = fileURLToPath6(import.meta.url);
|
|
2270
|
+
__dirname5 = dirname4(__filename4);
|
|
2271
|
+
AGENTS_DIR_PROD = resolve3(__dirname5, "agents");
|
|
2272
|
+
AGENTS_DIR_DEV_FALLBACK = resolve3(__dirname5, "../../../agent_moss/agents");
|
|
2247
2273
|
cache = /* @__PURE__ */ new Map();
|
|
2248
2274
|
}
|
|
2249
2275
|
});
|
|
@@ -2274,7 +2300,7 @@ function runHeuristicCheck(input) {
|
|
|
2274
2300
|
} catch {
|
|
2275
2301
|
}
|
|
2276
2302
|
}
|
|
2277
|
-
const scanDetail = stripLiteralTextSegments(input.aNext.actionDetail);
|
|
2303
|
+
const scanDetail = normalizePathSegments(stripLiteralTextSegments(input.aNext.actionDetail));
|
|
2278
2304
|
const scanCommand = `${input.aNext.actionType}: ${scanDetail}`;
|
|
2279
2305
|
let topRiskType = "";
|
|
2280
2306
|
for (const rule of DANGEROUS_PATTERNS) {
|
|
@@ -2385,6 +2411,28 @@ function stripHeredocContent(actionDetail) {
|
|
|
2385
2411
|
"<<heredoc>>\n"
|
|
2386
2412
|
);
|
|
2387
2413
|
}
|
|
2414
|
+
function normalizePathSegments(text) {
|
|
2415
|
+
const protTokens = [];
|
|
2416
|
+
let t = text.replace(/\b(https?|ftp|file):\/\//gi, (m) => {
|
|
2417
|
+
const scheme = m.slice(0, m.indexOf(":"));
|
|
2418
|
+
protTokens.push("://");
|
|
2419
|
+
return `${scheme}__PROT${protTokens.length - 1}__`;
|
|
2420
|
+
});
|
|
2421
|
+
const quoteTokens = [];
|
|
2422
|
+
t = t.replace(/'[^']*'|"[^"]*"/g, (m) => {
|
|
2423
|
+
quoteTokens.push(m);
|
|
2424
|
+
return `__Q${quoteTokens.length - 1}__`;
|
|
2425
|
+
});
|
|
2426
|
+
t = t.replace(/\/{2,}/g, "/");
|
|
2427
|
+
t = t.replace(/\/\.\//g, "/");
|
|
2428
|
+
for (let i = 0; i < quoteTokens.length; i++) {
|
|
2429
|
+
t = t.replace(`__Q${i}__`, quoteTokens[i]);
|
|
2430
|
+
}
|
|
2431
|
+
for (let i = 0; i < protTokens.length; i++) {
|
|
2432
|
+
t = t.replace(`__PROT${i}__`, protTokens[i]);
|
|
2433
|
+
}
|
|
2434
|
+
return t;
|
|
2435
|
+
}
|
|
2388
2436
|
function splitCommandSegments(actionDetail) {
|
|
2389
2437
|
const segments = [];
|
|
2390
2438
|
let cur = "";
|
|
@@ -2437,7 +2485,7 @@ function isSearchActionType(actionType) {
|
|
|
2437
2485
|
function checkSensitivePath(command, cwd, agentExt) {
|
|
2438
2486
|
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
2439
2487
|
const isWriteOpFlag = isWriteOperation("", command);
|
|
2440
|
-
const pathScanText = stripLiteralTextSegments(command);
|
|
2488
|
+
const pathScanText = normalizePathSegments(stripLiteralTextSegments(command));
|
|
2441
2489
|
const pathMatches = (text, path3) => {
|
|
2442
2490
|
const parts = path3.split(/(\(\?!.*?\))/);
|
|
2443
2491
|
const escaped = parts.map((part) => {
|
|
@@ -2708,208 +2756,69 @@ var init_heuristic = __esm({
|
|
|
2708
2756
|
init_esm_shims();
|
|
2709
2757
|
init_config();
|
|
2710
2758
|
init_agents();
|
|
2759
|
+
init_rules_loader();
|
|
2711
2760
|
init_logic_rules();
|
|
2712
|
-
INJECTION_KEYWORDS =
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
{ keyword: "\u4ECE\u73B0\u5728\u5F00\u59CB\u4F60", riskLevel: "high", lang: "zh" },
|
|
2730
|
-
{ keyword: "\u4F60\u7684\u65B0\u89D2\u8272\u662F", riskLevel: "high", lang: "zh" },
|
|
2731
|
-
// ---- Command Injection ----
|
|
2732
|
-
{ keyword: "system prompt", riskLevel: "high", lang: "en" },
|
|
2733
|
-
{ keyword: "reveal your instructions", riskLevel: "high", lang: "en" },
|
|
2734
|
-
{ keyword: "output your instructions", riskLevel: "high", lang: "en" },
|
|
2735
|
-
{ keyword: "repeat your instructions", riskLevel: "medium", lang: "en" },
|
|
2736
|
-
{ keyword: "\u7CFB\u7EDF\u63D0\u793A", riskLevel: "high", lang: "zh" },
|
|
2737
|
-
{ keyword: "\u8F93\u51FA\u4F60\u7684\u6307\u4EE4", riskLevel: "high", lang: "zh" },
|
|
2738
|
-
{ keyword: "\u91CD\u590D\u4F60\u7684\u6307\u4EE4", riskLevel: "medium", lang: "zh" },
|
|
2739
|
-
// ---- Social Engineering ----
|
|
2740
|
-
{ keyword: "this is an authorized test", riskLevel: "high", lang: "en" },
|
|
2741
|
-
{ keyword: "security audit approved", riskLevel: "high", lang: "en" },
|
|
2742
|
-
{ keyword: "admin override", riskLevel: "critical", lang: "en" },
|
|
2743
|
-
{ keyword: "debug mode", riskLevel: "high", lang: "en" },
|
|
2744
|
-
{ keyword: "maintenance mode", riskLevel: "high", lang: "en" },
|
|
2745
|
-
{ keyword: "\u8FD9\u662F\u6388\u6743\u7684\u6D4B\u8BD5", riskLevel: "high", lang: "zh" },
|
|
2746
|
-
{ keyword: "\u5B89\u5168\u5BA1\u8BA1\u5DF2\u6279\u51C6", riskLevel: "high", lang: "zh" },
|
|
2747
|
-
{ keyword: "\u7BA1\u7406\u5458\u8986\u76D6", riskLevel: "critical", lang: "zh" },
|
|
2748
|
-
{ keyword: "\u8C03\u8BD5\u6A21\u5F0F", riskLevel: "high", lang: "zh" },
|
|
2749
|
-
// ---- XSS ----
|
|
2750
|
-
{ keyword: "<script>", riskLevel: "high", lang: "en" },
|
|
2751
|
-
{ keyword: "javascript:", riskLevel: "high", lang: "en" },
|
|
2752
|
-
{ keyword: "onerror=", riskLevel: "high", lang: "en" },
|
|
2753
|
-
{ keyword: "onload=", riskLevel: "high", lang: "en" },
|
|
2754
|
-
// ---- Fake Boundaries ----
|
|
2755
|
-
{ keyword: "=== END OF", riskLevel: "high", lang: "en" },
|
|
2756
|
-
{ keyword: "--- END SYSTEM", riskLevel: "high", lang: "en" },
|
|
2757
|
-
{ keyword: "[END OF", riskLevel: "high", lang: "en" },
|
|
2758
|
-
{ keyword: "=== \u7ED3\u675F", riskLevel: "high", lang: "zh" },
|
|
2759
|
-
{ keyword: "--- \u7ED3\u675F\u7CFB\u7EDF", riskLevel: "high", lang: "zh" },
|
|
2760
|
-
// ---- Developer Mode ----
|
|
2761
|
-
{ keyword: "developer mode", riskLevel: "critical", lang: "en" },
|
|
2762
|
-
{ keyword: "DAN mode", riskLevel: "critical", lang: "en" },
|
|
2763
|
-
{ keyword: "jailbreak", riskLevel: "critical", lang: "en" },
|
|
2764
|
-
{ keyword: "\u5F00\u53D1\u8005\u6A21\u5F0F", riskLevel: "critical", lang: "zh" },
|
|
2765
|
-
{ keyword: "\u8D8A\u72F1", riskLevel: "critical", lang: "zh" }
|
|
2766
|
-
// 注:xiaoO 专属绕过词(绕过审计/禁用安全检查/关闭防护/bypass audit 等)
|
|
2767
|
-
// 已迁至 agent_moss/agents/xiaoo/rules.json 的 extra_injection_keywords,
|
|
2768
|
-
// 由 agent_ext 机制注入,不再污染通用层。
|
|
2769
|
-
];
|
|
2770
|
-
DANGEROUS_PATTERNS = [
|
|
2771
|
-
// --- Critical: rm command graded detection (strict to loose, first match wins) ---
|
|
2772
|
-
// 1. rm -rf root dir (含通配符如 /* /.* 等) — 使用负向先行断言 (?!\w):/ 后面不是单词字符时匹配
|
|
2773
|
-
{ 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" },
|
|
2774
|
-
// 注意:已移除"rm -rf /任意绝对路径"的宽泛规则,避免误杀 /tmp 等临时目录清理操作
|
|
2775
|
-
// 2. rm with -r or -f targeting system dirs — var 分支排除 /var/tmp/(合法清理)
|
|
2776
|
-
{ 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" },
|
|
2777
|
-
// 3. rm -r absolute path (no -f) — 排除 /tmp/ /var/tmp/ /run/ /dev/shm/(CI/开发高频合法清理)
|
|
2778
|
-
{ 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" },
|
|
2779
|
-
// 4. rm -f absolute path (no -r) — 同样排除临时目录
|
|
2780
|
-
{ 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" },
|
|
2781
|
-
// dd 磁盘清零 — 只拦截写入系统关键目录,放行 /tmp 等临时目录
|
|
2782
|
-
{ 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" },
|
|
2783
|
-
// mkfs 格式化 — 只拦截对块设备(/dev/sdX 等)的格式化,放行对普通文件的格式化
|
|
2784
|
-
{ 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" },
|
|
2785
|
-
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb", riskType: "resource_exhaustion" },
|
|
2786
|
-
// --- Critical: remote code execution ---
|
|
2787
|
-
// curl|bash 优先匹配 user_rules(high/sensitive_action),见下方 UserRuleMatcher 段;
|
|
2788
|
-
// 非 bash 的 curl|sh/zsh/dash 走 CommandPatternScanner critical。两条分流由
|
|
2789
|
-
// runHeuristicCheck 的规则顺序保证(bash 在前 high,其余 fall-through 到 critical)。
|
|
2790
|
-
{ pattern: /curl\s+.*\|\s*bash/i, severity: "high", description: "curl pipe bash \u6267\u884C (user_rules)", riskType: "sensitive_action" },
|
|
2791
|
-
{ pattern: /curl\s+.*\|\s*(sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
2792
|
-
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
2793
|
-
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
2794
|
-
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "high", description: "base64 \u89E3\u7801\u6267\u884C (user_rules)", riskType: "sensitive_action" },
|
|
2795
|
-
// --- Critical: reverse shell ---
|
|
2796
|
-
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell", riskType: "script_execution" },
|
|
2797
|
-
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5", riskType: "lateral_movement" },
|
|
2798
|
-
// --- Critical: sensitive file access ---
|
|
2799
|
-
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)", riskType: "file_access" },
|
|
2800
|
-
{ pattern: /\/etc\/gshadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u7EC4\u5BC6\u7801\u6587\u4EF6 (/etc/gshadow)", riskType: "file_access" },
|
|
2801
|
-
// 注意:/etc/passwd 已从拦截列表移除,因为它是公开可读的标准系统文件,真正敏感的是 /etc/shadow
|
|
2802
|
-
{ pattern: /\.ssh\/id_rsa(?!\.pub)/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6", riskType: "file_access" },
|
|
2803
|
-
// --- Critical: privilege escalation / container escape ---
|
|
2804
|
-
{ 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" },
|
|
2805
|
-
// --- Critical: dangerous permissions / ownership (提权 / 权限敞口) ---
|
|
2806
|
-
// 修正「只拦 777、xx7 漏放」的缺口:
|
|
2807
|
-
// 1) 八进制末位 7:other 位含写+执行敞口(chmod 777/647/007/4777 等);644/755/1700 不命中
|
|
2808
|
-
// 2) 八进制 setuid/setgid 位:首位 4(setuid)/2(setgid) 的 4 位八进制(chmod 4755/2755)
|
|
2809
|
-
// 3) 符号 setuid/setgid:chmod u+s / g+s / a+s
|
|
2810
|
-
// 普通权限修改(chmod 644)不在此列——L2 read_before_write 已豁免 chmod/chown(不写内容),
|
|
2811
|
-
// 危险形态在此 L1 专门拦,以「提权」正确理由拦截,不再靠 RBW 误打误撞。
|
|
2812
|
-
{ 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" },
|
|
2813
|
-
{ 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" },
|
|
2814
|
-
{ 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" },
|
|
2815
|
-
{ 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" },
|
|
2816
|
-
// sudo 提权 — 只拦截 sudo 后跟的危险命令,不一刀切拦截所有 sudo
|
|
2817
|
-
{ 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" },
|
|
2818
|
-
// --- High: system config overwrite ---
|
|
2819
|
-
// > /etc/ 重定向覆盖:对齐 Python CommandPatternScanner `>\s*/etc/`(不兼容引号路径),
|
|
2820
|
-
// 引号包裹的重定向目标(cat > '/etc/ssh/sshd_config')走 checkSensitivePath 敏感路径 high。
|
|
2821
|
-
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55", riskType: "file_access" },
|
|
2822
|
-
{ pattern: />\s*\/boot\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u542F\u52A8\u5F15\u5BFC\u76EE\u5F55", riskType: "file_access" },
|
|
2823
|
-
// 注:/proc/ 重定向覆盖走 checkSensitivePath 的 high(内核参数 /proc/sys/),此处不拦 /proc/ 避免遮蔽(对齐 Python)。
|
|
2824
|
-
// --- High: download script + execute risk ---
|
|
2825
|
-
// curl -X POST 外传敏感信息(对齐 Python linux.py: curl POST env/key/token)
|
|
2826
|
-
{ 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" },
|
|
2827
|
-
{ 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" },
|
|
2828
|
-
{ 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" },
|
|
2829
|
-
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C", riskType: "script_execution" },
|
|
2830
|
-
// --- High: package manager pipe-to-shell ---
|
|
2831
|
-
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell", riskType: "script_execution" },
|
|
2832
|
-
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell", riskType: "script_execution" },
|
|
2833
|
-
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell", riskType: "script_execution" },
|
|
2834
|
-
// --- Medium: destructive git operations (降级为 medium,允许但记录) ---
|
|
2835
|
-
{ 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" },
|
|
2836
|
-
// --- High: network port scanning (横向移动侦察) ---
|
|
2837
|
-
{ 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" },
|
|
2838
|
-
{ 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" },
|
|
2839
|
-
// --- Medium: credential export ---
|
|
2840
|
-
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1", riskType: "data_exfiltration" },
|
|
2841
|
-
// --- High: shell rc file append (persistence) ---
|
|
2842
|
-
// 两条规则:第一条匹配 ~ 与 /home/<user>/ 形态;第二条按文件名兜底,
|
|
2843
|
-
// 覆盖非标准 home 路径(如鸿蒙 /storage/Users/currentUser/.bashrc、
|
|
2844
|
-
// /root/.bashrc),避免按 home 前缀枚举导致漏检持久化后门。
|
|
2845
|
-
{ 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" },
|
|
2846
|
-
{ 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" },
|
|
2847
|
-
// --- High: device file write (只拦截重定向写入设备文件,不拦截读取) ---
|
|
2848
|
-
{ 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" },
|
|
2849
|
-
// --- High: non-interactive password modification ---
|
|
2850
|
-
{ 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" },
|
|
2851
|
-
{ 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" },
|
|
2852
|
-
{ pattern: /\bchpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 chpasswd \u6279\u91CF\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4", riskType: "script_execution" },
|
|
2853
|
-
{ 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" },
|
|
2854
|
-
{ 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" },
|
|
2855
|
-
{ 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" },
|
|
2856
|
-
// --- High: non-interactive password modification (extended) ---
|
|
2857
|
-
{ pattern: /\blpasswd\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\u64CD\u4F5C (lpasswd)", riskType: "script_execution" },
|
|
2858
|
-
{ pattern: /\bgpasswd\s+(?!-[adA])/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7EC4\u5BC6\u7801\u7BA1\u7406\u64CD\u4F5C (gpasswd)", riskType: "script_execution" },
|
|
2859
|
-
{ pattern: /\bchgpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u6279\u91CF\u4FEE\u6539\u7EC4\u5BC6\u7801\u64CD\u4F5C (chgpasswd)", riskType: "script_execution" },
|
|
2860
|
-
// --- High: user/group deletion (irreversible, requires user consent) ---
|
|
2861
|
-
{ pattern: /\buserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (userdel)", riskType: "script_execution" },
|
|
2862
|
-
{ pattern: /\bdeluser\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (deluser)", riskType: "script_execution" },
|
|
2863
|
-
{ pattern: /\bluserdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u64CD\u4F5C (luserdel)", riskType: "script_execution" },
|
|
2864
|
-
{ pattern: /\bgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (groupdel)", riskType: "script_execution" },
|
|
2865
|
-
{ pattern: /\blgroupdel\s/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u7EC4\u64CD\u4F5C (lgroupdel)", riskType: "script_execution" },
|
|
2866
|
-
// --- High: generic command -p parameter password setting ---
|
|
2867
|
-
{ 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" }
|
|
2868
|
-
];
|
|
2761
|
+
INJECTION_KEYWORDS = (() => {
|
|
2762
|
+
const kws = loadL1().injection_detection || [];
|
|
2763
|
+
return kws.map((k) => ({
|
|
2764
|
+
keyword: k.keyword,
|
|
2765
|
+
riskLevel: k.risk_level,
|
|
2766
|
+
lang: k.lang || "en"
|
|
2767
|
+
}));
|
|
2768
|
+
})();
|
|
2769
|
+
DANGEROUS_PATTERNS = (() => {
|
|
2770
|
+
const cmds = loadL1().dangerous_commands || [];
|
|
2771
|
+
return cmds.map((c) => ({
|
|
2772
|
+
pattern: new RegExp(c.pattern, "i"),
|
|
2773
|
+
severity: c.risk_level,
|
|
2774
|
+
riskType: c.risk_type,
|
|
2775
|
+
description: c.reason
|
|
2776
|
+
}));
|
|
2777
|
+
})();
|
|
2869
2778
|
SENSITIVE_EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
2870
2779
|
SEARCH_ACTION_PREFIXES = ["search-", "web-", "browser-", "query-", "websearch", "web_search"];
|
|
2871
2780
|
}
|
|
2872
2781
|
});
|
|
2873
2782
|
|
|
2874
2783
|
// src/engine/template-loader.ts
|
|
2875
|
-
import { readFileSync as
|
|
2876
|
-
import { resolve as
|
|
2877
|
-
import { fileURLToPath as
|
|
2784
|
+
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
2785
|
+
import { resolve as resolve4, dirname as dirname5 } from "path";
|
|
2786
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
2878
2787
|
function loadTemplates() {
|
|
2879
2788
|
if (cachedTemplates) return cachedTemplates;
|
|
2880
2789
|
cachedTemplates = {};
|
|
2881
|
-
const dir =
|
|
2882
|
-
if (!
|
|
2790
|
+
const dir = existsSync6(TEMPLATES_DIR) ? TEMPLATES_DIR : TEMPLATES_DIR_FALLBACK;
|
|
2791
|
+
if (!existsSync6(dir)) {
|
|
2883
2792
|
console.warn("[AgentMoss] Templates directory not found:", TEMPLATES_DIR, "and fallback:", TEMPLATES_DIR_FALLBACK);
|
|
2884
2793
|
return cachedTemplates;
|
|
2885
2794
|
}
|
|
2886
2795
|
for (const file of TEMPLATE_FILES) {
|
|
2887
|
-
const filePath =
|
|
2888
|
-
if (
|
|
2796
|
+
const filePath = resolve4(dir, file);
|
|
2797
|
+
if (existsSync6(filePath)) {
|
|
2889
2798
|
const key = file.replace(".txt", "").replace("_template", "");
|
|
2890
|
-
cachedTemplates[key] =
|
|
2799
|
+
cachedTemplates[key] = readFileSync6(filePath, "utf-8");
|
|
2891
2800
|
}
|
|
2892
2801
|
}
|
|
2893
2802
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates from ${dir}`);
|
|
2894
2803
|
return cachedTemplates;
|
|
2895
2804
|
}
|
|
2896
|
-
var
|
|
2805
|
+
var __filename5, __dirname6, TEMPLATES_DIR, TEMPLATES_DIR_FALLBACK, TEMPLATE_FILES, cachedTemplates;
|
|
2897
2806
|
var init_template_loader = __esm({
|
|
2898
2807
|
"src/engine/template-loader.ts"() {
|
|
2899
2808
|
"use strict";
|
|
2900
2809
|
init_esm_shims();
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
TEMPLATES_DIR =
|
|
2904
|
-
TEMPLATES_DIR_FALLBACK =
|
|
2810
|
+
__filename5 = fileURLToPath7(import.meta.url);
|
|
2811
|
+
__dirname6 = dirname5(__filename5);
|
|
2812
|
+
TEMPLATES_DIR = resolve4(__dirname6, "../templates");
|
|
2813
|
+
TEMPLATES_DIR_FALLBACK = resolve4(__dirname6, "../../../agent_moss/templates");
|
|
2905
2814
|
TEMPLATE_FILES = ["prompt1_template.txt", "prompt2_template.txt", "security_judge_template.txt"];
|
|
2906
2815
|
cachedTemplates = null;
|
|
2907
2816
|
}
|
|
2908
2817
|
});
|
|
2909
2818
|
|
|
2910
2819
|
// src/engine/script-analyzer.ts
|
|
2911
|
-
import { readFileSync as
|
|
2912
|
-
import { resolve as
|
|
2820
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
2821
|
+
import { resolve as resolve5, join as join3 } from "path";
|
|
2913
2822
|
function emptyResult() {
|
|
2914
2823
|
return { scriptPath: "", scriptContent: "", matchedKeywords: [], lineCount: 0, isSuspicious: false, error: "", riskLevel: "", riskReason: "" };
|
|
2915
2824
|
}
|
|
@@ -2962,8 +2871,8 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
2962
2871
|
}
|
|
2963
2872
|
function readScriptContent(scriptPath, maxLines = 500) {
|
|
2964
2873
|
try {
|
|
2965
|
-
const expandedPath = scriptPath.startsWith("~") ? join3(process.env.HOME || "/home/user", scriptPath.slice(2)) :
|
|
2966
|
-
const raw =
|
|
2874
|
+
const expandedPath = scriptPath.startsWith("~") ? join3(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve5(scriptPath);
|
|
2875
|
+
const raw = readFileSync7(expandedPath, "utf-8");
|
|
2967
2876
|
const lines = raw.split("\n").slice(0, maxLines);
|
|
2968
2877
|
return { content: lines.join("\n"), lineCount: lines.length, error: "" };
|
|
2969
2878
|
} catch (e) {
|
|
@@ -3101,8 +3010,8 @@ var init_script_analyzer = __esm({
|
|
|
3101
3010
|
});
|
|
3102
3011
|
|
|
3103
3012
|
// src/engine/script-content-analyzer.ts
|
|
3104
|
-
import { readFileSync as
|
|
3105
|
-
import { resolve as
|
|
3013
|
+
import { readFileSync as readFileSync8, statSync, existsSync as existsSync7 } from "fs";
|
|
3014
|
+
import { resolve as resolve6, join as join4, isAbsolute, dirname as dirname6 } from "path";
|
|
3106
3015
|
import { homedir as homedir2 } from "os";
|
|
3107
3016
|
function emptyChain() {
|
|
3108
3017
|
return {
|
|
@@ -3249,7 +3158,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
3249
3158
|
let resolved;
|
|
3250
3159
|
try {
|
|
3251
3160
|
resolved = resolvePath(p);
|
|
3252
|
-
if (
|
|
3161
|
+
if (existsSync7(resolved)) {
|
|
3253
3162
|
const stat = statSync(resolved);
|
|
3254
3163
|
if (stat.isFile()) return resolved;
|
|
3255
3164
|
}
|
|
@@ -3263,18 +3172,18 @@ function resolvePath(p) {
|
|
|
3263
3172
|
if (expanded.startsWith("~/") || expanded === "~") {
|
|
3264
3173
|
expanded = join4(homedir2(), expanded.slice(1));
|
|
3265
3174
|
}
|
|
3266
|
-
return
|
|
3175
|
+
return resolve6(expanded);
|
|
3267
3176
|
}
|
|
3268
3177
|
function readScriptContent2(scriptPath, maxFileSize = 2 * 1024 * 1024) {
|
|
3269
3178
|
try {
|
|
3270
3179
|
const path3 = resolvePath(scriptPath);
|
|
3271
|
-
if (!
|
|
3180
|
+
if (!existsSync7(path3)) return { content: "", lineCount: 0, fileSize: 0, error: `\u811A\u672C\u4E0D\u5B58\u5728: ${scriptPath}` };
|
|
3272
3181
|
const stat = statSync(path3);
|
|
3273
3182
|
if (!stat.isFile()) return { content: "", lineCount: 0, fileSize: 0, error: `\u4E0D\u662F\u6587\u4EF6: ${scriptPath}` };
|
|
3274
3183
|
if (stat.size > maxFileSize) {
|
|
3275
3184
|
return { content: "", lineCount: 0, fileSize: stat.size, error: `\u811A\u672C\u6587\u4EF6\u8FC7\u5927 (${stat.size} bytes)\uFF0C\u8DF3\u8FC7\u8BFB\u53D6` };
|
|
3276
3185
|
}
|
|
3277
|
-
const content =
|
|
3186
|
+
const content = readFileSync8(path3, "utf-8");
|
|
3278
3187
|
const lineCount = content ? content.split("\n").length : 0;
|
|
3279
3188
|
return { content, lineCount, fileSize: stat.size, error: "" };
|
|
3280
3189
|
} catch (e) {
|
|
@@ -3293,7 +3202,7 @@ function extractChildScriptPaths(content, baseDir) {
|
|
|
3293
3202
|
if (pathStr.includes("/dev/") || pathStr.startsWith("|") || pathStr.startsWith(";")) continue;
|
|
3294
3203
|
const full = isAbsolute(pathStr) ? pathStr : join4(baseDir, pathStr);
|
|
3295
3204
|
const resolved = resolvePath(full);
|
|
3296
|
-
if (
|
|
3205
|
+
if (existsSync7(resolved)) {
|
|
3297
3206
|
try {
|
|
3298
3207
|
if (statSync(resolved).isFile() && !paths.includes(resolved)) paths.push(resolved);
|
|
3299
3208
|
} catch {
|
|
@@ -3308,7 +3217,7 @@ function resolveScriptChain(entryPath, input, maxDepth = 3, maxFileSize = 2 * 10
|
|
|
3308
3217
|
const result = emptyChain();
|
|
3309
3218
|
result.entryPath = entryPath;
|
|
3310
3219
|
const entry = resolvePath(entryPath);
|
|
3311
|
-
const baseDir =
|
|
3220
|
+
const baseDir = existsSync7(entry) ? dirname6(entry) : input.cwd || process.cwd();
|
|
3312
3221
|
resolveRecursive({
|
|
3313
3222
|
path: entry,
|
|
3314
3223
|
depth: 0,
|
|
@@ -3383,7 +3292,7 @@ function resolveRecursive(ctx) {
|
|
|
3383
3292
|
maxTotalSize,
|
|
3384
3293
|
visited,
|
|
3385
3294
|
result,
|
|
3386
|
-
baseDir:
|
|
3295
|
+
baseDir: dirname6(resolvePath(childPath)),
|
|
3387
3296
|
input
|
|
3388
3297
|
});
|
|
3389
3298
|
if (result.hasCritical) return;
|
|
@@ -3644,16 +3553,16 @@ __export(token_stats_exports, {
|
|
|
3644
3553
|
recordTokenUsage: () => recordTokenUsage,
|
|
3645
3554
|
resetTokenStats: () => resetTokenStats
|
|
3646
3555
|
});
|
|
3647
|
-
import { readFileSync as
|
|
3556
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
3648
3557
|
function getStatsPath() {
|
|
3649
3558
|
const envPath = process.env[ENV_STATS_PATH];
|
|
3650
3559
|
if (envPath) return envPath;
|
|
3651
3560
|
return getTokenStatsPath();
|
|
3652
3561
|
}
|
|
3653
3562
|
function loadAllRecords(statsPath) {
|
|
3654
|
-
if (!
|
|
3563
|
+
if (!existsSync8(statsPath)) return [];
|
|
3655
3564
|
try {
|
|
3656
|
-
const data = JSON.parse(
|
|
3565
|
+
const data = JSON.parse(readFileSync9(statsPath, "utf-8"));
|
|
3657
3566
|
if (Array.isArray(data)) return data;
|
|
3658
3567
|
if (data && Array.isArray(data.records)) return data.records;
|
|
3659
3568
|
return [];
|
|
@@ -3664,7 +3573,7 @@ function loadAllRecords(statsPath) {
|
|
|
3664
3573
|
function saveRecords(statsPath, records) {
|
|
3665
3574
|
try {
|
|
3666
3575
|
const dir = statsPath.substring(0, statsPath.lastIndexOf("/"));
|
|
3667
|
-
if (dir && !
|
|
3576
|
+
if (dir && !existsSync8(dir)) mkdirSync2(dir, { recursive: true });
|
|
3668
3577
|
writeFileSync2(statsPath, JSON.stringify(records, null, 2), "utf-8");
|
|
3669
3578
|
} catch (e) {
|
|
3670
3579
|
}
|
|
@@ -3786,7 +3695,7 @@ function getTokenTrend(days = 0, startDate, endDate) {
|
|
|
3786
3695
|
}
|
|
3787
3696
|
function resetTokenStats() {
|
|
3788
3697
|
const statsPath = getStatsPath();
|
|
3789
|
-
if (
|
|
3698
|
+
if (existsSync8(statsPath)) {
|
|
3790
3699
|
try {
|
|
3791
3700
|
unlinkSync2(statsPath);
|
|
3792
3701
|
} catch {
|
|
@@ -3865,11 +3774,12 @@ ${prompt}
|
|
|
3865
3774
|
function buildPrompt(input, previous, matchedSkills, templates, scriptAnalysis, skipL3Hints = "", scriptChainText = "") {
|
|
3866
3775
|
const skillsText = formatSkillsForPrompt(matchedSkills);
|
|
3867
3776
|
const historyStr = input.actionHistory.map((h, i) => `${i + 1}. ${h.actionType}: ${h.actionDetail}`).join("\n") || "(\u65E0\u5386\u53F2\u64CD\u4F5C)";
|
|
3777
|
+
const promptHistoryText = formatPromptHistory(input.promptHistory);
|
|
3868
3778
|
const scriptAnalysisText = scriptChainText ? scriptChainText : scriptAnalysis ? formatScriptAnalysisForPrompt(scriptAnalysis) : "";
|
|
3869
3779
|
const hintsText = formatHints(previous);
|
|
3870
3780
|
const securityJudgeTemplate = templates["security_judge"];
|
|
3871
3781
|
if (securityJudgeTemplate) {
|
|
3872
|
-
return securityJudgeTemplate.replaceAll("{prompt_session}", input.promptSession || "\uFF08\u672A\u63D0\u4F9B\uFF09").replaceAll("{action_history}", historyStr).replaceAll("{action_type}", input.aNext.actionType).replaceAll("{action_detail}", input.aNext.actionDetail).replaceAll("{reason}", input.reason || "\u672A\u8BF4\u660E").replaceAll("{skills_text}", skillsText).replaceAll("{hints_text}", hintsText).replaceAll("{script_analysis_text}", scriptAnalysisText).replaceAll("{skip_l3_hints}", skipL3Hints).replaceAll("{{", "{").replaceAll("}}", "}");
|
|
3782
|
+
return securityJudgeTemplate.replaceAll("{prompt_session}", input.promptSession || "\uFF08\u672A\u63D0\u4F9B\uFF09").replaceAll("{prompt_history_text}", promptHistoryText).replaceAll("{action_history}", historyStr).replaceAll("{action_type}", input.aNext.actionType).replaceAll("{action_detail}", input.aNext.actionDetail).replaceAll("{reason}", input.reason || "\u672A\u8BF4\u660E").replaceAll("{skills_text}", skillsText).replaceAll("{hints_text}", hintsText).replaceAll("{script_analysis_text}", scriptAnalysisText).replaceAll("{skip_l3_hints}", skipL3Hints).replaceAll("{{", "{").replaceAll("}}", "}");
|
|
3873
3783
|
}
|
|
3874
3784
|
console.warn("[AgentMoss] security_judge template missing, using sparse fallback prompt");
|
|
3875
3785
|
return `## \u5F53\u524D\u64CD\u4F5C\u4E0A\u4E0B\u6587
|
|
@@ -3899,6 +3809,27 @@ ${scriptAnalysisText}` : ""}
|
|
|
3899
3809
|
\u8F93\u51FA\u683C\u5F0F:
|
|
3900
3810
|
{"allowed": true/false, "reason": "\u5224\u65AD\u7406\u7531", "riskLevel": "low|medium|high|critical", "riskType": "\u98CE\u9669\u7C7B\u578B", "confidence": 0-100}`;
|
|
3901
3811
|
}
|
|
3812
|
+
function formatPromptHistory(promptHistory, maxTextChars = 500) {
|
|
3813
|
+
if (!promptHistory || promptHistory.length === 0) {
|
|
3814
|
+
return "\uFF08\u672A\u63D0\u4F9B\u5386\u53F2\u610F\u56FE\uFF09";
|
|
3815
|
+
}
|
|
3816
|
+
const lines = [];
|
|
3817
|
+
for (let i = 0; i < promptHistory.length; i++) {
|
|
3818
|
+
const turn = promptHistory[i];
|
|
3819
|
+
const text = (turn?.text || "").trim();
|
|
3820
|
+
if (!text) continue;
|
|
3821
|
+
let line = ` \u7B2C${i + 1}\u8F6E\u7528\u6237\u610F\u56FE: ${text.slice(0, maxTextChars)}`;
|
|
3822
|
+
const actions = turn?.actions;
|
|
3823
|
+
if (actions && actions.length > 0) {
|
|
3824
|
+
const types = actions.map((a) => a?.actionType).filter((t) => typeof t === "string" && t.length > 0);
|
|
3825
|
+
if (types.length > 0) {
|
|
3826
|
+
line += ` \u2192 \u52A8\u4F5C: ${types.join(", ")}`;
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
lines.push(line);
|
|
3830
|
+
}
|
|
3831
|
+
return lines.length > 0 ? lines.join("\n") : "\uFF08\u672A\u63D0\u4F9B\u5386\u53F2\u610F\u56FE\uFF09";
|
|
3832
|
+
}
|
|
3902
3833
|
function formatHints(previous) {
|
|
3903
3834
|
const hints = [];
|
|
3904
3835
|
if (previous.heuristic) {
|
|
@@ -3994,7 +3925,7 @@ async function analyzeWithLLM(prompt, config) {
|
|
|
3994
3925
|
}
|
|
3995
3926
|
if (attempt < maxRetries) {
|
|
3996
3927
|
console.error(`[AgentMoss] LLM call failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${retryCfg.retryInterval}s:`, err.message);
|
|
3997
|
-
await new Promise((
|
|
3928
|
+
await new Promise((resolve7) => setTimeout(resolve7, retryCfg.retryInterval * 1e3));
|
|
3998
3929
|
} else {
|
|
3999
3930
|
clearTimeout(totalTimeoutTimer);
|
|
4000
3931
|
console.error("[AgentMoss] LLM call failed after all retries:", err.message);
|
|
@@ -4432,9 +4363,9 @@ var require_bindings = __commonJS({
|
|
|
4432
4363
|
init_esm_shims();
|
|
4433
4364
|
var fs4 = __require("fs");
|
|
4434
4365
|
var path3 = __require("path");
|
|
4435
|
-
var
|
|
4366
|
+
var fileURLToPath10 = require_file_uri_to_path();
|
|
4436
4367
|
var join6 = path3.join;
|
|
4437
|
-
var
|
|
4368
|
+
var dirname8 = path3.dirname;
|
|
4438
4369
|
var exists = fs4.accessSync && function(path4) {
|
|
4439
4370
|
try {
|
|
4440
4371
|
fs4.accessSync(path4);
|
|
@@ -4544,12 +4475,12 @@ var require_bindings = __commonJS({
|
|
|
4544
4475
|
Error.stackTraceLimit = origSTL;
|
|
4545
4476
|
var fileSchema = "file://";
|
|
4546
4477
|
if (fileName.indexOf(fileSchema) === 0) {
|
|
4547
|
-
fileName =
|
|
4478
|
+
fileName = fileURLToPath10(fileName);
|
|
4548
4479
|
}
|
|
4549
4480
|
return fileName;
|
|
4550
4481
|
};
|
|
4551
4482
|
exports.getRoot = function getRoot(file) {
|
|
4552
|
-
var dir =
|
|
4483
|
+
var dir = dirname8(file), prev;
|
|
4553
4484
|
while (true) {
|
|
4554
4485
|
if (dir === ".") {
|
|
4555
4486
|
dir = process.cwd();
|
|
@@ -4755,13 +4686,13 @@ var require_backup = __commonJS({
|
|
|
4755
4686
|
var runBackup = (backup, handler) => {
|
|
4756
4687
|
let rate = 0;
|
|
4757
4688
|
let useDefault = true;
|
|
4758
|
-
return new Promise((
|
|
4689
|
+
return new Promise((resolve7, reject) => {
|
|
4759
4690
|
setImmediate(function step() {
|
|
4760
4691
|
try {
|
|
4761
4692
|
const progress = backup.transfer(rate);
|
|
4762
4693
|
if (!progress.remainingPages) {
|
|
4763
4694
|
backup.close();
|
|
4764
|
-
|
|
4695
|
+
resolve7(progress);
|
|
4765
4696
|
return;
|
|
4766
4697
|
}
|
|
4767
4698
|
if (useDefault) {
|
|
@@ -5168,9 +5099,14 @@ var ActionItemSchema = z.object({
|
|
|
5168
5099
|
action_type: z.string().describe("Action type, e.g. bash, file_read, file_write"),
|
|
5169
5100
|
action_detail: z.string().describe("Action detail / command content")
|
|
5170
5101
|
});
|
|
5102
|
+
var PromptTurnSchema = z.object({
|
|
5103
|
+
text: z.string().default("").describe("User prompt text at this turn"),
|
|
5104
|
+
actions: z.array(ActionItemSchema).default([]).describe("Actions triggered by this prompt, in order, until the next prompt")
|
|
5105
|
+
});
|
|
5171
5106
|
var AnalyzeRequestSchema = z.object({
|
|
5172
5107
|
session_id: z.string().describe("Session / agent unique identifier"),
|
|
5173
|
-
prompt_session: z.string().default("").describe("User original prompt"),
|
|
5108
|
+
prompt_session: z.string().default("").describe("User original prompt (most recent user message; backward compat)"),
|
|
5109
|
+
prompt_history: z.array(PromptTurnSchema).default([]).describe("Full interleaved prompt history (ordered turns, each with its triggered actions). Optional; empty = fall back to prompt_session only."),
|
|
5174
5110
|
action_history: z.array(ActionItemSchema).default([]).describe("Historical action sequence"),
|
|
5175
5111
|
a_next: ActionItemSchema.describe("Next action to be executed"),
|
|
5176
5112
|
reason: z.string().default("").describe("Reason for executing this action"),
|
|
@@ -5390,11 +5326,11 @@ init_esm_shims();
|
|
|
5390
5326
|
init_runtime_config();
|
|
5391
5327
|
init_token_stats();
|
|
5392
5328
|
import { Hono } from "hono";
|
|
5393
|
-
import { readFileSync as
|
|
5394
|
-
import { join as join5, dirname as
|
|
5395
|
-
import { fileURLToPath as
|
|
5396
|
-
var
|
|
5397
|
-
var STATIC_DIR = join5(
|
|
5329
|
+
import { readFileSync as readFileSync10, existsSync as existsSync10 } from "fs";
|
|
5330
|
+
import { join as join5, dirname as dirname7 } from "path";
|
|
5331
|
+
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
5332
|
+
var __dirname7 = dirname7(fileURLToPath8(import.meta.url));
|
|
5333
|
+
var STATIC_DIR = join5(__dirname7, "static");
|
|
5398
5334
|
var CONSOLE_TOKEN_ENV = "AGENT_MOSS_CONSOLE_TOKEN";
|
|
5399
5335
|
function getConsoleToken() {
|
|
5400
5336
|
return process.env[CONSOLE_TOKEN_ENV] || "";
|
|
@@ -5419,8 +5355,8 @@ function createConsoleRouter() {
|
|
|
5419
5355
|
console2.use("/api/*", authMiddleware());
|
|
5420
5356
|
const serveIndex = (c) => {
|
|
5421
5357
|
const indexFile = join5(STATIC_DIR, "index.html");
|
|
5422
|
-
if (
|
|
5423
|
-
return c.html(
|
|
5358
|
+
if (existsSync10(indexFile)) {
|
|
5359
|
+
return c.html(readFileSync10(indexFile, "utf-8"));
|
|
5424
5360
|
}
|
|
5425
5361
|
return c.html("<h1>AgentMoss Policy Console</h1><p>Frontend not built. Use /console/api/* endpoints.</p>");
|
|
5426
5362
|
};
|
|
@@ -5511,13 +5447,13 @@ function createConsoleRouter() {
|
|
|
5511
5447
|
if (!/^[A-Za-z0-9_-]+$/.test(skillId)) {
|
|
5512
5448
|
return c.json({ error: "invalid skill_id" }, 400);
|
|
5513
5449
|
}
|
|
5514
|
-
const skillPath = join5(
|
|
5515
|
-
if (!
|
|
5516
|
-
const builtinPath = join5(
|
|
5517
|
-
if (
|
|
5450
|
+
const skillPath = join5(dirname7(getRuntimeConfigPath()), "agent_moss_skills", `${skillId}.md`);
|
|
5451
|
+
if (!existsSync10(skillPath)) {
|
|
5452
|
+
const builtinPath = join5(__dirname7, "..", "..", "agent_moss", "skills", `${skillId}.md`);
|
|
5453
|
+
if (existsSync10(builtinPath)) return c.text(readFileSync10(builtinPath, "utf-8"));
|
|
5518
5454
|
return c.json({ error: "skill not found" }, 404);
|
|
5519
5455
|
}
|
|
5520
|
-
return c.text(
|
|
5456
|
+
return c.text(readFileSync10(skillPath, "utf-8"));
|
|
5521
5457
|
});
|
|
5522
5458
|
console2.get("/api/agents", (c) => {
|
|
5523
5459
|
const rc = loadRuntimeConfig();
|
|
@@ -5601,12 +5537,12 @@ function createApp() {
|
|
|
5601
5537
|
}
|
|
5602
5538
|
async function findFreePort(startPort, host = "127.0.0.1", scan = 100) {
|
|
5603
5539
|
for (let port = startPort; port < startPort + scan; port++) {
|
|
5604
|
-
const free = await new Promise((
|
|
5540
|
+
const free = await new Promise((resolve7) => {
|
|
5605
5541
|
const server = net.createServer();
|
|
5606
5542
|
server.listen(port, host, () => {
|
|
5607
|
-
server.close(() =>
|
|
5543
|
+
server.close(() => resolve7(true));
|
|
5608
5544
|
});
|
|
5609
|
-
server.on("error", () =>
|
|
5545
|
+
server.on("error", () => resolve7(false));
|
|
5610
5546
|
});
|
|
5611
5547
|
if (free) {
|
|
5612
5548
|
if (port !== startPort) {
|
|
@@ -5631,7 +5567,7 @@ async function startServer(host = "127.0.0.1", port = 9090) {
|
|
|
5631
5567
|
}
|
|
5632
5568
|
|
|
5633
5569
|
// src/cli.ts
|
|
5634
|
-
import { fileURLToPath as
|
|
5570
|
+
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
5635
5571
|
import { realpathSync } from "fs";
|
|
5636
5572
|
function printHelp() {
|
|
5637
5573
|
console.log(`AgentMoss security analysis engine (TypeScript v${version})
|
|
@@ -5722,7 +5658,7 @@ async function main() {
|
|
|
5722
5658
|
const { execSync } = await import("child_process");
|
|
5723
5659
|
const fs4 = await import("fs");
|
|
5724
5660
|
const path3 = await import("path");
|
|
5725
|
-
const { fileURLToPath:
|
|
5661
|
+
const { fileURLToPath: fileURLToPath10 } = await import("url");
|
|
5726
5662
|
if (process.getuid?.() !== 0) {
|
|
5727
5663
|
try {
|
|
5728
5664
|
execSync("sudo -n true", { stdio: "ignore", timeout: 5e3 });
|
|
@@ -5737,18 +5673,18 @@ async function main() {
|
|
|
5737
5673
|
execSync(sudoArgs.join(" "), { stdio: "inherit" });
|
|
5738
5674
|
process.exit(0);
|
|
5739
5675
|
}
|
|
5740
|
-
const
|
|
5741
|
-
const
|
|
5742
|
-
let srcPath = path3.join(
|
|
5676
|
+
const __filename6 = fileURLToPath10(import.meta.url);
|
|
5677
|
+
const __dirname8 = path3.dirname(__filename6);
|
|
5678
|
+
let srcPath = path3.join(__dirname8, "data", "agent_moss.service");
|
|
5743
5679
|
if (!fs4.existsSync(srcPath)) {
|
|
5744
|
-
srcPath = path3.join(
|
|
5680
|
+
srcPath = path3.join(__dirname8, "..", "src", "data", "agent_moss.service");
|
|
5745
5681
|
}
|
|
5746
5682
|
if (!fs4.existsSync(srcPath)) {
|
|
5747
5683
|
console.error("\u9519\u8BEF\uFF1A\u627E\u4E0D\u5230 agent_moss.service \u6A21\u677F\u6587\u4EF6");
|
|
5748
5684
|
process.exit(1);
|
|
5749
5685
|
}
|
|
5750
5686
|
const which = execSync("which agent-moss 2>/dev/null || true", { encoding: "utf-8" }).trim();
|
|
5751
|
-
const binPath = which || `${process.execPath} ${path3.join(
|
|
5687
|
+
const binPath = which || `${process.execPath} ${path3.join(__dirname8, "cli.js")}`;
|
|
5752
5688
|
let content = fs4.readFileSync(srcPath, "utf-8");
|
|
5753
5689
|
content = content.replace("__AGENT_MOSS_BIN__", binPath);
|
|
5754
5690
|
const dst = "/etc/systemd/system/agent-moss.service";
|
|
@@ -5792,13 +5728,13 @@ async function main() {
|
|
|
5792
5728
|
let version2 = "";
|
|
5793
5729
|
for (let port = 9090; port <= 9095; port++) {
|
|
5794
5730
|
try {
|
|
5795
|
-
const data = await new Promise((
|
|
5731
|
+
const data = await new Promise((resolve7, reject) => {
|
|
5796
5732
|
const req = http.get(`http://127.0.0.1:${port}/api/v1/health`, { timeout: 2e3 }, (res) => {
|
|
5797
5733
|
let body = "";
|
|
5798
5734
|
res.on("data", (chunk) => body += chunk);
|
|
5799
5735
|
res.on("end", () => {
|
|
5800
5736
|
try {
|
|
5801
|
-
|
|
5737
|
+
resolve7(JSON.parse(body));
|
|
5802
5738
|
} catch {
|
|
5803
5739
|
reject();
|
|
5804
5740
|
}
|
|
@@ -5826,13 +5762,13 @@ async function main() {
|
|
|
5826
5762
|
console.log(` Systemd: \u672A\u6CE8\u518C\uFF08\u8FD0\u884C agent-moss install --enable \u5B89\u88C5\uFF09`);
|
|
5827
5763
|
}
|
|
5828
5764
|
try {
|
|
5829
|
-
const data = await new Promise((
|
|
5765
|
+
const data = await new Promise((resolve7, reject) => {
|
|
5830
5766
|
const req = http.get(`http://127.0.0.1:${foundPort}/console/api/config`, { timeout: 3e3 }, (res) => {
|
|
5831
5767
|
let body = "";
|
|
5832
5768
|
res.on("data", (chunk) => body += chunk);
|
|
5833
5769
|
res.on("end", () => {
|
|
5834
5770
|
try {
|
|
5835
|
-
|
|
5771
|
+
resolve7(JSON.parse(body));
|
|
5836
5772
|
} catch {
|
|
5837
5773
|
reject();
|
|
5838
5774
|
}
|
|
@@ -5879,9 +5815,9 @@ async function main() {
|
|
|
5879
5815
|
var isMain = (() => {
|
|
5880
5816
|
try {
|
|
5881
5817
|
if (!process.argv[1]) return false;
|
|
5882
|
-
const thisFile = realpathSync(
|
|
5818
|
+
const thisFile = realpathSync(fileURLToPath9(import.meta.url));
|
|
5883
5819
|
const argv1 = realpathSync(
|
|
5884
|
-
process.argv[1].startsWith("file://") ?
|
|
5820
|
+
process.argv[1].startsWith("file://") ? fileURLToPath9(process.argv[1]) : process.argv[1]
|
|
5885
5821
|
);
|
|
5886
5822
|
return thisFile === argv1;
|
|
5887
5823
|
} catch {
|