@kenhkl/agent-moss 0.17.5 → 0.17.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +65 -25
- package/dist/engine/coordinator.js +28 -11
- package/dist/server.js +65 -25
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1340,6 +1340,12 @@ function agentInflight() {
|
|
|
1340
1340
|
function boundAgentOf(principal) {
|
|
1341
1341
|
return principal.startsWith("agent:") ? principal.slice("agent:".length) : "";
|
|
1342
1342
|
}
|
|
1343
|
+
function chainScope() {
|
|
1344
|
+
return (env("AGENT_MOSS_CHAIN_SCOPE", "system") || "system").toLowerCase();
|
|
1345
|
+
}
|
|
1346
|
+
function chainBucket(agentId = "") {
|
|
1347
|
+
return chainScope() === "agent" ? agentId || "default" : "__system__";
|
|
1348
|
+
}
|
|
1343
1349
|
function rateLimitQps() {
|
|
1344
1350
|
return envInt("AGENT_MOSS_RATE_LIMIT_QPS", 100);
|
|
1345
1351
|
}
|
|
@@ -1411,6 +1417,8 @@ var init_models = __esm({
|
|
|
1411
1417
|
action_history: z.array(ActionItemSchema).default([]).describe("Historical action sequence"),
|
|
1412
1418
|
session_history: z.array(z.object({
|
|
1413
1419
|
session_id: z.string(),
|
|
1420
|
+
/** 来源 agent(AgentGate 逐会话带上):记录在链路径里供告警/取证,不参与链匹配。 */
|
|
1421
|
+
agent_id: z.string().optional(),
|
|
1414
1422
|
action_history: z.array(ActionItemSchema).default([])
|
|
1415
1423
|
})).default([]).describe("Multi-session historical actions (optional): for L2.2 formal engine cross-session combo-chain / sensitive-data-flow verification. Provided by caller (incl. future agentgate)."),
|
|
1416
1424
|
a_next: ActionItemSchema.describe("Next action to be executed"),
|
|
@@ -2095,12 +2103,19 @@ function hasUserConsent(actionHistory) {
|
|
|
2095
2103
|
return t === "ask_user_question" && String(h.output || "").trim().length > 0;
|
|
2096
2104
|
});
|
|
2097
2105
|
}
|
|
2106
|
+
function hasWeakConsent(actionHistory) {
|
|
2107
|
+
return actionHistory.some((h) => {
|
|
2108
|
+
if (String(h.actionType || "").toLowerCase() !== "ask_user_question") return false;
|
|
2109
|
+
return CONSENT_TOPIC.test(String(h.actionDetail || ""));
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2098
2112
|
function checkPasswordConsent(actionType, actionDetail, actionHistory, osType) {
|
|
2099
2113
|
if (actionType !== "bash") return null;
|
|
2100
2114
|
const pwdPatterns = runtimeConfigBridge.current?.effectivePasswordPatterns(osType) ?? PASSWORD_MODIFY_PATTERNS;
|
|
2101
2115
|
const isPasswordModify = pwdPatterns.some((p) => p.test(actionDetail));
|
|
2102
2116
|
if (!isPasswordModify) return null;
|
|
2103
2117
|
if (hasUserConsent(actionHistory)) return null;
|
|
2118
|
+
if (hasWeakConsent(actionHistory)) return null;
|
|
2104
2119
|
return {
|
|
2105
2120
|
allowed: false,
|
|
2106
2121
|
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",
|
|
@@ -2117,6 +2132,7 @@ function checkUserDeletionConsent(actionType, actionDetail, actionHistory, osTyp
|
|
|
2117
2132
|
const isUserDeletion = udPatterns.some((p) => p.test(actionDetail));
|
|
2118
2133
|
if (!isUserDeletion) return null;
|
|
2119
2134
|
if (hasUserConsent(actionHistory)) return null;
|
|
2135
|
+
if (hasWeakConsent(actionHistory)) return null;
|
|
2120
2136
|
return {
|
|
2121
2137
|
allowed: false,
|
|
2122
2138
|
reason: "\u6267\u884C\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u547D\u4EE4\uFF0C\u4F46\u5386\u53F2\u6267\u884C\u5E8F\u5217\u4E2D\u672A\u53D1\u73B0\u5411\u7528\u6237\u786E\u8BA4\u7684 ask_user_question \u64CD\u4F5C\uFF0C\u53EF\u80FD\u5B58\u5728\u672A\u6388\u6743\u7684\u7528\u6237\u5220\u9664\u98CE\u9669",
|
|
@@ -2218,7 +2234,7 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd, osType) {
|
|
|
2218
2234
|
violatedLayers: ["L2.1"]
|
|
2219
2235
|
};
|
|
2220
2236
|
}
|
|
2221
|
-
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, PSEUDO_FS_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;
|
|
2237
|
+
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, PSEUDO_FS_PREFIXES, WRITE_KEYWORDS, SED_INPLACE_RE, DEVNULL_REDIRECT_RE, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, COMBO_STAGES, COMBO_CHAINS, CONSENT_TOPIC, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW, _IFA, IFA_READ_KEYWORDS, IFA_WRITE_KEYWORDS, IFA_EXEC_KEYWORDS, IFA_OPEN_KEYWORDS;
|
|
2222
2238
|
var init_logic_rules = __esm({
|
|
2223
2239
|
"src/engine/logic-rules.ts"() {
|
|
2224
2240
|
"use strict";
|
|
@@ -2305,6 +2321,7 @@ var init_logic_rules = __esm({
|
|
|
2305
2321
|
reason: String(c.reason || "\u68C0\u6D4B\u5230\u7EC4\u5408\u653B\u51FB\u94FE")
|
|
2306
2322
|
}));
|
|
2307
2323
|
})();
|
|
2324
|
+
CONSENT_TOPIC = /密码|口令|passwd|password|凭据|凭证|用户|账户|账号|userdel|deluser|groupdel/i;
|
|
2308
2325
|
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;
|
|
2309
2326
|
DIR_TRAVERSAL_KW = loadInline().dir_traversal_keywords ?? [];
|
|
2310
2327
|
_IFA = loadLogicRules().indirect_file_access ?? {};
|
|
@@ -2990,7 +3007,7 @@ function _scenarioRulesToDefaults() {
|
|
|
2990
3007
|
if (!existsSync7(scenDir)) return out;
|
|
2991
3008
|
let entries;
|
|
2992
3009
|
try {
|
|
2993
|
-
entries = readdirSync4(scenDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
3010
|
+
entries = readdirSync4(scenDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("__")).map((d) => d.name);
|
|
2994
3011
|
} catch {
|
|
2995
3012
|
return out;
|
|
2996
3013
|
}
|
|
@@ -9370,7 +9387,7 @@ function markIntegrity(actionDetail) {
|
|
|
9370
9387
|
}
|
|
9371
9388
|
return { integrity: "medium", isLowSource: false };
|
|
9372
9389
|
}
|
|
9373
|
-
function initNode(sessionId, seq, actionType, actionDetail, timestamp) {
|
|
9390
|
+
function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId = "") {
|
|
9374
9391
|
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
9375
9392
|
return {
|
|
9376
9393
|
sessionId,
|
|
@@ -9378,13 +9395,14 @@ function initNode(sessionId, seq, actionType, actionDetail, timestamp) {
|
|
|
9378
9395
|
actionType,
|
|
9379
9396
|
actionDetail,
|
|
9380
9397
|
stage: markStage(actionDetail),
|
|
9398
|
+
agentId: agentId || void 0,
|
|
9381
9399
|
resources: extractResources(actionDetail),
|
|
9382
9400
|
integrity,
|
|
9383
9401
|
isLowSource,
|
|
9384
9402
|
timestamp: timestamp || void 0
|
|
9385
9403
|
};
|
|
9386
9404
|
}
|
|
9387
|
-
function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
9405
|
+
function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId = "") {
|
|
9388
9406
|
const nodes = [];
|
|
9389
9407
|
const edges = [];
|
|
9390
9408
|
const stageFlags = /* @__PURE__ */ new Set();
|
|
@@ -9394,18 +9412,20 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
|
9394
9412
|
if (ad) details.push({
|
|
9395
9413
|
actionType: String(a.actionType || ""),
|
|
9396
9414
|
actionDetail: ad,
|
|
9397
|
-
calledAt: a.calledAt || void 0
|
|
9415
|
+
calledAt: a.calledAt || void 0,
|
|
9416
|
+
agentId: a.agentId || agentId || void 0
|
|
9398
9417
|
});
|
|
9399
9418
|
}
|
|
9400
9419
|
if (aNext) {
|
|
9401
9420
|
details.push({
|
|
9402
9421
|
actionType: String(aNext.actionType || ""),
|
|
9403
9422
|
actionDetail: String(aNext.actionDetail || ""),
|
|
9404
|
-
calledAt: aNext.calledAt || void 0
|
|
9423
|
+
calledAt: aNext.calledAt || void 0,
|
|
9424
|
+
agentId: aNext.agentId || agentId || void 0
|
|
9405
9425
|
});
|
|
9406
9426
|
}
|
|
9407
9427
|
details.forEach((d, seq) => {
|
|
9408
|
-
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt);
|
|
9428
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt, d.agentId || "");
|
|
9409
9429
|
nodes.push(node);
|
|
9410
9430
|
if (node.stage) stageFlags.add(node.stage);
|
|
9411
9431
|
});
|
|
@@ -9422,7 +9442,7 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
9422
9442
|
}
|
|
9423
9443
|
for (const s of sessions) {
|
|
9424
9444
|
const sid = String(s.sessionId || "s");
|
|
9425
|
-
mg.sessions.push(buildSessionGraph(s.actionHistory || [], void 0, sid));
|
|
9445
|
+
mg.sessions.push(buildSessionGraph(s.actionHistory || [], void 0, sid, s.agentId || ""));
|
|
9426
9446
|
}
|
|
9427
9447
|
if (aNext) {
|
|
9428
9448
|
const last = mg.sessions[mg.sessions.length - 1];
|
|
@@ -9432,7 +9452,8 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
9432
9452
|
last.nodes.length,
|
|
9433
9453
|
String(aNext.actionType || ""),
|
|
9434
9454
|
String(aNext.actionDetail || ""),
|
|
9435
|
-
aNext.calledAt || void 0
|
|
9455
|
+
aNext.calledAt || void 0,
|
|
9456
|
+
aNext.agentId || ""
|
|
9436
9457
|
));
|
|
9437
9458
|
if (last.nodes.length > 1) {
|
|
9438
9459
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
@@ -10219,8 +10240,8 @@ var init_stateful = __esm({
|
|
|
10219
10240
|
}
|
|
10220
10241
|
/** 增量推进:把当前动作追加到时间线 → 链指针推进 → 判定。 */
|
|
10221
10242
|
advance(args) {
|
|
10222
|
-
const { aNext, sessionId = "current", isError = false } = args;
|
|
10223
|
-
const node = this.appendNode(aNext, sessionId, isError);
|
|
10243
|
+
const { aNext, sessionId = "current", isError = false, agentId = "" } = args;
|
|
10244
|
+
const node = this.appendNode(aNext, sessionId, isError, agentId);
|
|
10224
10245
|
if (!node) {
|
|
10225
10246
|
return { seq: this.seqNext, node: null, matched: null, pendingPrefixes: this.pendingPrefixes, exfil: [], shouldBlock: false };
|
|
10226
10247
|
}
|
|
@@ -10240,7 +10261,7 @@ var init_stateful = __esm({
|
|
|
10240
10261
|
}
|
|
10241
10262
|
};
|
|
10242
10263
|
}
|
|
10243
|
-
appendNode(action, sessionId, isError = false) {
|
|
10264
|
+
appendNode(action, sessionId, isError = false, agentId = "") {
|
|
10244
10265
|
const ad = String(action.actionDetail || "");
|
|
10245
10266
|
const at = String(action.actionType || "");
|
|
10246
10267
|
if (!ad) return null;
|
|
@@ -10257,6 +10278,7 @@ var init_stateful = __esm({
|
|
|
10257
10278
|
resources: extractResources2(ad),
|
|
10258
10279
|
instances: extractInstances(ad, stage),
|
|
10259
10280
|
isError,
|
|
10281
|
+
agentId: String(action.agentId || agentId || ""),
|
|
10260
10282
|
lifecycle: lifecycleFor(ad, stage, isError),
|
|
10261
10283
|
timestamp: typeof action.calledAt === "string" ? action.calledAt : _StatefulChainTracker.now()
|
|
10262
10284
|
};
|
|
@@ -10394,7 +10416,13 @@ var init_stateful = __esm({
|
|
|
10394
10416
|
let want = stages[0];
|
|
10395
10417
|
for (const n of this.nodes_) {
|
|
10396
10418
|
if (n.stage === want) {
|
|
10397
|
-
path6.push({
|
|
10419
|
+
path6.push({
|
|
10420
|
+
sessionId: n.sessionId,
|
|
10421
|
+
seq: n.seq,
|
|
10422
|
+
stage: n.stage,
|
|
10423
|
+
timestamp: n.timestamp,
|
|
10424
|
+
agentId: n.agentId
|
|
10425
|
+
});
|
|
10398
10426
|
const idx = stages.indexOf(n.stage);
|
|
10399
10427
|
if (idx + 1 < stages.length) {
|
|
10400
10428
|
want = stages[idx + 1];
|
|
@@ -10419,7 +10447,7 @@ var init_stateful = __esm({
|
|
|
10419
10447
|
}
|
|
10420
10448
|
if (taintedRes.size > 0) {
|
|
10421
10449
|
this.tainted.add(idx);
|
|
10422
|
-
for (const r of
|
|
10450
|
+
for (const r of node.resources) this.taintedResources.add(r);
|
|
10423
10451
|
}
|
|
10424
10452
|
}
|
|
10425
10453
|
resourceTainted(resource) {
|
|
@@ -10468,6 +10496,7 @@ var init_stateful = __esm({
|
|
|
10468
10496
|
this.nodes_.push({
|
|
10469
10497
|
seq: Number(raw.seq || 0),
|
|
10470
10498
|
sessionId: String(raw.sessionId || ""),
|
|
10499
|
+
agentId: String(raw.agentId || ""),
|
|
10471
10500
|
actionType: String(raw.actionType || ""),
|
|
10472
10501
|
actionDetail: String(raw.actionDetail || ""),
|
|
10473
10502
|
stage: String(raw.stage || ""),
|
|
@@ -10574,9 +10603,9 @@ var init_chain_state = __esm({
|
|
|
10574
10603
|
delete this.data[agentId];
|
|
10575
10604
|
this._scheduleWrite();
|
|
10576
10605
|
}
|
|
10577
|
-
applyAction(agentId, aNext, sessionId, isError = false) {
|
|
10606
|
+
applyAction(agentId, aNext, sessionId, isError = false, sourceAgent = "") {
|
|
10578
10607
|
const t = this.load(agentId) || new StatefulChainTracker(agentId);
|
|
10579
|
-
const r = t.advance({ aNext, sessionId, isError });
|
|
10608
|
+
const r = t.advance({ aNext, sessionId, isError, agentId: sourceAgent });
|
|
10580
10609
|
this.save(t);
|
|
10581
10610
|
return r;
|
|
10582
10611
|
}
|
|
@@ -10891,10 +10920,14 @@ async function runAnalysis(input) {
|
|
|
10891
10920
|
const formalSessions = [];
|
|
10892
10921
|
if (input.sessionHistory) {
|
|
10893
10922
|
for (const s of input.sessionHistory) {
|
|
10894
|
-
formalSessions.push({
|
|
10923
|
+
formalSessions.push({
|
|
10924
|
+
sessionId: s.sessionId || "s",
|
|
10925
|
+
...s.agentId ? { agentId: s.agentId } : {},
|
|
10926
|
+
actionHistory: s.actionHistory || []
|
|
10927
|
+
});
|
|
10895
10928
|
}
|
|
10896
10929
|
}
|
|
10897
|
-
formalSessions.push({ sessionId: "current", actionHistory: input.actionHistory });
|
|
10930
|
+
formalSessions.push({ sessionId: "current", agentId: input.agentId, actionHistory: input.actionHistory });
|
|
10898
10931
|
const formalResult = formalEngine.verify(formalSessions, input.aNext);
|
|
10899
10932
|
if (!formalResult.verified) {
|
|
10900
10933
|
const v = formalResult.violations[0];
|
|
@@ -11990,6 +12023,8 @@ async function analyzeRoute(c) {
|
|
|
11990
12023
|
})),
|
|
11991
12024
|
sessionHistory: (req.session_history || []).map((s) => ({
|
|
11992
12025
|
sessionId: s.session_id,
|
|
12026
|
+
// 来源 agent(AgentGate 逐会话带上,用于链路径取证展示;不参与链匹配)
|
|
12027
|
+
...s.agent_id ? { agentId: s.agent_id } : {},
|
|
11993
12028
|
actionHistory: (s.action_history || []).map((h) => ({
|
|
11994
12029
|
actionType: h.action_type,
|
|
11995
12030
|
actionDetail: h.action_detail,
|
|
@@ -12048,10 +12083,14 @@ async function analyzeRoute(c) {
|
|
|
12048
12083
|
if (incEnabled === "1" || incEnabled === "true" || incEnabled === "yes" || incEnabled === "on") {
|
|
12049
12084
|
try {
|
|
12050
12085
|
const store = getChainStateStoreFor(agentId);
|
|
12051
|
-
const inc = store.applyAction(
|
|
12052
|
-
|
|
12053
|
-
actionDetail: req.a_next.action_detail
|
|
12054
|
-
|
|
12086
|
+
const inc = store.applyAction(
|
|
12087
|
+
chainBucket(agentId),
|
|
12088
|
+
{ actionType: req.a_next.action_type, actionDetail: req.a_next.action_detail },
|
|
12089
|
+
req.session_id,
|
|
12090
|
+
Boolean(meta.is_error),
|
|
12091
|
+
agentId
|
|
12092
|
+
// 来源:真实 agent(桶 key 可能是 __system__)
|
|
12093
|
+
);
|
|
12055
12094
|
const judgment = incMatchedToDeny(inc);
|
|
12056
12095
|
if (judgment) {
|
|
12057
12096
|
const layers = [...result.violated_layers];
|
|
@@ -12116,7 +12155,7 @@ function getChainStateStoreFor(_agentId) {
|
|
|
12116
12155
|
}
|
|
12117
12156
|
function incMatchedToDeny(inc) {
|
|
12118
12157
|
if (inc.matched) {
|
|
12119
|
-
const chain = (inc.matched.path || []).map((p) => [p.sessionId, p.seq, p.stage, p.timestamp]);
|
|
12158
|
+
const chain = (inc.matched.path || []).map((p) => [p.sessionId, p.seq, p.stage, p.timestamp, p.agentId ?? null]);
|
|
12120
12159
|
return {
|
|
12121
12160
|
property_id: "cross-" + inc.matched.chainId,
|
|
12122
12161
|
reason: inc.matched.reason,
|
|
@@ -12141,9 +12180,10 @@ async function reviewRoute(c) {
|
|
|
12141
12180
|
const req = ReviewRequestSchema.parse(body);
|
|
12142
12181
|
const agentId = req.agent_id || "default";
|
|
12143
12182
|
const store = getChainStateStoreFor(agentId);
|
|
12144
|
-
|
|
12183
|
+
const bucket = chainBucket(agentId);
|
|
12184
|
+
let tracker = store.load(bucket);
|
|
12145
12185
|
if (!tracker) {
|
|
12146
|
-
tracker = new StatefulChainTracker(
|
|
12186
|
+
tracker = new StatefulChainTracker(bucket);
|
|
12147
12187
|
}
|
|
12148
12188
|
if (req.db_path && !pathWithin(req.db_path, reviewRoots())) {
|
|
12149
12189
|
return c.json({
|
|
@@ -1345,12 +1345,19 @@ function hasUserConsent(actionHistory) {
|
|
|
1345
1345
|
return t === "ask_user_question" && String(h.output || "").trim().length > 0;
|
|
1346
1346
|
});
|
|
1347
1347
|
}
|
|
1348
|
+
function hasWeakConsent(actionHistory) {
|
|
1349
|
+
return actionHistory.some((h) => {
|
|
1350
|
+
if (String(h.actionType || "").toLowerCase() !== "ask_user_question") return false;
|
|
1351
|
+
return CONSENT_TOPIC.test(String(h.actionDetail || ""));
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1348
1354
|
function checkPasswordConsent(actionType, actionDetail, actionHistory, osType) {
|
|
1349
1355
|
if (actionType !== "bash") return null;
|
|
1350
1356
|
const pwdPatterns = runtimeConfigBridge.current?.effectivePasswordPatterns(osType) ?? PASSWORD_MODIFY_PATTERNS;
|
|
1351
1357
|
const isPasswordModify = pwdPatterns.some((p) => p.test(actionDetail));
|
|
1352
1358
|
if (!isPasswordModify) return null;
|
|
1353
1359
|
if (hasUserConsent(actionHistory)) return null;
|
|
1360
|
+
if (hasWeakConsent(actionHistory)) return null;
|
|
1354
1361
|
return {
|
|
1355
1362
|
allowed: false,
|
|
1356
1363
|
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",
|
|
@@ -1367,6 +1374,7 @@ function checkUserDeletionConsent(actionType, actionDetail, actionHistory, osTyp
|
|
|
1367
1374
|
const isUserDeletion = udPatterns.some((p) => p.test(actionDetail));
|
|
1368
1375
|
if (!isUserDeletion) return null;
|
|
1369
1376
|
if (hasUserConsent(actionHistory)) return null;
|
|
1377
|
+
if (hasWeakConsent(actionHistory)) return null;
|
|
1370
1378
|
return {
|
|
1371
1379
|
allowed: false,
|
|
1372
1380
|
reason: "\u6267\u884C\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u547D\u4EE4\uFF0C\u4F46\u5386\u53F2\u6267\u884C\u5E8F\u5217\u4E2D\u672A\u53D1\u73B0\u5411\u7528\u6237\u786E\u8BA4\u7684 ask_user_question \u64CD\u4F5C\uFF0C\u53EF\u80FD\u5B58\u5728\u672A\u6388\u6743\u7684\u7528\u6237\u5220\u9664\u98CE\u9669",
|
|
@@ -1468,7 +1476,7 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd, osType) {
|
|
|
1468
1476
|
violatedLayers: ["L2.1"]
|
|
1469
1477
|
};
|
|
1470
1478
|
}
|
|
1471
|
-
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, PSEUDO_FS_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;
|
|
1479
|
+
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, PSEUDO_FS_PREFIXES, WRITE_KEYWORDS, SED_INPLACE_RE, DEVNULL_REDIRECT_RE, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, COMBO_STAGES, COMBO_CHAINS, CONSENT_TOPIC, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW, _IFA, IFA_READ_KEYWORDS, IFA_WRITE_KEYWORDS, IFA_EXEC_KEYWORDS, IFA_OPEN_KEYWORDS;
|
|
1472
1480
|
var init_logic_rules = __esm({
|
|
1473
1481
|
"src/engine/logic-rules.ts"() {
|
|
1474
1482
|
"use strict";
|
|
@@ -1555,6 +1563,7 @@ var init_logic_rules = __esm({
|
|
|
1555
1563
|
reason: String(c.reason || "\u68C0\u6D4B\u5230\u7EC4\u5408\u653B\u51FB\u94FE")
|
|
1556
1564
|
}));
|
|
1557
1565
|
})();
|
|
1566
|
+
CONSENT_TOPIC = /密码|口令|passwd|password|凭据|凭证|用户|账户|账号|userdel|deluser|groupdel/i;
|
|
1558
1567
|
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;
|
|
1559
1568
|
DIR_TRAVERSAL_KW = loadInline().dir_traversal_keywords ?? [];
|
|
1560
1569
|
_IFA = loadLogicRules().indirect_file_access ?? {};
|
|
@@ -2240,7 +2249,7 @@ function _scenarioRulesToDefaults() {
|
|
|
2240
2249
|
if (!existsSync5(scenDir)) return out;
|
|
2241
2250
|
let entries;
|
|
2242
2251
|
try {
|
|
2243
|
-
entries = readdirSync4(scenDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
2252
|
+
entries = readdirSync4(scenDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("__")).map((d) => d.name);
|
|
2244
2253
|
} catch {
|
|
2245
2254
|
return out;
|
|
2246
2255
|
}
|
|
@@ -8360,7 +8369,7 @@ function markIntegrity(actionDetail) {
|
|
|
8360
8369
|
}
|
|
8361
8370
|
return { integrity: "medium", isLowSource: false };
|
|
8362
8371
|
}
|
|
8363
|
-
function initNode(sessionId, seq, actionType, actionDetail, timestamp) {
|
|
8372
|
+
function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId = "") {
|
|
8364
8373
|
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
8365
8374
|
return {
|
|
8366
8375
|
sessionId,
|
|
@@ -8368,13 +8377,14 @@ function initNode(sessionId, seq, actionType, actionDetail, timestamp) {
|
|
|
8368
8377
|
actionType,
|
|
8369
8378
|
actionDetail,
|
|
8370
8379
|
stage: markStage(actionDetail),
|
|
8380
|
+
agentId: agentId || void 0,
|
|
8371
8381
|
resources: extractResources(actionDetail),
|
|
8372
8382
|
integrity,
|
|
8373
8383
|
isLowSource,
|
|
8374
8384
|
timestamp: timestamp || void 0
|
|
8375
8385
|
};
|
|
8376
8386
|
}
|
|
8377
|
-
function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
8387
|
+
function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId = "") {
|
|
8378
8388
|
const nodes = [];
|
|
8379
8389
|
const edges = [];
|
|
8380
8390
|
const stageFlags = /* @__PURE__ */ new Set();
|
|
@@ -8384,18 +8394,20 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
|
8384
8394
|
if (ad) details.push({
|
|
8385
8395
|
actionType: String(a.actionType || ""),
|
|
8386
8396
|
actionDetail: ad,
|
|
8387
|
-
calledAt: a.calledAt || void 0
|
|
8397
|
+
calledAt: a.calledAt || void 0,
|
|
8398
|
+
agentId: a.agentId || agentId || void 0
|
|
8388
8399
|
});
|
|
8389
8400
|
}
|
|
8390
8401
|
if (aNext) {
|
|
8391
8402
|
details.push({
|
|
8392
8403
|
actionType: String(aNext.actionType || ""),
|
|
8393
8404
|
actionDetail: String(aNext.actionDetail || ""),
|
|
8394
|
-
calledAt: aNext.calledAt || void 0
|
|
8405
|
+
calledAt: aNext.calledAt || void 0,
|
|
8406
|
+
agentId: aNext.agentId || agentId || void 0
|
|
8395
8407
|
});
|
|
8396
8408
|
}
|
|
8397
8409
|
details.forEach((d, seq) => {
|
|
8398
|
-
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt);
|
|
8410
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt, d.agentId || "");
|
|
8399
8411
|
nodes.push(node);
|
|
8400
8412
|
if (node.stage) stageFlags.add(node.stage);
|
|
8401
8413
|
});
|
|
@@ -8412,7 +8424,7 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
8412
8424
|
}
|
|
8413
8425
|
for (const s of sessions) {
|
|
8414
8426
|
const sid = String(s.sessionId || "s");
|
|
8415
|
-
mg.sessions.push(buildSessionGraph(s.actionHistory || [], void 0, sid));
|
|
8427
|
+
mg.sessions.push(buildSessionGraph(s.actionHistory || [], void 0, sid, s.agentId || ""));
|
|
8416
8428
|
}
|
|
8417
8429
|
if (aNext) {
|
|
8418
8430
|
const last = mg.sessions[mg.sessions.length - 1];
|
|
@@ -8422,7 +8434,8 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
8422
8434
|
last.nodes.length,
|
|
8423
8435
|
String(aNext.actionType || ""),
|
|
8424
8436
|
String(aNext.actionDetail || ""),
|
|
8425
|
-
aNext.calledAt || void 0
|
|
8437
|
+
aNext.calledAt || void 0,
|
|
8438
|
+
aNext.agentId || ""
|
|
8426
8439
|
));
|
|
8427
8440
|
if (last.nodes.length > 1) {
|
|
8428
8441
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
@@ -9316,10 +9329,14 @@ async function runAnalysis(input) {
|
|
|
9316
9329
|
const formalSessions = [];
|
|
9317
9330
|
if (input.sessionHistory) {
|
|
9318
9331
|
for (const s of input.sessionHistory) {
|
|
9319
|
-
formalSessions.push({
|
|
9332
|
+
formalSessions.push({
|
|
9333
|
+
sessionId: s.sessionId || "s",
|
|
9334
|
+
...s.agentId ? { agentId: s.agentId } : {},
|
|
9335
|
+
actionHistory: s.actionHistory || []
|
|
9336
|
+
});
|
|
9320
9337
|
}
|
|
9321
9338
|
}
|
|
9322
|
-
formalSessions.push({ sessionId: "current", actionHistory: input.actionHistory });
|
|
9339
|
+
formalSessions.push({ sessionId: "current", agentId: input.agentId, actionHistory: input.actionHistory });
|
|
9323
9340
|
const formalResult = formalEngine.verify(formalSessions, input.aNext);
|
|
9324
9341
|
if (!formalResult.verified) {
|
|
9325
9342
|
const v = formalResult.violations[0];
|
package/dist/server.js
CHANGED
|
@@ -1186,6 +1186,12 @@ function agentInflight() {
|
|
|
1186
1186
|
function boundAgentOf(principal) {
|
|
1187
1187
|
return principal.startsWith("agent:") ? principal.slice("agent:".length) : "";
|
|
1188
1188
|
}
|
|
1189
|
+
function chainScope() {
|
|
1190
|
+
return (env("AGENT_MOSS_CHAIN_SCOPE", "system") || "system").toLowerCase();
|
|
1191
|
+
}
|
|
1192
|
+
function chainBucket(agentId = "") {
|
|
1193
|
+
return chainScope() === "agent" ? agentId || "default" : "__system__";
|
|
1194
|
+
}
|
|
1189
1195
|
function rateLimitQps() {
|
|
1190
1196
|
return envInt("AGENT_MOSS_RATE_LIMIT_QPS", 100);
|
|
1191
1197
|
}
|
|
@@ -1845,12 +1851,19 @@ function hasUserConsent(actionHistory) {
|
|
|
1845
1851
|
return t === "ask_user_question" && String(h.output || "").trim().length > 0;
|
|
1846
1852
|
});
|
|
1847
1853
|
}
|
|
1854
|
+
function hasWeakConsent(actionHistory) {
|
|
1855
|
+
return actionHistory.some((h) => {
|
|
1856
|
+
if (String(h.actionType || "").toLowerCase() !== "ask_user_question") return false;
|
|
1857
|
+
return CONSENT_TOPIC.test(String(h.actionDetail || ""));
|
|
1858
|
+
});
|
|
1859
|
+
}
|
|
1848
1860
|
function checkPasswordConsent(actionType, actionDetail, actionHistory, osType) {
|
|
1849
1861
|
if (actionType !== "bash") return null;
|
|
1850
1862
|
const pwdPatterns = runtimeConfigBridge.current?.effectivePasswordPatterns(osType) ?? PASSWORD_MODIFY_PATTERNS;
|
|
1851
1863
|
const isPasswordModify = pwdPatterns.some((p) => p.test(actionDetail));
|
|
1852
1864
|
if (!isPasswordModify) return null;
|
|
1853
1865
|
if (hasUserConsent(actionHistory)) return null;
|
|
1866
|
+
if (hasWeakConsent(actionHistory)) return null;
|
|
1854
1867
|
return {
|
|
1855
1868
|
allowed: false,
|
|
1856
1869
|
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",
|
|
@@ -1867,6 +1880,7 @@ function checkUserDeletionConsent(actionType, actionDetail, actionHistory, osTyp
|
|
|
1867
1880
|
const isUserDeletion = udPatterns.some((p) => p.test(actionDetail));
|
|
1868
1881
|
if (!isUserDeletion) return null;
|
|
1869
1882
|
if (hasUserConsent(actionHistory)) return null;
|
|
1883
|
+
if (hasWeakConsent(actionHistory)) return null;
|
|
1870
1884
|
return {
|
|
1871
1885
|
allowed: false,
|
|
1872
1886
|
reason: "\u6267\u884C\u5220\u9664\u7CFB\u7EDF\u7528\u6237\u547D\u4EE4\uFF0C\u4F46\u5386\u53F2\u6267\u884C\u5E8F\u5217\u4E2D\u672A\u53D1\u73B0\u5411\u7528\u6237\u786E\u8BA4\u7684 ask_user_question \u64CD\u4F5C\uFF0C\u53EF\u80FD\u5B58\u5728\u672A\u6388\u6743\u7684\u7528\u6237\u5220\u9664\u98CE\u9669",
|
|
@@ -1968,7 +1982,7 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd, osType) {
|
|
|
1968
1982
|
violatedLayers: ["L2.1"]
|
|
1969
1983
|
};
|
|
1970
1984
|
}
|
|
1971
|
-
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, PSEUDO_FS_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;
|
|
1985
|
+
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, PSEUDO_FS_PREFIXES, WRITE_KEYWORDS, SED_INPLACE_RE, DEVNULL_REDIRECT_RE, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, COMBO_STAGES, COMBO_CHAINS, CONSENT_TOPIC, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW, _IFA, IFA_READ_KEYWORDS, IFA_WRITE_KEYWORDS, IFA_EXEC_KEYWORDS, IFA_OPEN_KEYWORDS;
|
|
1972
1986
|
var init_logic_rules = __esm({
|
|
1973
1987
|
"src/engine/logic-rules.ts"() {
|
|
1974
1988
|
"use strict";
|
|
@@ -2055,6 +2069,7 @@ var init_logic_rules = __esm({
|
|
|
2055
2069
|
reason: String(c.reason || "\u68C0\u6D4B\u5230\u7EC4\u5408\u653B\u51FB\u94FE")
|
|
2056
2070
|
}));
|
|
2057
2071
|
})();
|
|
2072
|
+
CONSENT_TOPIC = /密码|口令|passwd|password|凭据|凭证|用户|账户|账号|userdel|deluser|groupdel/i;
|
|
2058
2073
|
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;
|
|
2059
2074
|
DIR_TRAVERSAL_KW = loadInline().dir_traversal_keywords ?? [];
|
|
2060
2075
|
_IFA = loadLogicRules().indirect_file_access ?? {};
|
|
@@ -2740,7 +2755,7 @@ function _scenarioRulesToDefaults() {
|
|
|
2740
2755
|
if (!existsSync7(scenDir)) return out;
|
|
2741
2756
|
let entries;
|
|
2742
2757
|
try {
|
|
2743
|
-
entries = readdirSync4(scenDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
2758
|
+
entries = readdirSync4(scenDir, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith("__")).map((d) => d.name);
|
|
2744
2759
|
} catch {
|
|
2745
2760
|
return out;
|
|
2746
2761
|
}
|
|
@@ -8855,7 +8870,7 @@ function markIntegrity(actionDetail) {
|
|
|
8855
8870
|
}
|
|
8856
8871
|
return { integrity: "medium", isLowSource: false };
|
|
8857
8872
|
}
|
|
8858
|
-
function initNode(sessionId, seq, actionType, actionDetail, timestamp) {
|
|
8873
|
+
function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId = "") {
|
|
8859
8874
|
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
8860
8875
|
return {
|
|
8861
8876
|
sessionId,
|
|
@@ -8863,13 +8878,14 @@ function initNode(sessionId, seq, actionType, actionDetail, timestamp) {
|
|
|
8863
8878
|
actionType,
|
|
8864
8879
|
actionDetail,
|
|
8865
8880
|
stage: markStage(actionDetail),
|
|
8881
|
+
agentId: agentId || void 0,
|
|
8866
8882
|
resources: extractResources(actionDetail),
|
|
8867
8883
|
integrity,
|
|
8868
8884
|
isLowSource,
|
|
8869
8885
|
timestamp: timestamp || void 0
|
|
8870
8886
|
};
|
|
8871
8887
|
}
|
|
8872
|
-
function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
8888
|
+
function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId = "") {
|
|
8873
8889
|
const nodes = [];
|
|
8874
8890
|
const edges = [];
|
|
8875
8891
|
const stageFlags = /* @__PURE__ */ new Set();
|
|
@@ -8879,18 +8895,20 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
|
8879
8895
|
if (ad) details.push({
|
|
8880
8896
|
actionType: String(a.actionType || ""),
|
|
8881
8897
|
actionDetail: ad,
|
|
8882
|
-
calledAt: a.calledAt || void 0
|
|
8898
|
+
calledAt: a.calledAt || void 0,
|
|
8899
|
+
agentId: a.agentId || agentId || void 0
|
|
8883
8900
|
});
|
|
8884
8901
|
}
|
|
8885
8902
|
if (aNext) {
|
|
8886
8903
|
details.push({
|
|
8887
8904
|
actionType: String(aNext.actionType || ""),
|
|
8888
8905
|
actionDetail: String(aNext.actionDetail || ""),
|
|
8889
|
-
calledAt: aNext.calledAt || void 0
|
|
8906
|
+
calledAt: aNext.calledAt || void 0,
|
|
8907
|
+
agentId: aNext.agentId || agentId || void 0
|
|
8890
8908
|
});
|
|
8891
8909
|
}
|
|
8892
8910
|
details.forEach((d, seq) => {
|
|
8893
|
-
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt);
|
|
8911
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt, d.agentId || "");
|
|
8894
8912
|
nodes.push(node);
|
|
8895
8913
|
if (node.stage) stageFlags.add(node.stage);
|
|
8896
8914
|
});
|
|
@@ -8907,7 +8925,7 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
8907
8925
|
}
|
|
8908
8926
|
for (const s of sessions) {
|
|
8909
8927
|
const sid = String(s.sessionId || "s");
|
|
8910
|
-
mg.sessions.push(buildSessionGraph(s.actionHistory || [], void 0, sid));
|
|
8928
|
+
mg.sessions.push(buildSessionGraph(s.actionHistory || [], void 0, sid, s.agentId || ""));
|
|
8911
8929
|
}
|
|
8912
8930
|
if (aNext) {
|
|
8913
8931
|
const last = mg.sessions[mg.sessions.length - 1];
|
|
@@ -8917,7 +8935,8 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
8917
8935
|
last.nodes.length,
|
|
8918
8936
|
String(aNext.actionType || ""),
|
|
8919
8937
|
String(aNext.actionDetail || ""),
|
|
8920
|
-
aNext.calledAt || void 0
|
|
8938
|
+
aNext.calledAt || void 0,
|
|
8939
|
+
aNext.agentId || ""
|
|
8921
8940
|
));
|
|
8922
8941
|
if (last.nodes.length > 1) {
|
|
8923
8942
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
@@ -9704,8 +9723,8 @@ var init_stateful = __esm({
|
|
|
9704
9723
|
}
|
|
9705
9724
|
/** 增量推进:把当前动作追加到时间线 → 链指针推进 → 判定。 */
|
|
9706
9725
|
advance(args) {
|
|
9707
|
-
const { aNext, sessionId = "current", isError = false } = args;
|
|
9708
|
-
const node = this.appendNode(aNext, sessionId, isError);
|
|
9726
|
+
const { aNext, sessionId = "current", isError = false, agentId = "" } = args;
|
|
9727
|
+
const node = this.appendNode(aNext, sessionId, isError, agentId);
|
|
9709
9728
|
if (!node) {
|
|
9710
9729
|
return { seq: this.seqNext, node: null, matched: null, pendingPrefixes: this.pendingPrefixes, exfil: [], shouldBlock: false };
|
|
9711
9730
|
}
|
|
@@ -9725,7 +9744,7 @@ var init_stateful = __esm({
|
|
|
9725
9744
|
}
|
|
9726
9745
|
};
|
|
9727
9746
|
}
|
|
9728
|
-
appendNode(action, sessionId, isError = false) {
|
|
9747
|
+
appendNode(action, sessionId, isError = false, agentId = "") {
|
|
9729
9748
|
const ad = String(action.actionDetail || "");
|
|
9730
9749
|
const at = String(action.actionType || "");
|
|
9731
9750
|
if (!ad) return null;
|
|
@@ -9742,6 +9761,7 @@ var init_stateful = __esm({
|
|
|
9742
9761
|
resources: extractResources2(ad),
|
|
9743
9762
|
instances: extractInstances(ad, stage),
|
|
9744
9763
|
isError,
|
|
9764
|
+
agentId: String(action.agentId || agentId || ""),
|
|
9745
9765
|
lifecycle: lifecycleFor(ad, stage, isError),
|
|
9746
9766
|
timestamp: typeof action.calledAt === "string" ? action.calledAt : _StatefulChainTracker.now()
|
|
9747
9767
|
};
|
|
@@ -9879,7 +9899,13 @@ var init_stateful = __esm({
|
|
|
9879
9899
|
let want = stages[0];
|
|
9880
9900
|
for (const n of this.nodes_) {
|
|
9881
9901
|
if (n.stage === want) {
|
|
9882
|
-
path6.push({
|
|
9902
|
+
path6.push({
|
|
9903
|
+
sessionId: n.sessionId,
|
|
9904
|
+
seq: n.seq,
|
|
9905
|
+
stage: n.stage,
|
|
9906
|
+
timestamp: n.timestamp,
|
|
9907
|
+
agentId: n.agentId
|
|
9908
|
+
});
|
|
9883
9909
|
const idx = stages.indexOf(n.stage);
|
|
9884
9910
|
if (idx + 1 < stages.length) {
|
|
9885
9911
|
want = stages[idx + 1];
|
|
@@ -9904,7 +9930,7 @@ var init_stateful = __esm({
|
|
|
9904
9930
|
}
|
|
9905
9931
|
if (taintedRes.size > 0) {
|
|
9906
9932
|
this.tainted.add(idx);
|
|
9907
|
-
for (const r of
|
|
9933
|
+
for (const r of node.resources) this.taintedResources.add(r);
|
|
9908
9934
|
}
|
|
9909
9935
|
}
|
|
9910
9936
|
resourceTainted(resource) {
|
|
@@ -9953,6 +9979,7 @@ var init_stateful = __esm({
|
|
|
9953
9979
|
this.nodes_.push({
|
|
9954
9980
|
seq: Number(raw.seq || 0),
|
|
9955
9981
|
sessionId: String(raw.sessionId || ""),
|
|
9982
|
+
agentId: String(raw.agentId || ""),
|
|
9956
9983
|
actionType: String(raw.actionType || ""),
|
|
9957
9984
|
actionDetail: String(raw.actionDetail || ""),
|
|
9958
9985
|
stage: String(raw.stage || ""),
|
|
@@ -10059,9 +10086,9 @@ var init_chain_state = __esm({
|
|
|
10059
10086
|
delete this.data[agentId];
|
|
10060
10087
|
this._scheduleWrite();
|
|
10061
10088
|
}
|
|
10062
|
-
applyAction(agentId, aNext, sessionId, isError = false) {
|
|
10089
|
+
applyAction(agentId, aNext, sessionId, isError = false, sourceAgent = "") {
|
|
10063
10090
|
const t = this.load(agentId) || new StatefulChainTracker(agentId);
|
|
10064
|
-
const r = t.advance({ aNext, sessionId, isError });
|
|
10091
|
+
const r = t.advance({ aNext, sessionId, isError, agentId: sourceAgent });
|
|
10065
10092
|
this.save(t);
|
|
10066
10093
|
return r;
|
|
10067
10094
|
}
|
|
@@ -10376,10 +10403,14 @@ async function runAnalysis(input) {
|
|
|
10376
10403
|
const formalSessions = [];
|
|
10377
10404
|
if (input.sessionHistory) {
|
|
10378
10405
|
for (const s of input.sessionHistory) {
|
|
10379
|
-
formalSessions.push({
|
|
10406
|
+
formalSessions.push({
|
|
10407
|
+
sessionId: s.sessionId || "s",
|
|
10408
|
+
...s.agentId ? { agentId: s.agentId } : {},
|
|
10409
|
+
actionHistory: s.actionHistory || []
|
|
10410
|
+
});
|
|
10380
10411
|
}
|
|
10381
10412
|
}
|
|
10382
|
-
formalSessions.push({ sessionId: "current", actionHistory: input.actionHistory });
|
|
10413
|
+
formalSessions.push({ sessionId: "current", agentId: input.agentId, actionHistory: input.actionHistory });
|
|
10383
10414
|
const formalResult = formalEngine.verify(formalSessions, input.aNext);
|
|
10384
10415
|
if (!formalResult.verified) {
|
|
10385
10416
|
const v = formalResult.violations[0];
|
|
@@ -10747,6 +10778,8 @@ var AnalyzeRequestSchema = z.object({
|
|
|
10747
10778
|
action_history: z.array(ActionItemSchema).default([]).describe("Historical action sequence"),
|
|
10748
10779
|
session_history: z.array(z.object({
|
|
10749
10780
|
session_id: z.string(),
|
|
10781
|
+
/** 来源 agent(AgentGate 逐会话带上):记录在链路径里供告警/取证,不参与链匹配。 */
|
|
10782
|
+
agent_id: z.string().optional(),
|
|
10750
10783
|
action_history: z.array(ActionItemSchema).default([])
|
|
10751
10784
|
})).default([]).describe("Multi-session historical actions (optional): for L2.2 formal engine cross-session combo-chain / sensitive-data-flow verification. Provided by caller (incl. future agentgate)."),
|
|
10752
10785
|
a_next: ActionItemSchema.describe("Next action to be executed"),
|
|
@@ -11661,6 +11694,8 @@ async function analyzeRoute(c) {
|
|
|
11661
11694
|
})),
|
|
11662
11695
|
sessionHistory: (req.session_history || []).map((s) => ({
|
|
11663
11696
|
sessionId: s.session_id,
|
|
11697
|
+
// 来源 agent(AgentGate 逐会话带上,用于链路径取证展示;不参与链匹配)
|
|
11698
|
+
...s.agent_id ? { agentId: s.agent_id } : {},
|
|
11664
11699
|
actionHistory: (s.action_history || []).map((h) => ({
|
|
11665
11700
|
actionType: h.action_type,
|
|
11666
11701
|
actionDetail: h.action_detail,
|
|
@@ -11719,10 +11754,14 @@ async function analyzeRoute(c) {
|
|
|
11719
11754
|
if (incEnabled === "1" || incEnabled === "true" || incEnabled === "yes" || incEnabled === "on") {
|
|
11720
11755
|
try {
|
|
11721
11756
|
const store = getChainStateStoreFor(agentId);
|
|
11722
|
-
const inc = store.applyAction(
|
|
11723
|
-
|
|
11724
|
-
actionDetail: req.a_next.action_detail
|
|
11725
|
-
|
|
11757
|
+
const inc = store.applyAction(
|
|
11758
|
+
chainBucket(agentId),
|
|
11759
|
+
{ actionType: req.a_next.action_type, actionDetail: req.a_next.action_detail },
|
|
11760
|
+
req.session_id,
|
|
11761
|
+
Boolean(meta.is_error),
|
|
11762
|
+
agentId
|
|
11763
|
+
// 来源:真实 agent(桶 key 可能是 __system__)
|
|
11764
|
+
);
|
|
11726
11765
|
const judgment = incMatchedToDeny(inc);
|
|
11727
11766
|
if (judgment) {
|
|
11728
11767
|
const layers = [...result.violated_layers];
|
|
@@ -11788,7 +11827,7 @@ function getChainStateStoreFor(_agentId) {
|
|
|
11788
11827
|
}
|
|
11789
11828
|
function incMatchedToDeny(inc) {
|
|
11790
11829
|
if (inc.matched) {
|
|
11791
|
-
const chain = (inc.matched.path || []).map((p) => [p.sessionId, p.seq, p.stage, p.timestamp]);
|
|
11830
|
+
const chain = (inc.matched.path || []).map((p) => [p.sessionId, p.seq, p.stage, p.timestamp, p.agentId ?? null]);
|
|
11792
11831
|
return {
|
|
11793
11832
|
property_id: "cross-" + inc.matched.chainId,
|
|
11794
11833
|
reason: inc.matched.reason,
|
|
@@ -11813,9 +11852,10 @@ async function reviewRoute(c) {
|
|
|
11813
11852
|
const req = ReviewRequestSchema.parse(body);
|
|
11814
11853
|
const agentId = req.agent_id || "default";
|
|
11815
11854
|
const store = getChainStateStoreFor(agentId);
|
|
11816
|
-
|
|
11855
|
+
const bucket = chainBucket(agentId);
|
|
11856
|
+
let tracker = store.load(bucket);
|
|
11817
11857
|
if (!tracker) {
|
|
11818
|
-
tracker = new StatefulChainTracker(
|
|
11858
|
+
tracker = new StatefulChainTracker(bucket);
|
|
11819
11859
|
}
|
|
11820
11860
|
if (req.db_path && !pathWithin(req.db_path, reviewRoots())) {
|
|
11821
11861
|
return c.json({
|