@kenhkl/agent-moss 0.3.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/cli.js +334 -68
- package/dist/cli.js.map +1 -1
- package/package.json +5 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
+
}) : x)(function(x) {
|
|
7
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
+
});
|
|
4
10
|
var __esm = (fn, res) => function __init() {
|
|
5
11
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
12
|
};
|
|
@@ -12,13 +18,59 @@ var __export = (target, all) => {
|
|
|
12
18
|
// node_modules/tsup/assets/esm_shims.js
|
|
13
19
|
import path from "path";
|
|
14
20
|
import { fileURLToPath } from "url";
|
|
21
|
+
var getFilename, getDirname, __dirname;
|
|
15
22
|
var init_esm_shims = __esm({
|
|
16
23
|
"node_modules/tsup/assets/esm_shims.js"() {
|
|
17
24
|
"use strict";
|
|
25
|
+
getFilename = () => fileURLToPath(import.meta.url);
|
|
26
|
+
getDirname = () => path.dirname(getFilename());
|
|
27
|
+
__dirname = /* @__PURE__ */ getDirname();
|
|
18
28
|
}
|
|
19
29
|
});
|
|
20
30
|
|
|
21
31
|
// src/config.ts
|
|
32
|
+
import fs from "fs";
|
|
33
|
+
import path2 from "path";
|
|
34
|
+
import os from "os";
|
|
35
|
+
function loadConfigFile(filePath) {
|
|
36
|
+
try {
|
|
37
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
38
|
+
return JSON.parse(raw);
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function resolveConfigPath() {
|
|
44
|
+
const envPath = process.env.AGENT_MOSS_CONFIG_PATH;
|
|
45
|
+
if (envPath) return envPath;
|
|
46
|
+
const userConfig = path2.join(os.homedir(), ".config", "agentmoss", "config.json");
|
|
47
|
+
if (fs.existsSync(userConfig)) return userConfig;
|
|
48
|
+
const defaultConfig = path2.join(__dirname, "..", "..", "agent_moss", "infra", "config.json.example");
|
|
49
|
+
if (fs.existsSync(defaultConfig)) {
|
|
50
|
+
const configDir = path2.dirname(userConfig);
|
|
51
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
52
|
+
const pkgConfig = loadConfigFile(defaultConfig);
|
|
53
|
+
const safeConfig = pkgConfig ? { ...pkgConfig, llm: { ...pkgConfig.llm, api_key: "" } } : {};
|
|
54
|
+
fs.writeFileSync(userConfig, JSON.stringify(safeConfig, null, 4), "utf-8");
|
|
55
|
+
console.log(`[AgentMoss] \u5DF2\u521B\u5EFA\u7528\u6237\u914D\u7F6E\u6587\u4EF6: ${userConfig}`);
|
|
56
|
+
console.log(`[AgentMoss] \u8BF7\u7F16\u8F91\u8BE5\u6587\u4EF6\u914D\u7F6E\u4F60\u7684 LLM API Key`);
|
|
57
|
+
}
|
|
58
|
+
return userConfig;
|
|
59
|
+
}
|
|
60
|
+
function loadLLMConfigFromFile(configPath) {
|
|
61
|
+
const data = loadConfigFile(configPath);
|
|
62
|
+
if (!data?.llm) return {};
|
|
63
|
+
const llm = data.llm;
|
|
64
|
+
return {
|
|
65
|
+
provider: llm.provider || "",
|
|
66
|
+
baseUrl: llm.base_url || "",
|
|
67
|
+
apiKey: llm.api_key || "",
|
|
68
|
+
model: llm.model || "",
|
|
69
|
+
temperature: llm.temperature ?? 0.1,
|
|
70
|
+
maxTokens: llm.max_tokens ?? 4096,
|
|
71
|
+
timeout: llm.timeout ?? 300
|
|
72
|
+
};
|
|
73
|
+
}
|
|
22
74
|
function loadCustomRules() {
|
|
23
75
|
try {
|
|
24
76
|
const raw = process.env.AGENT_MOSS_CUSTOM_RULES;
|
|
@@ -84,15 +136,19 @@ var init_config = __esm({
|
|
|
84
136
|
"src/config.ts"() {
|
|
85
137
|
"use strict";
|
|
86
138
|
init_esm_shims();
|
|
87
|
-
llmConfig = {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
139
|
+
llmConfig = (() => {
|
|
140
|
+
const configPath = resolveConfigPath();
|
|
141
|
+
const fileConfig = fs.existsSync(configPath) ? loadLLMConfigFromFile(configPath) : {};
|
|
142
|
+
return {
|
|
143
|
+
provider: process.env.AGENT_MOSS_LLM_PROVIDER || fileConfig.provider || "openai",
|
|
144
|
+
baseUrl: process.env.AGENT_MOSS_LLM_BASE_URL || fileConfig.baseUrl || "https://api.openai.com/v1",
|
|
145
|
+
apiKey: process.env.AGENT_MOSS_LLM_API_KEY || process.env.OPENAI_API_KEY || fileConfig.apiKey || "",
|
|
146
|
+
model: process.env.AGENT_MOSS_LLM_MODEL || fileConfig.model || "gpt-4o",
|
|
147
|
+
temperature: parseFloat(process.env.AGENT_MOSS_LLM_TEMPERATURE || String(fileConfig.temperature ?? "0.1")),
|
|
148
|
+
maxTokens: parseInt(process.env.AGENT_MOSS_LLM_MAX_TOKENS || String(fileConfig.maxTokens ?? "4096"), 10),
|
|
149
|
+
timeout: parseInt(process.env.AGENT_MOSS_LLM_TIMEOUT || String(fileConfig.timeout ?? "300"), 10)
|
|
150
|
+
};
|
|
151
|
+
})();
|
|
96
152
|
customRules = loadCustomRules();
|
|
97
153
|
PROVIDER_HEADERS = {
|
|
98
154
|
"openrouter": {
|
|
@@ -111,6 +167,7 @@ function runHeuristicCheck(input) {
|
|
|
111
167
|
const command = `${input.aNext.actionType}: ${input.aNext.actionDetail}`;
|
|
112
168
|
const matched = [];
|
|
113
169
|
let highestSeverity = "low";
|
|
170
|
+
let highestRiskType = "";
|
|
114
171
|
const userRules = getCustomRules();
|
|
115
172
|
for (const rule of userRules) {
|
|
116
173
|
try {
|
|
@@ -120,20 +177,24 @@ function runHeuristicCheck(input) {
|
|
|
120
177
|
matched.push(`\u81EA\u5B9A\u4E49\u89C4\u5219: ${rule.pattern}`);
|
|
121
178
|
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
122
179
|
highestSeverity = rule.severity;
|
|
180
|
+
highestRiskType = "custom_rule";
|
|
123
181
|
}
|
|
124
182
|
}
|
|
125
183
|
}
|
|
126
184
|
} catch {
|
|
127
185
|
}
|
|
128
186
|
}
|
|
187
|
+
let topRiskType = "";
|
|
129
188
|
for (const rule of DANGEROUS_PATTERNS) {
|
|
130
189
|
if (rule.pattern.test(command)) {
|
|
131
190
|
matched.push(rule.description);
|
|
132
191
|
if (severityRank(rule.severity) > severityRank(highestSeverity)) {
|
|
133
192
|
highestSeverity = rule.severity;
|
|
193
|
+
topRiskType = rule.riskType;
|
|
134
194
|
}
|
|
135
195
|
}
|
|
136
196
|
}
|
|
197
|
+
highestRiskType = topRiskType || highestRiskType;
|
|
137
198
|
const injectionText = `${input.aNext.actionType} ${input.aNext.actionDetail} ${input.reason || ""} ${input.promptSession || ""}`.toLowerCase();
|
|
138
199
|
const injectionHits = checkInjectionKeywords(injectionText);
|
|
139
200
|
if (injectionHits.length > 0) {
|
|
@@ -141,15 +202,15 @@ function runHeuristicCheck(input) {
|
|
|
141
202
|
matched.push(...injectionHits.map((h) => `\u6CE8\u5165\u5173\u952E\u8BCD [${h.lang}]: ${h.keyword}`));
|
|
142
203
|
if (severityRank(topHit.riskLevel) > severityRank(highestSeverity)) {
|
|
143
204
|
highestSeverity = topHit.riskLevel;
|
|
205
|
+
highestRiskType = "prompt_injection";
|
|
144
206
|
}
|
|
145
207
|
}
|
|
146
208
|
if (matched.length > 0) {
|
|
147
|
-
const riskType = injectionHits.length > 0 ? "prompt_injection" : "dangerous_command";
|
|
148
209
|
return {
|
|
149
210
|
allowed: false,
|
|
150
211
|
reason: `\u68C0\u6D4B\u5230\u9AD8\u5371\u64CD\u4F5C: ${matched.join(", ")}`,
|
|
151
212
|
riskLevel: highestSeverity,
|
|
152
|
-
riskType,
|
|
213
|
+
riskType: highestRiskType,
|
|
153
214
|
confidence: 95,
|
|
154
215
|
source: "heuristic",
|
|
155
216
|
violatedLayers: ["1"]
|
|
@@ -166,6 +227,10 @@ function checkInjectionKeywords(text) {
|
|
|
166
227
|
}
|
|
167
228
|
return hits;
|
|
168
229
|
}
|
|
230
|
+
function isInlineScriptCommand(actionDetail) {
|
|
231
|
+
const re = /(?:^|\s)(?:python|python3|python3\.\d+|perl|perl5|ruby|jruby|mruby|node|php|lua)\s+(?:-[a-zA-Z]*[cer][a-zA-Z]*\s+)/i;
|
|
232
|
+
return re.test(actionDetail);
|
|
233
|
+
}
|
|
169
234
|
function severityRank(s) {
|
|
170
235
|
const ranks = { low: 1, medium: 2, high: 3, critical: 4 };
|
|
171
236
|
return ranks[s] || 0;
|
|
@@ -241,59 +306,66 @@ var init_heuristic = __esm({
|
|
|
241
306
|
DANGEROUS_PATTERNS = [
|
|
242
307
|
// --- Critical: rm command graded detection (strict to loose, first match wins) ---
|
|
243
308
|
// 1. rm -rf root dir
|
|
244
|
-
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\/\s/i, severity: "critical", description: "\u9012\u5F52\u5F3A\u5236\u5220\u9664\u6839\u76EE\u5F55 (rm -rf /)" },
|
|
309
|
+
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*f[a-zA-Z]*\s+\/\s/i, severity: "critical", description: "\u9012\u5F52\u5F3A\u5236\u5220\u9664\u6839\u76EE\u5F55 (rm -rf /)", riskType: "script_execution" },
|
|
245
310
|
// 2. rm -rf absolute path (both -r and -f)
|
|
246
|
-
{ pattern: /\brm\s+-(?=[^\s]*r)(?=[^\s]*f)[a-zA-Z]*\s+\//i, severity: "critical", description: "\u9012\u5F52\u5F3A\u5236\u5220\u9664\u7EDD\u5BF9\u8DEF\u5F84 (rm -rf /...)" },
|
|
311
|
+
{ pattern: /\brm\s+-(?=[^\s]*r)(?=[^\s]*f)[a-zA-Z]*\s+\//i, severity: "critical", description: "\u9012\u5F52\u5F3A\u5236\u5220\u9664\u7EDD\u5BF9\u8DEF\u5F84 (rm -rf /...)", riskType: "script_execution" },
|
|
247
312
|
// 3. rm with -r or -f targeting system dirs
|
|
248
|
-
{ pattern: /\brm\s+-[a-zA-Z]*[rf][a-zA-Z]*\s+\/(etc|var|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55" },
|
|
313
|
+
{ pattern: /\brm\s+-[a-zA-Z]*[rf][a-zA-Z]*\s+\/(etc|var|home|usr|boot|root|opt|srv|sys|proc)\b/i, severity: "critical", description: "\u5220\u9664\u5173\u952E\u7CFB\u7EDF\u76EE\u5F55", riskType: "script_execution" },
|
|
249
314
|
// 4. rm -r absolute path (no -f)
|
|
250
|
-
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*\s+\//i, severity: "high", description: "\u9012\u5F52\u5220\u9664\u64CD\u4F5C (rm -r /...)" },
|
|
315
|
+
{ pattern: /\brm\s+-[a-zA-Z]*r[a-zA-Z]*\s+\//i, severity: "high", description: "\u9012\u5F52\u5220\u9664\u64CD\u4F5C (rm -r /...)", riskType: "script_execution" },
|
|
251
316
|
// 5. rm -f absolute path (no -r)
|
|
252
|
-
{ pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*\s+\//i, severity: "medium", description: "\u5F3A\u5236\u5220\u9664\u6587\u4EF6 (rm -f /...)" },
|
|
253
|
-
{ pattern: /dd\s+if=\/dev\/zero|dd\s+if=.*of=\/dev\//i, severity: "critical", description: "\u78C1\u76D8\u6E05\u96F6/\u76F4\u63A5\u5199\u5165" },
|
|
254
|
-
{ pattern: /mkfs\b/i, severity: "critical", description: "\u683C\u5F0F\u5316\u6587\u4EF6\u7CFB\u7EDF" },
|
|
255
|
-
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb" },
|
|
317
|
+
{ pattern: /\brm\s+-[a-zA-Z]*f[a-zA-Z]*\s+\//i, severity: "medium", description: "\u5F3A\u5236\u5220\u9664\u6587\u4EF6 (rm -f /...)", riskType: "script_execution" },
|
|
318
|
+
{ pattern: /dd\s+if=\/dev\/zero|dd\s+if=.*of=\/dev\//i, severity: "critical", description: "\u78C1\u76D8\u6E05\u96F6/\u76F4\u63A5\u5199\u5165", riskType: "script_execution" },
|
|
319
|
+
{ pattern: /mkfs\b/i, severity: "critical", description: "\u683C\u5F0F\u5316\u6587\u4EF6\u7CFB\u7EDF", riskType: "script_execution" },
|
|
320
|
+
{ pattern: /:\(\)\s*\{.*:\|:&.*\};:/i, severity: "critical", description: "Fork Bomb", riskType: "resource_exhaustion" },
|
|
256
321
|
// --- Critical: remote code execution ---
|
|
257
|
-
{ pattern: /curl\s+.*\|\s*(bash|sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C" },
|
|
258
|
-
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C" },
|
|
259
|
-
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C" },
|
|
260
|
-
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "critical", description: "base64 \u89E3\u7801\u6267\u884C" },
|
|
322
|
+
{ pattern: /curl\s+.*\|\s*(bash|sh|zsh|dash)/i, severity: "critical", description: "curl pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
323
|
+
{ pattern: /wget\s+.*\|\s*(bash|sh)/i, severity: "critical", description: "wget pipe shell \u6267\u884C", riskType: "script_execution" },
|
|
324
|
+
{ pattern: /eval\s+\$\(curl|eval\s+\$\(wget/i, severity: "critical", description: "eval \u8FDC\u7A0B\u4EE3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
325
|
+
{ pattern: /base64\s+-d\s+.*\|\s*bash/i, severity: "critical", description: "base64 \u89E3\u7801\u6267\u884C", riskType: "script_execution" },
|
|
261
326
|
// --- Critical: reverse shell ---
|
|
262
|
-
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell" },
|
|
263
|
-
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5" },
|
|
327
|
+
{ pattern: /\/dev\/tcp\/|bash\s+-i\s+>&/i, severity: "critical", description: "\u53CD\u5F39 Shell", riskType: "script_execution" },
|
|
328
|
+
{ pattern: /nc\s+-[el]\s+.*\d{1,5}/i, severity: "high", description: "Netcat \u53CD\u5F39\u8FDE\u63A5", riskType: "lateral_movement" },
|
|
264
329
|
// --- Critical: sensitive file access ---
|
|
265
|
-
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)" },
|
|
266
|
-
{ pattern: /\.ssh\/id_rsa/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6" },
|
|
330
|
+
{ pattern: /\/etc\/shadow/i, severity: "critical", description: "\u8BBF\u95EE\u7CFB\u7EDF\u5BC6\u7801\u6587\u4EF6 (/etc/shadow)", riskType: "file_access" },
|
|
331
|
+
{ pattern: /\.ssh\/id_rsa/i, severity: "critical", description: "\u8BBF\u95EE SSH \u79C1\u94A5\u6587\u4EF6", riskType: "file_access" },
|
|
267
332
|
// --- Critical: privilege escalation / container escape ---
|
|
268
|
-
{ pattern: /\/var\/run\/docker\.sock/i, severity: "critical", description: "\u8BBF\u95EE Docker socket\uFF0C\u53EF\u80FD\u5BFC\u81F4\u5BB9\u5668\u9003\u9038" },
|
|
333
|
+
{ pattern: /\/var\/run\/docker\.sock/i, severity: "critical", description: "\u8BBF\u95EE Docker socket\uFF0C\u53EF\u80FD\u5BFC\u81F4\u5BB9\u5668\u9003\u9038", riskType: "privilege_escalation" },
|
|
269
334
|
// --- High: dangerous permissions / ownership ---
|
|
270
|
-
{ pattern: /chmod\s+[0-7]*777[0-7]*/i, severity: "high", description: "\u5168\u6743\u9650\u8BBE\u7F6E (chmod 777)" },
|
|
271
|
-
{ pattern: /chown\s+root|chown\s+-R\s+\w+:\w+\s+\//i, severity: "high", description: "\u4FEE\u6539\u6240\u6709\u8005\u4E3A root / \u9012\u5F52\u4FEE\u6539\u6839\u76EE\u5F55\u6240\u6709\u8005" },
|
|
272
|
-
{ pattern: /sudo\s+rm\s+-rf/i, severity: "high", description: "sudo \u5F3A\u5236\u5220\u9664" },
|
|
273
|
-
{ pattern: /sudo\s+/i, severity: "high", description: "\u63D0\u6743\u6267\u884C (sudo)" },
|
|
335
|
+
{ pattern: /chmod\s+[0-7]*777[0-7]*/i, severity: "high", description: "\u5168\u6743\u9650\u8BBE\u7F6E (chmod 777)", riskType: "script_execution" },
|
|
336
|
+
{ pattern: /chown\s+root|chown\s+-R\s+\w+:\w+\s+\//i, severity: "high", description: "\u4FEE\u6539\u6240\u6709\u8005\u4E3A root / \u9012\u5F52\u4FEE\u6539\u6839\u76EE\u5F55\u6240\u6709\u8005", riskType: "script_execution" },
|
|
337
|
+
{ pattern: /sudo\s+rm\s+-rf/i, severity: "high", description: "sudo \u5F3A\u5236\u5220\u9664", riskType: "script_execution" },
|
|
338
|
+
{ pattern: /sudo\s+/i, severity: "high", description: "\u63D0\u6743\u6267\u884C (sudo)", riskType: "privilege_escalation" },
|
|
274
339
|
// --- High: system config overwrite ---
|
|
275
|
-
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55" },
|
|
340
|
+
{ pattern: />\s*\/etc\//i, severity: "critical", description: "\u8986\u76D6\u5199\u5165\u7CFB\u7EDF\u914D\u7F6E\u76EE\u5F55", riskType: "file_access" },
|
|
276
341
|
// --- High: download script + execute risk ---
|
|
277
|
-
{ pattern: /(?:curl|wget)\s+.*(?:-o|--output|>)\s*\S+\.(?:sh|bash)\b/i, severity: "high", description: "\u8FDC\u7A0B\u4E0B\u8F7D\u811A\u672C\u5230\u672C\u5730" },
|
|
278
|
-
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C" },
|
|
342
|
+
{ pattern: /(?:curl|wget)\s+.*(?:-o|--output|>)\s*\S+\.(?:sh|bash)\b/i, severity: "high", description: "\u8FDC\u7A0B\u4E0B\u8F7D\u811A\u672C\u5230\u672C\u5730", riskType: "script_execution" },
|
|
343
|
+
{ pattern: /(?:curl|wget)\s+.*\s+&&?\s*(?:chmod\s+\+x|bash|sh)/i, severity: "high", description: "\u4E0B\u8F7D\u540E\u6267\u884C", riskType: "script_execution" },
|
|
279
344
|
// --- High: package manager pipe-to-shell ---
|
|
280
|
-
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell" },
|
|
281
|
-
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell" },
|
|
282
|
-
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell" },
|
|
345
|
+
{ pattern: /git\s+clone\s+.*\|.*bash/i, severity: "high", description: "git clone pipe shell", riskType: "script_execution" },
|
|
346
|
+
{ pattern: /pip\s+install\s+.*\|\s*bash/i, severity: "high", description: "pip install pipe shell", riskType: "script_execution" },
|
|
347
|
+
{ pattern: /npm\s+install\s+-g\s+.*\|\s*bash/i, severity: "high", description: "npm install pipe shell", riskType: "script_execution" },
|
|
283
348
|
// --- High: destructive git operations ---
|
|
284
|
-
{ pattern: /git\s+push\s+.*--force/i, severity: "high", description: "\u5F3A\u5236\u63A8\u9001\u64CD\u4F5C (git push --force)" },
|
|
349
|
+
{ pattern: /git\s+push\s+.*--force/i, severity: "high", description: "\u5F3A\u5236\u63A8\u9001\u64CD\u4F5C (git push --force)", riskType: "script_execution" },
|
|
285
350
|
// --- Medium: credential export ---
|
|
286
|
-
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1" },
|
|
351
|
+
{ pattern: /export\s+.*(?:TOKEN|KEY|SECRET|PASSWORD)/i, severity: "medium", description: "\u5BFC\u51FA\u654F\u611F\u51ED\u8BC1", riskType: "data_exfiltration" },
|
|
287
352
|
// --- High: shell rc file append (persistence) ---
|
|
288
|
-
{ pattern: />>\s*(~|\/home\/[^/]+)\/(\.bashrc|\.zshrc|\.profile|\.bash_profile|\.zprofile)/, severity: "high", description: "\u68C0\u6D4B\u5230\u4FEE\u6539 Shell \u914D\u7F6E\u6587\u4EF6\uFF08~/.bashrc \u7B49\uFF09\uFF0C\u53EF\u80FD\u7528\u4E8E\u6301\u4E45\u5316\u540E\u95E8" },
|
|
353
|
+
{ pattern: />>\s*(~|\/home\/[^/]+)\/(\.bashrc|\.zshrc|\.profile|\.bash_profile|\.zprofile)/, severity: "high", description: "\u68C0\u6D4B\u5230\u4FEE\u6539 Shell \u914D\u7F6E\u6587\u4EF6\uFF08~/.bashrc \u7B49\uFF09\uFF0C\u53EF\u80FD\u7528\u4E8E\u6301\u4E45\u5316\u540E\u95E8", riskType: "persistence" },
|
|
289
354
|
// --- High: device file access ---
|
|
290
|
-
{ pattern: /\/dev\/(mem|kmsg)\b/i, severity: "high", description: "\u8BBF\u95EE\u8BBE\u5907\u6587\u4EF6 (\u7269\u7406\u5185\u5B58/\u5185\u6838\u6D88\u606F)" }
|
|
355
|
+
{ pattern: /\/dev\/(mem|kmsg)\b/i, severity: "high", description: "\u8BBF\u95EE\u8BBE\u5907\u6587\u4EF6 (\u7269\u7406\u5185\u5B58/\u5185\u6838\u6D88\u606F)", riskType: "file_access" },
|
|
356
|
+
// --- High: non-interactive password modification ---
|
|
357
|
+
{ pattern: /\|\s*passwd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u7BA1\u9053\u65B9\u5F0F\u8C03\u7528 passwd\uFF08\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\uFF09", riskType: "script_execution" },
|
|
358
|
+
{ pattern: /\bpasswd\s+--stdin\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 passwd --stdin \u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u8F93\u5165", riskType: "script_execution" },
|
|
359
|
+
{ pattern: /\bchpasswd\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 chpasswd \u6279\u91CF\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4", riskType: "script_execution" },
|
|
360
|
+
{ pattern: /\bnewusers\b/i, severity: "high", description: "\u68C0\u6D4B\u5230 newusers \u6279\u91CF\u7528\u6237\u6DFB\u52A0\u547D\u4EE4", riskType: "script_execution" },
|
|
361
|
+
{ pattern: /\bpasswd\s+-[a-zA-Z]*d\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u5220\u9664\u7528\u6237\u5BC6\u7801\u64CD\u4F5C (passwd -d)", riskType: "script_execution" },
|
|
362
|
+
{ pattern: /\bpasswd\s+-[a-zA-Z]*l\b/i, severity: "high", description: "\u68C0\u6D4B\u5230\u9501\u5B9A\u7528\u6237\u8D26\u6237\u64CD\u4F5C (passwd -l)", riskType: "script_execution" }
|
|
291
363
|
];
|
|
292
364
|
}
|
|
293
365
|
});
|
|
294
366
|
|
|
295
367
|
// src/engine/logic-rules.ts
|
|
296
|
-
import * as
|
|
368
|
+
import * as fs2 from "fs";
|
|
297
369
|
function runLogicCheck(input) {
|
|
298
370
|
const { actionHistory, aNext, cwd } = input;
|
|
299
371
|
const actionDetail = aNext.actionDetail.toLowerCase();
|
|
@@ -375,6 +447,8 @@ function runLogicCheck(input) {
|
|
|
375
447
|
};
|
|
376
448
|
}
|
|
377
449
|
}
|
|
450
|
+
const pwdResult = checkPasswordConsent(actionType, actionDetail, actionHistory);
|
|
451
|
+
if (pwdResult) return pwdResult;
|
|
378
452
|
return null;
|
|
379
453
|
}
|
|
380
454
|
function extractFilePaths(text) {
|
|
@@ -387,7 +461,13 @@ function extractFilePaths(text) {
|
|
|
387
461
|
}
|
|
388
462
|
function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, cwd) {
|
|
389
463
|
if (NON_WRITE_TOOLS.has(actionType)) return null;
|
|
390
|
-
|
|
464
|
+
let isWrite = WRITE_KEYWORDS.some((kw) => actionType.includes(kw) || actionDetail.includes(kw));
|
|
465
|
+
if (!isWrite && actionDetail.includes(">")) {
|
|
466
|
+
const firstWord = actionDetail.split(/\s/)[0]?.toLowerCase() || "";
|
|
467
|
+
if (!READ_ONLY_REDIR_CMDS.has(firstWord)) {
|
|
468
|
+
isWrite = true;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
391
471
|
if (!isWrite) return null;
|
|
392
472
|
const targetPaths = extractFilePaths(actionDetail);
|
|
393
473
|
if (targetPaths.length === 0) return null;
|
|
@@ -403,17 +483,17 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
|
|
|
403
483
|
}
|
|
404
484
|
}
|
|
405
485
|
const unreadPaths = [];
|
|
406
|
-
for (const
|
|
486
|
+
for (const path3 of targetPaths) {
|
|
407
487
|
const hasRead = [...historyReadPaths].some(
|
|
408
|
-
(rp) =>
|
|
488
|
+
(rp) => path3 === rp || path3.startsWith(rp) || rp.startsWith(path3)
|
|
409
489
|
);
|
|
410
490
|
if (!hasRead) {
|
|
411
|
-
let isCreate = !
|
|
491
|
+
let isCreate = !fs2.existsSync(path3);
|
|
412
492
|
if (!isCreate) {
|
|
413
493
|
isCreate = CREATE_KEYWORDS.some((kw) => reason.toLowerCase().includes(kw) || actionDetail.includes(kw));
|
|
414
494
|
}
|
|
415
495
|
if (!isCreate) {
|
|
416
|
-
unreadPaths.push(
|
|
496
|
+
unreadPaths.push(path3);
|
|
417
497
|
}
|
|
418
498
|
}
|
|
419
499
|
}
|
|
@@ -495,7 +575,25 @@ function isLocalHost(host) {
|
|
|
495
575
|
const localNames = ["localhost", "127.0.0.1", "::1", process.env.HOSTNAME || "", "0.0.0.0"];
|
|
496
576
|
return localNames.includes(host.replace(/.*@/, ""));
|
|
497
577
|
}
|
|
498
|
-
|
|
578
|
+
function checkPasswordConsent(actionType, actionDetail, actionHistory) {
|
|
579
|
+
if (actionType !== "bash") return null;
|
|
580
|
+
const isPasswordModify = PASSWORD_MODIFY_PATTERNS.some((p) => p.test(actionDetail));
|
|
581
|
+
if (!isPasswordModify) return null;
|
|
582
|
+
const hasConsent = actionHistory.some(
|
|
583
|
+
(h) => h.actionType.toLowerCase() === "ask_user_question" && h.actionDetail.trim().length > 0
|
|
584
|
+
);
|
|
585
|
+
if (hasConsent) return null;
|
|
586
|
+
return {
|
|
587
|
+
allowed: false,
|
|
588
|
+
reason: "\u6267\u884C\u975E\u4EA4\u4E92\u5F0F\u5BC6\u7801\u4FEE\u6539\u547D\u4EE4\uFF0C\u4F46\u5386\u53F2\u6267\u884C\u5E8F\u5217\u4E2D\u672A\u53D1\u73B0\u5411\u7528\u6237\u786E\u8BA4\u5BC6\u7801\u7684 ask_user_question \u64CD\u4F5C\uFF0C\u53EF\u80FD\u5B58\u5728\u672A\u6388\u6743\u7684\u5BC6\u7801\u4FEE\u6539\u98CE\u9669",
|
|
589
|
+
riskLevel: "high",
|
|
590
|
+
riskType: "consent_missing",
|
|
591
|
+
confidence: 85,
|
|
592
|
+
source: "logic_rule",
|
|
593
|
+
violatedLayers: ["2"]
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
var ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, NON_WRITE_TOOLS, READ_ONLY_REDIR_CMDS, WRITE_KEYWORDS, READ_KEYWORDS, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, INTENT_DEVIATION_PATTERNS;
|
|
499
597
|
var init_logic_rules = __esm({
|
|
500
598
|
"src/engine/logic-rules.ts"() {
|
|
501
599
|
"use strict";
|
|
@@ -532,9 +630,18 @@ var init_logic_rules = __esm({
|
|
|
532
630
|
{ path: ".env", riskLevel: "high", desc: "\u73AF\u5883\u53D8\u91CF/\u51ED\u636E\u914D\u7F6E\u6587\u4EF6" }
|
|
533
631
|
];
|
|
534
632
|
NON_WRITE_TOOLS = /* @__PURE__ */ new Set(["ask_user_question", "glob", "grep", "list_dir", "count_text_length", "search"]);
|
|
633
|
+
READ_ONLY_REDIR_CMDS = /* @__PURE__ */ new Set(["cat", "head", "tail", "less", "more", "grep", "find", "awk", "sed", "sort", "uniq", "wc", "cut", "strings", "od", "xxd", "hexdump"]);
|
|
535
634
|
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"];
|
|
536
635
|
READ_KEYWORDS = ["read", "\u8BFB\u53D6", "cat", "head", "tail", "less", "more", "view", "\u67E5\u770B", "open", "\u6253\u5F00", "load", "\u52A0\u8F7D", "grep", "search", "\u641C\u7D22", "find", "\u67E5\u627E"];
|
|
537
636
|
CREATE_KEYWORDS = ["\u521B\u5EFA", "\u65B0\u5EFA", "create", "new file", "touch"];
|
|
637
|
+
PASSWORD_MODIFY_PATTERNS = [
|
|
638
|
+
/\|\s*passwd\b/i,
|
|
639
|
+
/\bpasswd\s+--stdin\b/i,
|
|
640
|
+
/\bchpasswd\b/i,
|
|
641
|
+
/\bnewusers\b/i,
|
|
642
|
+
/\bpasswd\s+-[a-zA-Z]*d\b/i,
|
|
643
|
+
/\bpasswd\s+-[a-zA-Z]*l\b/i
|
|
644
|
+
];
|
|
538
645
|
INTENT_DEVIATION_PATTERNS = [
|
|
539
646
|
{
|
|
540
647
|
intentKeywords: ["\u8BFB\u53D6", "\u67E5\u770B", "\u5206\u6790", "read", "analyze", "view", "list", "\u5217\u51FA"],
|
|
@@ -1069,8 +1176,12 @@ function matchesAny(cmd, patterns) {
|
|
|
1069
1176
|
}
|
|
1070
1177
|
async function runAnalysis(input) {
|
|
1071
1178
|
const heuristicResult = isHeuristicEnabled() ? runHeuristicCheck(input) : null;
|
|
1179
|
+
const isInlineScriptCmd = isInlineScriptCommand(input.aNext.actionDetail.toLowerCase());
|
|
1072
1180
|
if (heuristicResult && !heuristicResult.allowed) {
|
|
1073
|
-
|
|
1181
|
+
const skipInlineFileAccess = isInlineScriptCmd && heuristicResult.riskType === "file_access";
|
|
1182
|
+
if (!skipInlineFileAccess) {
|
|
1183
|
+
return heuristicResult;
|
|
1184
|
+
}
|
|
1074
1185
|
}
|
|
1075
1186
|
const actionType = input.aNext.actionType.toLowerCase();
|
|
1076
1187
|
const rawDetail = extractRawCommand(input.aNext.actionDetail);
|
|
@@ -1086,19 +1197,37 @@ async function runAnalysis(input) {
|
|
|
1086
1197
|
violatedLayers: []
|
|
1087
1198
|
};
|
|
1088
1199
|
}
|
|
1200
|
+
if (actionType === "skill" && TRUSTED_SKILLS.has(lowerDetail)) {
|
|
1201
|
+
return {
|
|
1202
|
+
allowed: true,
|
|
1203
|
+
reason: `\u5185\u7F6E\u5B89\u5168 Skill\uFF0C\u8DF3\u8FC7\u6DF1\u5EA6\u5206\u6790: ${lowerDetail}`,
|
|
1204
|
+
riskLevel: heuristicResult?.riskLevel || "low",
|
|
1205
|
+
riskType: "",
|
|
1206
|
+
confidence: 95,
|
|
1207
|
+
source: "whitelist_bypass",
|
|
1208
|
+
violatedLayers: []
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1089
1211
|
let skipLLM = READONLY_SENSITIVE_TOOLS.has(actionType);
|
|
1090
1212
|
if (actionType === "bash" || actionType === "executebash" || actionType === "terminal-executebash") {
|
|
1091
1213
|
const firstCmd = extractFirstCommand(lowerDetail);
|
|
1092
1214
|
if (matchesAny(firstCmd, FULLY_SAFE_BASH_PATTERNS)) {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1215
|
+
const fullCmdHit = DANGEROUS_PATTERNS.some(
|
|
1216
|
+
(p) => p.severity === "critical" || p.severity === "high"
|
|
1217
|
+
) && DANGEROUS_PATTERNS.some(
|
|
1218
|
+
(p) => (p.severity === "critical" || p.severity === "high") && p.pattern.test(lowerDetail)
|
|
1219
|
+
);
|
|
1220
|
+
if (!fullCmdHit) {
|
|
1221
|
+
return {
|
|
1222
|
+
allowed: true,
|
|
1223
|
+
reason: `\u5B89\u5168\u7684\u53EA\u8BFB bash \u547D\u4EE4: ${firstCmd}`,
|
|
1224
|
+
riskLevel: "low",
|
|
1225
|
+
riskType: "",
|
|
1226
|
+
confidence: 95,
|
|
1227
|
+
source: "whitelist_bypass",
|
|
1228
|
+
violatedLayers: []
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1102
1231
|
}
|
|
1103
1232
|
if (matchesAny(firstCmd, READONLY_SENSITIVE_BASH_PATTERNS)) {
|
|
1104
1233
|
skipLLM = true;
|
|
@@ -1106,7 +1235,10 @@ async function runAnalysis(input) {
|
|
|
1106
1235
|
}
|
|
1107
1236
|
const logicResult = isLogicRulesEnabled() ? runLogicCheck(input) : null;
|
|
1108
1237
|
if (logicResult && !logicResult.allowed) {
|
|
1109
|
-
|
|
1238
|
+
const skipInlineFileAccess = isInlineScriptCmd && logicResult.riskType === "sensitive_path_access";
|
|
1239
|
+
if (!skipInlineFileAccess) {
|
|
1240
|
+
return logicResult;
|
|
1241
|
+
}
|
|
1110
1242
|
}
|
|
1111
1243
|
if (skipLLM || !isLLMAvailable()) {
|
|
1112
1244
|
return {
|
|
@@ -1125,7 +1257,7 @@ async function runAnalysis(input) {
|
|
|
1125
1257
|
});
|
|
1126
1258
|
return llmResult;
|
|
1127
1259
|
}
|
|
1128
|
-
var FULLY_SAFE_TOOLS, READONLY_SENSITIVE_TOOLS, FULLY_SAFE_BASH_PATTERNS, READONLY_SENSITIVE_BASH_PATTERNS;
|
|
1260
|
+
var FULLY_SAFE_TOOLS, TRUSTED_SKILLS, READONLY_SENSITIVE_TOOLS, FULLY_SAFE_BASH_PATTERNS, READONLY_SENSITIVE_BASH_PATTERNS;
|
|
1129
1261
|
var init_coordinator = __esm({
|
|
1130
1262
|
"src/engine/coordinator.ts"() {
|
|
1131
1263
|
"use strict";
|
|
@@ -1142,6 +1274,7 @@ var init_coordinator = __esm({
|
|
|
1142
1274
|
"count_text_length",
|
|
1143
1275
|
"filemgr-globfiles"
|
|
1144
1276
|
]);
|
|
1277
|
+
TRUSTED_SKILLS = /* @__PURE__ */ new Set(["xiaoo-guardian"]);
|
|
1145
1278
|
READONLY_SENSITIVE_TOOLS = /* @__PURE__ */ new Set([
|
|
1146
1279
|
"read",
|
|
1147
1280
|
"file_read",
|
|
@@ -1167,7 +1300,20 @@ var init_coordinator = __esm({
|
|
|
1167
1300
|
/^echo\s+/i,
|
|
1168
1301
|
/^printf\s+/i,
|
|
1169
1302
|
/^type\s+/i,
|
|
1170
|
-
/^command\s+/i
|
|
1303
|
+
/^command\s+/i,
|
|
1304
|
+
// 系统信息查询(只读,不涉及文件/网络/权限)
|
|
1305
|
+
/^whoami(?:\s|$)/i,
|
|
1306
|
+
/^id(?:\s|$)/i,
|
|
1307
|
+
/^hostname(?:\s|$)/i,
|
|
1308
|
+
/^uname(?:\s|$)/i,
|
|
1309
|
+
/^date(?:\s|$)/i,
|
|
1310
|
+
/^env(?:\s|$)/i,
|
|
1311
|
+
/^printenv(?:\s|$)/i,
|
|
1312
|
+
/^tty(?:\s|$)/i,
|
|
1313
|
+
/^arch(?:\s|$)/i,
|
|
1314
|
+
/^uptime(?:\s|$)/i,
|
|
1315
|
+
/^groups(?:\s|$)/i,
|
|
1316
|
+
/^logname(?:\s|$)/i
|
|
1171
1317
|
];
|
|
1172
1318
|
READONLY_SENSITIVE_BASH_PATTERNS = [
|
|
1173
1319
|
/^cat\s+/i,
|
|
@@ -1236,6 +1382,109 @@ var HealthResponseSchema = z.object({
|
|
|
1236
1382
|
|
|
1237
1383
|
// src/routes.ts
|
|
1238
1384
|
init_coordinator();
|
|
1385
|
+
|
|
1386
|
+
// src/actrail.ts
|
|
1387
|
+
init_esm_shims();
|
|
1388
|
+
import * as fs3 from "fs";
|
|
1389
|
+
function escape(value) {
|
|
1390
|
+
return value.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/=/g, "\\e");
|
|
1391
|
+
}
|
|
1392
|
+
function sessionToTraceId(sessionId) {
|
|
1393
|
+
let hash = 0;
|
|
1394
|
+
for (let i = 0; i < sessionId.length; i++) {
|
|
1395
|
+
const char = sessionId.charCodeAt(i);
|
|
1396
|
+
hash = (hash << 5) - hash + char | 0;
|
|
1397
|
+
}
|
|
1398
|
+
return Math.abs((hash * 31 + sessionId.length) % Number.MAX_SAFE_INTEGER);
|
|
1399
|
+
}
|
|
1400
|
+
function isEnabled() {
|
|
1401
|
+
return process.env.ACTRAIL_ENABLED === "1" || process.env.ACTRAIL_ENABLED === "true";
|
|
1402
|
+
}
|
|
1403
|
+
function getStoragePath() {
|
|
1404
|
+
return process.env.ACTRAIL_STORAGE_PATH || "/tmp/actrail.sqlite";
|
|
1405
|
+
}
|
|
1406
|
+
function reportEnforcementEvent(opts) {
|
|
1407
|
+
if (!isEnabled()) return false;
|
|
1408
|
+
const storagePath = getStoragePath();
|
|
1409
|
+
if (!fs3.existsSync(storagePath)) return false;
|
|
1410
|
+
try {
|
|
1411
|
+
let Database;
|
|
1412
|
+
try {
|
|
1413
|
+
Database = __require("better-sqlite3");
|
|
1414
|
+
} catch {
|
|
1415
|
+
console.debug("[AgentMoss] better-sqlite3 not installed, AcTrail reporting disabled");
|
|
1416
|
+
return false;
|
|
1417
|
+
}
|
|
1418
|
+
const db = new Database(storagePath, { timeout: 100, readonly: false });
|
|
1419
|
+
const tableCheck = db.prepare(
|
|
1420
|
+
"SELECT name FROM sqlite_master WHERE type='table' AND name='events'"
|
|
1421
|
+
).get();
|
|
1422
|
+
if (!tableCheck) {
|
|
1423
|
+
db.close();
|
|
1424
|
+
return false;
|
|
1425
|
+
}
|
|
1426
|
+
const nowNs = BigInt(Date.now()) * 1000000n;
|
|
1427
|
+
const eventId = Number(nowNs % BigInt(2 ** 62));
|
|
1428
|
+
const traceIdInt = sessionToTraceId(opts.traceId);
|
|
1429
|
+
const rawFields = {
|
|
1430
|
+
"backend": "agent-moss",
|
|
1431
|
+
"operation": "tool_call",
|
|
1432
|
+
"decision": opts.decision,
|
|
1433
|
+
"result": opts.decision === "allow" ? "allowed" : "denied",
|
|
1434
|
+
"tool.name": opts.toolName,
|
|
1435
|
+
"tool.command": (opts.toolCommand || "").slice(0, 500),
|
|
1436
|
+
"agent.session_id": opts.sessionId,
|
|
1437
|
+
"agent.prompt": (opts.prompt || "").slice(0, 500),
|
|
1438
|
+
"risk.level": opts.riskLevel || "",
|
|
1439
|
+
"risk.type": opts.riskType || "",
|
|
1440
|
+
"reason": (opts.reason || "").slice(0, 500),
|
|
1441
|
+
"violated_layers": (opts.violatedLayers || []).join(","),
|
|
1442
|
+
"confidence": String(opts.confidence ?? 100),
|
|
1443
|
+
"duration_ms": (opts.durationMs ?? 0).toFixed(1)
|
|
1444
|
+
};
|
|
1445
|
+
const payloadFields = Object.entries(rawFields).map(([k, v]) => `${escape(k)}=${escape(v)}`).join("\n");
|
|
1446
|
+
db.prepare(`
|
|
1447
|
+
INSERT OR REPLACE INTO events (
|
|
1448
|
+
event_id, trace_id, observed_at,
|
|
1449
|
+
process_pid, process_task_id, process_start_ticks,
|
|
1450
|
+
process_pid_namespace, process_generation,
|
|
1451
|
+
collector, kind,
|
|
1452
|
+
bootstrap_observed, metadata_partial, policy_modified,
|
|
1453
|
+
payload_variant, payload_fields, payload_bytes,
|
|
1454
|
+
policy_verdict, policy_note,
|
|
1455
|
+
policy_redactions, policy_truncations
|
|
1456
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1457
|
+
`).run(
|
|
1458
|
+
eventId,
|
|
1459
|
+
traceIdInt,
|
|
1460
|
+
Number(nowNs),
|
|
1461
|
+
process.pid,
|
|
1462
|
+
0,
|
|
1463
|
+
0,
|
|
1464
|
+
null,
|
|
1465
|
+
0,
|
|
1466
|
+
"agent-moss",
|
|
1467
|
+
"enforcement",
|
|
1468
|
+
0,
|
|
1469
|
+
0,
|
|
1470
|
+
0,
|
|
1471
|
+
"enforcement",
|
|
1472
|
+
payloadFields,
|
|
1473
|
+
"",
|
|
1474
|
+
opts.decision === "allow" ? "allow" : "drop",
|
|
1475
|
+
opts.reason || "",
|
|
1476
|
+
"[]",
|
|
1477
|
+
"[]"
|
|
1478
|
+
);
|
|
1479
|
+
db.close();
|
|
1480
|
+
return true;
|
|
1481
|
+
} catch (err) {
|
|
1482
|
+
console.debug(`[AgentMoss] AcTrail write failed (non-fatal): ${err.message}`);
|
|
1483
|
+
return false;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
// src/routes.ts
|
|
1239
1488
|
async function healthRoute(c) {
|
|
1240
1489
|
return c.json(HealthResponseSchema.parse({}));
|
|
1241
1490
|
}
|
|
@@ -1264,6 +1513,23 @@ async function analyzeRoute(c) {
|
|
|
1264
1513
|
cwd: req.cwd
|
|
1265
1514
|
});
|
|
1266
1515
|
const durationMs = performance.now() - t0;
|
|
1516
|
+
try {
|
|
1517
|
+
reportEnforcementEvent({
|
|
1518
|
+
traceId: req.session_id,
|
|
1519
|
+
decision: result.allowed ? "allow" : "deny",
|
|
1520
|
+
toolName: req.a_next.action_type,
|
|
1521
|
+
toolCommand: req.a_next.action_detail,
|
|
1522
|
+
sessionId: req.session_id,
|
|
1523
|
+
prompt: req.prompt_session,
|
|
1524
|
+
riskLevel: result.riskLevel,
|
|
1525
|
+
riskType: result.riskType,
|
|
1526
|
+
reason: result.reason,
|
|
1527
|
+
violatedLayers: result.violatedLayers,
|
|
1528
|
+
confidence: result.confidence,
|
|
1529
|
+
durationMs: Math.round(durationMs * 10) / 10
|
|
1530
|
+
});
|
|
1531
|
+
} catch {
|
|
1532
|
+
}
|
|
1267
1533
|
return c.json(
|
|
1268
1534
|
AnalyzeResponseSchema.parse({
|
|
1269
1535
|
decision: result.allowed ? "Allow" : "Deny",
|
|
@@ -1323,7 +1589,7 @@ async function main() {
|
|
|
1323
1589
|
switch (command) {
|
|
1324
1590
|
case "init": {
|
|
1325
1591
|
const output = args[2] || "input.json";
|
|
1326
|
-
const
|
|
1592
|
+
const fs4 = await import("fs");
|
|
1327
1593
|
const template = {
|
|
1328
1594
|
session_id: "my-session-001",
|
|
1329
1595
|
prompt_session: "Read /var/log/app.log and analyze errors",
|
|
@@ -1333,7 +1599,7 @@ async function main() {
|
|
|
1333
1599
|
os_type: "",
|
|
1334
1600
|
cwd: "/home/user/project"
|
|
1335
1601
|
};
|
|
1336
|
-
|
|
1602
|
+
fs4.writeFileSync(output, JSON.stringify(template, null, 2), "utf-8");
|
|
1337
1603
|
console.log(`Template written to ${output}`);
|
|
1338
1604
|
break;
|
|
1339
1605
|
}
|
|
@@ -1342,11 +1608,11 @@ async function main() {
|
|
|
1342
1608
|
console.error("Usage: agent-moss analyze <input.json>");
|
|
1343
1609
|
process.exit(1);
|
|
1344
1610
|
}
|
|
1345
|
-
const
|
|
1346
|
-
const
|
|
1611
|
+
const fs4 = await import("fs");
|
|
1612
|
+
const path3 = await import("path");
|
|
1347
1613
|
const { runAnalysis: runAnalysis2 } = await Promise.resolve().then(() => (init_coordinator(), coordinator_exports));
|
|
1348
|
-
const filePath =
|
|
1349
|
-
const data = JSON.parse(
|
|
1614
|
+
const filePath = path3.resolve(args[1]);
|
|
1615
|
+
const data = JSON.parse(fs4.readFileSync(filePath, "utf-8"));
|
|
1350
1616
|
const result = await runAnalysis2({
|
|
1351
1617
|
sessionId: data.session_id || "unknown",
|
|
1352
1618
|
promptSession: data.prompt_session || "",
|