@kenhkl/agent-moss 0.16.12 → 0.16.14
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/README.md +3 -0
- package/dist/cli.js +1065 -1216
- package/dist/data/agent_moss.service +4 -0
- package/dist/engine/coordinator.js +514 -872
- package/dist/rules/formal_rules.json +61 -0
- package/dist/rules/heuristic_rules.json +40 -0
- package/dist/rules/inline_rules.json +151 -0
- package/dist/rules/l1_rules.json +115 -49
- package/dist/rules/logic_rules.json +73 -0
- package/dist/rules/manifest.json +6 -0
- package/dist/rules/platform_traits.json +389 -0
- package/dist/rules/script_rules.json +311 -0
- package/dist/server.js +877 -1050
- package/dist/static/index.html +26 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -25,6 +25,10 @@ var init_esm_shims = __esm({
|
|
|
25
25
|
import { join } from "path";
|
|
26
26
|
import { homedir } from "os";
|
|
27
27
|
import { readFileSync } from "fs";
|
|
28
|
+
function getRulesRoot() {
|
|
29
|
+
const raw = (process.env[ENV_RULES_ROOT] ?? "").trim();
|
|
30
|
+
return raw ? raw : null;
|
|
31
|
+
}
|
|
28
32
|
function isRoot() {
|
|
29
33
|
const getuid = process.getuid;
|
|
30
34
|
return typeof getuid === "function" && getuid() === 0;
|
|
@@ -94,7 +98,7 @@ function getTokenStatsPath() {
|
|
|
94
98
|
}
|
|
95
99
|
return join(getDataRoot(), "agent_moss_token_stats.json");
|
|
96
100
|
}
|
|
97
|
-
var ENV_DATA_ROOT, ENV_INSTANCE, DEFAULT_DATA_ROOT;
|
|
101
|
+
var ENV_DATA_ROOT, ENV_INSTANCE, DEFAULT_DATA_ROOT, ENV_RULES_ROOT;
|
|
98
102
|
var init_paths = __esm({
|
|
99
103
|
"src/infra/paths.ts"() {
|
|
100
104
|
"use strict";
|
|
@@ -102,282 +106,53 @@ var init_paths = __esm({
|
|
|
102
106
|
ENV_DATA_ROOT = "AGENT_MOSS_DATA_DIR";
|
|
103
107
|
ENV_INSTANCE = "AGENT_MOSS_INSTANCE";
|
|
104
108
|
DEFAULT_DATA_ROOT = join(homedir(), ".config", "agentmoss");
|
|
109
|
+
ENV_RULES_ROOT = "AGENT_MOSS_RULES_ROOT";
|
|
105
110
|
}
|
|
106
111
|
});
|
|
107
112
|
|
|
108
|
-
// src/
|
|
109
|
-
function
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
function splitCommandSegments(command) {
|
|
113
|
-
const segments = [];
|
|
114
|
-
let cur = "";
|
|
115
|
-
let quote = null;
|
|
116
|
-
for (let i = 0; i < command.length; i++) {
|
|
117
|
-
const ch = command[i];
|
|
118
|
-
if (quote) {
|
|
119
|
-
cur += ch;
|
|
120
|
-
if (ch === quote) quote = null;
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
if (ch === "'" || ch === '"') {
|
|
124
|
-
quote = ch;
|
|
125
|
-
cur += ch;
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
if (/\||&|;|\n/.test(ch)) {
|
|
129
|
-
segments.push(cur);
|
|
130
|
-
segments.push(ch);
|
|
131
|
-
cur = "";
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
cur += ch;
|
|
135
|
-
}
|
|
136
|
-
if (cur) segments.push(cur);
|
|
137
|
-
return segments.map((s) => s.trim()).filter((s) => s.length > 0 && !/^(?:\|\||&&|[|;&])$/.test(s));
|
|
113
|
+
// src/infra/rules-mode.ts
|
|
114
|
+
function truthy(name) {
|
|
115
|
+
return TRUTHY.has((process.env[name] || "").trim().toLowerCase());
|
|
138
116
|
}
|
|
139
|
-
function
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// src/engine/inline-analyzer.ts
|
|
153
|
-
function isLiteralTextCommand(command) {
|
|
154
|
-
const segments = splitCommandSegments(command);
|
|
155
|
-
if (segments.length === 0 || segments.some((s) => !ECHO_SEG_RE.test(s))) return false;
|
|
156
|
-
if (command.includes(">")) {
|
|
157
|
-
let d = command.replace(/<=>|>=|<=|<>|=>/g, " ");
|
|
158
|
-
d = d.replace(/(?:2|&|1)?\s*>\s*\/dev\/null\b/g, "");
|
|
159
|
-
d = d.replace(new RegExp(`>{1,2}\\s*(['"])([~./][^'"]+)\\1`, "g"), (_m, _q, p) => ">" + p);
|
|
160
|
-
d = d.replace(/'[^']*'|"[^"]*"/g, "");
|
|
161
|
-
if (/>{1,2}\s*(?!&)\S/.test(d)) {
|
|
162
|
-
return false;
|
|
117
|
+
function getRulesMode() {
|
|
118
|
+
if (cached !== null) return cached;
|
|
119
|
+
const raw = (process.env[ENV_RULES_MODE] || "").trim().toLowerCase();
|
|
120
|
+
if (raw) {
|
|
121
|
+
if (VALID_MODES.has(raw)) {
|
|
122
|
+
cached = raw;
|
|
123
|
+
} else {
|
|
124
|
+
console.error(
|
|
125
|
+
`[AgentMoss] ${ENV_RULES_MODE}=${JSON.stringify(raw)} \u975E\u6CD5\uFF08\u53EA\u652F\u6301 hot / cold / builtin\uFF09\uFF1B\u4E3A\u5B89\u5168\u8D77\u89C1\u6309 builtin\uFF08\u4EC5\u5185\u7F6E\u89C4\u5219\uFF09\u5904\u7406`
|
|
126
|
+
);
|
|
127
|
+
cached = "builtin";
|
|
163
128
|
}
|
|
129
|
+
return cached;
|
|
164
130
|
}
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return
|
|
169
|
-
}
|
|
170
|
-
function extractInlineCode(command) {
|
|
171
|
-
const parts = [];
|
|
172
|
-
let m;
|
|
173
|
-
INLINE_CODE_RE.lastIndex = 0;
|
|
174
|
-
while ((m = INLINE_CODE_RE.exec(command)) !== null) {
|
|
175
|
-
const code = m[1] ?? m[2];
|
|
176
|
-
if (code) parts.push(code);
|
|
177
|
-
}
|
|
178
|
-
ECHO_STRING_RE.lastIndex = 0;
|
|
179
|
-
while ((m = ECHO_STRING_RE.exec(command)) !== null) {
|
|
180
|
-
const code = m[1] ?? m[2];
|
|
181
|
-
if (code) parts.push(code);
|
|
182
|
-
}
|
|
183
|
-
return parts.join("\n");
|
|
131
|
+
if (truthy(ENV_RULES_BUILTIN_ONLY)) cached = "builtin";
|
|
132
|
+
else if (truthy(ENV_DISABLE_RULE_HOT_RELOAD)) cached = "cold";
|
|
133
|
+
else cached = "hot";
|
|
134
|
+
return cached;
|
|
184
135
|
}
|
|
185
|
-
function
|
|
186
|
-
return
|
|
187
|
-
p.lastIndex = 0;
|
|
188
|
-
return p.test(command);
|
|
189
|
-
});
|
|
136
|
+
function isHotReloadEnabled() {
|
|
137
|
+
return getRulesMode() === "hot";
|
|
190
138
|
}
|
|
191
|
-
function
|
|
192
|
-
|
|
193
|
-
return DIR_TRAVERSAL_KEYWORDS.some((kw) => lower.includes(kw));
|
|
139
|
+
function isRuntimeConfigDisabled() {
|
|
140
|
+
return getRulesMode() !== "hot";
|
|
194
141
|
}
|
|
195
|
-
function
|
|
196
|
-
|
|
197
|
-
return READ_WRITE_KEYWORDS.some((kw) => lower.includes(kw));
|
|
198
|
-
}
|
|
199
|
-
function analyzeInlineScript(command) {
|
|
200
|
-
const code = extractInlineCode(command);
|
|
201
|
-
if (!code) {
|
|
202
|
-
return { actionable: false, allowed: true, reason: "", riskLevel: "low", riskType: "" };
|
|
203
|
-
}
|
|
204
|
-
if (hasWriteExecChain(command)) {
|
|
205
|
-
return {
|
|
206
|
-
actionable: true,
|
|
207
|
-
allowed: false,
|
|
208
|
-
reason: "\u5185\u8054\u811A\u672C\u542B\u5199\u5165\u6587\u4EF6\u540E\u6267\u884C\u7684\u6A21\u5F0F\uFF0C\u7591\u4F3C\u7ED5\u8FC7\u654F\u611F\u8DEF\u5F84\u68C0\u6D4B",
|
|
209
|
-
riskLevel: "critical",
|
|
210
|
-
riskType: "script_execution"
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
const redirMatch = command.match(REDIRECT_TO_SENSITIVE_RE);
|
|
214
|
-
if (redirMatch) {
|
|
215
|
-
return {
|
|
216
|
-
actionable: true,
|
|
217
|
-
allowed: false,
|
|
218
|
-
reason: `\u91CD\u5B9A\u5411\u5199\u5165\u654F\u611F\u8DEF\u5F84: ${redirMatch[1]}`,
|
|
219
|
-
riskLevel: "critical",
|
|
220
|
-
riskType: "file_access"
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
const isEchoOrPrintf1 = isLiteralTextCommand(command);
|
|
224
|
-
if (!isEchoOrPrintf1 && hasDirTraversal(code) && hasReadWriteKeyword(code)) {
|
|
225
|
-
return { actionable: false, allowed: true, reason: "", riskLevel: "low", riskType: "" };
|
|
226
|
-
}
|
|
227
|
-
const isEchoOrPrintf = isLiteralTextCommand(command);
|
|
228
|
-
if (!isEchoOrPrintf && hasReadWriteKeyword(code)) {
|
|
229
|
-
return {
|
|
230
|
-
actionable: true,
|
|
231
|
-
allowed: false,
|
|
232
|
-
reason: "\u5185\u8054\u811A\u672C\u542B\u654F\u611F\u8DEF\u5F84\u4E14\u542B\u6587\u4EF6\u8BFB\u5199/\u547D\u4EE4\u6267\u884C\u8C03\u7528\uFF0C\u5224\u4E3A\u771F\u5B9E\u8BBF\u95EE",
|
|
233
|
-
riskLevel: "critical",
|
|
234
|
-
riskType: "file_access"
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
return {
|
|
238
|
-
actionable: true,
|
|
239
|
-
allowed: true,
|
|
240
|
-
reason: "\u654F\u611F\u8DEF\u5F84\u4EC5\u4F5C\u4E3A\u6587\u672C\u5B57\u9762\u91CF\u51FA\u73B0\uFF0C\u672A\u4F34\u968F\u8BFB\u5199\u64CD\u4F5C",
|
|
241
|
-
riskLevel: "low",
|
|
242
|
-
riskType: "file_access"
|
|
243
|
-
};
|
|
142
|
+
function isBuiltinOnly() {
|
|
143
|
+
return getRulesMode() === "builtin";
|
|
244
144
|
}
|
|
245
|
-
var
|
|
246
|
-
var
|
|
247
|
-
"src/
|
|
145
|
+
var ENV_RULES_MODE, ENV_RULES_BUILTIN_ONLY, ENV_DISABLE_RULE_HOT_RELOAD, TRUTHY, VALID_MODES, cached;
|
|
146
|
+
var init_rules_mode = __esm({
|
|
147
|
+
"src/infra/rules-mode.ts"() {
|
|
248
148
|
"use strict";
|
|
249
149
|
init_esm_shims();
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
"open(",
|
|
257
|
-
"read(",
|
|
258
|
-
"write(",
|
|
259
|
-
"fopen(",
|
|
260
|
-
"system(",
|
|
261
|
-
"exec(",
|
|
262
|
-
"eval(",
|
|
263
|
-
"popen(",
|
|
264
|
-
"load(",
|
|
265
|
-
"dump(",
|
|
266
|
-
// 文件读写(组合形态)
|
|
267
|
-
"readline",
|
|
268
|
-
"readlines",
|
|
269
|
-
"writelines",
|
|
270
|
-
"getpass",
|
|
271
|
-
"pickle.load",
|
|
272
|
-
"yaml.load",
|
|
273
|
-
"json.load",
|
|
274
|
-
"json.read",
|
|
275
|
-
"configparser",
|
|
276
|
-
"fread",
|
|
277
|
-
"fwrite",
|
|
278
|
-
"fgets",
|
|
279
|
-
// 子进程执行(组合形态)
|
|
280
|
-
"os.system",
|
|
281
|
-
"os.popen",
|
|
282
|
-
"subprocess",
|
|
283
|
-
"os.exec",
|
|
284
|
-
"os.spawn",
|
|
285
|
-
"import os",
|
|
286
|
-
"import subprocess",
|
|
287
|
-
"shell=true",
|
|
288
|
-
"check_output",
|
|
289
|
-
"check_call",
|
|
290
|
-
"run(",
|
|
291
|
-
// 绕过变体检测
|
|
292
|
-
"getattr(",
|
|
293
|
-
"__builtins__",
|
|
294
|
-
"globals(",
|
|
295
|
-
"locals(",
|
|
296
|
-
// PHP
|
|
297
|
-
"file_get_contents",
|
|
298
|
-
"file_put_contents",
|
|
299
|
-
"passthru",
|
|
300
|
-
"shell_exec",
|
|
301
|
-
"proc_open",
|
|
302
|
-
// Perl/Ruby
|
|
303
|
-
"<stdin>",
|
|
304
|
-
"open my",
|
|
305
|
-
// Node/JS(2026-09 补,与 Python _READ_WRITE_KEYWORDS 同步):历史缺口 ——
|
|
306
|
-
// 识别表里一条 Node API 都没有,于是 node -e "require('fs').readFileSync('/etc/shadow')"
|
|
307
|
-
// 判为纯文本字面量 → 放行(真漏报)。
|
|
308
|
-
"readfilesync(",
|
|
309
|
-
"writefilesync(",
|
|
310
|
-
"appendfilesync(",
|
|
311
|
-
"unlinksync(",
|
|
312
|
-
"rmsync(",
|
|
313
|
-
"mkdirsync(",
|
|
314
|
-
"execsync(",
|
|
315
|
-
"spawnsync(",
|
|
316
|
-
"execfile",
|
|
317
|
-
"createreadstream",
|
|
318
|
-
"createwritestream",
|
|
319
|
-
"fs.read",
|
|
320
|
-
"fs.write",
|
|
321
|
-
"fs.promises",
|
|
322
|
-
"require('fs')",
|
|
323
|
-
'require("fs")',
|
|
324
|
-
"require('node:fs')",
|
|
325
|
-
'require("node:fs")',
|
|
326
|
-
"require('child_process')",
|
|
327
|
-
'require("child_process")',
|
|
328
|
-
"require('https')",
|
|
329
|
-
'require("https")'
|
|
330
|
-
];
|
|
331
|
-
WRITE_EXEC_CHAIN_PATTERNS = [
|
|
332
|
-
// echo/cat/printf "..." > file && bash/sh/python file
|
|
333
|
-
/(?:echo|cat|printf)\b.*?>\s*\S+.*(?:&&|;|\|)\s*(?:bash|sh|zsh|python\d?|perl|ruby|node|php)\s/gis,
|
|
334
|
-
// ... | bash / | sh / | python(管道喂解释器执行)
|
|
335
|
-
/\|\s*(?:bash|sh|zsh|python\d?|perl|ruby|node|php)\b/gi,
|
|
336
|
-
// eval "$(cat ...)" / eval "$(echo ...)"
|
|
337
|
-
/eval\s+"\$\(/gi,
|
|
338
|
-
// xargs bash / xargs sh
|
|
339
|
-
/\|\s*xargs\s+(?:bash|sh|zsh)/gi
|
|
340
|
-
];
|
|
341
|
-
SHELL_RC_FRAGMENTS = [
|
|
342
|
-
".bashrc",
|
|
343
|
-
".zshrc",
|
|
344
|
-
".profile",
|
|
345
|
-
".bash_profile",
|
|
346
|
-
".zprofile"
|
|
347
|
-
];
|
|
348
|
-
SENSITIVE_PATH_FRAGMENTS = [
|
|
349
|
-
"/etc/shadow",
|
|
350
|
-
"/etc/gshadow",
|
|
351
|
-
"/etc/passwd",
|
|
352
|
-
"/etc/sudoers",
|
|
353
|
-
"/etc/hosts",
|
|
354
|
-
"/etc/crontab",
|
|
355
|
-
"/etc/systemd/",
|
|
356
|
-
"/etc/ssh/sshd_config",
|
|
357
|
-
"/boot/",
|
|
358
|
-
"/proc/sys/",
|
|
359
|
-
"/sys/",
|
|
360
|
-
"/dev/mem",
|
|
361
|
-
"/dev/kmsg",
|
|
362
|
-
".ssh/id_rsa",
|
|
363
|
-
".ssh/id_ed25519",
|
|
364
|
-
".ssh/authorized_keys",
|
|
365
|
-
...SHELL_RC_FRAGMENTS
|
|
366
|
-
];
|
|
367
|
-
REDIRECT_TO_SENSITIVE_RE = new RegExp(`>{1,2}\\s*(?:\\S*/)?(${SENSITIVE_PATH_FRAGMENTS.map((p) => p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})(?:\\s|$)`, "i");
|
|
368
|
-
DIR_TRAVERSAL_KEYWORDS = [
|
|
369
|
-
// Python 目录遍历
|
|
370
|
-
"os.listdir",
|
|
371
|
-
"os.walk",
|
|
372
|
-
"os.scandir",
|
|
373
|
-
"glob.glob",
|
|
374
|
-
"glob.iglob",
|
|
375
|
-
"pathlib.",
|
|
376
|
-
"iterdir",
|
|
377
|
-
"rglob",
|
|
378
|
-
"scandir(",
|
|
379
|
-
"listdir("
|
|
380
|
-
];
|
|
150
|
+
ENV_RULES_MODE = "AGENT_MOSS_RULES_MODE";
|
|
151
|
+
ENV_RULES_BUILTIN_ONLY = "AGENT_MOSS_RULES_BUILTIN_ONLY";
|
|
152
|
+
ENV_DISABLE_RULE_HOT_RELOAD = "AGENT_MOSS_DISABLE_RULE_HOT_RELOAD";
|
|
153
|
+
TRUTHY = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
|
|
154
|
+
VALID_MODES = /* @__PURE__ */ new Set(["hot", "cold", "builtin"]);
|
|
155
|
+
cached = null;
|
|
381
156
|
}
|
|
382
157
|
});
|
|
383
158
|
|
|
@@ -407,23 +182,51 @@ function parseDirEnv(envName) {
|
|
|
407
182
|
return raw.split(/[,;]/).map((s) => s.trim()).filter(Boolean).map((s) => resolve(s));
|
|
408
183
|
}
|
|
409
184
|
function rulesDirs() {
|
|
185
|
+
if (isBuiltinOnly()) return [];
|
|
410
186
|
const dirs = [];
|
|
411
187
|
for (const env of RULES_DIR_ENVS) dirs.push(...parseDirEnv(env));
|
|
412
188
|
dirs.push(resolve(dataRootDir(), "rules"));
|
|
413
189
|
return [...new Set(dirs)];
|
|
414
190
|
}
|
|
191
|
+
function rulesDirCands() {
|
|
192
|
+
const root = getRulesRoot();
|
|
193
|
+
if (root) return [join2(root, "rules")];
|
|
194
|
+
const cands = [
|
|
195
|
+
// 注:`<data_root>/rules/` 不再是"按内置文件名覆盖"的查找位 —— 2026-10 起
|
|
196
|
+
// 规则目录只认 override.json / extra.json(见 rulesDirs())。
|
|
197
|
+
// dist: __dirname=dist/ → dist/rules;__dirname=dist/engine/ → dist/engine/../rules=dist/rules
|
|
198
|
+
resolve(__dirname2, "../rules"),
|
|
199
|
+
resolve(__dirname2, "rules"),
|
|
200
|
+
// dev src: __dirname=ts/src/infra/ → ts/src/infra/../../../agent_moss/rules = 仓库根 agent_moss/rules
|
|
201
|
+
resolve(__dirname2, "../../../agent_moss/rules"),
|
|
202
|
+
// dist 但 __dirname 指向 dist/engine 再往上两级的仓库根 agent_moss/rules
|
|
203
|
+
resolve(__dirname2, "../../../../agent_moss/rules"),
|
|
204
|
+
// 相对当前工作目录的仓库根(兜底,兼容以仓库根为 cwd 运行)
|
|
205
|
+
resolve(process.cwd(), "agent_moss/rules")
|
|
206
|
+
];
|
|
207
|
+
return cands.filter((c) => existsSync(c));
|
|
208
|
+
}
|
|
415
209
|
function findRulesFile(name) {
|
|
416
|
-
for (const dir of
|
|
210
|
+
for (const dir of rulesDirCands()) {
|
|
417
211
|
const p = resolve(dir, name);
|
|
418
212
|
if (existsSync(p)) return p;
|
|
419
213
|
}
|
|
420
214
|
return null;
|
|
421
215
|
}
|
|
216
|
+
function resolveRulesFile(name) {
|
|
217
|
+
return findRulesFile(name);
|
|
218
|
+
}
|
|
422
219
|
function loadJson(name) {
|
|
220
|
+
if (!isHotReloadEnabled()) {
|
|
221
|
+
const cached2 = frozenJsonCache.get(name);
|
|
222
|
+
if (cached2 !== void 0) return cached2;
|
|
223
|
+
}
|
|
423
224
|
const p = findRulesFile(name);
|
|
424
225
|
if (!p) return {};
|
|
425
226
|
try {
|
|
426
|
-
|
|
227
|
+
const parsed = JSON.parse(readFileSync2(p, "utf-8")) || {};
|
|
228
|
+
if (!isHotReloadEnabled()) frozenJsonCache.set(name, parsed);
|
|
229
|
+
return parsed;
|
|
427
230
|
} catch {
|
|
428
231
|
return {};
|
|
429
232
|
}
|
|
@@ -463,6 +266,74 @@ function loadL1() {
|
|
|
463
266
|
function loadL2() {
|
|
464
267
|
return loadJson("l2_rules.json");
|
|
465
268
|
}
|
|
269
|
+
function regexFlags(flags) {
|
|
270
|
+
let out = "";
|
|
271
|
+
for (const ch of String(flags ?? "")) if (RE_FLAG_MAP[ch]) out += RE_FLAG_MAP[ch];
|
|
272
|
+
return out;
|
|
273
|
+
}
|
|
274
|
+
function compileRuleRegex(rule, extraFlags = "") {
|
|
275
|
+
return new RegExp(String(rule.pattern), regexFlags(rule.flags) + extraFlags);
|
|
276
|
+
}
|
|
277
|
+
function resolveKeywordSet(group, keywordSets) {
|
|
278
|
+
if (typeof group === "string") return new Set(keywordSets[group.slice(1)] ?? []);
|
|
279
|
+
return new Set(Array.isArray(group) ? group : []);
|
|
280
|
+
}
|
|
281
|
+
function loadFormalRules() {
|
|
282
|
+
return loadJson("formal_rules.json");
|
|
283
|
+
}
|
|
284
|
+
function loadLogicRules() {
|
|
285
|
+
return loadJson("logic_rules.json");
|
|
286
|
+
}
|
|
287
|
+
function loadHeuristicRules() {
|
|
288
|
+
return loadJson("heuristic_rules.json");
|
|
289
|
+
}
|
|
290
|
+
function loadScriptRules() {
|
|
291
|
+
return loadJson("script_rules.json");
|
|
292
|
+
}
|
|
293
|
+
function loadInline() {
|
|
294
|
+
return loadJson("inline_rules.json");
|
|
295
|
+
}
|
|
296
|
+
function loadPlatformTraits(osName) {
|
|
297
|
+
const data = loadJson("platform_traits.json");
|
|
298
|
+
if (!data || Object.keys(data).length === 0) {
|
|
299
|
+
console.error(
|
|
300
|
+
"[AgentMoss] \u274C \u89C4\u5219\u6587\u4EF6 platform_traits.json \u7F3A\u5931\u6216\u635F\u574F \u2014\u2014 \u5E73\u53F0\u7279\u5F81\u56DE\u843D\u4E3A\u7A7A\uFF08\u767D\u540D\u5355\u4E3A\u7A7A\uFF0C\u5224\u5B9A\u4F1A\u53D8\u4E25\uFF09\u3002\u8BF7\u68C0\u67E5\u5305\u5B8C\u6574\u6027\u3002"
|
|
301
|
+
);
|
|
302
|
+
return {};
|
|
303
|
+
}
|
|
304
|
+
const name = resolveTraitsOs(osName);
|
|
305
|
+
const entry = data[name];
|
|
306
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
307
|
+
console.error(`[AgentMoss] platform_traits.json \u91CC\u6CA1\u6709\u53EF\u7528\u7684 ${name} \u6761\u76EE \u2014\u2014 \u5E73\u53F0\u7279\u5F81\u4E3A\u7A7A\u3002`);
|
|
308
|
+
return {};
|
|
309
|
+
}
|
|
310
|
+
const out = {};
|
|
311
|
+
for (const f of TRAITS_FIELDS) if (f in entry) out[f] = entry[f];
|
|
312
|
+
return out;
|
|
313
|
+
}
|
|
314
|
+
function resolveTraitsOs(osName) {
|
|
315
|
+
const data = loadJson("platform_traits.json");
|
|
316
|
+
let name = String(osName || "").trim().toLowerCase() || TRAITS_OS_FALLBACK;
|
|
317
|
+
const seen = /* @__PURE__ */ new Set();
|
|
318
|
+
for (; ; ) {
|
|
319
|
+
if (seen.has(name)) {
|
|
320
|
+
console.error(`[AgentMoss] platform_traits.json \u7684 inherits \u6210\u73AF\uFF08${name}\uFF09\u2014\u2014 \u56DE\u843D linux\u3002`);
|
|
321
|
+
return TRAITS_OS_FALLBACK;
|
|
322
|
+
}
|
|
323
|
+
seen.add(name);
|
|
324
|
+
const entry = data[name];
|
|
325
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
326
|
+
const nxt = entry.inherits;
|
|
327
|
+
if (typeof nxt === "string" && nxt.trim().toLowerCase() !== name) {
|
|
328
|
+
name = nxt.trim().toLowerCase();
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
return name;
|
|
332
|
+
}
|
|
333
|
+
if (name === TRAITS_OS_FALLBACK) return name;
|
|
334
|
+
name = TRAITS_OS_FALLBACK;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
466
337
|
function loadL3() {
|
|
467
338
|
const data = { ...loadJson("l3_rules.json") };
|
|
468
339
|
try {
|
|
@@ -748,6 +619,7 @@ function scanRuleDirs() {
|
|
|
748
619
|
return { override, extra, loaded, ignored };
|
|
749
620
|
}
|
|
750
621
|
function rulesCached() {
|
|
622
|
+
if (!isHotReloadEnabled() && _RULES_CACHE) return _RULES_CACHE;
|
|
751
623
|
const dirs = rulesDirs();
|
|
752
624
|
const sig = RULES_DIR_ENVS.map((e) => `${e}=${process.env[e] || ""}`).join("|") + "|" + dirs.join("|");
|
|
753
625
|
const files = [];
|
|
@@ -783,9 +655,11 @@ function identicalToBuiltin(override) {
|
|
|
783
655
|
return Object.keys(override).length > 0;
|
|
784
656
|
}
|
|
785
657
|
function loadOverrideRules() {
|
|
658
|
+
if (isBuiltinOnly()) return {};
|
|
786
659
|
return rulesCached().override;
|
|
787
660
|
}
|
|
788
661
|
function loadExtraRules() {
|
|
662
|
+
if (isBuiltinOnly()) return {};
|
|
789
663
|
return rulesCached().extra;
|
|
790
664
|
}
|
|
791
665
|
function ruleFilesLoaded() {
|
|
@@ -794,35 +668,33 @@ function ruleFilesLoaded() {
|
|
|
794
668
|
function ignoredRuleFiles() {
|
|
795
669
|
return rulesCached().ignored;
|
|
796
670
|
}
|
|
797
|
-
var __filename2, __dirname2, OVERRIDE_FILENAME, EXTRA_FILENAME, RULES_DIR_ENVS,
|
|
671
|
+
var __filename2, __dirname2, OVERRIDE_FILENAME, EXTRA_FILENAME, RULES_DIR_ENVS, frozenJsonCache, SCENARIO_LIST_KEYS, RE_FLAG_MAP, TRAITS_FIELDS, TRAITS_OS_FALLBACK, EXTRA_CATEGORIES, STRUCT_KEYS, EXTRA_FLAT_FIELD, _RULES_CACHE, warnedIgnored;
|
|
798
672
|
var init_rules_loader = __esm({
|
|
799
673
|
"src/infra/rules-loader.ts"() {
|
|
800
674
|
"use strict";
|
|
801
675
|
init_esm_shims();
|
|
802
676
|
init_paths();
|
|
677
|
+
init_rules_mode();
|
|
803
678
|
init_runtime_config_bridge();
|
|
804
679
|
__filename2 = fileURLToPath2(import.meta.url);
|
|
805
680
|
__dirname2 = dirname(__filename2);
|
|
806
681
|
OVERRIDE_FILENAME = "override.json";
|
|
807
682
|
EXTRA_FILENAME = "extra.json";
|
|
808
683
|
RULES_DIR_ENVS = ["AGENT_MOSS_EXTRA_RULES_DIR", "AGENT_MOSS_OVERRIDE_RULES_DIR"];
|
|
809
|
-
|
|
810
|
-
const cands = [
|
|
811
|
-
// 注:`<data_root>/rules/` 不再是"按内置文件名覆盖"的查找位 —— 2026-10 起
|
|
812
|
-
// 规则目录只认 override.json / extra.json(见 rulesDirs())。
|
|
813
|
-
// dist: __dirname=dist/ → dist/rules;__dirname=dist/engine/ → dist/engine/../rules=dist/rules
|
|
814
|
-
resolve(__dirname2, "../rules"),
|
|
815
|
-
resolve(__dirname2, "rules"),
|
|
816
|
-
// dev src: __dirname=ts/src/infra/ → ts/src/infra/../../../agent_moss/rules = 仓库根 agent_moss/rules
|
|
817
|
-
resolve(__dirname2, "../../../agent_moss/rules"),
|
|
818
|
-
// dist 但 __dirname 指向 dist/engine 再往上两级的仓库根 agent_moss/rules
|
|
819
|
-
resolve(__dirname2, "../../../../agent_moss/rules"),
|
|
820
|
-
// 相对当前工作目录的仓库根(兜底,兼容以仓库根为 cwd 运行)
|
|
821
|
-
resolve(process.cwd(), "agent_moss/rules")
|
|
822
|
-
];
|
|
823
|
-
return cands.filter((c) => existsSync(c));
|
|
824
|
-
})();
|
|
684
|
+
frozenJsonCache = /* @__PURE__ */ new Map();
|
|
825
685
|
SCENARIO_LIST_KEYS = ["extra_command_patterns", "extra_injection_keywords", "extra_sensitive_paths"];
|
|
686
|
+
RE_FLAG_MAP = { i: "i", s: "s", m: "m" };
|
|
687
|
+
TRAITS_FIELDS = [
|
|
688
|
+
"write_keywords",
|
|
689
|
+
"read_keywords",
|
|
690
|
+
"write_command_res",
|
|
691
|
+
"read_only_commands",
|
|
692
|
+
"fully_safe_commands",
|
|
693
|
+
"readonly_sensitive_commands",
|
|
694
|
+
"safe_action_types",
|
|
695
|
+
"readonly_sensitive_action_types"
|
|
696
|
+
];
|
|
697
|
+
TRAITS_OS_FALLBACK = "linux";
|
|
826
698
|
EXTRA_CATEGORIES = {
|
|
827
699
|
dangerous_commands: ["pattern"],
|
|
828
700
|
injection_detection: ["keyword", "lang"],
|
|
@@ -844,7 +716,199 @@ var init_rules_loader = __esm({
|
|
|
844
716
|
}
|
|
845
717
|
});
|
|
846
718
|
|
|
719
|
+
// src/engine/shell-split.ts
|
|
720
|
+
function hasCommandSubstitution(text) {
|
|
721
|
+
return CMD_SUBSTITUTION.test(text);
|
|
722
|
+
}
|
|
723
|
+
function splitCommandSegments(command) {
|
|
724
|
+
const segments = [];
|
|
725
|
+
let cur = "";
|
|
726
|
+
let quote = null;
|
|
727
|
+
for (let i = 0; i < command.length; i++) {
|
|
728
|
+
const ch = command[i];
|
|
729
|
+
if (quote) {
|
|
730
|
+
cur += ch;
|
|
731
|
+
if (ch === quote) quote = null;
|
|
732
|
+
continue;
|
|
733
|
+
}
|
|
734
|
+
if (ch === "'" || ch === '"') {
|
|
735
|
+
quote = ch;
|
|
736
|
+
cur += ch;
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
if (/\||&|;|\n/.test(ch)) {
|
|
740
|
+
segments.push(cur);
|
|
741
|
+
segments.push(ch);
|
|
742
|
+
cur = "";
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
745
|
+
cur += ch;
|
|
746
|
+
}
|
|
747
|
+
if (cur) segments.push(cur);
|
|
748
|
+
return segments.map((s) => s.trim()).filter((s) => s.length > 0 && !/^(?:\|\||&&|[|;&])$/.test(s));
|
|
749
|
+
}
|
|
750
|
+
function extractFirstCommand(command) {
|
|
751
|
+
const segments = splitCommandSegments(command);
|
|
752
|
+
return segments.length ? segments[0] : "";
|
|
753
|
+
}
|
|
754
|
+
var CMD_SUBSTITUTION;
|
|
755
|
+
var init_shell_split = __esm({
|
|
756
|
+
"src/engine/shell-split.ts"() {
|
|
757
|
+
"use strict";
|
|
758
|
+
init_esm_shims();
|
|
759
|
+
CMD_SUBSTITUTION = /\$\(|`|</;
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
// src/engine/inline-analyzer.ts
|
|
764
|
+
function buildChainRegex(pattern, flags) {
|
|
765
|
+
return new RegExp(pattern, (flags || "") + "g");
|
|
766
|
+
}
|
|
767
|
+
function isLiteralTextCommand(command) {
|
|
768
|
+
const segments = splitCommandSegments(command);
|
|
769
|
+
if (segments.length === 0 || segments.some((s) => !ECHO_SEG_RE.test(s))) return false;
|
|
770
|
+
if (command.includes(">")) {
|
|
771
|
+
let d = command.replace(/<=>|>=|<=|<>|=>/g, " ");
|
|
772
|
+
d = d.replace(/(?:2|&|1)?\s*>\s*\/dev\/null\b/g, "");
|
|
773
|
+
d = d.replace(new RegExp(`>{1,2}\\s*(['"])([~./][^'"]+)\\1`, "g"), (_m, _q, p) => ">" + p);
|
|
774
|
+
d = d.replace(/'[^']*'|"[^"]*"/g, "");
|
|
775
|
+
if (/>{1,2}\s*(?!&)\S/.test(d)) {
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (/\|\s*\b(?:tee|tac|install)\b/i.test(command)) {
|
|
780
|
+
return false;
|
|
781
|
+
}
|
|
782
|
+
return true;
|
|
783
|
+
}
|
|
784
|
+
function extractInlineCode(command) {
|
|
785
|
+
const parts = [];
|
|
786
|
+
let m;
|
|
787
|
+
INLINE_CODE_RE.lastIndex = 0;
|
|
788
|
+
while ((m = INLINE_CODE_RE.exec(command)) !== null) {
|
|
789
|
+
const code = m[1] ?? m[2];
|
|
790
|
+
if (code) parts.push(code);
|
|
791
|
+
}
|
|
792
|
+
ECHO_STRING_RE.lastIndex = 0;
|
|
793
|
+
while ((m = ECHO_STRING_RE.exec(command)) !== null) {
|
|
794
|
+
const code = m[1] ?? m[2];
|
|
795
|
+
if (code) parts.push(code);
|
|
796
|
+
}
|
|
797
|
+
return parts.join("\n");
|
|
798
|
+
}
|
|
799
|
+
function hasWriteExecChain(command) {
|
|
800
|
+
return WRITE_EXEC_CHAIN_PATTERNS.some((p) => {
|
|
801
|
+
p.lastIndex = 0;
|
|
802
|
+
return p.test(command);
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
function hasDirTraversal(code) {
|
|
806
|
+
const lower = code.toLowerCase();
|
|
807
|
+
return DIR_TRAVERSAL_KEYWORDS.some((kw) => lower.includes(kw));
|
|
808
|
+
}
|
|
809
|
+
function hasReadWriteKeyword(code) {
|
|
810
|
+
const lower = code.toLowerCase();
|
|
811
|
+
return READ_WRITE_KEYWORDS.some((kw) => lower.includes(kw));
|
|
812
|
+
}
|
|
813
|
+
function analyzeInlineScript(command) {
|
|
814
|
+
const code = extractInlineCode(command);
|
|
815
|
+
if (!code) {
|
|
816
|
+
return { actionable: false, allowed: true, reason: "", riskLevel: "low", riskType: "" };
|
|
817
|
+
}
|
|
818
|
+
if (hasWriteExecChain(command)) {
|
|
819
|
+
return {
|
|
820
|
+
actionable: true,
|
|
821
|
+
allowed: false,
|
|
822
|
+
reason: "\u5185\u8054\u811A\u672C\u542B\u5199\u5165\u6587\u4EF6\u540E\u6267\u884C\u7684\u6A21\u5F0F\uFF0C\u7591\u4F3C\u7ED5\u8FC7\u654F\u611F\u8DEF\u5F84\u68C0\u6D4B",
|
|
823
|
+
riskLevel: "critical",
|
|
824
|
+
riskType: "script_execution"
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
const redirMatch = command.match(REDIRECT_TO_SENSITIVE_RE);
|
|
828
|
+
if (redirMatch) {
|
|
829
|
+
return {
|
|
830
|
+
actionable: true,
|
|
831
|
+
allowed: false,
|
|
832
|
+
reason: `\u91CD\u5B9A\u5411\u5199\u5165\u654F\u611F\u8DEF\u5F84: ${redirMatch[1]}`,
|
|
833
|
+
riskLevel: "critical",
|
|
834
|
+
riskType: "file_access"
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
const isEchoOrPrintf1 = isLiteralTextCommand(command);
|
|
838
|
+
if (!isEchoOrPrintf1 && hasDirTraversal(code) && hasReadWriteKeyword(code)) {
|
|
839
|
+
return { actionable: false, allowed: true, reason: "", riskLevel: "low", riskType: "" };
|
|
840
|
+
}
|
|
841
|
+
const isEchoOrPrintf = isLiteralTextCommand(command);
|
|
842
|
+
if (!isEchoOrPrintf && hasReadWriteKeyword(code)) {
|
|
843
|
+
return {
|
|
844
|
+
actionable: true,
|
|
845
|
+
allowed: false,
|
|
846
|
+
reason: "\u5185\u8054\u811A\u672C\u542B\u654F\u611F\u8DEF\u5F84\u4E14\u542B\u6587\u4EF6\u8BFB\u5199/\u547D\u4EE4\u6267\u884C\u8C03\u7528\uFF0C\u5224\u4E3A\u771F\u5B9E\u8BBF\u95EE",
|
|
847
|
+
riskLevel: "critical",
|
|
848
|
+
riskType: "file_access"
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
return {
|
|
852
|
+
actionable: true,
|
|
853
|
+
allowed: true,
|
|
854
|
+
reason: "\u654F\u611F\u8DEF\u5F84\u4EC5\u4F5C\u4E3A\u6587\u672C\u5B57\u9762\u91CF\u51FA\u73B0\uFF0C\u672A\u4F34\u968F\u8BFB\u5199\u64CD\u4F5C",
|
|
855
|
+
riskLevel: "low",
|
|
856
|
+
riskType: "file_access"
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
var INLINE_RULES, INLINE_CODE_RE, ECHO_STRING_RE, ECHO_SEG_RE, READ_WRITE_KEYWORDS, WRITE_EXEC_CHAIN_PATTERNS, _REDIRECT_PATHS, SHELL_RC_FRAGMENTS, SENSITIVE_PATH_FRAGMENTS, REDIRECT_TO_SENSITIVE_RE, DIR_TRAVERSAL_KEYWORDS;
|
|
860
|
+
var init_inline_analyzer = __esm({
|
|
861
|
+
"src/engine/inline-analyzer.ts"() {
|
|
862
|
+
"use strict";
|
|
863
|
+
init_esm_shims();
|
|
864
|
+
init_shell_split();
|
|
865
|
+
init_rules_loader();
|
|
866
|
+
INLINE_RULES = loadInline();
|
|
867
|
+
if (!INLINE_RULES || Object.keys(INLINE_RULES).length === 0) {
|
|
868
|
+
console.error(
|
|
869
|
+
"[AgentMoss] \u274C \u89C4\u5219\u6587\u4EF6 inline_rules.json \u7F3A\u5931\u6216\u635F\u574F \u2014\u2014 \u5185\u8054\u811A\u672C\u5224\u5B9A\u8BCD\u8868\u4E3A\u7A7A\uFF0C\u5185\u8054\u811A\u672C\u4E2D\u7684\u654F\u611F\u8DEF\u5F84\u8BFB\u5199\u5C06\u6309\u300C\u6587\u672C\u5B57\u9762\u91CF\u300D\u653E\u884C\uFF08\u6BD4\u6B63\u5E38\u66F4\u677E\uFF09\u3002\u8BF7\u68C0\u67E5\u5305\u5B8C\u6574\u6027\u3002"
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
INLINE_CODE_RE = /(?:python|python3|perl|perl5|ruby|jruby|mruby|node|php|lua)\s+(?:-[a-zA-Z]*[cera][a-zA-Z]*\s+)"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'/gi;
|
|
873
|
+
ECHO_STRING_RE = /\b(?:echo|printf)\s+"([^"\\]*(?:\\.[^"\\]*)*)"|\b(?:echo|printf)\s+'([^'\\]*(?:\\.[^'\\]*)*)'/gi;
|
|
874
|
+
ECHO_SEG_RE = /^\s*(?:echo|printf)(?:\s|$)/i;
|
|
875
|
+
READ_WRITE_KEYWORDS = INLINE_RULES.read_write_keywords ?? [];
|
|
876
|
+
WRITE_EXEC_CHAIN_PATTERNS = (INLINE_RULES.write_exec_chain_patterns ?? []).filter((p) => p && typeof p.pattern === "string").map((p) => buildChainRegex(p.pattern, p.flags ?? ""));
|
|
877
|
+
_REDIRECT_PATHS = INLINE_RULES.redirect_sensitive_paths ?? {};
|
|
878
|
+
SHELL_RC_FRAGMENTS = _REDIRECT_PATHS.shell_rc_fragments ?? [];
|
|
879
|
+
SENSITIVE_PATH_FRAGMENTS = [
|
|
880
|
+
..._REDIRECT_PATHS.ts_static ?? [],
|
|
881
|
+
...SHELL_RC_FRAGMENTS
|
|
882
|
+
];
|
|
883
|
+
REDIRECT_TO_SENSITIVE_RE = new RegExp(`>{1,2}\\s*(?:\\S*/)?(${SENSITIVE_PATH_FRAGMENTS.map((p) => p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})(?:\\s|$)`, "i");
|
|
884
|
+
DIR_TRAVERSAL_KEYWORDS = INLINE_RULES.dir_traversal_keywords ?? [];
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
|
|
847
888
|
// src/engine/platform-traits.ts
|
|
889
|
+
function buildTraits(osName) {
|
|
890
|
+
const t = loadPlatformTraits(osName);
|
|
891
|
+
const strs = (k) => Array.isArray(t[k]) ? t[k] : [];
|
|
892
|
+
return {
|
|
893
|
+
writeKeywords: strs("write_keywords"),
|
|
894
|
+
readKeywords: strs("read_keywords"),
|
|
895
|
+
writeCommandRes: strs("write_command_res").map((p) => new RegExp(p)),
|
|
896
|
+
readOnlyCommands: new Set(strs("read_only_commands")),
|
|
897
|
+
fullySafeCommands: strs("fully_safe_commands").map((p) => new RegExp(p, "i")),
|
|
898
|
+
readonlySensitiveCommands: strs("readonly_sensitive_commands").map((p) => new RegExp(p, "i")),
|
|
899
|
+
safeActionTypes: new Set(strs("safe_action_types")),
|
|
900
|
+
readonlySensitiveActionTypes: new Set(strs("readonly_sensitive_action_types"))
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
function traitsFor(key) {
|
|
904
|
+
const resolved = resolveTraitsOs(key);
|
|
905
|
+
let t = traitsCache.get(resolved);
|
|
906
|
+
if (!t) {
|
|
907
|
+
t = buildTraits(resolved);
|
|
908
|
+
traitsCache.set(resolved, t);
|
|
909
|
+
}
|
|
910
|
+
return t;
|
|
911
|
+
}
|
|
848
912
|
function getPlatformTraits(osType) {
|
|
849
913
|
const accepted = acceptedOsValues(osType);
|
|
850
914
|
if (accepted.includes("windows")) return WINDOWS_TRAITS;
|
|
@@ -852,368 +916,18 @@ function getPlatformTraits(osType) {
|
|
|
852
916
|
if (accepted.includes("harmony")) return HARMONY_TRAITS;
|
|
853
917
|
return LINUX_TRAITS;
|
|
854
918
|
}
|
|
855
|
-
var LINUX_TRAITS, WINDOWS_TRAITS, MACOS_TRAITS, HARMONY_TRAITS;
|
|
919
|
+
var traitsCache, LINUX_TRAITS, WINDOWS_TRAITS, MACOS_TRAITS, HARMONY_TRAITS;
|
|
856
920
|
var init_platform_traits = __esm({
|
|
857
921
|
"src/engine/platform-traits.ts"() {
|
|
858
922
|
"use strict";
|
|
859
923
|
init_esm_shims();
|
|
860
924
|
init_logic_rules();
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
"modify",
|
|
868
|
-
"\u4FEE\u6539",
|
|
869
|
-
"update",
|
|
870
|
-
"\u66F4\u65B0",
|
|
871
|
-
"delete",
|
|
872
|
-
"\u5220\u9664",
|
|
873
|
-
"remove",
|
|
874
|
-
"\u79FB\u9664",
|
|
875
|
-
"create",
|
|
876
|
-
"\u521B\u5EFA",
|
|
877
|
-
"append",
|
|
878
|
-
"\u8FFD\u52A0",
|
|
879
|
-
"truncate",
|
|
880
|
-
"\u622A\u65AD",
|
|
881
|
-
"overwrite",
|
|
882
|
-
"\u8986\u76D6",
|
|
883
|
-
"replace",
|
|
884
|
-
"\u66FF\u6362",
|
|
885
|
-
"edit"
|
|
886
|
-
],
|
|
887
|
-
readKeywords: [
|
|
888
|
-
"read",
|
|
889
|
-
"\u8BFB\u53D6",
|
|
890
|
-
"cat",
|
|
891
|
-
"head",
|
|
892
|
-
"tail",
|
|
893
|
-
"less",
|
|
894
|
-
"more",
|
|
895
|
-
"view",
|
|
896
|
-
"\u67E5\u770B",
|
|
897
|
-
"open",
|
|
898
|
-
"\u6253\u5F00",
|
|
899
|
-
"load",
|
|
900
|
-
"\u52A0\u8F7D",
|
|
901
|
-
"grep",
|
|
902
|
-
"search",
|
|
903
|
-
"\u641C\u7D22",
|
|
904
|
-
"find",
|
|
905
|
-
"\u67E5\u627E"
|
|
906
|
-
],
|
|
907
|
-
writeCommandRes: [
|
|
908
|
-
/\brm\b/,
|
|
909
|
-
/\bunlink\b/,
|
|
910
|
-
/\brmdir\b/,
|
|
911
|
-
/\bshred\b/,
|
|
912
|
-
/\bcp\b/,
|
|
913
|
-
/\bmv\b/,
|
|
914
|
-
/\binstall\b/,
|
|
915
|
-
/\btee\b/,
|
|
916
|
-
/\bdd\b/,
|
|
917
|
-
/\bmkfs\b/,
|
|
918
|
-
/\b(fdisk|parted|cfdisk|sfdisk)\b/,
|
|
919
|
-
/\bchmod\b/,
|
|
920
|
-
/\bchown\b/,
|
|
921
|
-
/\btruncate\b/
|
|
922
|
-
],
|
|
923
|
-
readOnlyCommands: /* @__PURE__ */ new Set([
|
|
924
|
-
"cat",
|
|
925
|
-
"head",
|
|
926
|
-
"tail",
|
|
927
|
-
"less",
|
|
928
|
-
"more",
|
|
929
|
-
"grep",
|
|
930
|
-
"find",
|
|
931
|
-
"awk",
|
|
932
|
-
"sed",
|
|
933
|
-
"sort",
|
|
934
|
-
"uniq",
|
|
935
|
-
"wc",
|
|
936
|
-
"cut",
|
|
937
|
-
"strings",
|
|
938
|
-
"od",
|
|
939
|
-
"xxd",
|
|
940
|
-
"hexdump",
|
|
941
|
-
"tr",
|
|
942
|
-
"file",
|
|
943
|
-
"stat",
|
|
944
|
-
"du",
|
|
945
|
-
"df",
|
|
946
|
-
"ls",
|
|
947
|
-
"dir",
|
|
948
|
-
"tree",
|
|
949
|
-
"nl",
|
|
950
|
-
"tac",
|
|
951
|
-
"rev",
|
|
952
|
-
"echo",
|
|
953
|
-
"printf",
|
|
954
|
-
"lsblk",
|
|
955
|
-
"blockdev",
|
|
956
|
-
"smartctl",
|
|
957
|
-
"udevadm",
|
|
958
|
-
"dmidecode",
|
|
959
|
-
"lscpu",
|
|
960
|
-
"lspci",
|
|
961
|
-
"lsusb",
|
|
962
|
-
"lsmem",
|
|
963
|
-
"lsns",
|
|
964
|
-
"lsof",
|
|
965
|
-
"hwinfo",
|
|
966
|
-
"inxi",
|
|
967
|
-
"fdisk",
|
|
968
|
-
"parted",
|
|
969
|
-
"dmesg",
|
|
970
|
-
"journalctl",
|
|
971
|
-
"systemctl",
|
|
972
|
-
"hostnamectl",
|
|
973
|
-
"localectl",
|
|
974
|
-
"timedatectl",
|
|
975
|
-
"ps",
|
|
976
|
-
"top",
|
|
977
|
-
"free",
|
|
978
|
-
"vmstat",
|
|
979
|
-
"iostat",
|
|
980
|
-
"mpstat",
|
|
981
|
-
"pidof",
|
|
982
|
-
"pgrep",
|
|
983
|
-
"ip",
|
|
984
|
-
"ifconfig",
|
|
985
|
-
"route",
|
|
986
|
-
"ss",
|
|
987
|
-
"netstat",
|
|
988
|
-
"arp",
|
|
989
|
-
"ethtool",
|
|
990
|
-
"nmcli",
|
|
991
|
-
"uname",
|
|
992
|
-
"arch",
|
|
993
|
-
"nproc",
|
|
994
|
-
"getconf",
|
|
995
|
-
"getent",
|
|
996
|
-
"id",
|
|
997
|
-
"whoami",
|
|
998
|
-
"who",
|
|
999
|
-
"w",
|
|
1000
|
-
"last",
|
|
1001
|
-
"uptime",
|
|
1002
|
-
"lsmod",
|
|
1003
|
-
"modinfo",
|
|
1004
|
-
"sysctl"
|
|
1005
|
-
]),
|
|
1006
|
-
fullySafeCommands: [
|
|
1007
|
-
/^ls(?:\s|$)/i,
|
|
1008
|
-
/^dir(?:\s|$)/i,
|
|
1009
|
-
/^pwd(?:\s|$)/i,
|
|
1010
|
-
/^which\s+/i,
|
|
1011
|
-
/^whereis\s+/i,
|
|
1012
|
-
/^realpath\s+/i,
|
|
1013
|
-
/^basename\s+/i,
|
|
1014
|
-
/^dirname\s+/i,
|
|
1015
|
-
/^file\s+/i,
|
|
1016
|
-
/^stat\s+/i,
|
|
1017
|
-
/^du(?:\s|$)/i,
|
|
1018
|
-
/^echo\s+/i,
|
|
1019
|
-
/^printf\s+/i,
|
|
1020
|
-
/^type\s+/i,
|
|
1021
|
-
/^command\s+/i,
|
|
1022
|
-
// 系统信息查询(只读,不涉及文件/网络/权限)
|
|
1023
|
-
/^whoami(?:\s|$)/i,
|
|
1024
|
-
/^id(?:\s|$)/i,
|
|
1025
|
-
/^hostname(?:\s|$)/i,
|
|
1026
|
-
/^uname(?:\s|$)/i,
|
|
1027
|
-
/^date(?:\s|$)/i,
|
|
1028
|
-
/^env(?:\s|$)/i,
|
|
1029
|
-
/^printenv(?:\s|$)/i,
|
|
1030
|
-
/^tty(?:\s|$)/i,
|
|
1031
|
-
/^arch(?:\s|$)/i,
|
|
1032
|
-
/^uptime(?:\s|$)/i,
|
|
1033
|
-
/^groups(?:\s|$)/i,
|
|
1034
|
-
/^logname(?:\s|$)/i,
|
|
1035
|
-
// 系统资源/硬件信息(只读,不读文件内容、无状态变更选项)
|
|
1036
|
-
// 与上面 uptime/uname/id 同性质;缺了它们时开 L3 的部署每查一次磁盘/内存
|
|
1037
|
-
// 都要走 LLM(实测 df -h 从 5ms 变成十几秒)。
|
|
1038
|
-
/^df(?:\s|$)/i,
|
|
1039
|
-
/^free(?:\s|$)/i,
|
|
1040
|
-
/^vmstat(?:\s|$)/i,
|
|
1041
|
-
/^nproc(?:\s|$)/i,
|
|
1042
|
-
/^lscpu(?:\s|$)/i,
|
|
1043
|
-
/^lsblk(?:\s|$)/i,
|
|
1044
|
-
/^lspci(?:\s|$)/i,
|
|
1045
|
-
/^lsusb(?:\s|$)/i,
|
|
1046
|
-
/^lsmod(?:\s|$)/i
|
|
1047
|
-
],
|
|
1048
|
-
readonlySensitiveCommands: [
|
|
1049
|
-
/^cat\s+/i,
|
|
1050
|
-
/^head(?:\s|$)/i,
|
|
1051
|
-
/^tail(?:\s|$)/i,
|
|
1052
|
-
/^less(?:\s|$)/i,
|
|
1053
|
-
/^more(?:\s|$)/i,
|
|
1054
|
-
/^wc(?:\s|$)/i,
|
|
1055
|
-
/^grep(?:\s|$)/i,
|
|
1056
|
-
/^find\s+/i,
|
|
1057
|
-
/^ag(?:\s|$)/i,
|
|
1058
|
-
/^rg(?:\s|$)/i,
|
|
1059
|
-
/^awk\s+/i,
|
|
1060
|
-
// NEW-FN-P(M03):sed -i/--in-place 是原地写,挡出白名单走 L2 read_before_write。
|
|
1061
|
-
// 前瞻放最前(外层 ^sed\s+ 会消费 -i 前的空格)。与 Python profiles/linux.py 对齐。
|
|
1062
|
-
/^(?!.*(?:\s|['"])-[a-zA-Z]*i[a-zA-Z]*\b)(?!.*(?:\s|['"])--in-place)sed\s+/i,
|
|
1063
|
-
/^cut\s+/i,
|
|
1064
|
-
/^sort(?:\s|$)/i,
|
|
1065
|
-
/^uniq(?:\s|$)/i,
|
|
1066
|
-
// 进程/网络/打开文件信息:只读,但会暴露进程命令行、连接对端、打开的文件
|
|
1067
|
-
// 路径,故只跳 L3、保留 L2(L1 敏感路径检测照常生效)。
|
|
1068
|
-
/^ps(?:\s|$)/i,
|
|
1069
|
-
/^ss(?:\s|$)/i,
|
|
1070
|
-
/^netstat(?:\s|$)/i,
|
|
1071
|
-
/^lsof(?:\s|$)/i,
|
|
1072
|
-
// 只读子命令级白名单:匹配的是「第一段命令」而非首词(extractFirstCommand
|
|
1073
|
-
// 按 | && || 切分),所以能精确到子命令。systemctl stop/disable 等不在此列。
|
|
1074
|
-
/^systemctl\s+(?:status|is-active|is-enabled|is-failed|list-units|list-unit-files|list-dependencies|show|cat)\b/i,
|
|
1075
|
-
/^service\s+\S+\s+status\b/i,
|
|
1076
|
-
// journalctl 整族是只读的,但 --vacuum-*/--rotate/--flush/--sync 会删改日志,
|
|
1077
|
-
// 用否定前瞻挡掉后再放行。注意前瞻里必须用 .* 扫描**整段**:只写 (?!\s+--...)
|
|
1078
|
-
// 的话只看紧跟 journalctl 的第一个参数,
|
|
1079
|
-
// `journalctl -u sshd --vacuum-size=100M` 就漏过去了。
|
|
1080
|
-
/^journalctl\b(?!.*--(?:vacuum-size|vacuum-time|vacuum-files|rotate|flush|sync)\b)/i
|
|
1081
|
-
]
|
|
1082
|
-
};
|
|
1083
|
-
WINDOWS_TRAITS = {
|
|
1084
|
-
writeKeywords: [
|
|
1085
|
-
"write",
|
|
1086
|
-
"\u5199\u5165",
|
|
1087
|
-
"save",
|
|
1088
|
-
"\u4FDD\u5B58",
|
|
1089
|
-
"modify",
|
|
1090
|
-
"\u4FEE\u6539",
|
|
1091
|
-
"update",
|
|
1092
|
-
"\u66F4\u65B0",
|
|
1093
|
-
"delete",
|
|
1094
|
-
"\u5220\u9664",
|
|
1095
|
-
"remove",
|
|
1096
|
-
"\u79FB\u9664",
|
|
1097
|
-
"create",
|
|
1098
|
-
"\u521B\u5EFA",
|
|
1099
|
-
"append",
|
|
1100
|
-
"\u8FFD\u52A0",
|
|
1101
|
-
"overwrite",
|
|
1102
|
-
"\u8986\u76D6",
|
|
1103
|
-
"replace",
|
|
1104
|
-
"\u66FF\u6362",
|
|
1105
|
-
"set",
|
|
1106
|
-
"\u8BBE\u7F6E"
|
|
1107
|
-
// 注意:这里**不能放 `reg` / `注册表`**。关键词是子串包含匹配,放进去等于
|
|
1108
|
-
// 「只要命令里出现 reg 字样就算写操作」——`reg query`(读)会被判成写,
|
|
1109
|
-
// 进而误拦对 deny_write 路径的只读查询。注册表的写判定交给下面的
|
|
1110
|
-
// writeCommandRes(只认写子命令)。两端语义必须一致。
|
|
1111
|
-
],
|
|
1112
|
-
readKeywords: [
|
|
1113
|
-
"read",
|
|
1114
|
-
"\u8BFB\u53D6",
|
|
1115
|
-
"type",
|
|
1116
|
-
"findstr",
|
|
1117
|
-
"dir",
|
|
1118
|
-
"view",
|
|
1119
|
-
"\u67E5\u770B",
|
|
1120
|
-
"open",
|
|
1121
|
-
"\u6253\u5F00",
|
|
1122
|
-
"load",
|
|
1123
|
-
"\u52A0\u8F7D",
|
|
1124
|
-
"search",
|
|
1125
|
-
"\u641C\u7D22",
|
|
1126
|
-
"find",
|
|
1127
|
-
"\u67E5\u627E",
|
|
1128
|
-
"get",
|
|
1129
|
-
"\u83B7\u53D6"
|
|
1130
|
-
],
|
|
1131
|
-
// Windows 写/删命令:del/copy/move/xcopy/replace/rmdir/icacls/reg delete 等
|
|
1132
|
-
writeCommandRes: [
|
|
1133
|
-
/\b(del|erase)\b/,
|
|
1134
|
-
/\brmdir\b/,
|
|
1135
|
-
/\b(rd)\b/,
|
|
1136
|
-
/\bcopy\b/,
|
|
1137
|
-
/\b(xcopy|robocopy)\b/,
|
|
1138
|
-
/\b(move|movefile)\b/,
|
|
1139
|
-
/\breplace\b/,
|
|
1140
|
-
/\bicacls\b/,
|
|
1141
|
-
/\battrib\b/,
|
|
1142
|
-
// 注册表:**只认写子命令**(对齐 Python WindowsProfile.write_command_res)。
|
|
1143
|
-
// 此前是 /\breg\b/,把 reg query(读)也判成写 → 误拦对 deny_write 路径的只读查询。
|
|
1144
|
-
// 写子命令 add/delete/copy/save/restore/import/load/unload;
|
|
1145
|
-
// 读子命令 query/compare/export/flags/help 不在此列。
|
|
1146
|
-
/\breg(?:\.exe)?\s+(?:add|delete|copy|save|restore|import|load|unload)\b/,
|
|
1147
|
-
/\bformat\b/,
|
|
1148
|
-
/\bdiskpart\b/,
|
|
1149
|
-
/\bmkdir\b/,
|
|
1150
|
-
/\bmd\b/,
|
|
1151
|
-
/\bsetx\b/,
|
|
1152
|
-
/\bwmic\b/
|
|
1153
|
-
],
|
|
1154
|
-
// Windows 只读命令(重定向写判定用):type/findstr/more/tree/dir 等
|
|
1155
|
-
readOnlyCommands: /* @__PURE__ */ new Set([
|
|
1156
|
-
"type",
|
|
1157
|
-
"findstr",
|
|
1158
|
-
"more",
|
|
1159
|
-
"tree",
|
|
1160
|
-
"dir",
|
|
1161
|
-
"where",
|
|
1162
|
-
"ver",
|
|
1163
|
-
"cls",
|
|
1164
|
-
"echo",
|
|
1165
|
-
"help",
|
|
1166
|
-
"fc",
|
|
1167
|
-
"comp",
|
|
1168
|
-
"find",
|
|
1169
|
-
"sort",
|
|
1170
|
-
"powershell",
|
|
1171
|
-
"cmd",
|
|
1172
|
-
"netstat",
|
|
1173
|
-
"ipconfig",
|
|
1174
|
-
"tasklist",
|
|
1175
|
-
"systeminfo",
|
|
1176
|
-
"driverquery",
|
|
1177
|
-
"reg",
|
|
1178
|
-
"wmic",
|
|
1179
|
-
"whoami",
|
|
1180
|
-
"hostname",
|
|
1181
|
-
"getmac",
|
|
1182
|
-
"query",
|
|
1183
|
-
"w32tm",
|
|
1184
|
-
"diskpart"
|
|
1185
|
-
]),
|
|
1186
|
-
// Windows 完全安全命令(对齐 WindowsProfile.fully_safe_commands)
|
|
1187
|
-
fullySafeCommands: [
|
|
1188
|
-
/^dir(?:\s|$)/,
|
|
1189
|
-
/^where\s+/,
|
|
1190
|
-
/^echo\s+/,
|
|
1191
|
-
/^cd(?:\s|$)/,
|
|
1192
|
-
/^tree(?:\s|$)/,
|
|
1193
|
-
/^help(?:\s|$)/,
|
|
1194
|
-
/^cls(?:\s|$)/,
|
|
1195
|
-
/^ver(?:\s|$)/,
|
|
1196
|
-
// 系统信息查询(只读,不读文件内容、无状态变更选项),与 Linux 侧 df/free 对齐
|
|
1197
|
-
/^whoami(?:\s|$)/,
|
|
1198
|
-
/^hostname(?:\s|$)/,
|
|
1199
|
-
/^systeminfo(?:\s|$)/,
|
|
1200
|
-
/^tasklist(?:\s|$)/,
|
|
1201
|
-
/^getmac(?:\s|$)/,
|
|
1202
|
-
/^driverquery(?:\s|$)/,
|
|
1203
|
-
/^netstat(?:\s|$)/
|
|
1204
|
-
],
|
|
1205
|
-
// Windows 安全但可能访问敏感路径的命令(对齐 WindowsProfile.readonly_sensitive_commands)
|
|
1206
|
-
readonlySensitiveCommands: [
|
|
1207
|
-
/^type\s+/,
|
|
1208
|
-
/^findstr\s+/,
|
|
1209
|
-
// 只读子命令级白名单(匹配「第一段命令」而非首词);
|
|
1210
|
-
// sc create/delete/start/stop、reg add/delete/set 均不在此列。
|
|
1211
|
-
/^sc\s+query\b/,
|
|
1212
|
-
/^reg\s+query\b/
|
|
1213
|
-
]
|
|
1214
|
-
};
|
|
1215
|
-
MACOS_TRAITS = LINUX_TRAITS;
|
|
1216
|
-
HARMONY_TRAITS = LINUX_TRAITS;
|
|
925
|
+
init_rules_loader();
|
|
926
|
+
traitsCache = /* @__PURE__ */ new Map();
|
|
927
|
+
LINUX_TRAITS = traitsFor("linux");
|
|
928
|
+
WINDOWS_TRAITS = traitsFor("windows");
|
|
929
|
+
MACOS_TRAITS = traitsFor("macos");
|
|
930
|
+
HARMONY_TRAITS = traitsFor("harmony");
|
|
1217
931
|
}
|
|
1218
932
|
});
|
|
1219
933
|
|
|
@@ -1372,7 +1086,6 @@ function checkIntentConsistency(input) {
|
|
|
1372
1086
|
const { aNext, promptSession, promptHistory } = input;
|
|
1373
1087
|
const actionDetail = aNext.actionDetail.toLowerCase();
|
|
1374
1088
|
const actionType = aNext.actionType.toLowerCase();
|
|
1375
|
-
const EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
1376
1089
|
if (EXCLUDED_PREFIXES.some((p) => actionType.startsWith(p))) return null;
|
|
1377
1090
|
if (INLINE_SCRIPT_RE.test(actionDetail)) return null;
|
|
1378
1091
|
const intentTexts = collectIntentTexts(promptSession, promptHistory);
|
|
@@ -1400,7 +1113,6 @@ function runLogicCheck(input, opts) {
|
|
|
1400
1113
|
const actionDetail = aNext.actionDetail.toLowerCase();
|
|
1401
1114
|
const actionType = aNext.actionType.toLowerCase();
|
|
1402
1115
|
const resolvedCwd = cwd || "/";
|
|
1403
|
-
const EXCLUDED_PREFIXES = ["memory-", "skill-", "skill-manager-", "mailbox-", "app-"];
|
|
1404
1116
|
const isExcludedType = EXCLUDED_PREFIXES.some((p) => actionType.startsWith(p));
|
|
1405
1117
|
if (!opts?.skipReadBeforeWrite) {
|
|
1406
1118
|
const rbwResult = checkReadBeforeWrite(actionType, actionDetail, actionHistory, input.reason, resolvedCwd, input.osType);
|
|
@@ -1512,7 +1224,7 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
|
|
|
1512
1224
|
const isBashLike = actionType === "bash" || actionType === "executebash" || actionType === "terminal-executebash";
|
|
1513
1225
|
const isWrite = isBashLike ? isWriteOperation(actionType, actionDetail, void 0, osType) : getPlatformTraits(osType).writeKeywords.some((kw) => actionType.includes(kw));
|
|
1514
1226
|
if (!isWrite) return null;
|
|
1515
|
-
const WRITE_CMDS =
|
|
1227
|
+
const WRITE_CMDS = new Set(_LOGIC.write_commands ?? []);
|
|
1516
1228
|
if (isBashLike) {
|
|
1517
1229
|
const detailNoCompare = actionDetail.replace(/<=>|>=|<=|<>|=>/g, " ");
|
|
1518
1230
|
const detailNoDevnull = detailNoCompare.replace(DEVNULL_REDIRECT_RE, "");
|
|
@@ -1544,7 +1256,7 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
|
|
|
1544
1256
|
}
|
|
1545
1257
|
if (!hasWriteSeg) return null;
|
|
1546
1258
|
}
|
|
1547
|
-
const SOURCE_ARG_CMDS =
|
|
1259
|
+
const SOURCE_ARG_CMDS = new Set(_LOGIC.source_arg_commands ?? []);
|
|
1548
1260
|
const REDIRECT_TARGET_RE = new RegExp(`>{1,2}\\s*(?!&)(?:'(/[^']+)'|"(/[^\\"]+)"|(/[^\\s;|&><'\\"]+))`);
|
|
1549
1261
|
const targetPaths = [];
|
|
1550
1262
|
for (const seg of splitCommandSegments(actionDetail)) {
|
|
@@ -1592,7 +1304,6 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
|
|
|
1592
1304
|
}
|
|
1593
1305
|
}
|
|
1594
1306
|
}
|
|
1595
|
-
const TEMP_DIRS = ["/tmp/", "/var/tmp/", "/dev/shm/", "/run/"];
|
|
1596
1307
|
let filteredPaths = uniqueTargetPaths;
|
|
1597
1308
|
if (/\bdd\b/i.test(actionDetail) && /\bif=\/dev\/zero\b/i.test(actionDetail)) {
|
|
1598
1309
|
filteredPaths = uniqueTargetPaths.filter(
|
|
@@ -1693,10 +1404,10 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd, osType) {
|
|
|
1693
1404
|
if (!hasTraversal) {
|
|
1694
1405
|
return null;
|
|
1695
1406
|
}
|
|
1696
|
-
const READ_KEYWORDS =
|
|
1697
|
-
const WRITE_KEYWORDS2 =
|
|
1698
|
-
const EXEC_KEYWORDS =
|
|
1699
|
-
const OPEN_KEYWORDS =
|
|
1407
|
+
const READ_KEYWORDS = IFA_READ_KEYWORDS;
|
|
1408
|
+
const WRITE_KEYWORDS2 = IFA_WRITE_KEYWORDS;
|
|
1409
|
+
const EXEC_KEYWORDS = IFA_EXEC_KEYWORDS;
|
|
1410
|
+
const OPEN_KEYWORDS = IFA_OPEN_KEYWORDS;
|
|
1700
1411
|
const code = extractInlineCode(actionDetail);
|
|
1701
1412
|
if (!code) return null;
|
|
1702
1413
|
const codeLower = code.toLowerCase();
|
|
@@ -1759,7 +1470,7 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd, osType) {
|
|
|
1759
1470
|
violatedLayers: ["L2.1"]
|
|
1760
1471
|
};
|
|
1761
1472
|
}
|
|
1762
|
-
var ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, ROOT_SENSITIVE_PATHS_WINDOWS, HOME_SENSITIVE_PATHS_WINDOWS, CREDENTIAL_PATHS_WINDOWS, ROOT_SENSITIVE_PATHS_MACOS, HOME_SENSITIVE_PATHS_MACOS, CREDENTIAL_PATHS_MACOS, ROOT_SENSITIVE_PATHS_HARMONY, HOME_SENSITIVE_PATHS_HARMONY, CREDENTIAL_PATHS_HARMONY, _scopeIndex, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, WRITE_KEYWORDS, SED_INPLACE_RE, DEVNULL_REDIRECT_RE, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, COMBO_STAGES, COMBO_CHAINS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW;
|
|
1473
|
+
var _LOGIC, _HEURISTIC, EXCLUDED_PREFIXES, TEMP_DIRS, ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, ROOT_SENSITIVE_PATHS_WINDOWS, HOME_SENSITIVE_PATHS_WINDOWS, CREDENTIAL_PATHS_WINDOWS, ROOT_SENSITIVE_PATHS_MACOS, HOME_SENSITIVE_PATHS_MACOS, CREDENTIAL_PATHS_MACOS, ROOT_SENSITIVE_PATHS_HARMONY, HOME_SENSITIVE_PATHS_HARMONY, CREDENTIAL_PATHS_HARMONY, _scopeIndex, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, WRITE_KEYWORDS, SED_INPLACE_RE, DEVNULL_REDIRECT_RE, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, COMBO_STAGES, COMBO_CHAINS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW, _IFA, IFA_READ_KEYWORDS, IFA_WRITE_KEYWORDS, IFA_EXEC_KEYWORDS, IFA_OPEN_KEYWORDS;
|
|
1763
1474
|
var init_logic_rules = __esm({
|
|
1764
1475
|
"src/engine/logic-rules.ts"() {
|
|
1765
1476
|
"use strict";
|
|
@@ -1769,6 +1480,10 @@ var init_logic_rules = __esm({
|
|
|
1769
1480
|
init_rules_loader();
|
|
1770
1481
|
init_platform_traits();
|
|
1771
1482
|
init_shell_split();
|
|
1483
|
+
_LOGIC = loadLogicRules();
|
|
1484
|
+
_HEURISTIC = loadHeuristicRules();
|
|
1485
|
+
EXCLUDED_PREFIXES = _HEURISTIC.sensitive_excluded_prefixes ?? [];
|
|
1486
|
+
TEMP_DIRS = (_HEURISTIC.temp_dirs ?? []).map((d) => d + "/");
|
|
1772
1487
|
ROOT_SENSITIVE_PATHS = _loadSensitivePathScope("root");
|
|
1773
1488
|
HOME_SENSITIVE_PATHS = _loadSensitivePathScope("home");
|
|
1774
1489
|
CREDENTIAL_PATHS = _loadSensitivePathScope("credential").map(({ path: path6, riskLevel, desc, dirDelOnly }) => ({ path: path6, riskLevel, desc, credential: true, dirDelOnly }));
|
|
@@ -1789,7 +1504,7 @@ var init_logic_rules = __esm({
|
|
|
1789
1504
|
"list_dir",
|
|
1790
1505
|
"count_text_length",
|
|
1791
1506
|
"search",
|
|
1792
|
-
// filemgr 只读三件套(globfiles 在
|
|
1507
|
+
// filemgr 只读三件套(globfiles 在 platform-traits 的 safeActionTypes 提前放行,此处兜底防御非 coordinator 入口)
|
|
1793
1508
|
"filemgr-globfiles",
|
|
1794
1509
|
"filemgr-readfile",
|
|
1795
1510
|
"filemgr-grepfiles",
|
|
@@ -1801,7 +1516,7 @@ var init_logic_rules = __esm({
|
|
|
1801
1516
|
"tail",
|
|
1802
1517
|
"cat"
|
|
1803
1518
|
]);
|
|
1804
|
-
NON_WRITE_TOOL_PREFIXES =
|
|
1519
|
+
NON_WRITE_TOOL_PREFIXES = _LOGIC.non_write_tool_prefixes ?? [];
|
|
1805
1520
|
WRITE_KEYWORDS = ["write", "\u5199\u5165", "save", "\u4FDD\u5B58", "modify", "\u4FEE\u6539", "update", "\u66F4\u65B0", "delete", "\u5220\u9664", "remove", "\u79FB\u9664", "create", "\u521B\u5EFA", "append", "\u8FFD\u52A0", "truncate", "\u622A\u65AD", "overwrite", "\u8986\u76D6", "replace", "\u66FF\u6362", "edit"];
|
|
1806
1521
|
SED_INPLACE_RE = /\bsed\s+(?:-\S+\s+)*(?:-[a-zA-Z]*i[a-zA-Z]*|--in-place)\b/i;
|
|
1807
1522
|
DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/g;
|
|
@@ -1842,25 +1557,24 @@ var init_logic_rules = __esm({
|
|
|
1842
1557
|
}));
|
|
1843
1558
|
})();
|
|
1844
1559
|
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;
|
|
1845
|
-
DIR_TRAVERSAL_KW = [
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
"pathlib.",
|
|
1852
|
-
"iterdir",
|
|
1853
|
-
"rglob",
|
|
1854
|
-
"scandir(",
|
|
1855
|
-
"listdir("
|
|
1856
|
-
];
|
|
1560
|
+
DIR_TRAVERSAL_KW = loadInline().dir_traversal_keywords ?? [];
|
|
1561
|
+
_IFA = loadLogicRules().indirect_file_access ?? {};
|
|
1562
|
+
IFA_READ_KEYWORDS = _IFA.read_keywords ?? [];
|
|
1563
|
+
IFA_WRITE_KEYWORDS = _IFA.write_keywords ?? [];
|
|
1564
|
+
IFA_EXEC_KEYWORDS = _IFA.exec_keywords ?? [];
|
|
1565
|
+
IFA_OPEN_KEYWORDS = _IFA.open_keywords ?? [];
|
|
1857
1566
|
}
|
|
1858
1567
|
});
|
|
1859
1568
|
|
|
1860
1569
|
// src/engine/asset-dir.ts
|
|
1861
|
-
import { existsSync as
|
|
1862
|
-
import { resolve as resolve2 } from "path";
|
|
1570
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1571
|
+
import { join as join4, resolve as resolve2 } from "path";
|
|
1863
1572
|
function assetDirCandidates(moduleDir, name) {
|
|
1573
|
+
const root = getRulesRoot();
|
|
1574
|
+
if (root) {
|
|
1575
|
+
const p = join4(root, name);
|
|
1576
|
+
return [p, p];
|
|
1577
|
+
}
|
|
1864
1578
|
return [
|
|
1865
1579
|
resolve2(moduleDir, name),
|
|
1866
1580
|
resolve2(moduleDir, "../../..", "agent_moss", name)
|
|
@@ -1868,7 +1582,7 @@ function assetDirCandidates(moduleDir, name) {
|
|
|
1868
1582
|
}
|
|
1869
1583
|
function resolveAssetDir(moduleDir, name) {
|
|
1870
1584
|
for (const dir of assetDirCandidates(moduleDir, name)) {
|
|
1871
|
-
if (
|
|
1585
|
+
if (existsSync4(dir)) return dir;
|
|
1872
1586
|
}
|
|
1873
1587
|
return null;
|
|
1874
1588
|
}
|
|
@@ -1876,11 +1590,12 @@ var init_asset_dir = __esm({
|
|
|
1876
1590
|
"src/engine/asset-dir.ts"() {
|
|
1877
1591
|
"use strict";
|
|
1878
1592
|
init_esm_shims();
|
|
1593
|
+
init_paths();
|
|
1879
1594
|
}
|
|
1880
1595
|
});
|
|
1881
1596
|
|
|
1882
1597
|
// src/engine/skill-loader.ts
|
|
1883
|
-
import { readFileSync as
|
|
1598
|
+
import { readFileSync as readFileSync4, readdirSync as readdirSync3, existsSync as existsSync5 } from "fs";
|
|
1884
1599
|
import { resolve as resolve3, dirname as dirname2 } from "path";
|
|
1885
1600
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1886
1601
|
function loadAllSkills() {
|
|
@@ -1895,7 +1610,7 @@ function loadAllSkills() {
|
|
|
1895
1610
|
const files = readdirSync3(dir).filter((f) => f.endsWith(".md"));
|
|
1896
1611
|
for (const f of files) {
|
|
1897
1612
|
const name = f.replace(".md", "");
|
|
1898
|
-
cachedSkills[name] =
|
|
1613
|
+
cachedSkills[name] = readFileSync4(resolve3(dir, f), "utf-8");
|
|
1899
1614
|
}
|
|
1900
1615
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills from ${dir}`);
|
|
1901
1616
|
return cachedSkills;
|
|
@@ -1904,6 +1619,7 @@ function userSkillsDir() {
|
|
|
1904
1619
|
return resolve3(getDataRoot(), "agent_moss_skills");
|
|
1905
1620
|
}
|
|
1906
1621
|
function runtimeCustomSkillKeywords() {
|
|
1622
|
+
if (isRuntimeConfigDisabled()) return {};
|
|
1907
1623
|
try {
|
|
1908
1624
|
const rt = runtimeConfigBridge.current?.loadRuntimeConfig?.();
|
|
1909
1625
|
if (!rt) return {};
|
|
@@ -1921,10 +1637,11 @@ function runtimeCustomSkillKeywords() {
|
|
|
1921
1637
|
}
|
|
1922
1638
|
}
|
|
1923
1639
|
function loadUserSkill(name) {
|
|
1640
|
+
if (isRuntimeConfigDisabled()) return "";
|
|
1924
1641
|
if (userSkillCache[name] !== void 0) return userSkillCache[name];
|
|
1925
1642
|
try {
|
|
1926
1643
|
const p = resolve3(userSkillsDir(), `${name}.md`);
|
|
1927
|
-
userSkillCache[name] =
|
|
1644
|
+
userSkillCache[name] = existsSync5(p) ? readFileSync4(p, "utf-8") : "";
|
|
1928
1645
|
} catch {
|
|
1929
1646
|
userSkillCache[name] = "";
|
|
1930
1647
|
}
|
|
@@ -1989,6 +1706,7 @@ var init_skill_loader = __esm({
|
|
|
1989
1706
|
init_esm_shims();
|
|
1990
1707
|
init_rules_loader();
|
|
1991
1708
|
init_paths();
|
|
1709
|
+
init_rules_mode();
|
|
1992
1710
|
init_asset_dir();
|
|
1993
1711
|
init_runtime_config_bridge();
|
|
1994
1712
|
__filename3 = fileURLToPath3(import.meta.url);
|
|
@@ -2049,6 +1767,7 @@ __export(runtime_config_exports, {
|
|
|
2049
1767
|
getEnabledScenarioExtensions: () => getEnabledScenarioExtensions,
|
|
2050
1768
|
getEnvOverrides: () => getEnvOverrides,
|
|
2051
1769
|
getProfileOrDetect: () => getProfileOrDetect,
|
|
1770
|
+
getRuleSourceFingerprint: () => getRuleSourceFingerprint,
|
|
2052
1771
|
getRuntimeConfigPath: () => getRuntimeConfigPath,
|
|
2053
1772
|
getScenarioRules: () => getScenarioRules,
|
|
2054
1773
|
hasRuntimeConfig: () => hasRuntimeConfig,
|
|
@@ -2071,8 +1790,8 @@ __export(runtime_config_exports, {
|
|
|
2071
1790
|
updateSkillCategoryEnabled: () => updateSkillCategoryEnabled,
|
|
2072
1791
|
updateSkillEnabled: () => updateSkillEnabled
|
|
2073
1792
|
});
|
|
2074
|
-
import { readFileSync as
|
|
2075
|
-
import { join as
|
|
1793
|
+
import { readFileSync as readFileSync5, writeFileSync, existsSync as existsSync6, mkdirSync, unlinkSync, readdirSync as readdirSync4, statSync as statSync2 } from "fs";
|
|
1794
|
+
import { join as join5 } from "path";
|
|
2076
1795
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2077
1796
|
import { dirname as dirname3 } from "path";
|
|
2078
1797
|
function runtimeDir() {
|
|
@@ -2083,10 +1802,25 @@ function getRuntimeConfigPath() {
|
|
|
2083
1802
|
if (envPath) return envPath;
|
|
2084
1803
|
return RUNTIME_CONFIG_PATH;
|
|
2085
1804
|
}
|
|
1805
|
+
function getRuleSourceFingerprint() {
|
|
1806
|
+
if (isRuntimeConfigDisabled()) return `mode:${getRulesMode()}`;
|
|
1807
|
+
const p = getRuntimeConfigPath();
|
|
1808
|
+
try {
|
|
1809
|
+
const st = statSync2(p);
|
|
1810
|
+
return `${p}|${st.mtimeMs}|${st.size}`;
|
|
1811
|
+
} catch {
|
|
1812
|
+
return `${p}|absent`;
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
2086
1815
|
function saveRuntimeConfig(config) {
|
|
1816
|
+
if (isRuntimeConfigDisabled()) {
|
|
1817
|
+
throw new Error(
|
|
1818
|
+
`\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u4E3A ${getRulesMode()}\uFF08runtime \u914D\u7F6E\u5DF2\u7981\u7528\uFF09\uFF1A\u4FEE\u6539\u89C4\u5219\u4E0D\u4F1A\u751F\u6548\uFF0C\u8BF7\u5207\u6362\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u5E76\u91CD\u542F\u670D\u52A1\u3002`
|
|
1819
|
+
);
|
|
1820
|
+
}
|
|
2087
1821
|
const p = getRuntimeConfigPath();
|
|
2088
1822
|
const dir = p.substring(0, p.lastIndexOf("/"));
|
|
2089
|
-
if (dir && !
|
|
1823
|
+
if (dir && !existsSync6(dir)) mkdirSync(dir, { recursive: true });
|
|
2090
1824
|
writeFileSync(p, JSON.stringify(config, null, 2), "utf-8");
|
|
2091
1825
|
invalidateRuntimeConfigCache();
|
|
2092
1826
|
}
|
|
@@ -2107,8 +1841,20 @@ function invalidateRuntimeConfigCache() {
|
|
|
2107
1841
|
hasRuntimeConfigCache.clear();
|
|
2108
1842
|
}
|
|
2109
1843
|
function loadRuntimeConfig() {
|
|
1844
|
+
if (isRuntimeConfigDisabled()) {
|
|
1845
|
+
return {
|
|
1846
|
+
version: 1,
|
|
1847
|
+
layers: { ...DEFAULT_LAYERS },
|
|
1848
|
+
L1_rules: {},
|
|
1849
|
+
L2_rules: {},
|
|
1850
|
+
L3_skills: {},
|
|
1851
|
+
L2_2: {},
|
|
1852
|
+
agent_rules: {},
|
|
1853
|
+
scenario_rules: {}
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
2110
1856
|
const p = getRuntimeConfigPath();
|
|
2111
|
-
if (!
|
|
1857
|
+
if (!existsSync6(p)) {
|
|
2112
1858
|
const seeded = mergeConfig({}, generateSourceDefaults());
|
|
2113
1859
|
try {
|
|
2114
1860
|
saveRuntimeConfig(seeded);
|
|
@@ -2122,7 +1868,7 @@ function loadRuntimeConfig() {
|
|
|
2122
1868
|
if (runtimeConfigCache && runtimeConfigCache.key === cacheKey) {
|
|
2123
1869
|
return runtimeConfigCache.value;
|
|
2124
1870
|
}
|
|
2125
|
-
const data = JSON.parse(
|
|
1871
|
+
const data = JSON.parse(readFileSync5(p, "utf-8"));
|
|
2126
1872
|
const merged = mergeConfig(data, generateSourceDefaults());
|
|
2127
1873
|
const result = {
|
|
2128
1874
|
version: data.version || 1,
|
|
@@ -2153,6 +1899,7 @@ function loadRuntimeConfig() {
|
|
|
2153
1899
|
function isLayerEnabled(layerKey) {
|
|
2154
1900
|
const disableKey = LAYER_DISABLE_ENV[layerKey];
|
|
2155
1901
|
if (disableKey && process.env[disableKey] === "1") return false;
|
|
1902
|
+
if (isRuntimeConfigDisabled()) return true;
|
|
2156
1903
|
const runtime = loadRuntimeConfig();
|
|
2157
1904
|
const layers = runtime.layers || {};
|
|
2158
1905
|
if (layerKey in layers) return !!layers[layerKey];
|
|
@@ -2179,7 +1926,10 @@ function filterEnabledRules(rules, categoryEnabled = true) {
|
|
|
2179
1926
|
}
|
|
2180
1927
|
function _filterRulesByOs(rules, osType) {
|
|
2181
1928
|
const accepted = acceptedOsValues(osType);
|
|
2182
|
-
return rules.filter((r) =>
|
|
1929
|
+
return rules.filter((r) => {
|
|
1930
|
+
const os4 = String(r.os || "linux").toLowerCase();
|
|
1931
|
+
return os4 === "all" || accepted.includes(os4);
|
|
1932
|
+
});
|
|
2183
1933
|
}
|
|
2184
1934
|
function _userCustomRules(runtime, layers, requiredKey) {
|
|
2185
1935
|
const list = Array.isArray(layers) ? layers : [layers];
|
|
@@ -2253,6 +2003,7 @@ function getEnabledL2SensitivePaths(runtime, osType) {
|
|
|
2253
2003
|
});
|
|
2254
2004
|
}
|
|
2255
2005
|
function hasRuntimeConfig() {
|
|
2006
|
+
if (isRuntimeConfigDisabled()) return false;
|
|
2256
2007
|
const p = getRuntimeConfigPath();
|
|
2257
2008
|
let key;
|
|
2258
2009
|
try {
|
|
@@ -2261,11 +2012,11 @@ function hasRuntimeConfig() {
|
|
|
2261
2012
|
} catch {
|
|
2262
2013
|
return false;
|
|
2263
2014
|
}
|
|
2264
|
-
const
|
|
2265
|
-
if (
|
|
2015
|
+
const cached2 = hasRuntimeConfigCache.get(key);
|
|
2016
|
+
if (cached2 !== void 0) return cached2;
|
|
2266
2017
|
let ok = false;
|
|
2267
2018
|
try {
|
|
2268
|
-
JSON.parse(
|
|
2019
|
+
JSON.parse(readFileSync5(p, "utf-8"));
|
|
2269
2020
|
ok = true;
|
|
2270
2021
|
} catch {
|
|
2271
2022
|
ok = false;
|
|
@@ -2365,6 +2116,9 @@ function _l1InjectionKeywordsToRules() {
|
|
|
2365
2116
|
keyword: kw.keyword,
|
|
2366
2117
|
risk_level: kw.riskLevel,
|
|
2367
2118
|
lang: kw.lang || "en",
|
|
2119
|
+
// 带上条目自己的 os(`all` = 全平台通用),别丢 —— 丢了 Windows 会拿到
|
|
2120
|
+
// 本不该给它的条目。与 Python `_l1_injection_keywords_to_rules` 对齐。
|
|
2121
|
+
os: kw.os,
|
|
2368
2122
|
enabled: true,
|
|
2369
2123
|
builtin: true
|
|
2370
2124
|
}));
|
|
@@ -2482,8 +2236,9 @@ function _l3SkillsToRules() {
|
|
|
2482
2236
|
}
|
|
2483
2237
|
function _scenarioRulesToDefaults() {
|
|
2484
2238
|
const out = {};
|
|
2485
|
-
const
|
|
2486
|
-
|
|
2239
|
+
const _root = getRulesRoot();
|
|
2240
|
+
const scenDir = _root ? join5(_root, "scenarios") : existsSync6(_SCENARIOS_DIR_PROD) ? _SCENARIOS_DIR_PROD : existsSync6(_SCENARIOS_DIR_DEV) ? _SCENARIOS_DIR_DEV : _SCENARIOS_DIR_PROD;
|
|
2241
|
+
if (!existsSync6(scenDir)) return out;
|
|
2487
2242
|
let entries;
|
|
2488
2243
|
try {
|
|
2489
2244
|
entries = readdirSync4(scenDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -2491,11 +2246,11 @@ function _scenarioRulesToDefaults() {
|
|
|
2491
2246
|
return out;
|
|
2492
2247
|
}
|
|
2493
2248
|
for (const scenarioId of entries) {
|
|
2494
|
-
const rulesFile = resolveScenarioRulesFile(scenarioId) ??
|
|
2495
|
-
if (!
|
|
2249
|
+
const rulesFile = resolveScenarioRulesFile(scenarioId) ?? join5(scenDir, scenarioId, "rules.json");
|
|
2250
|
+
if (!existsSync6(rulesFile)) continue;
|
|
2496
2251
|
let data;
|
|
2497
2252
|
try {
|
|
2498
|
-
data = JSON.parse(
|
|
2253
|
+
data = JSON.parse(readFileSync5(rulesFile, "utf-8"));
|
|
2499
2254
|
} catch {
|
|
2500
2255
|
continue;
|
|
2501
2256
|
}
|
|
@@ -2531,8 +2286,9 @@ function _scenarioRulesToDefaults() {
|
|
|
2531
2286
|
}
|
|
2532
2287
|
function _agentRulesToDefaults() {
|
|
2533
2288
|
const out = {};
|
|
2534
|
-
const
|
|
2535
|
-
|
|
2289
|
+
const _root = getRulesRoot();
|
|
2290
|
+
const agentsDir = _root ? join5(_root, "agents") : existsSync6(_AGENTS_DIR_PROD) ? _AGENTS_DIR_PROD : existsSync6(_AGENTS_DIR_DEV) ? _AGENTS_DIR_DEV : _AGENTS_DIR_PROD;
|
|
2291
|
+
if (!existsSync6(agentsDir)) return out;
|
|
2536
2292
|
let entries;
|
|
2537
2293
|
try {
|
|
2538
2294
|
entries = readdirSync4(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -2540,11 +2296,11 @@ function _agentRulesToDefaults() {
|
|
|
2540
2296
|
return out;
|
|
2541
2297
|
}
|
|
2542
2298
|
for (const agentId of entries) {
|
|
2543
|
-
const rulesFile =
|
|
2544
|
-
if (!
|
|
2299
|
+
const rulesFile = join5(agentsDir, agentId, "rules.json");
|
|
2300
|
+
if (!existsSync6(rulesFile)) continue;
|
|
2545
2301
|
let data;
|
|
2546
2302
|
try {
|
|
2547
|
-
data = JSON.parse(
|
|
2303
|
+
data = JSON.parse(readFileSync5(rulesFile, "utf-8"));
|
|
2548
2304
|
} catch {
|
|
2549
2305
|
continue;
|
|
2550
2306
|
}
|
|
@@ -2919,7 +2675,11 @@ function getDisabledSkillIds(runtime) {
|
|
|
2919
2675
|
}
|
|
2920
2676
|
function _filterDefaultsByOs(rules, osType) {
|
|
2921
2677
|
const accepted = acceptedOsValues(osType);
|
|
2922
|
-
return rules.filter((r) =>
|
|
2678
|
+
return rules.filter((r) => {
|
|
2679
|
+
if (!r.os) return true;
|
|
2680
|
+
const os4 = String(r.os).toLowerCase();
|
|
2681
|
+
return os4 === "all" || accepted.includes(os4);
|
|
2682
|
+
});
|
|
2923
2683
|
}
|
|
2924
2684
|
function _hasRulesForOs(rules, osType) {
|
|
2925
2685
|
return _filterRulesByOs(rules || [], osType || "linux").length > 0;
|
|
@@ -3142,13 +2902,18 @@ function deleteCustomRule(layer, category, ruleId) {
|
|
|
3142
2902
|
}
|
|
3143
2903
|
function addCustomSkill(skillId, category, keywords, content) {
|
|
3144
2904
|
_validateSkillId(skillId);
|
|
2905
|
+
if (isRuntimeConfigDisabled()) {
|
|
2906
|
+
throw new Error(
|
|
2907
|
+
`\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u4E3A ${getRulesMode()}\uFF08runtime \u914D\u7F6E\u5DF2\u7981\u7528\uFF09\uFF0C\u4E0D\u5141\u8BB8\u65B0\u589E\u81EA\u5B9A\u4E49 skill\u3002`
|
|
2908
|
+
);
|
|
2909
|
+
}
|
|
3145
2910
|
const runtime = loadRuntimeConfig();
|
|
3146
|
-
const skillsDir =
|
|
2911
|
+
const skillsDir = join5(getRuntimeConfigDir(), "agent_moss_skills");
|
|
3147
2912
|
try {
|
|
3148
2913
|
mkdirSync(skillsDir, { recursive: true });
|
|
3149
2914
|
} catch {
|
|
3150
2915
|
}
|
|
3151
|
-
writeFileSync(
|
|
2916
|
+
writeFileSync(join5(skillsDir, `${skillId}.md`), content, "utf-8");
|
|
3152
2917
|
const l3 = runtime.L3_skills || (runtime.L3_skills = {});
|
|
3153
2918
|
const cat = l3[category] || (l3[category] = { category_enabled: true, category_desc: "", skills: [] });
|
|
3154
2919
|
(cat.skills || (cat.skills = [])).push({ id: skillId, keywords, enabled: true, builtin: false });
|
|
@@ -3163,9 +2928,9 @@ function deleteCustomSkill(skillId, category) {
|
|
|
3163
2928
|
if (idx >= 0) {
|
|
3164
2929
|
if (skills[idx].builtin) return null;
|
|
3165
2930
|
skills.splice(idx, 1);
|
|
3166
|
-
const skillPath =
|
|
2931
|
+
const skillPath = join5(getRuntimeConfigDir(), "agent_moss_skills", `${skillId}.md`);
|
|
3167
2932
|
try {
|
|
3168
|
-
if (
|
|
2933
|
+
if (existsSync6(skillPath)) unlinkSync(skillPath);
|
|
3169
2934
|
} catch {
|
|
3170
2935
|
}
|
|
3171
2936
|
saveRuntimeConfig(runtime);
|
|
@@ -3368,10 +3133,11 @@ var init_runtime_config = __esm({
|
|
|
3368
3133
|
init_skill_loader();
|
|
3369
3134
|
init_rules_loader();
|
|
3370
3135
|
init_runtime_config_bridge();
|
|
3136
|
+
init_rules_mode();
|
|
3371
3137
|
__dirname4 = dirname3(fileURLToPath4(import.meta.url));
|
|
3372
3138
|
ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
|
|
3373
3139
|
RUNTIME_CONFIG_DIR = runtimeDir();
|
|
3374
|
-
RUNTIME_CONFIG_PATH =
|
|
3140
|
+
RUNTIME_CONFIG_PATH = join5(RUNTIME_CONFIG_DIR, "agent_moss_runtime.json");
|
|
3375
3141
|
LAYER_DISABLE_ENV = {
|
|
3376
3142
|
L1_heuristic: "AGENT_MOSS_DISABLE_HEURISTIC",
|
|
3377
3143
|
L2_logic_rules: "AGENT_MOSS_DISABLE_LOGIC_RULES",
|
|
@@ -3399,10 +3165,10 @@ var init_runtime_config = __esm({
|
|
|
3399
3165
|
intent_consistency: ["intent_keywords", "reason"]
|
|
3400
3166
|
};
|
|
3401
3167
|
hasRuntimeConfigCache = /* @__PURE__ */ new Map();
|
|
3402
|
-
_AGENTS_DIR_PROD =
|
|
3403
|
-
_AGENTS_DIR_DEV =
|
|
3404
|
-
_SCENARIOS_DIR_PROD =
|
|
3405
|
-
_SCENARIOS_DIR_DEV =
|
|
3168
|
+
_AGENTS_DIR_PROD = join5(__dirname4, "agents");
|
|
3169
|
+
_AGENTS_DIR_DEV = join5(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
3170
|
+
_SCENARIOS_DIR_PROD = join5(__dirname4, "scenarios");
|
|
3171
|
+
_SCENARIOS_DIR_DEV = join5(__dirname4, "..", "..", "..", "agent_moss", "scenarios");
|
|
3406
3172
|
_effectiveCache = /* @__PURE__ */ new WeakMap();
|
|
3407
3173
|
SKILL_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
3408
3174
|
registerRuntimeConfigBridge({
|
|
@@ -3439,6 +3205,7 @@ __export(config_exports, {
|
|
|
3439
3205
|
isPolicyGenEnabled: () => isPolicyGenEnabled,
|
|
3440
3206
|
isPolicySaveEnabled: () => isPolicySaveEnabled,
|
|
3441
3207
|
probeLLMConnection: () => probeLLMConnection,
|
|
3208
|
+
reloadCustomRules: () => reloadCustomRules,
|
|
3442
3209
|
updateLLMConfig: () => updateLLMConfig,
|
|
3443
3210
|
userRuleVariantPattern: () => userRuleVariantPattern,
|
|
3444
3211
|
wildcardToRegExp: () => wildcardToRegExp
|
|
@@ -3519,17 +3286,19 @@ function wildcardToRegExp(pattern) {
|
|
|
3519
3286
|
}
|
|
3520
3287
|
function loadCustomRules() {
|
|
3521
3288
|
const rules = [];
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3289
|
+
if (!isBuiltinOnly()) {
|
|
3290
|
+
try {
|
|
3291
|
+
const raw = process.env.AGENT_MOSS_CUSTOM_RULES;
|
|
3292
|
+
if (raw) {
|
|
3293
|
+
const parsed = JSON.parse(raw);
|
|
3294
|
+
if (Array.isArray(parsed)) {
|
|
3295
|
+
for (const r of parsed) {
|
|
3296
|
+
if (r && r.pattern && r.action) rules.push({ pattern: r.pattern, action: r.action, severity: r.severity || "high" });
|
|
3297
|
+
}
|
|
3529
3298
|
}
|
|
3530
3299
|
}
|
|
3300
|
+
} catch {
|
|
3531
3301
|
}
|
|
3532
|
-
} catch {
|
|
3533
3302
|
}
|
|
3534
3303
|
for (const rulesPath of USER_RULES_PATHS) {
|
|
3535
3304
|
try {
|
|
@@ -3558,6 +3327,9 @@ function userRuleVariantPattern(pattern) {
|
|
|
3558
3327
|
}
|
|
3559
3328
|
return null;
|
|
3560
3329
|
}
|
|
3330
|
+
function reloadCustomRules() {
|
|
3331
|
+
customRules = loadCustomRules();
|
|
3332
|
+
}
|
|
3561
3333
|
function getLLMConfig() {
|
|
3562
3334
|
return llmConfig;
|
|
3563
3335
|
}
|
|
@@ -3645,6 +3417,7 @@ function layerEnabledOrDefault(key) {
|
|
|
3645
3417
|
}
|
|
3646
3418
|
}
|
|
3647
3419
|
function isBrainEnabled() {
|
|
3420
|
+
if (isRuntimeConfigDisabled()) return false;
|
|
3648
3421
|
return getAgentMossSetting("AGENT_MOSS_BRAIN_ENABLED", "") === "1";
|
|
3649
3422
|
}
|
|
3650
3423
|
function getAgentMossSetting(key, def = "") {
|
|
@@ -3686,6 +3459,7 @@ var init_config = __esm({
|
|
|
3686
3459
|
init_esm_shims();
|
|
3687
3460
|
init_paths();
|
|
3688
3461
|
init_runtime_config();
|
|
3462
|
+
init_rules_mode();
|
|
3689
3463
|
__configModuleDir = (() => {
|
|
3690
3464
|
try {
|
|
3691
3465
|
return path2.dirname(fileURLToPath5(import.meta.url));
|
|
@@ -3732,17 +3506,21 @@ var init_config = __esm({
|
|
|
3732
3506
|
});
|
|
3733
3507
|
|
|
3734
3508
|
// src/agents/index.ts
|
|
3735
|
-
import { readFileSync as
|
|
3736
|
-
import { resolve as resolve4, dirname as dirname4 } from "path";
|
|
3509
|
+
import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
|
|
3510
|
+
import { resolve as resolve4, dirname as dirname4, join as join6 } from "path";
|
|
3737
3511
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
3738
3512
|
function resolveAgentsDir() {
|
|
3739
|
-
|
|
3740
|
-
if (
|
|
3513
|
+
const root = getRulesRoot();
|
|
3514
|
+
if (root) return join6(root, "agents");
|
|
3515
|
+
if (existsSync7(AGENTS_DIR_PROD)) return AGENTS_DIR_PROD;
|
|
3516
|
+
if (existsSync7(AGENTS_DIR_DEV_FALLBACK)) return AGENTS_DIR_DEV_FALLBACK;
|
|
3741
3517
|
return AGENTS_DIR_PROD;
|
|
3742
3518
|
}
|
|
3743
3519
|
function getAgentExtensions(agentId) {
|
|
3744
3520
|
if (!agentId) return null;
|
|
3745
|
-
|
|
3521
|
+
const fp = getRuleSourceFingerprint();
|
|
3522
|
+
const cached2 = cache.get(agentId);
|
|
3523
|
+
if (cached2 && cached2.fp === fp) return cached2.ext;
|
|
3746
3524
|
let ext = null;
|
|
3747
3525
|
try {
|
|
3748
3526
|
if (hasRuntimeConfig()) {
|
|
@@ -3753,25 +3531,25 @@ function getAgentExtensions(agentId) {
|
|
|
3753
3531
|
if (ext === null) {
|
|
3754
3532
|
const agentsDir = resolveAgentsDir();
|
|
3755
3533
|
const rulesFile = resolve4(agentsDir, agentId, "rules.json");
|
|
3756
|
-
if (!
|
|
3757
|
-
cache.set(agentId, null);
|
|
3534
|
+
if (!existsSync7(rulesFile)) {
|
|
3535
|
+
cache.set(agentId, { fp, ext: null });
|
|
3758
3536
|
return null;
|
|
3759
3537
|
}
|
|
3760
3538
|
try {
|
|
3761
|
-
const raw =
|
|
3539
|
+
const raw = readFileSync6(rulesFile, "utf-8");
|
|
3762
3540
|
ext = JSON.parse(raw);
|
|
3763
3541
|
if (!ext.agent_id) {
|
|
3764
3542
|
console.warn(`[AgentMoss agents] rules.json \u7F3A\u5C11 agent_id \u5B57\u6BB5: ${rulesFile}`);
|
|
3765
|
-
cache.set(agentId, null);
|
|
3543
|
+
cache.set(agentId, { fp, ext: null });
|
|
3766
3544
|
return null;
|
|
3767
3545
|
}
|
|
3768
3546
|
} catch (e) {
|
|
3769
3547
|
console.error(`[AgentMoss agents] \u52A0\u8F7D agent ${agentId} rules.json \u5931\u8D25:`, e.message);
|
|
3770
|
-
cache.set(agentId, null);
|
|
3548
|
+
cache.set(agentId, { fp, ext: null });
|
|
3771
3549
|
return null;
|
|
3772
3550
|
}
|
|
3773
3551
|
}
|
|
3774
|
-
cache.set(agentId, ext);
|
|
3552
|
+
cache.set(agentId, { fp, ext });
|
|
3775
3553
|
console.error(
|
|
3776
3554
|
`[AgentMoss agents] \u52A0\u8F7D agent ${agentId} \u5B9A\u5236\u89C4\u5219: ${ext.extra_command_patterns?.length ?? 0} cmd patterns, ${ext.extra_injection_keywords?.length ?? 0} injection keywords, ${ext.extra_sensitive_paths?.length ?? 0} sensitive paths, ${ext.builtin_safe_skills?.length ?? 0} builtin safe skills, ${ext.builtin_safe_action_types?.length ?? 0} builtin safe action types`
|
|
3777
3555
|
);
|
|
@@ -3797,6 +3575,7 @@ var init_agents = __esm({
|
|
|
3797
3575
|
"src/agents/index.ts"() {
|
|
3798
3576
|
"use strict";
|
|
3799
3577
|
init_esm_shims();
|
|
3578
|
+
init_paths();
|
|
3800
3579
|
init_runtime_config();
|
|
3801
3580
|
__filename4 = fileURLToPath6(import.meta.url);
|
|
3802
3581
|
__dirname5 = dirname4(__filename4);
|
|
@@ -3807,17 +3586,21 @@ var init_agents = __esm({
|
|
|
3807
3586
|
});
|
|
3808
3587
|
|
|
3809
3588
|
// src/scenarios/index.ts
|
|
3810
|
-
import { readFileSync as
|
|
3811
|
-
import { resolve as resolve5, dirname as dirname5 } from "path";
|
|
3589
|
+
import { readFileSync as readFileSync7, existsSync as existsSync8 } from "fs";
|
|
3590
|
+
import { resolve as resolve5, dirname as dirname5, join as join7 } from "path";
|
|
3812
3591
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
3813
3592
|
function resolveScenariosDir() {
|
|
3814
|
-
|
|
3815
|
-
if (
|
|
3593
|
+
const root = getRulesRoot();
|
|
3594
|
+
if (root) return join7(root, "scenarios");
|
|
3595
|
+
if (existsSync8(SCENARIOS_DIR_PROD)) return SCENARIOS_DIR_PROD;
|
|
3596
|
+
if (existsSync8(SCENARIOS_DIR_DEV_FALLBACK)) return SCENARIOS_DIR_DEV_FALLBACK;
|
|
3816
3597
|
return SCENARIOS_DIR_PROD;
|
|
3817
3598
|
}
|
|
3818
3599
|
function getScenarioExtensions(scenarioId) {
|
|
3819
3600
|
if (!scenarioId) return null;
|
|
3820
|
-
|
|
3601
|
+
const fp = getRuleSourceFingerprint();
|
|
3602
|
+
const cached2 = cache2.get(scenarioId);
|
|
3603
|
+
if (cached2 && cached2.fp === fp) return cached2.ext;
|
|
3821
3604
|
let ext = null;
|
|
3822
3605
|
let overrideHit = null;
|
|
3823
3606
|
try {
|
|
@@ -3840,17 +3623,17 @@ function getScenarioExtensions(scenarioId) {
|
|
|
3840
3623
|
`[AgentMoss] \u26A0\uFE0F \u573A\u666F ${scenarioId} \u89C4\u5219\u88AB\u8986\u76D6\u76EE\u5F55\u8986\u76D6: ${overrideHit}\uFF08\u5185\u7F6E\u9ED8\u8BA4 ${builtinFile} \u88AB\u5FFD\u7565\uFF09\u3002\u8BE5\u6587\u4EF6\u7531\u90E8\u7F72\u4FA7\u81EA\u884C\u7EF4\u62A4\uFF0C\u5185\u7F6E\u573A\u666F\u89C4\u5219\u66F4\u65B0\u4E0D\u4F1A\u53CD\u6620\u5230\u5B83\u4E0A\u9762\u3002`
|
|
3841
3624
|
);
|
|
3842
3625
|
}
|
|
3843
|
-
if (!
|
|
3844
|
-
cache2.set(scenarioId, null);
|
|
3626
|
+
if (!existsSync8(rulesFile)) {
|
|
3627
|
+
cache2.set(scenarioId, { fp, ext: null });
|
|
3845
3628
|
return null;
|
|
3846
3629
|
}
|
|
3847
3630
|
try {
|
|
3848
|
-
const raw =
|
|
3631
|
+
const raw = readFileSync7(rulesFile, "utf-8");
|
|
3849
3632
|
const data = JSON.parse(raw);
|
|
3850
3633
|
const id = data.scenario_id || data.agent_id || "";
|
|
3851
3634
|
if (!id) {
|
|
3852
3635
|
console.warn(`[AgentMoss scenarios] rules.json \u7F3A\u5C11 scenario_id \u5B57\u6BB5: ${rulesFile}`);
|
|
3853
|
-
cache2.set(scenarioId, null);
|
|
3636
|
+
cache2.set(scenarioId, { fp, ext: null });
|
|
3854
3637
|
return null;
|
|
3855
3638
|
}
|
|
3856
3639
|
ext = {
|
|
@@ -3865,11 +3648,11 @@ function getScenarioExtensions(scenarioId) {
|
|
|
3865
3648
|
};
|
|
3866
3649
|
} catch (e) {
|
|
3867
3650
|
console.error(`[AgentMoss scenarios] \u52A0\u8F7D\u573A\u666F ${scenarioId} rules.json \u5931\u8D25:`, e.message);
|
|
3868
|
-
cache2.set(scenarioId, null);
|
|
3651
|
+
cache2.set(scenarioId, { fp, ext: null });
|
|
3869
3652
|
return null;
|
|
3870
3653
|
}
|
|
3871
3654
|
}
|
|
3872
|
-
cache2.set(scenarioId, ext);
|
|
3655
|
+
cache2.set(scenarioId, { fp, ext });
|
|
3873
3656
|
console.error(
|
|
3874
3657
|
`[AgentMoss scenarios] \u52A0\u8F7D\u573A\u666F ${scenarioId} \u5B9A\u5236\u89C4\u5219: ${ext.extra_command_patterns?.length ?? 0} cmd patterns, ${ext.extra_injection_keywords?.length ?? 0} injection keywords, ${ext.extra_sensitive_paths?.length ?? 0} sensitive paths`
|
|
3875
3658
|
);
|
|
@@ -3889,6 +3672,7 @@ var init_scenarios = __esm({
|
|
|
3889
3672
|
"src/scenarios/index.ts"() {
|
|
3890
3673
|
"use strict";
|
|
3891
3674
|
init_esm_shims();
|
|
3675
|
+
init_paths();
|
|
3892
3676
|
init_agents();
|
|
3893
3677
|
init_runtime_config();
|
|
3894
3678
|
init_rules_loader();
|
|
@@ -4295,7 +4079,7 @@ function severityRank(s) {
|
|
|
4295
4079
|
}
|
|
4296
4080
|
function isSearchActionType(actionType) {
|
|
4297
4081
|
const at = actionType.toLowerCase();
|
|
4298
|
-
return SEARCH_ACTION_PREFIXES.some((p) => at.startsWith(p)) ||
|
|
4082
|
+
return SEARCH_ACTION_PREFIXES.some((p) => at.startsWith(p)) || SEARCH_ACTION_EXACT.includes(at);
|
|
4299
4083
|
}
|
|
4300
4084
|
function checkSensitivePath(command, cwd, agentExt, osType) {
|
|
4301
4085
|
const expandedCwd = cwd.replace(/^~/, process.env.HOME || "/home/user");
|
|
@@ -4585,8 +4369,7 @@ function isSshKeygenGenerate(command) {
|
|
|
4585
4369
|
function checkDangerousPatterns(actionType, actionDetail) {
|
|
4586
4370
|
if (actionType === "file_write" || actionType === "file_edit") return null;
|
|
4587
4371
|
const scan = stripHeredocContent(actionDetail);
|
|
4588
|
-
const
|
|
4589
|
-
const isTempPath = TEMP_DIRS.some(
|
|
4372
|
+
const isTempPath = TEMP_DIRS2.some(
|
|
4590
4373
|
(td) => new RegExp(`(?:^|[\\s/])${td.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:[\\s/]|$)`).test(actionDetail)
|
|
4591
4374
|
) || /(?:^|[\s;]|&&\s*|\|\|\s*)var\/tmp(?:[/\s;]|$)/.test(actionDetail);
|
|
4592
4375
|
const wildcardDeleteRe = /(?:\brm\b|\b(r?mdir|del|delete|remove|rmdir|unlink)\b|\b删除\b|\b移除\b)[\s\S]{0,40}?[*?]|[*?][\s\S]{0,40}?\b(?:rm|del|delete|remove|rmdir|unlink)\b|rm\s+-[a-zA-Z]*[rf][a-zA-Z]*\s+\S*[*?]/i;
|
|
@@ -4732,7 +4515,7 @@ function checkLateralMovement(actionDetail) {
|
|
|
4732
4515
|
}
|
|
4733
4516
|
return null;
|
|
4734
4517
|
}
|
|
4735
|
-
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS2, DANGEROUS_PATTERNS_WINDOWS, DANGEROUS_PATTERNS_MACOS, DANGEROUS_PATTERNS_HARMONY, LOOPBACK_URL_RE, LOOPBACK_HOSTS, PATH_CONTEXT_TRIGGER_RE, HOME_PREFIX_RE, PY_EXEC_IO_RE, PY_PRINT_RE, PY_BIGNUM_RE, PY_INLINE_C_RE, PY_CMD_SUBST_C_RE, SENSITIVE_EXCLUDED_PREFIXES, SEARCH_ACTION_PREFIXES, HOME_TARGET_RE, HOME_ASSIGN_RE;
|
|
4518
|
+
var INJECTION_KEYWORDS, DANGEROUS_PATTERNS2, DANGEROUS_PATTERNS_WINDOWS, DANGEROUS_PATTERNS_MACOS, DANGEROUS_PATTERNS_HARMONY, LOOPBACK_URL_RE, HEURISTIC_RULES, LOOPBACK_HOSTS, TEMP_DIRS2, PATH_CONTEXT_TRIGGER_RE, HOME_PREFIX_RE, PY_EXEC_IO_RE, PY_PRINT_RE, PY_BIGNUM_RE, PY_INLINE_C_RE, PY_CMD_SUBST_C_RE, SENSITIVE_EXCLUDED_PREFIXES, SEARCH_ACTION_PREFIXES, SEARCH_ACTION_EXACT, HOME_TARGET_RE, HOME_ASSIGN_RE;
|
|
4736
4519
|
var init_heuristic = __esm({
|
|
4737
4520
|
"src/engine/heuristic.ts"() {
|
|
4738
4521
|
"use strict";
|
|
@@ -4749,7 +4532,8 @@ var init_heuristic = __esm({
|
|
|
4749
4532
|
return kws.map((k) => ({
|
|
4750
4533
|
keyword: k.keyword,
|
|
4751
4534
|
riskLevel: k.risk_level,
|
|
4752
|
-
lang: k.lang || "en"
|
|
4535
|
+
lang: k.lang || "en",
|
|
4536
|
+
os: String(k.os || "all").toLowerCase()
|
|
4753
4537
|
}));
|
|
4754
4538
|
})();
|
|
4755
4539
|
DANGEROUS_PATTERNS2 = _loadDangerousPatterns("linux");
|
|
@@ -4757,7 +4541,9 @@ var init_heuristic = __esm({
|
|
|
4757
4541
|
DANGEROUS_PATTERNS_MACOS = _loadDangerousPatterns("macos");
|
|
4758
4542
|
DANGEROUS_PATTERNS_HARMONY = _loadDangerousPatterns("harmony");
|
|
4759
4543
|
LOOPBACK_URL_RE = /https?:\/\/([^\/\s;'"|&)]+)/i;
|
|
4760
|
-
|
|
4544
|
+
HEURISTIC_RULES = loadHeuristicRules();
|
|
4545
|
+
LOOPBACK_HOSTS = new Set(HEURISTIC_RULES.loopback_hosts ?? []);
|
|
4546
|
+
TEMP_DIRS2 = HEURISTIC_RULES.temp_dirs ?? [];
|
|
4761
4547
|
PATH_CONTEXT_TRIGGER_RE = /(?:^|[;&|]\s*)(?:rm|rmdir|unlink|ln|mv|cp|dd|truncate|shred|chmod|chown)\b/i;
|
|
4762
4548
|
HOME_PREFIX_RE = /(?:~|~(?=\/)|\$HOME\b|\$\{HOME\}|\/home\/[a-z0-9_.-]+)/gi;
|
|
4763
4549
|
PY_EXEC_IO_RE = /os\.system|os\.popen|subprocess|eval\s*\(|exec\s*\(|__import__|open\s*\(|socket|urllib|requests\.|shutil|os\.(?:remove|unlink|rename|makedirs?|listdir|scandir|walk|chmod|chown|kill|environ)|iterdir|glob\s*\(|path\(/i;
|
|
@@ -4765,15 +4551,16 @@ var init_heuristic = __esm({
|
|
|
4765
4551
|
PY_BIGNUM_RE = /\d{6,}/;
|
|
4766
4552
|
PY_INLINE_C_RE = /(python(?:3(?:\.\d+)?)?|perl5?|ruby|node|php|lua)\s+(?:-[a-zA-Z]+\s+)*-c\s+(?:"([^"]*)"|'([^']*)')/i;
|
|
4767
4553
|
PY_CMD_SUBST_C_RE = /\$\(\s*(python(?:3(?:\.\d+)?)?|perl5?|ruby|node|php|lua)\s+(?:-[a-zA-Z]+\s+)*-c\s+(?:"([^"]*)"'|'([^']*)')\s*\)/i;
|
|
4768
|
-
SENSITIVE_EXCLUDED_PREFIXES =
|
|
4769
|
-
SEARCH_ACTION_PREFIXES =
|
|
4554
|
+
SENSITIVE_EXCLUDED_PREFIXES = HEURISTIC_RULES.sensitive_excluded_prefixes ?? [];
|
|
4555
|
+
SEARCH_ACTION_PREFIXES = HEURISTIC_RULES.search_action_prefixes ?? [];
|
|
4556
|
+
SEARCH_ACTION_EXACT = HEURISTIC_RULES.search_action_exact ?? [];
|
|
4770
4557
|
HOME_TARGET_RE = /(?:^|[\s="'($])(?:~|(?:\$home|\$\{home\}))(?:\/(?:\.\*|\*|\.)?)?(?=[\s"';}|&)]|$)/i;
|
|
4771
4558
|
HOME_ASSIGN_RE = /([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(~[A-Za-z0-9_./-]*|\$HOME[A-Za-z0-9_./-]*|\$\{HOME\}[A-Za-z0-9_./-]*|\/home\/[^\s;|&]+|\$\((?:[^()]|\([^()]*\))*\))(?=\s|;|$|\||&)/gi;
|
|
4772
4559
|
}
|
|
4773
4560
|
});
|
|
4774
4561
|
|
|
4775
4562
|
// src/engine/template-loader.ts
|
|
4776
|
-
import { readFileSync as
|
|
4563
|
+
import { readFileSync as readFileSync8, existsSync as existsSync9 } from "fs";
|
|
4777
4564
|
import { resolve as resolve6, dirname as dirname6 } from "path";
|
|
4778
4565
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
4779
4566
|
function loadTemplates() {
|
|
@@ -4787,9 +4574,9 @@ function loadTemplates() {
|
|
|
4787
4574
|
}
|
|
4788
4575
|
for (const file of TEMPLATE_FILES) {
|
|
4789
4576
|
const filePath = resolve6(dir, file);
|
|
4790
|
-
if (
|
|
4577
|
+
if (existsSync9(filePath)) {
|
|
4791
4578
|
const key = file.replace(".txt", "").replace("_template", "");
|
|
4792
|
-
cachedTemplates[key] =
|
|
4579
|
+
cachedTemplates[key] = readFileSync8(filePath, "utf-8");
|
|
4793
4580
|
}
|
|
4794
4581
|
}
|
|
4795
4582
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates from ${dir}`);
|
|
@@ -4809,8 +4596,8 @@ var init_template_loader = __esm({
|
|
|
4809
4596
|
});
|
|
4810
4597
|
|
|
4811
4598
|
// src/engine/script-analyzer.ts
|
|
4812
|
-
import { readFileSync as
|
|
4813
|
-
import { resolve as resolve7, join as
|
|
4599
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
4600
|
+
import { resolve as resolve7, join as join8 } from "path";
|
|
4814
4601
|
function emptyResult() {
|
|
4815
4602
|
return { scriptPath: "", scriptContent: "", matchedKeywords: [], lineCount: 0, isSuspicious: false, error: "", riskLevel: "", riskReason: "" };
|
|
4816
4603
|
}
|
|
@@ -4836,10 +4623,10 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
4836
4623
|
const hitGroup2 = rule.group2.size === 0 ? true : [...rule.group2].some((k) => keywordSet.has(k));
|
|
4837
4624
|
if (hitGroup1 && hitGroup2) return { level: rule.level, reason: rule.reason };
|
|
4838
4625
|
}
|
|
4839
|
-
const networkPostKeywords =
|
|
4626
|
+
const networkPostKeywords = new Set(KEYWORD_SETS.network_post ?? []);
|
|
4840
4627
|
const hasNetworkPost = [...networkPostKeywords].some((k) => keywordSet.has(k));
|
|
4841
4628
|
if (hasNetworkPost) {
|
|
4842
|
-
const envPatterns =
|
|
4629
|
+
const envPatterns = SCRIPT_RULES.env_exfil_patterns ?? [];
|
|
4843
4630
|
const contentLower = scriptContent.toLowerCase();
|
|
4844
4631
|
for (const p of envPatterns) {
|
|
4845
4632
|
if (contentLower.includes(p.toLowerCase())) {
|
|
@@ -4863,8 +4650,8 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
4863
4650
|
}
|
|
4864
4651
|
function readScriptContent(scriptPath, maxLines = 500) {
|
|
4865
4652
|
try {
|
|
4866
|
-
const expandedPath = scriptPath === "~" || scriptPath.startsWith("~/") ?
|
|
4867
|
-
const raw =
|
|
4653
|
+
const expandedPath = scriptPath === "~" || scriptPath.startsWith("~/") ? join8(process.env.HOME || "/home/user", scriptPath.slice(1)) : resolve7(scriptPath);
|
|
4654
|
+
const raw = readFileSync9(expandedPath, "utf-8");
|
|
4868
4655
|
const lines = raw.split("\n").slice(0, maxLines);
|
|
4869
4656
|
return { content: lines.join("\n"), lineCount: lines.length, error: "" };
|
|
4870
4657
|
} catch (e) {
|
|
@@ -4913,90 +4700,28 @@ ${result.scriptContent}
|
|
|
4913
4700
|
\`\`\`
|
|
4914
4701
|
`;
|
|
4915
4702
|
}
|
|
4916
|
-
var SUSPICIOUS_PATTERNS, SCRIPT_EXEC_PATTERNS, KEYWORD_COMBINATION_RISKS, SINGLE_KEYWORD_RISKS, LEVEL_ORDER;
|
|
4703
|
+
var SCRIPT_RULES, SUSPICIOUS_PATTERNS, SCRIPT_EXEC_PATTERNS, KEYWORD_SETS, KEYWORD_COMBINATION_RISKS, SINGLE_KEYWORD_RISKS, LEVEL_ORDER;
|
|
4917
4704
|
var init_script_analyzer = __esm({
|
|
4918
4705
|
"src/engine/script-analyzer.ts"() {
|
|
4919
4706
|
"use strict";
|
|
4920
4707
|
init_esm_shims();
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
{ name: "/etc/shadow", pattern: /\/etc\/shadow/ },
|
|
4939
|
-
{ name: "id_rsa", pattern: /\bid_rsa\b/ },
|
|
4940
|
-
{ name: "id_ed25519", pattern: /\bid_ed25519\b/ },
|
|
4941
|
-
// Persistence backdoor
|
|
4942
|
-
{ name: "crontab install", pattern: /crontab\s+-/ },
|
|
4943
|
-
{ name: "authorized_keys", pattern: /authorized_keys/ },
|
|
4944
|
-
{ name: "ssh no host key check", pattern: /ssh\s+.*StrictHostKeyChecking\s*=\s*no/ }
|
|
4945
|
-
];
|
|
4946
|
-
SCRIPT_EXEC_PATTERNS = [
|
|
4947
|
-
/bash\s+(\S+\.sh)/,
|
|
4948
|
-
/sh\s+(\S+\.sh)/,
|
|
4949
|
-
/\.\/(\S+\.sh)/,
|
|
4950
|
-
/source\s+(\S+\.sh)/,
|
|
4951
|
-
/\.\s+(\S+\.sh)/,
|
|
4952
|
-
/zsh\s+(\S+\.sh)/
|
|
4953
|
-
];
|
|
4954
|
-
KEYWORD_COMBINATION_RISKS = [
|
|
4955
|
-
{
|
|
4956
|
-
group1: /* @__PURE__ */ new Set(["curl POST", "curl --data", "curl -d", "wget --post-data", "wget --post-file"]),
|
|
4957
|
-
group2: /* @__PURE__ */ new Set(["$(base64", "`base64", "base64 decode pipe"]),
|
|
4958
|
-
level: "critical",
|
|
4959
|
-
reason: "\u68C0\u6D4B\u5230\u7F51\u7EDC\u6570\u636E\u53D1\u9001 + Base64\u7F16\u7801\u7EC4\u5408\uFF0C\u6784\u6210 Critical \u7EA7\u522B\u6570\u636E\u5916\u4F20\u98CE\u9669\u3002\u653B\u51FB\u8005\u53EF\u80FD\u5C06\u654F\u611F\u6570\u636E\u7F16\u7801\u540E\u5916\u4F20\u3002"
|
|
4960
|
-
},
|
|
4961
|
-
{
|
|
4962
|
-
group1: /* @__PURE__ */ new Set(["curl POST", "curl --data", "curl -d", "wget --post-data", "wget --post-file"]),
|
|
4963
|
-
group2: /* @__PURE__ */ new Set(["/etc/shadow", "id_rsa", "id_ed25519"]),
|
|
4964
|
-
level: "critical",
|
|
4965
|
-
reason: "\u68C0\u6D4B\u5230\u7F51\u7EDC\u6570\u636E\u53D1\u9001 + \u654F\u611F\u6587\u4EF6\u8BBF\u95EE\u7EC4\u5408\uFF0C\u6784\u6210 Critical \u7EA7\u522B\u51ED\u8BC1\u5916\u4F20\u98CE\u9669\u3002"
|
|
4966
|
-
},
|
|
4967
|
-
{
|
|
4968
|
-
group1: /* @__PURE__ */ new Set(["nc -e", "ncat -e", "/dev/tcp", "/dev/udp"]),
|
|
4969
|
-
group2: /* @__PURE__ */ new Set(),
|
|
4970
|
-
level: "high",
|
|
4971
|
-
reason: "\u68C0\u6D4B\u5230\u53CD\u5F39 Shell \u7279\u5F81\uFF0C\u653B\u51FB\u8005\u53EF\u80FD\u5EFA\u7ACB\u8FDC\u7A0B\u63A7\u5236\u901A\u9053\u3002"
|
|
4972
|
-
},
|
|
4973
|
-
{
|
|
4974
|
-
group1: /* @__PURE__ */ new Set(["crontab install", "authorized_keys", "ssh no host key check"]),
|
|
4975
|
-
group2: /* @__PURE__ */ new Set(),
|
|
4976
|
-
level: "high",
|
|
4977
|
-
reason: "\u68C0\u6D4B\u5230\u6301\u4E45\u5316\u540E\u95E8\u7279\u5F81\uFF0C\u653B\u51FB\u8005\u53EF\u80FD\u5728\u7CFB\u7EDF\u4E2D\u690D\u5165\u540E\u95E8\u3002"
|
|
4978
|
-
}
|
|
4979
|
-
];
|
|
4980
|
-
SINGLE_KEYWORD_RISKS = {
|
|
4981
|
-
"curl POST": { level: "high", reason: "\u68C0\u6D4B\u5230 curl POST \u8BF7\u6C42\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6570\u636E\u3002" },
|
|
4982
|
-
"curl --data": { level: "high", reason: "\u68C0\u6D4B\u5230 curl --data \u53C2\u6570\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6570\u636E\u3002" },
|
|
4983
|
-
"curl -d": { level: "high", reason: "\u68C0\u6D4B\u5230 curl -d \u53C2\u6570\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6570\u636E\u3002" },
|
|
4984
|
-
"wget --post-data": { level: "high", reason: "\u68C0\u6D4B\u5230 wget POST \u8BF7\u6C42\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6570\u636E\u3002" },
|
|
4985
|
-
"wget --post-file": { level: "high", reason: "\u68C0\u6D4B\u5230 wget \u6587\u4EF6\u4E0A\u4F20\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6587\u4EF6\u3002" },
|
|
4986
|
-
"nc -e": { level: "critical", reason: "\u68C0\u6D4B\u5230 nc -e \u53CD\u5F39 Shell \u7279\u5F81\u3002" },
|
|
4987
|
-
"ncat -e": { level: "critical", reason: "\u68C0\u6D4B\u5230 ncat -e \u53CD\u5F39 Shell \u7279\u5F81\u3002" },
|
|
4988
|
-
"/dev/tcp": { level: "critical", reason: "\u68C0\u6D4B\u5230 /dev/tcp \u53CD\u5F39 Shell \u7279\u5F81\u3002" },
|
|
4989
|
-
"/dev/udp": { level: "critical", reason: "\u68C0\u6D4B\u5230 /dev/udp \u53CD\u5F39 Shell \u7279\u5F81\u3002" },
|
|
4990
|
-
"$(base64": { level: "high", reason: "\u68C0\u6D4B\u5230 Base64 \u7F16\u7801\u6267\u884C\uFF0C\u53EF\u80FD\u662F\u6DF7\u6DC6\u9003\u9038\u3002" },
|
|
4991
|
-
"`base64": { level: "high", reason: "\u68C0\u6D4B\u5230 Base64 \u7F16\u7801\u6267\u884C\uFF0C\u53EF\u80FD\u662F\u6DF7\u6DC6\u9003\u9038\u3002" },
|
|
4992
|
-
"base64 decode pipe": { level: "high", reason: "\u68C0\u6D4B\u5230 Base64 \u89E3\u7801\u540E\u7BA1\u9053\u6267\u884C\uFF0C\u53EF\u80FD\u662F\u6DF7\u6DC6\u9003\u9038\u3002" },
|
|
4993
|
-
"/etc/shadow": { level: "critical", reason: "\u68C0\u6D4B\u5230\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6\u3002" },
|
|
4994
|
-
"id_rsa": { level: "critical", reason: "\u68C0\u6D4B\u5230\u8BBF\u95EE SSH \u79C1\u94A5\u3002" },
|
|
4995
|
-
"id_ed25519": { level: "critical", reason: "\u68C0\u6D4B\u5230\u8BBF\u95EE SSH \u79C1\u94A5\u3002" },
|
|
4996
|
-
"crontab install": { level: "high", reason: "\u68C0\u6D4B\u5230\u4FEE\u6539\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u53EF\u80FD\u662F\u6301\u4E45\u5316\u540E\u95E8\u3002" },
|
|
4997
|
-
"authorized_keys": { level: "high", reason: "\u68C0\u6D4B\u5230\u4FEE\u6539 SSH \u6388\u6743\u5BC6\u94A5\uFF0C\u53EF\u80FD\u662F\u6301\u4E45\u5316\u540E\u95E8\u3002" },
|
|
4998
|
-
"ssh no host key check": { level: "high", reason: "\u68C0\u6D4B\u5230 SSH \u8DF3\u8FC7\u4E3B\u673A\u5BC6\u94A5\u9A8C\u8BC1\uFF0C\u53EF\u80FD\u662F\u6A2A\u5411\u79FB\u52A8\u3002" }
|
|
4999
|
-
};
|
|
4708
|
+
init_rules_loader();
|
|
4709
|
+
SCRIPT_RULES = loadScriptRules();
|
|
4710
|
+
if (!SCRIPT_RULES || Object.keys(SCRIPT_RULES).length === 0) {
|
|
4711
|
+
console.error(
|
|
4712
|
+
"[AgentMoss] \u274C \u89C4\u5219\u6587\u4EF6 script_rules.json \u7F3A\u5931\u6216\u635F\u574F \u2014\u2014 \u811A\u672C\u5173\u952E\u8BCD\u626B\u63CF\u5C06\u4E0D\u547D\u4E2D\u4EFB\u4F55\u6A21\u5F0F\uFF08\u6BD4\u6B63\u5E38\u66F4\u677E\uFF09\u3002\u8BF7\u68C0\u67E5\u5305\u5B8C\u6574\u6027\u3002"
|
|
4713
|
+
);
|
|
4714
|
+
}
|
|
4715
|
+
SUSPICIOUS_PATTERNS = (SCRIPT_RULES.suspicious_patterns ?? []).map((r) => ({ name: r.name, pattern: compileRuleRegex(r) }));
|
|
4716
|
+
SCRIPT_EXEC_PATTERNS = ((SCRIPT_RULES.script_exec_patterns ?? {}).legacy ?? []).map((r) => compileRuleRegex(r));
|
|
4717
|
+
KEYWORD_SETS = SCRIPT_RULES.keyword_sets ?? {};
|
|
4718
|
+
KEYWORD_COMBINATION_RISKS = (SCRIPT_RULES.keyword_combination_risks ?? []).map((r) => ({
|
|
4719
|
+
group1: resolveKeywordSet(r.group1, KEYWORD_SETS),
|
|
4720
|
+
group2: resolveKeywordSet(r.group2, KEYWORD_SETS),
|
|
4721
|
+
level: String(r.level),
|
|
4722
|
+
reason: String(r.reason)
|
|
4723
|
+
}));
|
|
4724
|
+
SINGLE_KEYWORD_RISKS = SCRIPT_RULES.single_keyword_risks ?? {};
|
|
5000
4725
|
LEVEL_ORDER = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
5001
4726
|
}
|
|
5002
4727
|
});
|
|
@@ -6540,8 +6265,8 @@ var init_tracker = __esm({
|
|
|
6540
6265
|
});
|
|
6541
6266
|
|
|
6542
6267
|
// src/engine/script-content-analyzer.ts
|
|
6543
|
-
import { statSync as statSync4, existsSync as
|
|
6544
|
-
import { resolve as resolve9, join as
|
|
6268
|
+
import { statSync as statSync4, existsSync as existsSync11 } from "fs";
|
|
6269
|
+
import { resolve as resolve9, join as join10, isAbsolute as isAbsolute2 } from "path";
|
|
6545
6270
|
import { homedir as homedir3 } from "os";
|
|
6546
6271
|
function emptyChain() {
|
|
6547
6272
|
return {
|
|
@@ -6574,10 +6299,10 @@ function assessKeywordCombinationRisk2(matchedKeywords, scriptContent) {
|
|
|
6574
6299
|
const hitGroup2 = rule.group2.size === 0 ? true : [...rule.group2].some((k) => keywordSet.has(k));
|
|
6575
6300
|
if (hitGroup1 && hitGroup2) return { level: rule.level, reason: rule.reason };
|
|
6576
6301
|
}
|
|
6577
|
-
const networkPostKeywords =
|
|
6302
|
+
const networkPostKeywords = new Set(KEYWORD_SETS2.network_post ?? []);
|
|
6578
6303
|
const hasNetworkPost = [...networkPostKeywords].some((k) => keywordSet.has(k));
|
|
6579
6304
|
if (hasNetworkPost) {
|
|
6580
|
-
const envPatterns =
|
|
6305
|
+
const envPatterns = SCRIPT_RULES2.env_exfil_patterns ?? [];
|
|
6581
6306
|
const contentLower = scriptContent.toLowerCase();
|
|
6582
6307
|
for (const p of envPatterns) {
|
|
6583
6308
|
if (contentLower.includes(p.toLowerCase())) {
|
|
@@ -6653,7 +6378,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
6653
6378
|
if (looksLikeScriptPath(tok)) {
|
|
6654
6379
|
try {
|
|
6655
6380
|
const resolved = resolvePath2(tok.replace(/^['"]|['"]$/g, ""));
|
|
6656
|
-
if (
|
|
6381
|
+
if (existsSync11(resolved)) {
|
|
6657
6382
|
const stat = statSync4(resolved);
|
|
6658
6383
|
if (stat.isFile()) return resolved;
|
|
6659
6384
|
}
|
|
@@ -6667,7 +6392,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
6667
6392
|
const p = m[1];
|
|
6668
6393
|
try {
|
|
6669
6394
|
const resolved = resolvePath2(p);
|
|
6670
|
-
if (
|
|
6395
|
+
if (existsSync11(resolved)) {
|
|
6671
6396
|
const stat = statSync4(resolved);
|
|
6672
6397
|
if (stat.isFile()) return resolved;
|
|
6673
6398
|
}
|
|
@@ -6683,7 +6408,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
6683
6408
|
let resolved;
|
|
6684
6409
|
try {
|
|
6685
6410
|
resolved = resolvePath2(p);
|
|
6686
|
-
if (
|
|
6411
|
+
if (existsSync11(resolved)) {
|
|
6687
6412
|
const stat = statSync4(resolved);
|
|
6688
6413
|
if (stat.isFile()) return resolved;
|
|
6689
6414
|
}
|
|
@@ -6724,7 +6449,7 @@ function shlexSplit(s) {
|
|
|
6724
6449
|
function resolvePath2(p) {
|
|
6725
6450
|
let expanded = p;
|
|
6726
6451
|
if (expanded.startsWith("~/") || expanded === "~") {
|
|
6727
|
-
expanded =
|
|
6452
|
+
expanded = join10(homedir3(), expanded.slice(1));
|
|
6728
6453
|
}
|
|
6729
6454
|
return resolve9(expanded);
|
|
6730
6455
|
}
|
|
@@ -6848,7 +6573,7 @@ function analyzeScriptContent2(input, ext) {
|
|
|
6848
6573
|
isInline = true;
|
|
6849
6574
|
}
|
|
6850
6575
|
if (resolvedPath && !isAbsolute2(resolvedPath) && !resolvedPath.startsWith("~/")) {
|
|
6851
|
-
resolvedPath =
|
|
6576
|
+
resolvedPath = join10(input.cwd || process.cwd(), resolvedPath);
|
|
6852
6577
|
}
|
|
6853
6578
|
const l1Adapter = (content) => {
|
|
6854
6579
|
const j = scanDangerousCommandPatterns("bash", content, input.osType);
|
|
@@ -6933,7 +6658,7 @@ ${contentPreview}
|
|
|
6933
6658
|
if (chain.maxSizeReached) header += "\u26A0\uFE0F \u6CE8\u610F\uFF1A\u7D2F\u8BA1\u6587\u4EF6\u5927\u5C0F\u89E6\u8FBE\u4E0A\u9650\uFF0C\u90E8\u5206\u811A\u672C\u53EF\u80FD\u672A\u88AB\u5B8C\u6574\u8BFB\u53D6\u3002\n";
|
|
6934
6659
|
return header + parts.join("\n---\n\n");
|
|
6935
6660
|
}
|
|
6936
|
-
var SUSPICIOUS_PATTERNS2, SCRIPT_EXEC_PATTERNS2, KEYWORD_COMBINATION_RISKS2, SINGLE_KEYWORD_RISKS2, LEVEL_ORDER2;
|
|
6661
|
+
var SCRIPT_RULES2, SUSPICIOUS_PATTERNS2, SCRIPT_EXEC_PATTERNS2, KEYWORD_SETS2, KEYWORD_COMBINATION_RISKS2, SINGLE_KEYWORD_RISKS2, LEVEL_ORDER2;
|
|
6937
6662
|
var init_script_content_analyzer = __esm({
|
|
6938
6663
|
"src/engine/script-content-analyzer.ts"() {
|
|
6939
6664
|
"use strict";
|
|
@@ -6943,87 +6668,23 @@ var init_script_content_analyzer = __esm({
|
|
|
6943
6668
|
init_logic_rules();
|
|
6944
6669
|
init_inline_analyzer();
|
|
6945
6670
|
init_tracker();
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
{ name: "authorized_keys", pattern: /authorized_keys/ },
|
|
6964
|
-
{ name: "ssh no host key check", pattern: /ssh\s+.*StrictHostKeyChecking\s*=\s*no/ }
|
|
6965
|
-
];
|
|
6966
|
-
SCRIPT_EXEC_PATTERNS2 = [
|
|
6967
|
-
/(?:^|\s|&&|\|\|)\s*bash\s+(\S+)/i,
|
|
6968
|
-
/(?:^|\s|&&|\|\|)\s*\/bin\/bash\s+(\S+)/i,
|
|
6969
|
-
/(?:^|\s|&&|\|\|)\s*sh\s+(\S+)/i,
|
|
6970
|
-
/(?:^|\s|&&|\|\|)\s*zsh\s+(\S+)/i,
|
|
6971
|
-
/\.\/(\S+)/,
|
|
6972
|
-
/(?:^|\s|&&|\|\|)\s*source\s+(\S+)/i,
|
|
6973
|
-
/(?:^|\s|&&|\|\|)\s*\.\s+(\S+)/,
|
|
6974
|
-
/(?:^|\s|&&|\|\|)\s*python3?\s+(\S+\.py)/i,
|
|
6975
|
-
/(?:^|\s|&&|\|\|)\s*node\s+(\S+\.js)/i,
|
|
6976
|
-
/(?:^|\s|&&|\|\|)\s*ruby\s+(\S+\.rb)/i,
|
|
6977
|
-
/(?:^|\s|&&|\|\|)\s*perl\s+(\S+\.pl)/i,
|
|
6978
|
-
/(?:^|\s|&&|\|\|)\s*php\s+(\S+\.php)/i,
|
|
6979
|
-
/(?:^|\s|&&|\|\|)\s*lua\s+(\S+\.lua)/i
|
|
6980
|
-
];
|
|
6981
|
-
KEYWORD_COMBINATION_RISKS2 = [
|
|
6982
|
-
{
|
|
6983
|
-
group1: /* @__PURE__ */ new Set(["curl POST", "curl --data", "curl -d", "wget --post-data", "wget --post-file"]),
|
|
6984
|
-
group2: /* @__PURE__ */ new Set(["$(base64", "`base64", "base64 decode pipe"]),
|
|
6985
|
-
level: "critical",
|
|
6986
|
-
reason: "\u68C0\u6D4B\u5230\u7F51\u7EDC\u6570\u636E\u53D1\u9001 + Base64\u7F16\u7801\u7EC4\u5408\uFF0C\u6784\u6210 Critical \u7EA7\u522B\u6570\u636E\u5916\u4F20\u98CE\u9669\u3002\u653B\u51FB\u8005\u53EF\u80FD\u5C06\u654F\u611F\u6570\u636E\u7F16\u7801\u540E\u5916\u4F20\u3002"
|
|
6987
|
-
},
|
|
6988
|
-
{
|
|
6989
|
-
group1: /* @__PURE__ */ new Set(["curl POST", "curl --data", "curl -d", "wget --post-data", "wget --post-file"]),
|
|
6990
|
-
group2: /* @__PURE__ */ new Set(["/etc/shadow", "id_rsa", "id_ed25519"]),
|
|
6991
|
-
level: "critical",
|
|
6992
|
-
reason: "\u68C0\u6D4B\u5230\u7F51\u7EDC\u6570\u636E\u53D1\u9001 + \u654F\u611F\u6587\u4EF6\u8BBF\u95EE\u7EC4\u5408\uFF0C\u6784\u6210 Critical \u7EA7\u522B\u51ED\u8BC1\u5916\u4F20\u98CE\u9669\u3002"
|
|
6993
|
-
},
|
|
6994
|
-
{
|
|
6995
|
-
group1: /* @__PURE__ */ new Set(["nc -e", "ncat -e", "/dev/tcp", "/dev/udp"]),
|
|
6996
|
-
group2: /* @__PURE__ */ new Set(),
|
|
6997
|
-
level: "high",
|
|
6998
|
-
reason: "\u68C0\u6D4B\u5230\u53CD\u5F39 Shell \u7279\u5F81\uFF0C\u653B\u51FB\u8005\u53EF\u80FD\u5EFA\u7ACB\u8FDC\u7A0B\u63A7\u5236\u901A\u9053\u3002"
|
|
6999
|
-
},
|
|
7000
|
-
{
|
|
7001
|
-
group1: /* @__PURE__ */ new Set(["crontab install", "authorized_keys", "ssh no host key check"]),
|
|
7002
|
-
group2: /* @__PURE__ */ new Set(),
|
|
7003
|
-
level: "high",
|
|
7004
|
-
reason: "\u68C0\u6D4B\u5230\u6301\u4E45\u5316\u540E\u95E8\u7279\u5F81\uFF0C\u653B\u51FB\u8005\u53EF\u80FD\u5728\u7CFB\u7EDF\u4E2D\u690D\u5165\u540E\u95E8\u3002"
|
|
7005
|
-
}
|
|
7006
|
-
];
|
|
7007
|
-
SINGLE_KEYWORD_RISKS2 = {
|
|
7008
|
-
"curl POST": { level: "high", reason: "\u68C0\u6D4B\u5230 curl POST \u8BF7\u6C42\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6570\u636E\u3002" },
|
|
7009
|
-
"curl --data": { level: "high", reason: "\u68C0\u6D4B\u5230 curl --data \u53C2\u6570\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6570\u636E\u3002" },
|
|
7010
|
-
"curl -d": { level: "high", reason: "\u68C0\u6D4B\u5230 curl -d \u53C2\u6570\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6570\u636E\u3002" },
|
|
7011
|
-
"wget --post-data": { level: "high", reason: "\u68C0\u6D4B\u5230 wget POST \u8BF7\u6C42\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6570\u636E\u3002" },
|
|
7012
|
-
"wget --post-file": { level: "high", reason: "\u68C0\u6D4B\u5230 wget \u6587\u4EF6\u4E0A\u4F20\uFF0C\u53EF\u80FD\u5411\u5916\u90E8\u670D\u52A1\u5668\u53D1\u9001\u6587\u4EF6\u3002" },
|
|
7013
|
-
"nc -e": { level: "critical", reason: "\u68C0\u6D4B\u5230 nc -e \u53CD\u5F39 Shell \u7279\u5F81\u3002" },
|
|
7014
|
-
"ncat -e": { level: "critical", reason: "\u68C0\u6D4B\u5230 ncat -e \u53CD\u5F39 Shell \u7279\u5F81\u3002" },
|
|
7015
|
-
"/dev/tcp": { level: "critical", reason: "\u68C0\u6D4B\u5230 /dev/tcp \u53CD\u5F39 Shell \u7279\u5F81\u3002" },
|
|
7016
|
-
"/dev/udp": { level: "critical", reason: "\u68C0\u6D4B\u5230 /dev/udp \u53CD\u5F39 Shell \u7279\u5F81\u3002" },
|
|
7017
|
-
"$(base64": { level: "high", reason: "\u68C0\u6D4B\u5230 Base64 \u7F16\u7801\u6267\u884C\uFF0C\u53EF\u80FD\u662F\u6DF7\u6DC6\u9003\u9038\u3002" },
|
|
7018
|
-
"`base64": { level: "high", reason: "\u68C0\u6D4B\u5230 Base64 \u7F16\u7801\u6267\u884C\uFF0C\u53EF\u80FD\u662F\u6DF7\u6DC6\u9003\u9038\u3002" },
|
|
7019
|
-
"base64 decode pipe": { level: "high", reason: "\u68C0\u6D4B\u5230 Base64 \u89E3\u7801\u540E\u7BA1\u9053\u6267\u884C\uFF0C\u53EF\u80FD\u662F\u6DF7\u6DC6\u9003\u9038\u3002" },
|
|
7020
|
-
"/etc/shadow": { level: "critical", reason: "\u68C0\u6D4B\u5230\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6\u3002" },
|
|
7021
|
-
"id_rsa": { level: "critical", reason: "\u68C0\u6D4B\u5230\u8BBF\u95EE SSH \u79C1\u94A5\u3002" },
|
|
7022
|
-
"id_ed25519": { level: "critical", reason: "\u68C0\u6D4B\u5230\u8BBF\u95EE SSH \u79C1\u94A5\u3002" },
|
|
7023
|
-
"crontab install": { level: "high", reason: "\u68C0\u6D4B\u5230\u4FEE\u6539\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u53EF\u80FD\u662F\u6301\u4E45\u5316\u540E\u95E8\u3002" },
|
|
7024
|
-
"authorized_keys": { level: "high", reason: "\u68C0\u6D4B\u5230\u4FEE\u6539 SSH \u6388\u6743\u5BC6\u94A5\uFF0C\u53EF\u80FD\u662F\u6301\u4E45\u5316\u540E\u95E8\u3002" },
|
|
7025
|
-
"ssh no host key check": { level: "high", reason: "\u68C0\u6D4B\u5230 SSH \u8DF3\u8FC7\u4E3B\u673A\u5BC6\u94A5\u9A8C\u8BC1\uFF0C\u53EF\u80FD\u662F\u6A2A\u5411\u79FB\u52A8\u3002" }
|
|
7026
|
-
};
|
|
6671
|
+
init_rules_loader();
|
|
6672
|
+
SCRIPT_RULES2 = loadScriptRules();
|
|
6673
|
+
if (!SCRIPT_RULES2 || Object.keys(SCRIPT_RULES2).length === 0) {
|
|
6674
|
+
console.error(
|
|
6675
|
+
"[AgentMoss] \u274C \u89C4\u5219\u6587\u4EF6 script_rules.json \u7F3A\u5931\u6216\u635F\u574F \u2014\u2014 \u811A\u672C\u5185\u5BB9\u5173\u952E\u8BCD\u626B\u63CF\u5C06\u4E0D\u547D\u4E2D\u4EFB\u4F55\u6A21\u5F0F\uFF08\u6BD4\u6B63\u5E38\u66F4\u677E\uFF09\u3002\u8BF7\u68C0\u67E5\u5305\u5B8C\u6574\u6027\u3002"
|
|
6676
|
+
);
|
|
6677
|
+
}
|
|
6678
|
+
SUSPICIOUS_PATTERNS2 = (SCRIPT_RULES2.suspicious_patterns ?? []).map((r) => ({ name: r.name, pattern: compileRuleRegex(r) }));
|
|
6679
|
+
SCRIPT_EXEC_PATTERNS2 = ((SCRIPT_RULES2.script_exec_patterns ?? {}).chain ?? []).map((r) => compileRuleRegex(r));
|
|
6680
|
+
KEYWORD_SETS2 = SCRIPT_RULES2.keyword_sets ?? {};
|
|
6681
|
+
KEYWORD_COMBINATION_RISKS2 = (SCRIPT_RULES2.keyword_combination_risks ?? []).map((r) => ({
|
|
6682
|
+
group1: resolveKeywordSet(r.group1, KEYWORD_SETS2),
|
|
6683
|
+
group2: resolveKeywordSet(r.group2, KEYWORD_SETS2),
|
|
6684
|
+
level: String(r.level),
|
|
6685
|
+
reason: String(r.reason)
|
|
6686
|
+
}));
|
|
6687
|
+
SINGLE_KEYWORD_RISKS2 = SCRIPT_RULES2.single_keyword_risks ?? {};
|
|
7027
6688
|
LEVEL_ORDER2 = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
7028
6689
|
}
|
|
7029
6690
|
});
|
|
@@ -7038,16 +6699,16 @@ __export(token_stats_exports, {
|
|
|
7038
6699
|
recordTokenUsage: () => recordTokenUsage,
|
|
7039
6700
|
resetTokenStats: () => resetTokenStats
|
|
7040
6701
|
});
|
|
7041
|
-
import { readFileSync as
|
|
6702
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
7042
6703
|
function getStatsPath() {
|
|
7043
6704
|
const envPath = process.env[ENV_STATS_PATH];
|
|
7044
6705
|
if (envPath) return envPath;
|
|
7045
6706
|
return getTokenStatsPath();
|
|
7046
6707
|
}
|
|
7047
6708
|
function loadAllRecords(statsPath) {
|
|
7048
|
-
if (!
|
|
6709
|
+
if (!existsSync12(statsPath)) return [];
|
|
7049
6710
|
try {
|
|
7050
|
-
const data = JSON.parse(
|
|
6711
|
+
const data = JSON.parse(readFileSync12(statsPath, "utf-8"));
|
|
7051
6712
|
if (Array.isArray(data)) return data;
|
|
7052
6713
|
if (data && Array.isArray(data.records)) return data.records;
|
|
7053
6714
|
return [];
|
|
@@ -7058,7 +6719,7 @@ function loadAllRecords(statsPath) {
|
|
|
7058
6719
|
function saveRecords(statsPath, records) {
|
|
7059
6720
|
try {
|
|
7060
6721
|
const dir = statsPath.substring(0, statsPath.lastIndexOf("/"));
|
|
7061
|
-
if (dir && !
|
|
6722
|
+
if (dir && !existsSync12(dir)) mkdirSync2(dir, { recursive: true });
|
|
7062
6723
|
writeFileSync2(statsPath, JSON.stringify(records, null, 2), "utf-8");
|
|
7063
6724
|
} catch (e) {
|
|
7064
6725
|
}
|
|
@@ -7185,7 +6846,7 @@ function getTokenTrend(days = 0, startDate, endDate) {
|
|
|
7185
6846
|
}
|
|
7186
6847
|
function resetTokenStats() {
|
|
7187
6848
|
const statsPath = getStatsPath();
|
|
7188
|
-
if (
|
|
6849
|
+
if (existsSync12(statsPath)) {
|
|
7189
6850
|
try {
|
|
7190
6851
|
unlinkSync2(statsPath);
|
|
7191
6852
|
} catch {
|
|
@@ -7223,10 +6884,10 @@ async function runLLMAnalysis(input, previous) {
|
|
|
7223
6884
|
const config = input.llmConfig?.apiKey ? { ...globalConfig, ...input.llmConfig } : globalConfig;
|
|
7224
6885
|
const rawDetail = input.aNext.actionDetail.replace(/^terminal-\w+:\s*command=([^,]+).*/, "$1").trim();
|
|
7225
6886
|
const cacheKey = `${input.aNext.actionType}:${rawDetail || input.aNext.actionDetail}`;
|
|
7226
|
-
const
|
|
7227
|
-
if (
|
|
6887
|
+
const cached2 = llmCache.get(cacheKey);
|
|
6888
|
+
if (cached2) {
|
|
7228
6889
|
console.log("[AgentMoss] LLM cache hit");
|
|
7229
|
-
return
|
|
6890
|
+
return cached2;
|
|
7230
6891
|
}
|
|
7231
6892
|
const matchedSkills = matchSkills(input.aNext.actionType, input.aNext.actionDetail, input.reason);
|
|
7232
6893
|
const templates = loadTemplates();
|
|
@@ -7442,8 +7103,8 @@ var init_llm_analyzer = __esm({
|
|
|
7442
7103
|
});
|
|
7443
7104
|
|
|
7444
7105
|
// src/brain/rule-store.ts
|
|
7445
|
-
import { existsSync as
|
|
7446
|
-
import { join as
|
|
7106
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
7107
|
+
import { join as join11 } from "path";
|
|
7447
7108
|
import { homedir as homedir4 } from "os";
|
|
7448
7109
|
function getRulesPath() {
|
|
7449
7110
|
const envPath = process.env[ENV_RULES_PATH];
|
|
@@ -7462,7 +7123,7 @@ var init_rule_store = __esm({
|
|
|
7462
7123
|
"src/brain/rule-store.ts"() {
|
|
7463
7124
|
"use strict";
|
|
7464
7125
|
init_esm_shims();
|
|
7465
|
-
DEFAULT_RULES_PATH =
|
|
7126
|
+
DEFAULT_RULES_PATH = join11(homedir4(), ".agentmoss", "brain", "rules.json");
|
|
7466
7127
|
ENV_RULES_PATH = "AGENT_MOSS_BRAIN_RULES_PATH";
|
|
7467
7128
|
STATUS_DRAFT = "draft";
|
|
7468
7129
|
STATUS_APPROVED = "approved";
|
|
@@ -7479,11 +7140,11 @@ var init_rule_store = __esm({
|
|
|
7479
7140
|
this.data = this.load();
|
|
7480
7141
|
}
|
|
7481
7142
|
load() {
|
|
7482
|
-
if (!
|
|
7143
|
+
if (!existsSync13(this.path)) {
|
|
7483
7144
|
return { version: 1, rules: [], pattern_candidates: [] };
|
|
7484
7145
|
}
|
|
7485
7146
|
try {
|
|
7486
|
-
const raw = JSON.parse(
|
|
7147
|
+
const raw = JSON.parse(readFileSync13(this.path, "utf-8"));
|
|
7487
7148
|
return {
|
|
7488
7149
|
version: raw.version || 1,
|
|
7489
7150
|
rules: raw.rules || [],
|
|
@@ -8077,9 +7738,9 @@ var init_reviewer = __esm({
|
|
|
8077
7738
|
});
|
|
8078
7739
|
|
|
8079
7740
|
// src/brain/skill-manager.ts
|
|
8080
|
-
import { existsSync as
|
|
7741
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync4, readFileSync as readFileSync14, renameSync, writeFileSync as writeFileSync4 } from "fs";
|
|
8081
7742
|
import { homedir as homedir5 } from "os";
|
|
8082
|
-
import { join as
|
|
7743
|
+
import { join as join12 } from "path";
|
|
8083
7744
|
import { randomUUID } from "crypto";
|
|
8084
7745
|
function getMetaPath(override) {
|
|
8085
7746
|
return override || process.env[ENV_SKILL_META_PATH] || DEFAULT_SKILL_META_PATH;
|
|
@@ -8089,14 +7750,14 @@ var init_skill_manager = __esm({
|
|
|
8089
7750
|
"src/brain/skill-manager.ts"() {
|
|
8090
7751
|
"use strict";
|
|
8091
7752
|
init_esm_shims();
|
|
8092
|
-
DEFAULT_SKILL_META_PATH =
|
|
7753
|
+
DEFAULT_SKILL_META_PATH = join12(homedir5(), ".agentmoss", "brain", "skill_meta.json");
|
|
8093
7754
|
ENV_SKILL_META_PATH = "AGENT_MOSS_BRAIN_SKILL_META_PATH";
|
|
8094
7755
|
BrainSkillManager = class {
|
|
8095
7756
|
constructor(skillsDir, metaPath) {
|
|
8096
7757
|
this.skillsDir = skillsDir;
|
|
8097
7758
|
this.metaPath = getMetaPath(metaPath);
|
|
8098
7759
|
try {
|
|
8099
|
-
mkdirSync4(
|
|
7760
|
+
mkdirSync4(join12(this.metaPath, ".."), { recursive: true });
|
|
8100
7761
|
} catch {
|
|
8101
7762
|
}
|
|
8102
7763
|
this.load();
|
|
@@ -8106,9 +7767,9 @@ var init_skill_manager = __esm({
|
|
|
8106
7767
|
skills = [];
|
|
8107
7768
|
metaPath;
|
|
8108
7769
|
load() {
|
|
8109
|
-
if (!
|
|
7770
|
+
if (!existsSync14(this.metaPath)) return;
|
|
8110
7771
|
try {
|
|
8111
|
-
const data = JSON.parse(
|
|
7772
|
+
const data = JSON.parse(readFileSync14(this.metaPath, "utf-8"));
|
|
8112
7773
|
this.skills = data.skills || [];
|
|
8113
7774
|
} catch {
|
|
8114
7775
|
this.skills = [];
|
|
@@ -8131,7 +7792,7 @@ var init_skill_manager = __esm({
|
|
|
8131
7792
|
let changed = false;
|
|
8132
7793
|
for (const sk of this.skills) {
|
|
8133
7794
|
if (sk.status !== "active") continue;
|
|
8134
|
-
if (!
|
|
7795
|
+
if (!existsSync14(join12(this.skillsDir, `${sk.name}.md`))) {
|
|
8135
7796
|
sk.status = "stale";
|
|
8136
7797
|
changed = true;
|
|
8137
7798
|
}
|
|
@@ -8142,9 +7803,9 @@ var init_skill_manager = __esm({
|
|
|
8142
7803
|
addSkill(skill) {
|
|
8143
7804
|
const id = skill.id || randomUUID();
|
|
8144
7805
|
const name = skill.name || `brain_${id.slice(0, 8)}`;
|
|
8145
|
-
if (!
|
|
8146
|
-
const mdPath =
|
|
8147
|
-
if (
|
|
7806
|
+
if (!existsSync14(this.skillsDir)) return "";
|
|
7807
|
+
const mdPath = join12(this.skillsDir, `${name}.md`);
|
|
7808
|
+
if (existsSync14(mdPath)) return "";
|
|
8148
7809
|
try {
|
|
8149
7810
|
writeFileSync4(mdPath, skill.content, "utf-8");
|
|
8150
7811
|
} catch {
|
|
@@ -8193,12 +7854,12 @@ var init_skill_manager = __esm({
|
|
|
8193
7854
|
const out = [];
|
|
8194
7855
|
for (const sk of this.skills) {
|
|
8195
7856
|
if (sk.origin_node !== "local" || sk.status !== "active") continue;
|
|
8196
|
-
const mdPath =
|
|
8197
|
-
if (!
|
|
7857
|
+
const mdPath = join12(this.skillsDir, `${sk.name}.md`);
|
|
7858
|
+
if (!existsSync14(mdPath)) continue;
|
|
8198
7859
|
out.push({
|
|
8199
7860
|
name: sk.name,
|
|
8200
7861
|
category: sk.category || "",
|
|
8201
|
-
content:
|
|
7862
|
+
content: readFileSync14(mdPath, "utf-8"),
|
|
8202
7863
|
keywords: sk.keywords || []
|
|
8203
7864
|
});
|
|
8204
7865
|
}
|
|
@@ -8486,9 +8147,10 @@ var init_decode = __esm({
|
|
|
8486
8147
|
"src/engine/formal-engine/decode.ts"() {
|
|
8487
8148
|
"use strict";
|
|
8488
8149
|
init_esm_shims();
|
|
8150
|
+
init_rules_loader();
|
|
8489
8151
|
B64_TOKEN_RE = /[A-Za-z0-9+/]+={0,2}/g;
|
|
8490
8152
|
QUOTED_STR_RE = /('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`)/g;
|
|
8491
|
-
OUTPUT_CMDS =
|
|
8153
|
+
OUTPUT_CMDS = new Set(loadFormalRules().output_commands ?? []);
|
|
8492
8154
|
STAGE_PRIORITY = ["EXFIL", "PRIVESC", "PERSIST", "SCAN", "LISTEN"];
|
|
8493
8155
|
PURPOSE_EXEC_RE = /subprocess\.\w+\s*\(|os\.system\s*\(|shell\s*=\s*True|\beval\s*\(|\bexec\s*\(|os\.popen\s*\(|\/exec\b/i;
|
|
8494
8156
|
LISTEN_LEAD_RE = /http\.server|flask\s+run|nohup\b|nc\s+-l|socat\s+TCP-LISTEN/i;
|
|
@@ -9206,7 +8868,7 @@ function checkSensitiveDataAggregation(graph) {
|
|
|
9206
8868
|
}
|
|
9207
8869
|
return violations;
|
|
9208
8870
|
}
|
|
9209
|
-
var CROSS_SESSION_CHAINS, CRED_FILE_RE, EXFIL_RE, EBPF_NET_RE, REMOTE_RE, EXFIL_ACTION_RE, CRED_STRICT_RE, INLINE_SHELL_RE, PKG_MGR, SHELLS, TOOL_REGISTRY, COMPUTE_RE, STRONG_COMPUTE_TYPES, DL_OR_LOW_RE, ALL_PROPERTIES;
|
|
8871
|
+
var CROSS_SESSION_CHAINS, CRED_FILE_RE, EXFIL_RE, EBPF_NET_RE, REMOTE_RE, EXFIL_ACTION_RE, CRED_STRICT_RE, INLINE_SHELL_RE, FORMAL_RULES, PKG_MGR, SHELLS, TOOL_REGISTRY, COMPUTE_RE, STRONG_COMPUTE_TYPES, DL_OR_LOW_RE, ALL_PROPERTIES;
|
|
9210
8872
|
var init_properties = __esm({
|
|
9211
8873
|
"src/engine/formal-engine/properties.ts"() {
|
|
9212
8874
|
"use strict";
|
|
@@ -9223,11 +8885,12 @@ var init_properties = __esm({
|
|
|
9223
8885
|
EXFIL_ACTION_RE = /\bcurl\b|\bwget\b|\bscp\b|\brsync\b|\brclone\b|\bftp\b|connect\s+.*\d+\.\d+\.\d+\.\d+|open\s+.*tcp|base64\s+.*\-o/i;
|
|
9224
8886
|
CRED_STRICT_RE = /(known_hosts|\.ssh|id_rsa|\.pem|\b\.key\b|\/etc\/shadow|\/etc\/passwd|\.aws\/credentials|credentials\.json|netrc|password|secrets?\.ya?ml|credentials?\s*(file|path)?\s*(=|\:)|\bconfig.*(password|token))/i;
|
|
9225
8887
|
INLINE_SHELL_RE = /(?:os\.system|os\.popen)\s*\(\s*['"]([^'"]+)['"]|subprocess\.[a-z_]+\(\s*\[([^\]]+)\]|subprocess\.[a-z_]+\(\s*['"]([^'"]+)['"]|(?:bash|sh|zsh)\s+-c\s*['"]([^'"]+)['"]/gi;
|
|
9226
|
-
|
|
9227
|
-
|
|
8888
|
+
FORMAL_RULES = loadFormalRules();
|
|
8889
|
+
PKG_MGR = new Set(FORMAL_RULES.privesc?.package_managers ?? []);
|
|
8890
|
+
SHELLS = new Set(FORMAL_RULES.privesc?.bare_shells ?? []);
|
|
9228
8891
|
TOOL_REGISTRY = null;
|
|
9229
8892
|
COMPUTE_RE = /subprocess|os\.system|shell\s*=\s*True|\beval\(|\bexec\(|bash\s+[^\s]|sh\s+-c|python3?\s+|node\s+|\btimeout\s+|nohup\s+|\b\.\/[\w./-]+/i;
|
|
9230
|
-
STRONG_COMPUTE_TYPES =
|
|
8893
|
+
STRONG_COMPUTE_TYPES = new Set(FORMAL_RULES.compute_action_types ?? []);
|
|
9231
8894
|
DL_OR_LOW_RE = /curl\s+.*-o\b|wget\s+.*\s+-O\b|curl\s+.*\|\s*(bash|sh|python)|wget\s+.*\|\s*(bash|sh|python)|git\s+clone|docker\s+pull|pip\s+install|npm\s+install|base64\s+-d/i;
|
|
9232
8895
|
ALL_PROPERTIES = [
|
|
9233
8896
|
{ id: "cross-session-chain", check: checkCrossSessionChain, shortName: "P1" },
|
|
@@ -9751,10 +9414,10 @@ var init_stateful = __esm({
|
|
|
9751
9414
|
import * as fs4 from "fs";
|
|
9752
9415
|
import * as os2 from "os";
|
|
9753
9416
|
import * as path4 from "path";
|
|
9754
|
-
import { createHash } from "crypto";
|
|
9417
|
+
import { createHash as createHash2 } from "crypto";
|
|
9755
9418
|
function defaultStateDbPath() {
|
|
9756
9419
|
const dir = process.env.AGENT_MOSS_STATE_DIR || path4.join(os2.homedir(), ".agentmoss");
|
|
9757
|
-
const tag =
|
|
9420
|
+
const tag = createHash2("sha1").update("agentmoss-stateful").digest("hex").slice(0, 8);
|
|
9758
9421
|
return path4.join(dir, `stateful_chains_${tag}.json`);
|
|
9759
9422
|
}
|
|
9760
9423
|
var ChainStateStore;
|
|
@@ -10014,7 +9677,7 @@ async function runAnalysis(input) {
|
|
|
10014
9677
|
const actionType = input.aNext.actionType.toLowerCase();
|
|
10015
9678
|
const rawDetail = extractRawCommand(input.aNext.actionDetail);
|
|
10016
9679
|
const lowerDetail = rawDetail.toLowerCase();
|
|
10017
|
-
if (
|
|
9680
|
+
if (getPlatformTraits(input.osType).safeActionTypes.has(actionType)) {
|
|
10018
9681
|
return {
|
|
10019
9682
|
allowed: true,
|
|
10020
9683
|
reason: `\u5B8C\u5168\u5B89\u5168\u5DE5\u5177\uFF0C\u8DF3\u8FC7\u6DF1\u5EA6\u5206\u6790: ${actionType}`,
|
|
@@ -10057,7 +9720,7 @@ async function runAnalysis(input) {
|
|
|
10057
9720
|
violatedLayers: []
|
|
10058
9721
|
};
|
|
10059
9722
|
}
|
|
10060
|
-
let skipLLM =
|
|
9723
|
+
let skipLLM = getPlatformTraits(input.osType).readonlySensitiveActionTypes.has(actionType);
|
|
10061
9724
|
if (actionType === "bash" || actionType === "executebash" || actionType === "terminal-executebash") {
|
|
10062
9725
|
const firstCmd = extractFirstCommand(lowerDetail);
|
|
10063
9726
|
const { fullySafeCommands, readonlySensitiveCommands } = getPlatformTraits(input.osType);
|
|
@@ -10289,7 +9952,7 @@ async function runAnalysis(input) {
|
|
|
10289
9952
|
}
|
|
10290
9953
|
return llmResult;
|
|
10291
9954
|
}
|
|
10292
|
-
var
|
|
9955
|
+
var TRUSTED_SKILLS_BASE, _brainStore, _brainExtractor, _brainSkillManager, _brainCurator, _brainInitialized, _brainLastMaintenance, BRAIN_MAINT_INTERVAL_MS, formalEngine;
|
|
10293
9956
|
var init_coordinator = __esm({
|
|
10294
9957
|
"src/engine/coordinator.ts"() {
|
|
10295
9958
|
"use strict";
|
|
@@ -10312,25 +9975,7 @@ var init_coordinator = __esm({
|
|
|
10312
9975
|
init_asset_dir();
|
|
10313
9976
|
init_runtime_config_bridge();
|
|
10314
9977
|
init_formal_engine();
|
|
10315
|
-
FULLY_SAFE_TOOLS = /* @__PURE__ */ new Set([
|
|
10316
|
-
"ask_user_question",
|
|
10317
|
-
"glob",
|
|
10318
|
-
"list_dir",
|
|
10319
|
-
"ls",
|
|
10320
|
-
"count_text_length",
|
|
10321
|
-
"filemgr-globfiles"
|
|
10322
|
-
]);
|
|
10323
9978
|
TRUSTED_SKILLS_BASE = /* @__PURE__ */ new Set([]);
|
|
10324
|
-
READONLY_SENSITIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
10325
|
-
"read",
|
|
10326
|
-
"file_read",
|
|
10327
|
-
"read_file",
|
|
10328
|
-
"head",
|
|
10329
|
-
"tail",
|
|
10330
|
-
"grep",
|
|
10331
|
-
"filemgr-readfile",
|
|
10332
|
-
"filemgr-grepfiles"
|
|
10333
|
-
]);
|
|
10334
9979
|
_brainStore = null;
|
|
10335
9980
|
_brainExtractor = null;
|
|
10336
9981
|
_brainSkillManager = null;
|
|
@@ -10345,10 +9990,150 @@ var init_coordinator = __esm({
|
|
|
10345
9990
|
// src/server.ts
|
|
10346
9991
|
init_esm_shims();
|
|
10347
9992
|
import { Hono as Hono2 } from "hono";
|
|
9993
|
+
|
|
9994
|
+
// src/infra/rules-contract.ts
|
|
9995
|
+
init_esm_shims();
|
|
9996
|
+
init_paths();
|
|
9997
|
+
init_rules_loader();
|
|
9998
|
+
import { createHash } from "crypto";
|
|
9999
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
10000
|
+
import { join as join3 } from "path";
|
|
10001
|
+
var RULES_SCHEMA_VERSION = 1;
|
|
10002
|
+
var REQUIRED_RULE_FILES = {
|
|
10003
|
+
"l1_rules.json": ["dangerous_commands", "injection_detection", "sensitive_path_access"],
|
|
10004
|
+
"l2_rules.json": ["intent_consistency", "password_modify_consent", "user_deletion_consent"],
|
|
10005
|
+
"l3_rules.json": [],
|
|
10006
|
+
"mc_rules.json": ["rules", "ap_patterns"],
|
|
10007
|
+
"tool_registry.json": ["tools"],
|
|
10008
|
+
"platform_traits.json": ["linux", "windows"],
|
|
10009
|
+
"inline_rules.json": ["read_write_keywords", "dir_traversal_keywords", "write_exec_chain_patterns"],
|
|
10010
|
+
"script_rules.json": [
|
|
10011
|
+
"suspicious_patterns",
|
|
10012
|
+
"keyword_combination_risks",
|
|
10013
|
+
"single_keyword_risks",
|
|
10014
|
+
"script_exec_patterns"
|
|
10015
|
+
],
|
|
10016
|
+
"heuristic_rules.json": [
|
|
10017
|
+
"sensitive_excluded_prefixes",
|
|
10018
|
+
"search_action_prefixes",
|
|
10019
|
+
"loopback_hosts",
|
|
10020
|
+
"temp_dirs"
|
|
10021
|
+
],
|
|
10022
|
+
"logic_rules.json": ["indirect_file_access", "write_commands", "source_arg_commands"],
|
|
10023
|
+
"formal_rules.json": ["privesc", "compute_action_types", "pattern_miner", "output_commands"]
|
|
10024
|
+
};
|
|
10025
|
+
var MANIFEST_FILE = "manifest.json";
|
|
10026
|
+
function sha256Short(data, n = 12) {
|
|
10027
|
+
return createHash("sha256").update(data).digest("hex").slice(0, n);
|
|
10028
|
+
}
|
|
10029
|
+
function rulesDir() {
|
|
10030
|
+
if (getRulesRoot()) return join3(getRulesRoot(), "rules");
|
|
10031
|
+
const probe = resolveRulesFile("l1_rules.json");
|
|
10032
|
+
return probe ? probe.slice(0, probe.length - "l1_rules.json".length - 1) : null;
|
|
10033
|
+
}
|
|
10034
|
+
function checkRulesAssets() {
|
|
10035
|
+
const rep = {
|
|
10036
|
+
ok: true,
|
|
10037
|
+
schemaVersion: 0,
|
|
10038
|
+
fingerprint: "",
|
|
10039
|
+
fileHashes: {},
|
|
10040
|
+
errors: [],
|
|
10041
|
+
external: getRulesRoot() !== null
|
|
10042
|
+
};
|
|
10043
|
+
const dir = rulesDir();
|
|
10044
|
+
if (!dir) {
|
|
10045
|
+
rep.errors.push("\u627E\u4E0D\u5230\u89C4\u5219\u76EE\u5F55\uFF08\u5305\u5185\u89C4\u5219\u6587\u4EF6\u7F3A\u5931\uFF0C\u4E14\u672A\u8BBE AGENT_MOSS_RULES_ROOT\uFF09");
|
|
10046
|
+
rep.ok = false;
|
|
10047
|
+
return rep;
|
|
10048
|
+
}
|
|
10049
|
+
const manifestPath = join3(dir, MANIFEST_FILE);
|
|
10050
|
+
if (!existsSync2(manifestPath)) {
|
|
10051
|
+
rep.errors.push(`\u7F3A\u5C11 ${MANIFEST_FILE}\uFF08\u89C4\u5219\u5305\u5FC5\u987B\u58F0\u660E schema \u7248\u672C\uFF09`);
|
|
10052
|
+
} else {
|
|
10053
|
+
try {
|
|
10054
|
+
const m = JSON.parse(readFileSync3(manifestPath, "utf-8")) || {};
|
|
10055
|
+
const ver = m.schema_version;
|
|
10056
|
+
if (typeof ver !== "number" || !Number.isInteger(ver)) {
|
|
10057
|
+
rep.errors.push(`${MANIFEST_FILE} \u7F3A\u5C11\u6574\u6570 schema_version`);
|
|
10058
|
+
} else {
|
|
10059
|
+
rep.schemaVersion = ver;
|
|
10060
|
+
if (ver !== RULES_SCHEMA_VERSION) {
|
|
10061
|
+
rep.errors.push(
|
|
10062
|
+
`schema \u7248\u672C\u4E0D\u5339\u914D\uFF1A\u89C4\u5219\u5305\u662F ${ver}\uFF0C\u672C\u5F15\u64CE\u8BA4\u8BC6 ${RULES_SCHEMA_VERSION}\u3002\u8BF7\u5347\u7EA7\u5F15\u64CE\u6216\u6539\u7528\u5BF9\u5E94\u7248\u672C\u7684\u89C4\u5219\u5305\u3002`
|
|
10063
|
+
);
|
|
10064
|
+
}
|
|
10065
|
+
}
|
|
10066
|
+
} catch (e) {
|
|
10067
|
+
rep.errors.push(`${MANIFEST_FILE} \u8BFB\u53D6/\u89E3\u6790\u5931\u8D25: ${String(e)}`);
|
|
10068
|
+
}
|
|
10069
|
+
}
|
|
10070
|
+
const fpParts = [];
|
|
10071
|
+
for (const [name, requiredKeys] of Object.entries(REQUIRED_RULE_FILES)) {
|
|
10072
|
+
const p = join3(dir, name);
|
|
10073
|
+
if (!existsSync2(p)) {
|
|
10074
|
+
rep.errors.push(`\u7F3A\u5C11\u89C4\u5219\u6587\u4EF6 ${name}`);
|
|
10075
|
+
rep.fileHashes[name] = "MISSING";
|
|
10076
|
+
fpParts.push(`${name}:MISSING`);
|
|
10077
|
+
continue;
|
|
10078
|
+
}
|
|
10079
|
+
let raw = null;
|
|
10080
|
+
try {
|
|
10081
|
+
raw = readFileSync3(p);
|
|
10082
|
+
} catch (e) {
|
|
10083
|
+
rep.errors.push(`${name} \u8BFB\u53D6\u5931\u8D25: ${String(e)}`);
|
|
10084
|
+
rep.fileHashes[name] = "UNREADABLE";
|
|
10085
|
+
fpParts.push(`${name}:UNREADABLE`);
|
|
10086
|
+
continue;
|
|
10087
|
+
}
|
|
10088
|
+
rep.fileHashes[name] = sha256Short(raw);
|
|
10089
|
+
fpParts.push(`${name}:${rep.fileHashes[name]}`);
|
|
10090
|
+
let data = null;
|
|
10091
|
+
try {
|
|
10092
|
+
data = JSON.parse(raw.toString("utf-8")) || {};
|
|
10093
|
+
} catch (e) {
|
|
10094
|
+
rep.errors.push(`${name} \u89E3\u6790\u5931\u8D25: ${String(e)}`);
|
|
10095
|
+
rep.fileHashes[name] = "BADJSON";
|
|
10096
|
+
continue;
|
|
10097
|
+
}
|
|
10098
|
+
if (typeof data !== "object" || Array.isArray(data)) {
|
|
10099
|
+
rep.errors.push(`${name} \u9876\u5C42\u5FC5\u987B\u662F JSON \u5BF9\u8C61`);
|
|
10100
|
+
continue;
|
|
10101
|
+
}
|
|
10102
|
+
const missing = requiredKeys.filter((k) => !(k in data));
|
|
10103
|
+
if (missing.length) rep.errors.push(`${name} \u7F3A\u5C11\u9876\u5C42\u952E: ${missing.join(", ")}`);
|
|
10104
|
+
}
|
|
10105
|
+
rep.fingerprint = sha256Short([...fpParts].sort().join("\n"));
|
|
10106
|
+
rep.ok = rep.errors.length === 0;
|
|
10107
|
+
return rep;
|
|
10108
|
+
}
|
|
10109
|
+
function formatRulesIntegrity(rep) {
|
|
10110
|
+
const src = rep.external ? `\u5916\u90E8\u89C4\u5219\u5305 ${getRulesRoot()}` : "\u5305\u5185\u89C4\u5219";
|
|
10111
|
+
const head = `\u89C4\u5219\u5305: ${src} | schema v${rep.schemaVersion} | \u6307\u7EB9 ${rep.fingerprint || "-"}`;
|
|
10112
|
+
if (rep.ok) return head;
|
|
10113
|
+
return `${head} | \u274C ${rep.errors.length} \u4E2A\u95EE\u9898: ${rep.errors.slice(0, 5).join("\uFF1B")}`;
|
|
10114
|
+
}
|
|
10115
|
+
function enforceRulesContract() {
|
|
10116
|
+
const rep = checkRulesAssets();
|
|
10117
|
+
if (rep.ok) {
|
|
10118
|
+
console.log(`[AgentMoss] ${formatRulesIntegrity(rep)}`);
|
|
10119
|
+
return rep;
|
|
10120
|
+
}
|
|
10121
|
+
const msg = formatRulesIntegrity(rep);
|
|
10122
|
+
if (rep.external) {
|
|
10123
|
+
console.error(`[AgentMoss] \u274C ${msg}`);
|
|
10124
|
+
throw new Error(
|
|
10125
|
+
`\u89C4\u5219\u5305\u6821\u9A8C\u5931\u8D25\uFF0C\u62D2\u7EDD\u542F\u52A8\uFF08AGENT_MOSS_RULES_ROOT \u5DF2\u663E\u5F0F\u6307\u5B9A\uFF0C\u4E0D\u5141\u8BB8\u5E26\u7740\u6B8B\u7F3A\u89C4\u5219\u8FD0\u884C\uFF09\uFF1A${rep.errors.join("\uFF1B")}`
|
|
10126
|
+
);
|
|
10127
|
+
}
|
|
10128
|
+
console.error(`[AgentMoss] \u26A0\uFE0F ${msg}\uFF08\u4F7F\u7528\u5305\u5185\u89C4\u5219\uFF0C\u7167\u5E38\u542F\u52A8\uFF1B\u82E5\u662F npm \u5B89\u88C5\u8BF7\u91CD\u88C5\uFF09`);
|
|
10129
|
+
return rep;
|
|
10130
|
+
}
|
|
10131
|
+
|
|
10132
|
+
// src/server.ts
|
|
10348
10133
|
import { cors } from "hono/cors";
|
|
10349
10134
|
import { logger } from "hono/logger";
|
|
10350
10135
|
import net from "net";
|
|
10351
|
-
import { existsSync as
|
|
10136
|
+
import { existsSync as existsSync20 } from "fs";
|
|
10352
10137
|
|
|
10353
10138
|
// src/routes.ts
|
|
10354
10139
|
init_esm_shims();
|
|
@@ -10438,18 +10223,18 @@ var ReviewResponseSchema = z.object({
|
|
|
10438
10223
|
// src/engine/analyzer.ts
|
|
10439
10224
|
init_esm_shims();
|
|
10440
10225
|
init_coordinator();
|
|
10441
|
-
import { existsSync as
|
|
10226
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync17, writeFileSync as writeFileSync7 } from "fs";
|
|
10442
10227
|
import { tmpdir as tmpdir2 } from "os";
|
|
10443
|
-
import { join as
|
|
10228
|
+
import { join as join15, resolve as resolve10 } from "path";
|
|
10444
10229
|
|
|
10445
10230
|
// src/infra/policy-cache.ts
|
|
10446
10231
|
init_esm_shims();
|
|
10447
10232
|
init_config();
|
|
10448
|
-
import { createHash as
|
|
10449
|
-
import { existsSync as
|
|
10233
|
+
import { createHash as createHash3 } from "crypto";
|
|
10234
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync6, readdirSync as readdirSync5, readFileSync as readFileSync16, rmdirSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
10450
10235
|
import { tmpdir } from "os";
|
|
10451
|
-
import { join as
|
|
10452
|
-
var CACHE_DIR =
|
|
10236
|
+
import { join as join14 } from "path";
|
|
10237
|
+
var CACHE_DIR = join14(tmpdir(), "agent_moss_policy_cache");
|
|
10453
10238
|
var cacheDirOverride = null;
|
|
10454
10239
|
function cacheDir() {
|
|
10455
10240
|
return cacheDirOverride ?? CACHE_DIR;
|
|
@@ -10465,9 +10250,9 @@ var PolicyCache = class {
|
|
|
10465
10250
|
return `${sessionId}::${promptSession}`;
|
|
10466
10251
|
}
|
|
10467
10252
|
cacheFilePath(sessionId, promptSession) {
|
|
10468
|
-
const promptHash =
|
|
10253
|
+
const promptHash = createHash3("md5").update(promptSession).digest("hex").slice(0, 12);
|
|
10469
10254
|
const safeSessionId = sessionId.replace(/\//g, "_").replace(/\\/g, "_");
|
|
10470
|
-
return
|
|
10255
|
+
return join14(cacheDir(), safeSessionId, `${promptHash}.toml`);
|
|
10471
10256
|
}
|
|
10472
10257
|
/** 取缓存:内存 → 文件;未命中返回 null。 */
|
|
10473
10258
|
get(sessionId, promptSession) {
|
|
@@ -10480,9 +10265,9 @@ var PolicyCache = class {
|
|
|
10480
10265
|
return hit;
|
|
10481
10266
|
}
|
|
10482
10267
|
const file = this.cacheFilePath(sessionId, promptSession);
|
|
10483
|
-
if (
|
|
10268
|
+
if (existsSync16(file)) {
|
|
10484
10269
|
try {
|
|
10485
|
-
const policy =
|
|
10270
|
+
const policy = readFileSync16(file, "utf-8");
|
|
10486
10271
|
this.remember(key, policy);
|
|
10487
10272
|
return policy;
|
|
10488
10273
|
} catch {
|
|
@@ -10496,7 +10281,7 @@ var PolicyCache = class {
|
|
|
10496
10281
|
this.remember(this.cacheKey(sessionId, promptSession), policy);
|
|
10497
10282
|
const file = this.cacheFilePath(sessionId, promptSession);
|
|
10498
10283
|
try {
|
|
10499
|
-
mkdirSync6(
|
|
10284
|
+
mkdirSync6(join14(cacheDir(), sessionId.replace(/\//g, "_").replace(/\\/g, "_")), { recursive: true });
|
|
10500
10285
|
writeFileSync6(file, policy, "utf-8");
|
|
10501
10286
|
} catch {
|
|
10502
10287
|
}
|
|
@@ -10522,12 +10307,12 @@ var PolicyCache = class {
|
|
|
10522
10307
|
if (k.startsWith(`${sessionId}::`)) this.memory.delete(k);
|
|
10523
10308
|
}
|
|
10524
10309
|
const safeSessionId = sessionId.replace(/\//g, "_").replace(/\\/g, "_");
|
|
10525
|
-
const dir =
|
|
10310
|
+
const dir = join14(cacheDir(), safeSessionId);
|
|
10526
10311
|
try {
|
|
10527
|
-
if (
|
|
10312
|
+
if (existsSync16(dir)) {
|
|
10528
10313
|
for (const f of readdirSync5(dir)) {
|
|
10529
10314
|
try {
|
|
10530
|
-
unlinkSync3(
|
|
10315
|
+
unlinkSync3(join14(dir, f));
|
|
10531
10316
|
} catch {
|
|
10532
10317
|
}
|
|
10533
10318
|
}
|
|
@@ -10539,11 +10324,11 @@ var PolicyCache = class {
|
|
|
10539
10324
|
clear() {
|
|
10540
10325
|
this.memory.clear();
|
|
10541
10326
|
try {
|
|
10542
|
-
if (
|
|
10327
|
+
if (existsSync16(cacheDir())) {
|
|
10543
10328
|
for (const sessionDir of readdirSync5(cacheDir())) {
|
|
10544
|
-
const dir =
|
|
10329
|
+
const dir = join14(cacheDir(), sessionDir);
|
|
10545
10330
|
try {
|
|
10546
|
-
for (const f of readdirSync5(dir)) unlinkSync3(
|
|
10331
|
+
for (const f of readdirSync5(dir)) unlinkSync3(join14(dir, f));
|
|
10547
10332
|
rmdirSync(dir);
|
|
10548
10333
|
} catch {
|
|
10549
10334
|
}
|
|
@@ -10630,7 +10415,7 @@ ${safe(policy, 2e3)}`);
|
|
|
10630
10415
|
|
|
10631
10416
|
// src/engine/analyzer.ts
|
|
10632
10417
|
import { parse as parseToml } from "smol-toml";
|
|
10633
|
-
var POLICY_OUTPUT_DIR =
|
|
10418
|
+
var POLICY_OUTPUT_DIR = join15(tmpdir2(), "agent_moss");
|
|
10634
10419
|
var policyOutputDirOverride = null;
|
|
10635
10420
|
function policyOutputDir() {
|
|
10636
10421
|
return policyOutputDirOverride ?? POLICY_OUTPUT_DIR;
|
|
@@ -10666,7 +10451,7 @@ function savePolicyToFile(sessionId, policyToml) {
|
|
|
10666
10451
|
const outDir = policyOutputDir();
|
|
10667
10452
|
mkdirSync7(outDir, { recursive: true });
|
|
10668
10453
|
const safeName = sessionId.replace(/\//g, "_").replace(/\\/g, "_");
|
|
10669
|
-
const filepath =
|
|
10454
|
+
const filepath = join15(outDir, `${safeName}.toml`);
|
|
10670
10455
|
writeFileSync7(filepath, policyToml, "utf-8");
|
|
10671
10456
|
return filepath;
|
|
10672
10457
|
} catch (err) {
|
|
@@ -10705,11 +10490,11 @@ function loadPolicyMappingDoc() {
|
|
|
10705
10490
|
const dir = resolveAssetDir(__dirname, "templates");
|
|
10706
10491
|
if (dir) {
|
|
10707
10492
|
const p = resolve10(dir, "policy_mapping.md");
|
|
10708
|
-
if (
|
|
10493
|
+
if (existsSync17(p)) return readFileSync17(p, "utf-8");
|
|
10709
10494
|
}
|
|
10710
10495
|
for (const cand of assetDirCandidates(__dirname, "templates")) {
|
|
10711
10496
|
const p = resolve10(cand, "policy_mapping.md");
|
|
10712
|
-
if (
|
|
10497
|
+
if (existsSync17(p)) return readFileSync17(p, "utf-8");
|
|
10713
10498
|
}
|
|
10714
10499
|
return "";
|
|
10715
10500
|
}
|
|
@@ -10814,12 +10599,12 @@ async function analyzeInner(input, mossLog) {
|
|
|
10814
10599
|
}
|
|
10815
10600
|
const cache3 = getDefaultCache();
|
|
10816
10601
|
mossLog.startStep("step2_cache_lookup");
|
|
10817
|
-
const
|
|
10818
|
-
if (
|
|
10602
|
+
const cached2 = cache3.get(input.sessionId, input.promptSession);
|
|
10603
|
+
if (cached2 !== null) {
|
|
10819
10604
|
mossLog.endStep("step2_cache_lookup", "\u7F13\u5B58\u547D\u4E2D");
|
|
10820
|
-
savePolicyToFile(input.sessionId,
|
|
10821
|
-
const res = allowResult(
|
|
10822
|
-
mossLog.logResult("Allow", res.reason,
|
|
10605
|
+
savePolicyToFile(input.sessionId, cached2);
|
|
10606
|
+
const res = allowResult(cached2, judgment);
|
|
10607
|
+
mossLog.logResult("Allow", res.reason, cached2);
|
|
10823
10608
|
return res;
|
|
10824
10609
|
}
|
|
10825
10610
|
if (!isPolicyGenEnabled()) {
|
|
@@ -10984,9 +10769,11 @@ init_formal_engine();
|
|
|
10984
10769
|
|
|
10985
10770
|
// src/engine/formal-engine/pattern_miner.ts
|
|
10986
10771
|
init_esm_shims();
|
|
10772
|
+
init_rules_loader();
|
|
10987
10773
|
init_builder();
|
|
10988
|
-
var
|
|
10989
|
-
var
|
|
10774
|
+
var _PM = loadFormalRules().pattern_miner ?? {};
|
|
10775
|
+
var DANGER_STAGES = new Set(_PM.danger_stages ?? []);
|
|
10776
|
+
var SENSITIVE_PAIRS = new Set((_PM.sensitive_pairs ?? []).map((p) => p.join("|")));
|
|
10990
10777
|
function projectStages(actionHistory) {
|
|
10991
10778
|
const stages = [];
|
|
10992
10779
|
let prev = null;
|
|
@@ -11226,7 +11013,7 @@ function normalizeObservablePayload(body) {
|
|
|
11226
11013
|
init_rule_store();
|
|
11227
11014
|
init_skill_manager();
|
|
11228
11015
|
init_asset_dir();
|
|
11229
|
-
import { join as
|
|
11016
|
+
import { join as join17, dirname as dirname11 } from "path";
|
|
11230
11017
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
11231
11018
|
var __dirname9 = dirname11(fileURLToPath10(import.meta.url));
|
|
11232
11019
|
async function healthRoute(c) {
|
|
@@ -11477,7 +11264,7 @@ function getBrainRuleStore() {
|
|
|
11477
11264
|
return new BrainRuleStore();
|
|
11478
11265
|
}
|
|
11479
11266
|
function getBrainSkillManager() {
|
|
11480
|
-
const dir = resolveAssetDir(__dirname9, "skills") ??
|
|
11267
|
+
const dir = resolveAssetDir(__dirname9, "skills") ?? join17(__dirname9, "..", "..", "agent_moss", "skills");
|
|
11481
11268
|
return new BrainSkillManager(dir);
|
|
11482
11269
|
}
|
|
11483
11270
|
async function brainRulesRoute(c) {
|
|
@@ -11578,12 +11365,13 @@ init_runtime_config();
|
|
|
11578
11365
|
init_token_stats();
|
|
11579
11366
|
init_rules_loader();
|
|
11580
11367
|
init_asset_dir();
|
|
11368
|
+
init_rules_mode();
|
|
11581
11369
|
import { Hono } from "hono";
|
|
11582
|
-
import { readFileSync as
|
|
11583
|
-
import { join as
|
|
11370
|
+
import { readFileSync as readFileSync19, existsSync as existsSync19, unlinkSync as unlinkSync4 } from "fs";
|
|
11371
|
+
import { join as join18, dirname as dirname12 } from "path";
|
|
11584
11372
|
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
11585
11373
|
var __dirname10 = dirname12(fileURLToPath11(import.meta.url));
|
|
11586
|
-
var STATIC_DIR =
|
|
11374
|
+
var STATIC_DIR = join18(__dirname10, "static");
|
|
11587
11375
|
var CONSOLE_TOKEN_ENV = "AGENT_MOSS_CONSOLE_TOKEN";
|
|
11588
11376
|
function getConsoleToken() {
|
|
11589
11377
|
return process.env[CONSOLE_TOKEN_ENV] || "";
|
|
@@ -11603,21 +11391,35 @@ function authMiddleware() {
|
|
|
11603
11391
|
await next();
|
|
11604
11392
|
};
|
|
11605
11393
|
}
|
|
11394
|
+
function displayRuntimeConfig() {
|
|
11395
|
+
return isRuntimeConfigDisabled() ? generateSourceDefaults() : loadRuntimeConfig();
|
|
11396
|
+
}
|
|
11397
|
+
function builtinOnlyReadOnlyMiddleware() {
|
|
11398
|
+
return async (c, next) => {
|
|
11399
|
+
if (isRuntimeConfigDisabled() && !["GET", "HEAD", "OPTIONS"].includes(c.req.method)) {
|
|
11400
|
+
return c.json({
|
|
11401
|
+
detail: `\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u4E3A ${getRulesMode()}\uFF08runtime \u914D\u7F6E\u5DF2\u7981\u7528\uFF09\uFF1AConsole \u53EA\u8BFB\uFF0C\u4FEE\u6539\u4E0D\u4F1A\u4FDD\u5B58\u3002\u8BF7\u5207\u6362\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u5E76\u91CD\u542F\u670D\u52A1\u540E\u518D\u6539\u89C4\u5219\u3002`
|
|
11402
|
+
}, 403);
|
|
11403
|
+
}
|
|
11404
|
+
await next();
|
|
11405
|
+
};
|
|
11406
|
+
}
|
|
11606
11407
|
function createConsoleRouter() {
|
|
11607
11408
|
const console2 = new Hono();
|
|
11608
11409
|
console2.use("/api/*", authMiddleware());
|
|
11410
|
+
console2.use("/api/*", builtinOnlyReadOnlyMiddleware());
|
|
11609
11411
|
const serveIndex = (c) => {
|
|
11610
|
-
const indexFile =
|
|
11611
|
-
if (
|
|
11612
|
-
return c.html(
|
|
11412
|
+
const indexFile = join18(STATIC_DIR, "index.html");
|
|
11413
|
+
if (existsSync19(indexFile)) {
|
|
11414
|
+
return c.html(readFileSync19(indexFile, "utf-8"));
|
|
11613
11415
|
}
|
|
11614
11416
|
return c.html("<h1>AgentMoss Policy Console</h1><p>Frontend not built. Use /console/api/* endpoints.</p>");
|
|
11615
11417
|
};
|
|
11616
11418
|
console2.get("/", serveIndex);
|
|
11617
11419
|
console2.get("", serveIndex);
|
|
11618
11420
|
console2.get("/api/layers", (c) => {
|
|
11619
|
-
const rc =
|
|
11620
|
-
return c.json({ layers: rc.layers, env_overrides: getEnvOverrides() });
|
|
11421
|
+
const rc = displayRuntimeConfig();
|
|
11422
|
+
return c.json({ layers: rc.layers, env_overrides: getEnvOverrides(), builtin_only: isBuiltinOnly(), rules_mode: getRulesMode() });
|
|
11621
11423
|
});
|
|
11622
11424
|
console2.put("/api/layers", async (c) => {
|
|
11623
11425
|
const body = await c.req.json();
|
|
@@ -11652,7 +11454,7 @@ function createConsoleRouter() {
|
|
|
11652
11454
|
const rules = mc.rules || [];
|
|
11653
11455
|
let catEnabled = true;
|
|
11654
11456
|
try {
|
|
11655
|
-
const rt =
|
|
11457
|
+
const rt = displayRuntimeConfig();
|
|
11656
11458
|
catEnabled = rt.L2_2?.ltl_rules?.category_enabled !== false;
|
|
11657
11459
|
} catch {
|
|
11658
11460
|
}
|
|
@@ -11708,7 +11510,7 @@ function createConsoleRouter() {
|
|
|
11708
11510
|
return rc;
|
|
11709
11511
|
}
|
|
11710
11512
|
console2.get("/api/rules", (c) => {
|
|
11711
|
-
const rc =
|
|
11513
|
+
const rc = displayRuntimeConfig();
|
|
11712
11514
|
const layer = c.req.query("layer");
|
|
11713
11515
|
const category = c.req.query("category");
|
|
11714
11516
|
const out = {};
|
|
@@ -11773,8 +11575,8 @@ function createConsoleRouter() {
|
|
|
11773
11575
|
return c.json(withL22View(rc));
|
|
11774
11576
|
});
|
|
11775
11577
|
console2.get("/api/skills", (c) => {
|
|
11776
|
-
const rc =
|
|
11777
|
-
return c.json(rc.L3_skills);
|
|
11578
|
+
const rc = displayRuntimeConfig();
|
|
11579
|
+
return c.json(rc.L3_skills || {});
|
|
11778
11580
|
});
|
|
11779
11581
|
console2.put("/api/skills/enabled", async (c) => {
|
|
11780
11582
|
const b = await c.req.json();
|
|
@@ -11804,18 +11606,21 @@ function createConsoleRouter() {
|
|
|
11804
11606
|
if (!/^[A-Za-z0-9_-]+$/.test(skillId)) {
|
|
11805
11607
|
return c.json({ detail: "\u975E\u6CD5 skill id" }, 400);
|
|
11806
11608
|
}
|
|
11807
|
-
const userPath =
|
|
11609
|
+
const userPath = join18(dirname12(getRuntimeConfigPath()), "agent_moss_skills", `${skillId}.md`);
|
|
11808
11610
|
const builtinDir = resolveAssetDir(__dirname10, "skills");
|
|
11809
|
-
const candidates = [
|
|
11611
|
+
const candidates = [
|
|
11612
|
+
...isRuntimeConfigDisabled() ? [] : [userPath],
|
|
11613
|
+
builtinDir ? join18(builtinDir, `${skillId}.md`) : ""
|
|
11614
|
+
].filter(Boolean);
|
|
11810
11615
|
for (const p of candidates) {
|
|
11811
|
-
if (
|
|
11812
|
-
return c.json({ skill_id: skillId, path: p, content:
|
|
11616
|
+
if (existsSync19(p)) {
|
|
11617
|
+
return c.json({ skill_id: skillId, path: p, content: readFileSync19(p, "utf-8") });
|
|
11813
11618
|
}
|
|
11814
11619
|
}
|
|
11815
11620
|
return c.json({ detail: `skill ${skillId} \u4E0D\u5B58\u5728` }, 404);
|
|
11816
11621
|
});
|
|
11817
11622
|
console2.get("/api/agents", (c) => {
|
|
11818
|
-
const rc =
|
|
11623
|
+
const rc = displayRuntimeConfig();
|
|
11819
11624
|
return c.json({ agents: getAgentRules(rc) });
|
|
11820
11625
|
});
|
|
11821
11626
|
console2.put("/api/agents/rules/enabled", async (c) => {
|
|
@@ -11854,7 +11659,7 @@ function createConsoleRouter() {
|
|
|
11854
11659
|
});
|
|
11855
11660
|
const enabledScenarioIds = () => (process.env.AGENT_MOSS_SCENARIO || "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
11856
11661
|
console2.get("/api/scenarios", (c) => {
|
|
11857
|
-
const all = getScenarioRules(
|
|
11662
|
+
const all = getScenarioRules(displayRuntimeConfig());
|
|
11858
11663
|
const enabled = enabledScenarioIds();
|
|
11859
11664
|
if (!enabled.length) return c.json({ scenarios: {}, enabled: [] });
|
|
11860
11665
|
const shown = {};
|
|
@@ -11896,8 +11701,8 @@ function createConsoleRouter() {
|
|
|
11896
11701
|
return c.json({ scenarios: getScenarioRules(rc), enabled: enabledScenarioIds() });
|
|
11897
11702
|
});
|
|
11898
11703
|
console2.get("/api/config", (c) => {
|
|
11899
|
-
const rc =
|
|
11900
|
-
return c.json({ ...rc, L2_2: getL22View() });
|
|
11704
|
+
const rc = displayRuntimeConfig();
|
|
11705
|
+
return c.json({ ...rc, L2_2: getL22View(), builtin_only: isBuiltinOnly(), rules_mode: getRulesMode() });
|
|
11901
11706
|
});
|
|
11902
11707
|
console2.get("/api/env-overrides", (c) => {
|
|
11903
11708
|
return c.json({ overrides: getEnvOverrides() });
|
|
@@ -11906,7 +11711,7 @@ function createConsoleRouter() {
|
|
|
11906
11711
|
const defaults = generateSourceDefaults();
|
|
11907
11712
|
try {
|
|
11908
11713
|
const p = getRuntimeConfigPath();
|
|
11909
|
-
if (
|
|
11714
|
+
if (existsSync19(p)) unlinkSync4(p);
|
|
11910
11715
|
} catch {
|
|
11911
11716
|
}
|
|
11912
11717
|
return c.json(withL22View(defaults));
|
|
@@ -11935,37 +11740,58 @@ function createConsoleRouter() {
|
|
|
11935
11740
|
|
|
11936
11741
|
// src/server.ts
|
|
11937
11742
|
init_runtime_config();
|
|
11743
|
+
init_rules_mode();
|
|
11938
11744
|
init_rules_loader();
|
|
11939
11745
|
function logDeploymentSelfCheck() {
|
|
11940
11746
|
try {
|
|
11747
|
+
const mode = getRulesMode();
|
|
11748
|
+
const builtinOnly = isBuiltinOnly();
|
|
11749
|
+
const runtimeDisabled = isRuntimeConfigDisabled();
|
|
11941
11750
|
console.log("================ AgentMoss \u90E8\u7F72\u81EA\u68C0 ================");
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
11948
|
-
|
|
11949
|
-
}
|
|
11950
|
-
const loaded = ruleFilesLoaded();
|
|
11951
|
-
if (loaded.length > 0) {
|
|
11952
|
-
const ov = loadOverrideRules();
|
|
11953
|
-
const ex = loadExtraRules();
|
|
11954
|
-
console.error(`\u26A0\uFE0F \u5DF2\u4ECE\u89C4\u5219\u76EE\u5F55\u52A0\u8F7D ${loaded.length} \u4E2A\u6587\u4EF6\uFF08\u6574\u4EFD\u66FF\u6362 / \u8FFD\u52A0\uFF0C\u5185\u7F6E\u66F4\u65B0\u4E0D\u4F1A\u53CD\u6620\u5230\u5B83\u4EEC\u4E0A\u9762\uFF09:`);
|
|
11955
|
-
for (const f of loaded) console.error(` ${f}`);
|
|
11956
|
-
const ovs = Object.entries(ov).sort().map(([k, v]) => `${k}\xD7${v.length}`).join(", ");
|
|
11957
|
-
if (ovs) console.error(` \u8986\u76D6\u7C7B\u522B: ${ovs}\uFF08**\u6574\u4EFD\u66FF\u6362**\uFF1A\u672A\u5217\u51FA\u7684\u5185\u7F6E\u89C4\u5219\u4E0D\u518D\u751F\u6548\uFF09`);
|
|
11958
|
-
const exs = Object.entries(ex).sort().map(([k, v]) => `${k}\xD7${v.length}`).join(", ");
|
|
11959
|
-
if (exs) console.log(` \u8FFD\u52A0\u7C7B\u522B: ${exs}\uFF08\u5185\u7F6E\u4FDD\u7559\uFF0C\u8FFD\u52A0\u5728\u5176\u540E\u4E00\u8D77\u5224\u5B9A\uFF09`);
|
|
11960
|
-
}
|
|
11961
|
-
const ignored = ignoredRuleFiles();
|
|
11962
|
-
if (ignored.length > 0) {
|
|
11751
|
+
if (runtimeDisabled) {
|
|
11752
|
+
console.log(`runtime \u914D\u7F6E: ${getRuntimeConfigPath()}\uFF08**\u5DF2\u5FFD\u7565**\uFF1A\u89C4\u5219\u6765\u6E90\u6A21\u5F0F=${mode}\uFF09`);
|
|
11753
|
+
if (builtinOnly) {
|
|
11754
|
+
console.error(
|
|
11755
|
+
"\u89C4\u5219\u6765\u6E90: **\u4EC5\u5185\u7F6E** \u2014\u2014 \u4E0D\u8BFB runtime \u914D\u7F6E / Console \u81EA\u5B9A\u4E49 / \u89C4\u5219\u76EE\u5F55 / AGENT_MOSS_CUSTOM_RULES\uFF1B\u4E0D seed\u3001\u4E0D merge\u3001\u4E0D\u5199\u56DE\u3002"
|
|
11756
|
+
);
|
|
11757
|
+
} else {
|
|
11963
11758
|
console.error(
|
|
11964
|
-
|
|
11759
|
+
"\u89C4\u5219\u6765\u6E90: **\u51B7\u542F\u52A8\uFF08cold\uFF09** \u2014\u2014 \u542F\u52A8\u65F6\u8BFB\u53D6\u5185\u7F6E\u89C4\u5219 + \u89C4\u5219\u76EE\u5F55 / AGENT_MOSS_CUSTOM_RULES / \u573A\u666F\uFF0C\u4E4B\u540E\u51BB\u7ED3\uFF1B\u4E0D\u8BFB runtime \u914D\u7F6E / Console\uFF0C\u4E0D seed\u3001\u4E0D merge\u3001\u4E0D\u5199\u56DE\u3002"
|
|
11965
11760
|
);
|
|
11966
|
-
|
|
11761
|
+
console.error("\u89C4\u5219\u76EE\u5F55\u5185\u5BB9\u6539\u52A8\u9700\u91CD\u542F\u670D\u52A1\u624D\u751F\u6548\u3002");
|
|
11762
|
+
}
|
|
11763
|
+
console.error("Console: \u53EA\u8BFB\uFF08\u89C4\u5219\u5199\u63A5\u53E3\u8FD4\u56DE 403\uFF09\uFF1B\u4FEE\u6539\u89C4\u5219\u9700\u91CD\u542F\u670D\u52A1\u5E76\u5207\u6362\u89C4\u5219\u6765\u6E90\u6A21\u5F0F\u3002");
|
|
11764
|
+
} else {
|
|
11765
|
+
console.log(`runtime \u914D\u7F6E: ${getRuntimeConfigPath()}`);
|
|
11766
|
+
}
|
|
11767
|
+
const layerKeys = ["L1_heuristic", "L2_logic_rules", "L3_llm_analysis", "agent_rules_enabled", "scenario_rules_enabled"];
|
|
11768
|
+
console.log("\u5C42\u7EA7\u5F00\u5173: " + layerKeys.map((k) => `${k}=${isLayerEnabled(k) ? "on" : "OFF"}`).join(" "));
|
|
11769
|
+
if (!builtinOnly) {
|
|
11770
|
+
try {
|
|
11771
|
+
const dirs = rulesDirs().filter((d) => existsSync20(d));
|
|
11772
|
+
if (dirs.length > 0) {
|
|
11773
|
+
console.log(`\u89C4\u5219\u76EE\u5F55: ${dirs.join(", ")}\uFF08\u53EA\u8BFB\u5176\u4E2D ${OVERRIDE_FILENAME} / ${EXTRA_FILENAME}\uFF09`);
|
|
11774
|
+
}
|
|
11775
|
+
const loaded = ruleFilesLoaded();
|
|
11776
|
+
if (loaded.length > 0) {
|
|
11777
|
+
const ov = loadOverrideRules();
|
|
11778
|
+
const ex = loadExtraRules();
|
|
11779
|
+
console.error(`\u26A0\uFE0F \u5DF2\u4ECE\u89C4\u5219\u76EE\u5F55\u52A0\u8F7D ${loaded.length} \u4E2A\u6587\u4EF6\uFF08\u6574\u4EFD\u66FF\u6362 / \u8FFD\u52A0\uFF0C\u5185\u7F6E\u66F4\u65B0\u4E0D\u4F1A\u53CD\u6620\u5230\u5B83\u4EEC\u4E0A\u9762\uFF09:`);
|
|
11780
|
+
for (const f of loaded) console.error(` ${f}`);
|
|
11781
|
+
const ovs = Object.entries(ov).sort().map(([k, v]) => `${k}\xD7${v.length}`).join(", ");
|
|
11782
|
+
if (ovs) console.error(` \u8986\u76D6\u7C7B\u522B: ${ovs}\uFF08**\u6574\u4EFD\u66FF\u6362**\uFF1A\u672A\u5217\u51FA\u7684\u5185\u7F6E\u89C4\u5219\u4E0D\u518D\u751F\u6548\uFF09`);
|
|
11783
|
+
const exs = Object.entries(ex).sort().map(([k, v]) => `${k}\xD7${v.length}`).join(", ");
|
|
11784
|
+
if (exs) console.log(` \u8FFD\u52A0\u7C7B\u522B: ${exs}\uFF08\u5185\u7F6E\u4FDD\u7559\uFF0C\u8FFD\u52A0\u5728\u5176\u540E\u4E00\u8D77\u5224\u5B9A\uFF09`);
|
|
11785
|
+
}
|
|
11786
|
+
const ignored = ignoredRuleFiles();
|
|
11787
|
+
if (ignored.length > 0) {
|
|
11788
|
+
console.error(
|
|
11789
|
+
`\u26A0\uFE0F \u89C4\u5219\u76EE\u5F55\u91CC\u6709 ${ignored.length} \u4E2A json **\u4E0D\u4F1A\u88AB\u8BFB\u53D6**\uFF08\u53EA\u8BA4 ${OVERRIDE_FILENAME} / ${EXTRA_FILENAME}\uFF09:`
|
|
11790
|
+
);
|
|
11791
|
+
for (const f of ignored) console.error(` ${f}`);
|
|
11792
|
+
}
|
|
11793
|
+
} catch {
|
|
11967
11794
|
}
|
|
11968
|
-
} catch {
|
|
11969
11795
|
}
|
|
11970
11796
|
const scenarioRaw = (process.env.AGENT_MOSS_SCENARIO || "").trim();
|
|
11971
11797
|
if (scenarioRaw) {
|
|
@@ -11981,6 +11807,7 @@ function logDeploymentSelfCheck() {
|
|
|
11981
11807
|
}
|
|
11982
11808
|
}
|
|
11983
11809
|
function createApp() {
|
|
11810
|
+
enforceRulesContract();
|
|
11984
11811
|
const app = new Hono2();
|
|
11985
11812
|
app.use("*", cors({ origin: "*", allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], allowHeaders: ["*"] }));
|
|
11986
11813
|
app.use("*", logger());
|
|
@@ -12075,7 +11902,7 @@ async function startUnixSocketServer(socketPath = "/var/run/agent_moss/agent_mos
|
|
|
12075
11902
|
server = null;
|
|
12076
11903
|
},
|
|
12077
11904
|
serve: async () => {
|
|
12078
|
-
const { mkdirSync: mkdirSync8, existsSync:
|
|
11905
|
+
const { mkdirSync: mkdirSync8, existsSync: existsSync21, unlinkSync: unlinkSync5 } = await import("fs");
|
|
12079
11906
|
const { dirname: dirname13 } = await import("path");
|
|
12080
11907
|
const dir = dirname13(socketPath);
|
|
12081
11908
|
if (dir) {
|
|
@@ -12084,7 +11911,7 @@ async function startUnixSocketServer(socketPath = "/var/run/agent_moss/agent_mos
|
|
|
12084
11911
|
} catch {
|
|
12085
11912
|
}
|
|
12086
11913
|
}
|
|
12087
|
-
if (
|
|
11914
|
+
if (existsSync21(socketPath)) {
|
|
12088
11915
|
const { connect } = await import("net");
|
|
12089
11916
|
const inUse = await new Promise((resolve11) => {
|
|
12090
11917
|
const probe = connect(socketPath);
|