@kenhkl/agent-moss 0.17.8 → 0.17.10
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 +85 -35
- package/dist/engine/coordinator.d.ts +4 -0
- package/dist/engine/coordinator.js +34 -13
- package/dist/server.js +85 -35
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1246,31 +1246,42 @@ function hardenExistingPaths() {
|
|
|
1246
1246
|
function chainDetailMode() {
|
|
1247
1247
|
return (env("AGENT_MOSS_CHAIN_DETAIL", "redacted") || "redacted").toLowerCase();
|
|
1248
1248
|
}
|
|
1249
|
-
function redactChain(chain, currentSessionId) {
|
|
1249
|
+
function redactChain(chain, currentInstanceId = "", currentSessionId = "") {
|
|
1250
1250
|
if (!chain || chain.length === 0) return [];
|
|
1251
1251
|
if (chainDetailMode() === "full") return [...chain];
|
|
1252
1252
|
return chain.map((step) => {
|
|
1253
1253
|
if (Array.isArray(step) && step.length >= 3) {
|
|
1254
1254
|
const [sid, seq, , ts] = step;
|
|
1255
|
-
|
|
1255
|
+
const inst = step.length > 5 ? String(step[5] ?? "") : "";
|
|
1256
|
+
const sameInstance = !!(inst && currentInstanceId && inst === String(currentInstanceId));
|
|
1257
|
+
const sameSessionFallback = !inst && !!currentSessionId && String(sid) === String(currentSessionId);
|
|
1258
|
+
if (sameInstance || sameSessionFallback) return [...step];
|
|
1256
1259
|
return ["<other-session>", seq, "<\u5DF2\u9690\u85CF>", ts ?? ""];
|
|
1257
1260
|
}
|
|
1258
1261
|
return step;
|
|
1259
1262
|
});
|
|
1260
1263
|
}
|
|
1261
|
-
function redactGraph(graph, currentSessionId) {
|
|
1264
|
+
function redactGraph(graph, currentInstanceId = "", currentSessionId = "") {
|
|
1262
1265
|
if (!graph) return null;
|
|
1263
1266
|
if (chainDetailMode() === "full") return graph;
|
|
1264
1267
|
const nodes = (graph.nodes || []).map((n) => {
|
|
1265
1268
|
const m = { ...n };
|
|
1266
|
-
|
|
1269
|
+
const inst = String(m.instance_id ?? "") || "";
|
|
1270
|
+
const sid = String(m.session_id ?? "") || "";
|
|
1271
|
+
const sameInstance = !!(inst && currentInstanceId && inst === String(currentInstanceId));
|
|
1272
|
+
const sameSessionFallback = !inst && !!currentSessionId && sid === String(currentSessionId);
|
|
1273
|
+
if (!(sameInstance || sameSessionFallback)) {
|
|
1267
1274
|
m.session_id = "<other-session>";
|
|
1268
1275
|
m.action_detail = "<\u5DF2\u9690\u85CF>";
|
|
1269
1276
|
m.resources = [];
|
|
1270
1277
|
}
|
|
1271
1278
|
return m;
|
|
1272
1279
|
});
|
|
1273
|
-
|
|
1280
|
+
const out = { nodes, edges: graph.edges || [] };
|
|
1281
|
+
for (const key of ["property_id", "property_short", "property_name", "property_expression"]) {
|
|
1282
|
+
if (graph[key] !== void 0) out[key] = graph[key];
|
|
1283
|
+
}
|
|
1284
|
+
return out;
|
|
1274
1285
|
}
|
|
1275
1286
|
function sessionSweepThreshold() {
|
|
1276
1287
|
return envInt("AGENT_MOSS_SESSION_SWEEP_THRESHOLD", 50);
|
|
@@ -1433,6 +1444,8 @@ var init_models = __esm({
|
|
|
1433
1444
|
session_id: z.string(),
|
|
1434
1445
|
/** 来源 agent(AgentGate 逐会话带上):记录在链路径里供告警/取证,不参与链匹配。 */
|
|
1435
1446
|
agent_id: z.string().optional(),
|
|
1447
|
+
/** 来源实例:仅用于展示层脱敏(同实例不隐藏),不参与链匹配。 */
|
|
1448
|
+
instance_id: z.string().optional(),
|
|
1436
1449
|
action_history: z.array(ActionItemSchema).default([])
|
|
1437
1450
|
})).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)."),
|
|
1438
1451
|
a_next: ActionItemSchema.describe("Next action to be executed"),
|
|
@@ -1440,6 +1453,7 @@ var init_models = __esm({
|
|
|
1440
1453
|
os_type: z.string().default("").describe("OS type: 'linux', 'windows', or empty for auto-detect"),
|
|
1441
1454
|
cwd: z.string().default("").describe("Current working directory"),
|
|
1442
1455
|
agent_id: z.string().default("").describe("Caller agent identifier, e.g. 'xiaoo' / 'opencode' / 'opendesk'. Empty = generic mode (no agent-specific rules)."),
|
|
1456
|
+
instance_id: z.string().default("").describe("Agent installation/instance identifier. Used only for display-layer redaction: nodes from the same instance are returned unredacted. Does not affect detection."),
|
|
1443
1457
|
metadata: z.record(z.unknown()).optional().describe("Extended metadata")
|
|
1444
1458
|
});
|
|
1445
1459
|
AnalyzeResponseSchema = z.object({
|
|
@@ -1477,7 +1491,9 @@ var init_models = __esm({
|
|
|
1477
1491
|
// 节点在性质中的角色:source/carrier/sink(P2)或阶段名(P1)
|
|
1478
1492
|
role: z.string().optional(),
|
|
1479
1493
|
// 是否为违例见证节点(当前动作补全链 / 触发外传)
|
|
1480
|
-
witness: z.boolean().optional()
|
|
1494
|
+
witness: z.boolean().optional(),
|
|
1495
|
+
// 来源实例(仅展示层脱敏:同实例不隐藏)
|
|
1496
|
+
instance_id: z.string().optional()
|
|
1481
1497
|
})
|
|
1482
1498
|
),
|
|
1483
1499
|
edges: z.array(
|
|
@@ -9436,7 +9452,7 @@ function markIntegrity(actionDetail) {
|
|
|
9436
9452
|
}
|
|
9437
9453
|
return { integrity: "medium", isLowSource: false };
|
|
9438
9454
|
}
|
|
9439
|
-
function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId = "") {
|
|
9455
|
+
function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId = "", instanceId = "") {
|
|
9440
9456
|
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
9441
9457
|
return {
|
|
9442
9458
|
sessionId,
|
|
@@ -9445,13 +9461,14 @@ function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId =
|
|
|
9445
9461
|
actionDetail,
|
|
9446
9462
|
stage: markStage(actionDetail),
|
|
9447
9463
|
agentId: agentId || void 0,
|
|
9464
|
+
instanceId: instanceId || void 0,
|
|
9448
9465
|
resources: extractResources(actionDetail),
|
|
9449
9466
|
integrity,
|
|
9450
9467
|
isLowSource,
|
|
9451
9468
|
timestamp: timestamp || void 0
|
|
9452
9469
|
};
|
|
9453
9470
|
}
|
|
9454
|
-
function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId = "") {
|
|
9471
|
+
function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId = "", instanceId = "") {
|
|
9455
9472
|
const nodes = [];
|
|
9456
9473
|
const edges = [];
|
|
9457
9474
|
const stageFlags = /* @__PURE__ */ new Set();
|
|
@@ -9462,7 +9479,8 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId
|
|
|
9462
9479
|
actionType: String(a.actionType || ""),
|
|
9463
9480
|
actionDetail: ad,
|
|
9464
9481
|
calledAt: a.calledAt || void 0,
|
|
9465
|
-
agentId: a.agentId || agentId || void 0
|
|
9482
|
+
agentId: a.agentId || agentId || void 0,
|
|
9483
|
+
instanceId: a.instanceId || instanceId || void 0
|
|
9466
9484
|
});
|
|
9467
9485
|
}
|
|
9468
9486
|
if (aNext) {
|
|
@@ -9470,11 +9488,12 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId
|
|
|
9470
9488
|
actionType: String(aNext.actionType || ""),
|
|
9471
9489
|
actionDetail: String(aNext.actionDetail || ""),
|
|
9472
9490
|
calledAt: aNext.calledAt || void 0,
|
|
9473
|
-
agentId: aNext.agentId || agentId || void 0
|
|
9491
|
+
agentId: aNext.agentId || agentId || void 0,
|
|
9492
|
+
instanceId: aNext.instanceId || instanceId || void 0
|
|
9474
9493
|
});
|
|
9475
9494
|
}
|
|
9476
9495
|
details.forEach((d, seq) => {
|
|
9477
|
-
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt, d.agentId || "");
|
|
9496
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt, d.agentId || "", d.instanceId || "");
|
|
9478
9497
|
nodes.push(node);
|
|
9479
9498
|
if (node.stage) stageFlags.add(node.stage);
|
|
9480
9499
|
});
|
|
@@ -9486,12 +9505,18 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId
|
|
|
9486
9505
|
function buildMultiSessionGraph(sessions, aNext) {
|
|
9487
9506
|
const mg = { sessions: [], crossEdges: [] };
|
|
9488
9507
|
if (!sessions || sessions.length === 0) {
|
|
9489
|
-
mg.sessions.push(buildSessionGraph([], aNext, "current"));
|
|
9508
|
+
mg.sessions.push(buildSessionGraph([], aNext, "current", "", aNext?.instanceId || ""));
|
|
9490
9509
|
return mg;
|
|
9491
9510
|
}
|
|
9492
9511
|
for (const s of sessions) {
|
|
9493
9512
|
const sid = String(s.sessionId || "s");
|
|
9494
|
-
mg.sessions.push(buildSessionGraph(
|
|
9513
|
+
mg.sessions.push(buildSessionGraph(
|
|
9514
|
+
s.actionHistory || [],
|
|
9515
|
+
void 0,
|
|
9516
|
+
sid,
|
|
9517
|
+
s.agentId || "",
|
|
9518
|
+
s.instanceId || ""
|
|
9519
|
+
));
|
|
9495
9520
|
}
|
|
9496
9521
|
if (aNext) {
|
|
9497
9522
|
const last = mg.sessions[mg.sessions.length - 1];
|
|
@@ -9502,13 +9527,14 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
9502
9527
|
String(aNext.actionType || ""),
|
|
9503
9528
|
String(aNext.actionDetail || ""),
|
|
9504
9529
|
aNext.calledAt || void 0,
|
|
9505
|
-
aNext.agentId || ""
|
|
9530
|
+
aNext.agentId || "",
|
|
9531
|
+
aNext.instanceId || ""
|
|
9506
9532
|
));
|
|
9507
9533
|
if (last.nodes.length > 1) {
|
|
9508
9534
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
9509
9535
|
}
|
|
9510
9536
|
} else {
|
|
9511
|
-
mg.sessions.push(buildSessionGraph([], aNext, "current"));
|
|
9537
|
+
mg.sessions.push(buildSessionGraph([], aNext, "current", "", aNext.instanceId || ""));
|
|
9512
9538
|
}
|
|
9513
9539
|
}
|
|
9514
9540
|
addCrossDataEdges(mg);
|
|
@@ -9572,7 +9598,8 @@ function graphFromPath(nodes, path6, edgeType = "next", propertyMeta, roles, wit
|
|
|
9572
9598
|
seq: item.seq,
|
|
9573
9599
|
stage: n ? n.stage : "",
|
|
9574
9600
|
action_detail: n ? n.actionDetail : item.detail,
|
|
9575
|
-
resources: n ? [...n.resources].sort() : []
|
|
9601
|
+
resources: n ? [...n.resources].sort() : [],
|
|
9602
|
+
instance_id: n ? n.instanceId || "" : ""
|
|
9576
9603
|
});
|
|
9577
9604
|
if (gNodes.length > 1) {
|
|
9578
9605
|
gEdges.push({ from: gNodes.length - 2, to: gNodes.length - 1, type: edgeType });
|
|
@@ -9740,7 +9767,8 @@ function checkSensitiveDataFlow(graph) {
|
|
|
9740
9767
|
stage: n.stage,
|
|
9741
9768
|
action_detail: n.actionDetail,
|
|
9742
9769
|
resources: [...n.resources].sort(),
|
|
9743
|
-
role
|
|
9770
|
+
role,
|
|
9771
|
+
instance_id: n.instanceId || ""
|
|
9744
9772
|
});
|
|
9745
9773
|
if (k > 0) {
|
|
9746
9774
|
const prev = chain[k - 1];
|
|
@@ -10383,7 +10411,7 @@ var init_stateful = __esm({
|
|
|
10383
10411
|
for (const s of sessions || []) {
|
|
10384
10412
|
const sid = String(s.sessionId || "s");
|
|
10385
10413
|
for (const a of s.actionHistory || []) {
|
|
10386
|
-
const node = this.appendNode(a, sid);
|
|
10414
|
+
const node = this.appendNode(a, sid, false, s.agentId || "", s.instanceId || "");
|
|
10387
10415
|
if (!node) {
|
|
10388
10416
|
continue;
|
|
10389
10417
|
}
|
|
@@ -10397,8 +10425,8 @@ var init_stateful = __esm({
|
|
|
10397
10425
|
}
|
|
10398
10426
|
/** 增量推进:把当前动作追加到时间线 → 链指针推进 → 判定。 */
|
|
10399
10427
|
advance(args) {
|
|
10400
|
-
const { aNext, sessionId = "current", isError = false, agentId = "" } = args;
|
|
10401
|
-
const node = this.appendNode(aNext, sessionId, isError, agentId);
|
|
10428
|
+
const { aNext, sessionId = "current", isError = false, agentId = "", instanceId = "" } = args;
|
|
10429
|
+
const node = this.appendNode(aNext, sessionId, isError, agentId, instanceId);
|
|
10402
10430
|
if (!node) {
|
|
10403
10431
|
return { seq: this.seqNext, node: null, matched: null, pendingPrefixes: this.pendingPrefixes, exfil: [], shouldBlock: false };
|
|
10404
10432
|
}
|
|
@@ -10418,7 +10446,7 @@ var init_stateful = __esm({
|
|
|
10418
10446
|
}
|
|
10419
10447
|
};
|
|
10420
10448
|
}
|
|
10421
|
-
appendNode(action, sessionId, isError = false, agentId = "") {
|
|
10449
|
+
appendNode(action, sessionId, isError = false, agentId = "", instanceId = "") {
|
|
10422
10450
|
const ad = String(action.actionDetail || "");
|
|
10423
10451
|
const at = String(action.actionType || "");
|
|
10424
10452
|
if (!ad) return null;
|
|
@@ -10436,6 +10464,7 @@ var init_stateful = __esm({
|
|
|
10436
10464
|
instances: extractInstances(ad, stage),
|
|
10437
10465
|
isError,
|
|
10438
10466
|
agentId: String(action.agentId || agentId || ""),
|
|
10467
|
+
instanceId: String(action.instanceId || instanceId || ""),
|
|
10439
10468
|
lifecycle: lifecycleFor(ad, stage, isError),
|
|
10440
10469
|
timestamp: typeof action.calledAt === "string" ? action.calledAt : _StatefulChainTracker.now()
|
|
10441
10470
|
};
|
|
@@ -10579,7 +10608,8 @@ var init_stateful = __esm({
|
|
|
10579
10608
|
seq: n.seq,
|
|
10580
10609
|
stage: n.stage,
|
|
10581
10610
|
timestamp: n.timestamp,
|
|
10582
|
-
agentId: n.agentId
|
|
10611
|
+
agentId: n.agentId,
|
|
10612
|
+
instanceId: n.instanceId
|
|
10583
10613
|
});
|
|
10584
10614
|
const idx = stages.indexOf(n.stage);
|
|
10585
10615
|
if (idx + 1 < stages.length) {
|
|
@@ -10602,7 +10632,8 @@ var init_stateful = __esm({
|
|
|
10602
10632
|
stage: p.stage,
|
|
10603
10633
|
action_detail: n ? n.actionDetail : "",
|
|
10604
10634
|
resources: n ? [...n.resources].sort() : [],
|
|
10605
|
-
role: stages[i] || ""
|
|
10635
|
+
role: stages[i] || "",
|
|
10636
|
+
instance_id: p.instanceId || ""
|
|
10606
10637
|
};
|
|
10607
10638
|
});
|
|
10608
10639
|
const gEdges = [];
|
|
@@ -10670,7 +10701,7 @@ var init_stateful = __esm({
|
|
|
10670
10701
|
risk_level: "critical",
|
|
10671
10702
|
path: chain.map((j) => {
|
|
10672
10703
|
const n = this.nodes_[j];
|
|
10673
|
-
return [n.sessionId, n.seq, n.actionDetail.slice(0, 60), n.timestamp];
|
|
10704
|
+
return [n.sessionId, n.seq, n.actionDetail.slice(0, 60), n.timestamp, null, n.instanceId];
|
|
10674
10705
|
}),
|
|
10675
10706
|
graph: this.taintGraph(chain)
|
|
10676
10707
|
}];
|
|
@@ -10702,7 +10733,8 @@ var init_stateful = __esm({
|
|
|
10702
10733
|
stage: n.stage,
|
|
10703
10734
|
action_detail: n.actionDetail,
|
|
10704
10735
|
resources: [...n.resources].sort(),
|
|
10705
|
-
role
|
|
10736
|
+
role,
|
|
10737
|
+
instance_id: n.instanceId
|
|
10706
10738
|
});
|
|
10707
10739
|
if (k > 0) {
|
|
10708
10740
|
const prev = chain[k - 1];
|
|
@@ -10774,6 +10806,8 @@ var init_stateful = __esm({
|
|
|
10774
10806
|
seq: Number(raw.seq || 0),
|
|
10775
10807
|
sessionId: String(raw.sessionId || ""),
|
|
10776
10808
|
agentId: String(raw.agentId || ""),
|
|
10809
|
+
instanceId: String(raw.instanceId || ""),
|
|
10810
|
+
// 旧快照无此字段 → 空
|
|
10777
10811
|
actionType: String(raw.actionType || ""),
|
|
10778
10812
|
actionDetail: String(raw.actionDetail || ""),
|
|
10779
10813
|
stage: String(raw.stage || ""),
|
|
@@ -10918,9 +10952,9 @@ var init_chain_state = __esm({
|
|
|
10918
10952
|
delete this.data[agentId];
|
|
10919
10953
|
this._scheduleWrite();
|
|
10920
10954
|
}
|
|
10921
|
-
applyAction(agentId, aNext, sessionId, isError = false, sourceAgent = "") {
|
|
10955
|
+
applyAction(agentId, aNext, sessionId, isError = false, sourceAgent = "", instanceId = "") {
|
|
10922
10956
|
const t = this.load(agentId) || new StatefulChainTracker(agentId);
|
|
10923
|
-
const r = t.advance({ aNext, sessionId, isError, agentId: sourceAgent });
|
|
10957
|
+
const r = t.advance({ aNext, sessionId, isError, agentId: sourceAgent, instanceId });
|
|
10924
10958
|
this.save(t);
|
|
10925
10959
|
return r;
|
|
10926
10960
|
}
|
|
@@ -11238,12 +11272,21 @@ async function runAnalysis(input) {
|
|
|
11238
11272
|
formalSessions.push({
|
|
11239
11273
|
sessionId: s.sessionId || "s",
|
|
11240
11274
|
...s.agentId ? { agentId: s.agentId } : {},
|
|
11275
|
+
...s.instanceId ? { instanceId: s.instanceId } : {},
|
|
11241
11276
|
actionHistory: s.actionHistory || []
|
|
11242
11277
|
});
|
|
11243
11278
|
}
|
|
11244
11279
|
}
|
|
11245
|
-
formalSessions.push({
|
|
11246
|
-
|
|
11280
|
+
formalSessions.push({
|
|
11281
|
+
sessionId: "current",
|
|
11282
|
+
agentId: input.agentId,
|
|
11283
|
+
instanceId: input.instanceId || "",
|
|
11284
|
+
actionHistory: input.actionHistory
|
|
11285
|
+
});
|
|
11286
|
+
const formalResult = formalEngine.verify(formalSessions, {
|
|
11287
|
+
...input.aNext,
|
|
11288
|
+
instanceId: input.instanceId || ""
|
|
11289
|
+
});
|
|
11247
11290
|
if (!formalResult.verified) {
|
|
11248
11291
|
const v = formalResult.violations[0];
|
|
11249
11292
|
if (isFormalObserveMode()) {
|
|
@@ -12327,6 +12370,9 @@ async function analyzeRoute(c) {
|
|
|
12327
12370
|
`[AgentMoss] \u26A0\uFE0F \u8DE8\u4F1A\u8BDD\u6279\u91CF\u8BBF\u95EE: key=${_sweepKey} \u7A97\u53E3\u5185 ${_sweepN} \u4E2A\u4E0D\u540C session\uFF08\u9608\u503C ${sessionSweepThreshold()}\uFF09`
|
|
12328
12371
|
);
|
|
12329
12372
|
}
|
|
12373
|
+
const instanceId = String(
|
|
12374
|
+
req.instance_id || req.metadata?.instance_id || ""
|
|
12375
|
+
);
|
|
12330
12376
|
const result = await analyze({
|
|
12331
12377
|
sessionId: req.session_id,
|
|
12332
12378
|
promptSession: req.prompt_session,
|
|
@@ -12342,8 +12388,9 @@ async function analyzeRoute(c) {
|
|
|
12342
12388
|
})),
|
|
12343
12389
|
sessionHistory: (req.session_history || []).map((s) => ({
|
|
12344
12390
|
sessionId: s.session_id,
|
|
12345
|
-
// 来源 agent
|
|
12391
|
+
// 来源 agent/实例(AgentGate 逐会话带上,用于链路径取证/展示脱敏;不参与链匹配)
|
|
12346
12392
|
...s.agent_id ? { agentId: s.agent_id } : {},
|
|
12393
|
+
...s.instance_id ? { instanceId: s.instance_id } : {},
|
|
12347
12394
|
actionHistory: (s.action_history || []).map((h) => ({
|
|
12348
12395
|
actionType: h.action_type,
|
|
12349
12396
|
actionDetail: h.action_detail,
|
|
@@ -12367,11 +12414,13 @@ async function analyzeRoute(c) {
|
|
|
12367
12414
|
})),
|
|
12368
12415
|
aNext: {
|
|
12369
12416
|
actionType: req.a_next.action_type,
|
|
12370
|
-
actionDetail: req.a_next.action_detail
|
|
12417
|
+
actionDetail: req.a_next.action_detail,
|
|
12418
|
+
instanceId
|
|
12371
12419
|
},
|
|
12372
12420
|
reason: req.reason,
|
|
12373
12421
|
osType,
|
|
12374
12422
|
cwd: req.cwd,
|
|
12423
|
+
instanceId,
|
|
12375
12424
|
// agent_id:AgentGate V1 normalizer 历史上把 agent_type 塞 metadata,
|
|
12376
12425
|
// 顶层为空时兜底(OpenDesk 的 agent-moss 需 agent_id 加载专属规则)。
|
|
12377
12426
|
agentId,
|
|
@@ -12407,8 +12456,9 @@ async function analyzeRoute(c) {
|
|
|
12407
12456
|
{ actionType: req.a_next.action_type, actionDetail: req.a_next.action_detail },
|
|
12408
12457
|
req.session_id,
|
|
12409
12458
|
Boolean(meta.is_error),
|
|
12410
|
-
agentId
|
|
12459
|
+
agentId,
|
|
12411
12460
|
// 来源:真实 agent(桶 key 可能是 __system__)
|
|
12461
|
+
instanceId
|
|
12412
12462
|
);
|
|
12413
12463
|
const judgment = incMatchedToDeny(inc);
|
|
12414
12464
|
if (judgment) {
|
|
@@ -12429,8 +12479,8 @@ async function analyzeRoute(c) {
|
|
|
12429
12479
|
confidence: 90,
|
|
12430
12480
|
analysis_duration_ms: Math.round((performance.now() - t0) * 10) / 10,
|
|
12431
12481
|
// 跨会话节点脱敏(时间线按 agent_id 共享,原样返回等于泄露别人的命令原文)
|
|
12432
|
-
violation_chain: redactChain(judgment.violation_chain, req.session_id),
|
|
12433
|
-
violation_graph: redactGraph(judgment.violation_graph, req.session_id)
|
|
12482
|
+
violation_chain: redactChain(judgment.violation_chain, instanceId, req.session_id),
|
|
12483
|
+
violation_graph: redactGraph(judgment.violation_graph, instanceId, req.session_id)
|
|
12434
12484
|
})
|
|
12435
12485
|
);
|
|
12436
12486
|
}
|
|
@@ -12452,7 +12502,7 @@ async function analyzeRoute(c) {
|
|
|
12452
12502
|
confidence: result.confidence,
|
|
12453
12503
|
analysis_duration_ms: Math.round(durationMs * 10) / 10,
|
|
12454
12504
|
violation_chain: result.violation_chain ?? [],
|
|
12455
|
-
violation_graph: redactGraph(result.violation_graph, req.session_id)
|
|
12505
|
+
violation_graph: redactGraph(result.violation_graph, instanceId, req.session_id)
|
|
12456
12506
|
})
|
|
12457
12507
|
);
|
|
12458
12508
|
} catch (err) {
|
|
@@ -81,6 +81,7 @@ interface AnalysisInput {
|
|
|
81
81
|
* 由调用方(含未来 agentgate 非侵入式采集)提供。 */
|
|
82
82
|
sessionHistory?: {
|
|
83
83
|
sessionId?: string;
|
|
84
|
+
instanceId?: string;
|
|
84
85
|
actionHistory: {
|
|
85
86
|
actionType: string;
|
|
86
87
|
actionDetail: string;
|
|
@@ -90,12 +91,15 @@ interface AnalysisInput {
|
|
|
90
91
|
aNext: {
|
|
91
92
|
actionType: string;
|
|
92
93
|
actionDetail: string;
|
|
94
|
+
instanceId?: string;
|
|
93
95
|
};
|
|
94
96
|
reason: string;
|
|
95
97
|
osType: string;
|
|
96
98
|
cwd: string;
|
|
97
99
|
/** 调用方 agent 标识(如 'xiaoo' / 'opencode' / 'opendesk')。空 = 通用模式。 */
|
|
98
100
|
agentId: string;
|
|
101
|
+
/** 调用方实例标识(安装级)。仅用于展示层脱敏:同实例节点不隐藏。 */
|
|
102
|
+
instanceId?: string;
|
|
99
103
|
/** 调用方场景标识(如 'bank'),用于加载场景定制规则(客户沙箱的目录访问边界/禁 ssh 等)。
|
|
100
104
|
* 空时兜底环境变量 AGENT_MOSS_SCENARIO(部署级,客户沙箱设一次,所有请求生效)。 */
|
|
101
105
|
scenarioId?: string;
|
|
@@ -8369,7 +8369,7 @@ function markIntegrity(actionDetail) {
|
|
|
8369
8369
|
}
|
|
8370
8370
|
return { integrity: "medium", isLowSource: false };
|
|
8371
8371
|
}
|
|
8372
|
-
function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId = "") {
|
|
8372
|
+
function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId = "", instanceId = "") {
|
|
8373
8373
|
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
8374
8374
|
return {
|
|
8375
8375
|
sessionId,
|
|
@@ -8378,13 +8378,14 @@ function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId =
|
|
|
8378
8378
|
actionDetail,
|
|
8379
8379
|
stage: markStage(actionDetail),
|
|
8380
8380
|
agentId: agentId || void 0,
|
|
8381
|
+
instanceId: instanceId || void 0,
|
|
8381
8382
|
resources: extractResources(actionDetail),
|
|
8382
8383
|
integrity,
|
|
8383
8384
|
isLowSource,
|
|
8384
8385
|
timestamp: timestamp || void 0
|
|
8385
8386
|
};
|
|
8386
8387
|
}
|
|
8387
|
-
function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId = "") {
|
|
8388
|
+
function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId = "", instanceId = "") {
|
|
8388
8389
|
const nodes = [];
|
|
8389
8390
|
const edges = [];
|
|
8390
8391
|
const stageFlags = /* @__PURE__ */ new Set();
|
|
@@ -8395,7 +8396,8 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId
|
|
|
8395
8396
|
actionType: String(a.actionType || ""),
|
|
8396
8397
|
actionDetail: ad,
|
|
8397
8398
|
calledAt: a.calledAt || void 0,
|
|
8398
|
-
agentId: a.agentId || agentId || void 0
|
|
8399
|
+
agentId: a.agentId || agentId || void 0,
|
|
8400
|
+
instanceId: a.instanceId || instanceId || void 0
|
|
8399
8401
|
});
|
|
8400
8402
|
}
|
|
8401
8403
|
if (aNext) {
|
|
@@ -8403,11 +8405,12 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId
|
|
|
8403
8405
|
actionType: String(aNext.actionType || ""),
|
|
8404
8406
|
actionDetail: String(aNext.actionDetail || ""),
|
|
8405
8407
|
calledAt: aNext.calledAt || void 0,
|
|
8406
|
-
agentId: aNext.agentId || agentId || void 0
|
|
8408
|
+
agentId: aNext.agentId || agentId || void 0,
|
|
8409
|
+
instanceId: aNext.instanceId || instanceId || void 0
|
|
8407
8410
|
});
|
|
8408
8411
|
}
|
|
8409
8412
|
details.forEach((d, seq) => {
|
|
8410
|
-
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt, d.agentId || "");
|
|
8413
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt, d.agentId || "", d.instanceId || "");
|
|
8411
8414
|
nodes.push(node);
|
|
8412
8415
|
if (node.stage) stageFlags.add(node.stage);
|
|
8413
8416
|
});
|
|
@@ -8419,12 +8422,18 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId
|
|
|
8419
8422
|
function buildMultiSessionGraph(sessions, aNext) {
|
|
8420
8423
|
const mg = { sessions: [], crossEdges: [] };
|
|
8421
8424
|
if (!sessions || sessions.length === 0) {
|
|
8422
|
-
mg.sessions.push(buildSessionGraph([], aNext, "current"));
|
|
8425
|
+
mg.sessions.push(buildSessionGraph([], aNext, "current", "", aNext?.instanceId || ""));
|
|
8423
8426
|
return mg;
|
|
8424
8427
|
}
|
|
8425
8428
|
for (const s of sessions) {
|
|
8426
8429
|
const sid = String(s.sessionId || "s");
|
|
8427
|
-
mg.sessions.push(buildSessionGraph(
|
|
8430
|
+
mg.sessions.push(buildSessionGraph(
|
|
8431
|
+
s.actionHistory || [],
|
|
8432
|
+
void 0,
|
|
8433
|
+
sid,
|
|
8434
|
+
s.agentId || "",
|
|
8435
|
+
s.instanceId || ""
|
|
8436
|
+
));
|
|
8428
8437
|
}
|
|
8429
8438
|
if (aNext) {
|
|
8430
8439
|
const last = mg.sessions[mg.sessions.length - 1];
|
|
@@ -8435,13 +8444,14 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
8435
8444
|
String(aNext.actionType || ""),
|
|
8436
8445
|
String(aNext.actionDetail || ""),
|
|
8437
8446
|
aNext.calledAt || void 0,
|
|
8438
|
-
aNext.agentId || ""
|
|
8447
|
+
aNext.agentId || "",
|
|
8448
|
+
aNext.instanceId || ""
|
|
8439
8449
|
));
|
|
8440
8450
|
if (last.nodes.length > 1) {
|
|
8441
8451
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
8442
8452
|
}
|
|
8443
8453
|
} else {
|
|
8444
|
-
mg.sessions.push(buildSessionGraph([], aNext, "current"));
|
|
8454
|
+
mg.sessions.push(buildSessionGraph([], aNext, "current", "", aNext.instanceId || ""));
|
|
8445
8455
|
}
|
|
8446
8456
|
}
|
|
8447
8457
|
addCrossDataEdges(mg);
|
|
@@ -8495,7 +8505,8 @@ function graphFromPath(nodes, path5, edgeType = "next", propertyMeta, roles, wit
|
|
|
8495
8505
|
seq: item.seq,
|
|
8496
8506
|
stage: n ? n.stage : "",
|
|
8497
8507
|
action_detail: n ? n.actionDetail : item.detail,
|
|
8498
|
-
resources: n ? [...n.resources].sort() : []
|
|
8508
|
+
resources: n ? [...n.resources].sort() : [],
|
|
8509
|
+
instance_id: n ? n.instanceId || "" : ""
|
|
8499
8510
|
});
|
|
8500
8511
|
if (gNodes.length > 1) {
|
|
8501
8512
|
gEdges.push({ from: gNodes.length - 2, to: gNodes.length - 1, type: edgeType });
|
|
@@ -8666,7 +8677,8 @@ function checkSensitiveDataFlow(graph) {
|
|
|
8666
8677
|
stage: n.stage,
|
|
8667
8678
|
action_detail: n.actionDetail,
|
|
8668
8679
|
resources: [...n.resources].sort(),
|
|
8669
|
-
role
|
|
8680
|
+
role,
|
|
8681
|
+
instance_id: n.instanceId || ""
|
|
8670
8682
|
});
|
|
8671
8683
|
if (k > 0) {
|
|
8672
8684
|
const prev = chain[k - 1];
|
|
@@ -9434,12 +9446,21 @@ async function runAnalysis(input) {
|
|
|
9434
9446
|
formalSessions.push({
|
|
9435
9447
|
sessionId: s.sessionId || "s",
|
|
9436
9448
|
...s.agentId ? { agentId: s.agentId } : {},
|
|
9449
|
+
...s.instanceId ? { instanceId: s.instanceId } : {},
|
|
9437
9450
|
actionHistory: s.actionHistory || []
|
|
9438
9451
|
});
|
|
9439
9452
|
}
|
|
9440
9453
|
}
|
|
9441
|
-
formalSessions.push({
|
|
9442
|
-
|
|
9454
|
+
formalSessions.push({
|
|
9455
|
+
sessionId: "current",
|
|
9456
|
+
agentId: input.agentId,
|
|
9457
|
+
instanceId: input.instanceId || "",
|
|
9458
|
+
actionHistory: input.actionHistory
|
|
9459
|
+
});
|
|
9460
|
+
const formalResult = formalEngine.verify(formalSessions, {
|
|
9461
|
+
...input.aNext,
|
|
9462
|
+
instanceId: input.instanceId || ""
|
|
9463
|
+
});
|
|
9443
9464
|
if (!formalResult.verified) {
|
|
9444
9465
|
const v = formalResult.violations[0];
|
|
9445
9466
|
if (isFormalObserveMode()) {
|
package/dist/server.js
CHANGED
|
@@ -1092,31 +1092,42 @@ function hardenExistingPaths() {
|
|
|
1092
1092
|
function chainDetailMode() {
|
|
1093
1093
|
return (env("AGENT_MOSS_CHAIN_DETAIL", "redacted") || "redacted").toLowerCase();
|
|
1094
1094
|
}
|
|
1095
|
-
function redactChain(chain, currentSessionId) {
|
|
1095
|
+
function redactChain(chain, currentInstanceId = "", currentSessionId = "") {
|
|
1096
1096
|
if (!chain || chain.length === 0) return [];
|
|
1097
1097
|
if (chainDetailMode() === "full") return [...chain];
|
|
1098
1098
|
return chain.map((step) => {
|
|
1099
1099
|
if (Array.isArray(step) && step.length >= 3) {
|
|
1100
1100
|
const [sid, seq, , ts] = step;
|
|
1101
|
-
|
|
1101
|
+
const inst = step.length > 5 ? String(step[5] ?? "") : "";
|
|
1102
|
+
const sameInstance = !!(inst && currentInstanceId && inst === String(currentInstanceId));
|
|
1103
|
+
const sameSessionFallback = !inst && !!currentSessionId && String(sid) === String(currentSessionId);
|
|
1104
|
+
if (sameInstance || sameSessionFallback) return [...step];
|
|
1102
1105
|
return ["<other-session>", seq, "<\u5DF2\u9690\u85CF>", ts ?? ""];
|
|
1103
1106
|
}
|
|
1104
1107
|
return step;
|
|
1105
1108
|
});
|
|
1106
1109
|
}
|
|
1107
|
-
function redactGraph(graph, currentSessionId) {
|
|
1110
|
+
function redactGraph(graph, currentInstanceId = "", currentSessionId = "") {
|
|
1108
1111
|
if (!graph) return null;
|
|
1109
1112
|
if (chainDetailMode() === "full") return graph;
|
|
1110
1113
|
const nodes = (graph.nodes || []).map((n) => {
|
|
1111
1114
|
const m = { ...n };
|
|
1112
|
-
|
|
1115
|
+
const inst = String(m.instance_id ?? "") || "";
|
|
1116
|
+
const sid = String(m.session_id ?? "") || "";
|
|
1117
|
+
const sameInstance = !!(inst && currentInstanceId && inst === String(currentInstanceId));
|
|
1118
|
+
const sameSessionFallback = !inst && !!currentSessionId && sid === String(currentSessionId);
|
|
1119
|
+
if (!(sameInstance || sameSessionFallback)) {
|
|
1113
1120
|
m.session_id = "<other-session>";
|
|
1114
1121
|
m.action_detail = "<\u5DF2\u9690\u85CF>";
|
|
1115
1122
|
m.resources = [];
|
|
1116
1123
|
}
|
|
1117
1124
|
return m;
|
|
1118
1125
|
});
|
|
1119
|
-
|
|
1126
|
+
const out = { nodes, edges: graph.edges || [] };
|
|
1127
|
+
for (const key of ["property_id", "property_short", "property_name", "property_expression"]) {
|
|
1128
|
+
if (graph[key] !== void 0) out[key] = graph[key];
|
|
1129
|
+
}
|
|
1130
|
+
return out;
|
|
1120
1131
|
}
|
|
1121
1132
|
function sessionSweepThreshold() {
|
|
1122
1133
|
return envInt("AGENT_MOSS_SESSION_SWEEP_THRESHOLD", 50);
|
|
@@ -8884,7 +8895,7 @@ function markIntegrity(actionDetail) {
|
|
|
8884
8895
|
}
|
|
8885
8896
|
return { integrity: "medium", isLowSource: false };
|
|
8886
8897
|
}
|
|
8887
|
-
function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId = "") {
|
|
8898
|
+
function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId = "", instanceId = "") {
|
|
8888
8899
|
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
8889
8900
|
return {
|
|
8890
8901
|
sessionId,
|
|
@@ -8893,13 +8904,14 @@ function initNode(sessionId, seq, actionType, actionDetail, timestamp, agentId =
|
|
|
8893
8904
|
actionDetail,
|
|
8894
8905
|
stage: markStage(actionDetail),
|
|
8895
8906
|
agentId: agentId || void 0,
|
|
8907
|
+
instanceId: instanceId || void 0,
|
|
8896
8908
|
resources: extractResources(actionDetail),
|
|
8897
8909
|
integrity,
|
|
8898
8910
|
isLowSource,
|
|
8899
8911
|
timestamp: timestamp || void 0
|
|
8900
8912
|
};
|
|
8901
8913
|
}
|
|
8902
|
-
function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId = "") {
|
|
8914
|
+
function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId = "", instanceId = "") {
|
|
8903
8915
|
const nodes = [];
|
|
8904
8916
|
const edges = [];
|
|
8905
8917
|
const stageFlags = /* @__PURE__ */ new Set();
|
|
@@ -8910,7 +8922,8 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId
|
|
|
8910
8922
|
actionType: String(a.actionType || ""),
|
|
8911
8923
|
actionDetail: ad,
|
|
8912
8924
|
calledAt: a.calledAt || void 0,
|
|
8913
|
-
agentId: a.agentId || agentId || void 0
|
|
8925
|
+
agentId: a.agentId || agentId || void 0,
|
|
8926
|
+
instanceId: a.instanceId || instanceId || void 0
|
|
8914
8927
|
});
|
|
8915
8928
|
}
|
|
8916
8929
|
if (aNext) {
|
|
@@ -8918,11 +8931,12 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId
|
|
|
8918
8931
|
actionType: String(aNext.actionType || ""),
|
|
8919
8932
|
actionDetail: String(aNext.actionDetail || ""),
|
|
8920
8933
|
calledAt: aNext.calledAt || void 0,
|
|
8921
|
-
agentId: aNext.agentId || agentId || void 0
|
|
8934
|
+
agentId: aNext.agentId || agentId || void 0,
|
|
8935
|
+
instanceId: aNext.instanceId || instanceId || void 0
|
|
8922
8936
|
});
|
|
8923
8937
|
}
|
|
8924
8938
|
details.forEach((d, seq) => {
|
|
8925
|
-
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt, d.agentId || "");
|
|
8939
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt, d.agentId || "", d.instanceId || "");
|
|
8926
8940
|
nodes.push(node);
|
|
8927
8941
|
if (node.stage) stageFlags.add(node.stage);
|
|
8928
8942
|
});
|
|
@@ -8934,12 +8948,18 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current", agentId
|
|
|
8934
8948
|
function buildMultiSessionGraph(sessions, aNext) {
|
|
8935
8949
|
const mg = { sessions: [], crossEdges: [] };
|
|
8936
8950
|
if (!sessions || sessions.length === 0) {
|
|
8937
|
-
mg.sessions.push(buildSessionGraph([], aNext, "current"));
|
|
8951
|
+
mg.sessions.push(buildSessionGraph([], aNext, "current", "", aNext?.instanceId || ""));
|
|
8938
8952
|
return mg;
|
|
8939
8953
|
}
|
|
8940
8954
|
for (const s of sessions) {
|
|
8941
8955
|
const sid = String(s.sessionId || "s");
|
|
8942
|
-
mg.sessions.push(buildSessionGraph(
|
|
8956
|
+
mg.sessions.push(buildSessionGraph(
|
|
8957
|
+
s.actionHistory || [],
|
|
8958
|
+
void 0,
|
|
8959
|
+
sid,
|
|
8960
|
+
s.agentId || "",
|
|
8961
|
+
s.instanceId || ""
|
|
8962
|
+
));
|
|
8943
8963
|
}
|
|
8944
8964
|
if (aNext) {
|
|
8945
8965
|
const last = mg.sessions[mg.sessions.length - 1];
|
|
@@ -8950,13 +8970,14 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
8950
8970
|
String(aNext.actionType || ""),
|
|
8951
8971
|
String(aNext.actionDetail || ""),
|
|
8952
8972
|
aNext.calledAt || void 0,
|
|
8953
|
-
aNext.agentId || ""
|
|
8973
|
+
aNext.agentId || "",
|
|
8974
|
+
aNext.instanceId || ""
|
|
8954
8975
|
));
|
|
8955
8976
|
if (last.nodes.length > 1) {
|
|
8956
8977
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
8957
8978
|
}
|
|
8958
8979
|
} else {
|
|
8959
|
-
mg.sessions.push(buildSessionGraph([], aNext, "current"));
|
|
8980
|
+
mg.sessions.push(buildSessionGraph([], aNext, "current", "", aNext.instanceId || ""));
|
|
8960
8981
|
}
|
|
8961
8982
|
}
|
|
8962
8983
|
addCrossDataEdges(mg);
|
|
@@ -9020,7 +9041,8 @@ function graphFromPath(nodes, path6, edgeType = "next", propertyMeta, roles, wit
|
|
|
9020
9041
|
seq: item.seq,
|
|
9021
9042
|
stage: n ? n.stage : "",
|
|
9022
9043
|
action_detail: n ? n.actionDetail : item.detail,
|
|
9023
|
-
resources: n ? [...n.resources].sort() : []
|
|
9044
|
+
resources: n ? [...n.resources].sort() : [],
|
|
9045
|
+
instance_id: n ? n.instanceId || "" : ""
|
|
9024
9046
|
});
|
|
9025
9047
|
if (gNodes.length > 1) {
|
|
9026
9048
|
gEdges.push({ from: gNodes.length - 2, to: gNodes.length - 1, type: edgeType });
|
|
@@ -9188,7 +9210,8 @@ function checkSensitiveDataFlow(graph) {
|
|
|
9188
9210
|
stage: n.stage,
|
|
9189
9211
|
action_detail: n.actionDetail,
|
|
9190
9212
|
resources: [...n.resources].sort(),
|
|
9191
|
-
role
|
|
9213
|
+
role,
|
|
9214
|
+
instance_id: n.instanceId || ""
|
|
9192
9215
|
});
|
|
9193
9216
|
if (k > 0) {
|
|
9194
9217
|
const prev = chain[k - 1];
|
|
@@ -9831,7 +9854,7 @@ var init_stateful = __esm({
|
|
|
9831
9854
|
for (const s of sessions || []) {
|
|
9832
9855
|
const sid = String(s.sessionId || "s");
|
|
9833
9856
|
for (const a of s.actionHistory || []) {
|
|
9834
|
-
const node = this.appendNode(a, sid);
|
|
9857
|
+
const node = this.appendNode(a, sid, false, s.agentId || "", s.instanceId || "");
|
|
9835
9858
|
if (!node) {
|
|
9836
9859
|
continue;
|
|
9837
9860
|
}
|
|
@@ -9845,8 +9868,8 @@ var init_stateful = __esm({
|
|
|
9845
9868
|
}
|
|
9846
9869
|
/** 增量推进:把当前动作追加到时间线 → 链指针推进 → 判定。 */
|
|
9847
9870
|
advance(args) {
|
|
9848
|
-
const { aNext, sessionId = "current", isError = false, agentId = "" } = args;
|
|
9849
|
-
const node = this.appendNode(aNext, sessionId, isError, agentId);
|
|
9871
|
+
const { aNext, sessionId = "current", isError = false, agentId = "", instanceId = "" } = args;
|
|
9872
|
+
const node = this.appendNode(aNext, sessionId, isError, agentId, instanceId);
|
|
9850
9873
|
if (!node) {
|
|
9851
9874
|
return { seq: this.seqNext, node: null, matched: null, pendingPrefixes: this.pendingPrefixes, exfil: [], shouldBlock: false };
|
|
9852
9875
|
}
|
|
@@ -9866,7 +9889,7 @@ var init_stateful = __esm({
|
|
|
9866
9889
|
}
|
|
9867
9890
|
};
|
|
9868
9891
|
}
|
|
9869
|
-
appendNode(action, sessionId, isError = false, agentId = "") {
|
|
9892
|
+
appendNode(action, sessionId, isError = false, agentId = "", instanceId = "") {
|
|
9870
9893
|
const ad = String(action.actionDetail || "");
|
|
9871
9894
|
const at = String(action.actionType || "");
|
|
9872
9895
|
if (!ad) return null;
|
|
@@ -9884,6 +9907,7 @@ var init_stateful = __esm({
|
|
|
9884
9907
|
instances: extractInstances(ad, stage),
|
|
9885
9908
|
isError,
|
|
9886
9909
|
agentId: String(action.agentId || agentId || ""),
|
|
9910
|
+
instanceId: String(action.instanceId || instanceId || ""),
|
|
9887
9911
|
lifecycle: lifecycleFor(ad, stage, isError),
|
|
9888
9912
|
timestamp: typeof action.calledAt === "string" ? action.calledAt : _StatefulChainTracker.now()
|
|
9889
9913
|
};
|
|
@@ -10027,7 +10051,8 @@ var init_stateful = __esm({
|
|
|
10027
10051
|
seq: n.seq,
|
|
10028
10052
|
stage: n.stage,
|
|
10029
10053
|
timestamp: n.timestamp,
|
|
10030
|
-
agentId: n.agentId
|
|
10054
|
+
agentId: n.agentId,
|
|
10055
|
+
instanceId: n.instanceId
|
|
10031
10056
|
});
|
|
10032
10057
|
const idx = stages.indexOf(n.stage);
|
|
10033
10058
|
if (idx + 1 < stages.length) {
|
|
@@ -10050,7 +10075,8 @@ var init_stateful = __esm({
|
|
|
10050
10075
|
stage: p.stage,
|
|
10051
10076
|
action_detail: n ? n.actionDetail : "",
|
|
10052
10077
|
resources: n ? [...n.resources].sort() : [],
|
|
10053
|
-
role: stages[i] || ""
|
|
10078
|
+
role: stages[i] || "",
|
|
10079
|
+
instance_id: p.instanceId || ""
|
|
10054
10080
|
};
|
|
10055
10081
|
});
|
|
10056
10082
|
const gEdges = [];
|
|
@@ -10118,7 +10144,7 @@ var init_stateful = __esm({
|
|
|
10118
10144
|
risk_level: "critical",
|
|
10119
10145
|
path: chain.map((j) => {
|
|
10120
10146
|
const n = this.nodes_[j];
|
|
10121
|
-
return [n.sessionId, n.seq, n.actionDetail.slice(0, 60), n.timestamp];
|
|
10147
|
+
return [n.sessionId, n.seq, n.actionDetail.slice(0, 60), n.timestamp, null, n.instanceId];
|
|
10122
10148
|
}),
|
|
10123
10149
|
graph: this.taintGraph(chain)
|
|
10124
10150
|
}];
|
|
@@ -10150,7 +10176,8 @@ var init_stateful = __esm({
|
|
|
10150
10176
|
stage: n.stage,
|
|
10151
10177
|
action_detail: n.actionDetail,
|
|
10152
10178
|
resources: [...n.resources].sort(),
|
|
10153
|
-
role
|
|
10179
|
+
role,
|
|
10180
|
+
instance_id: n.instanceId
|
|
10154
10181
|
});
|
|
10155
10182
|
if (k > 0) {
|
|
10156
10183
|
const prev = chain[k - 1];
|
|
@@ -10222,6 +10249,8 @@ var init_stateful = __esm({
|
|
|
10222
10249
|
seq: Number(raw.seq || 0),
|
|
10223
10250
|
sessionId: String(raw.sessionId || ""),
|
|
10224
10251
|
agentId: String(raw.agentId || ""),
|
|
10252
|
+
instanceId: String(raw.instanceId || ""),
|
|
10253
|
+
// 旧快照无此字段 → 空
|
|
10225
10254
|
actionType: String(raw.actionType || ""),
|
|
10226
10255
|
actionDetail: String(raw.actionDetail || ""),
|
|
10227
10256
|
stage: String(raw.stage || ""),
|
|
@@ -10366,9 +10395,9 @@ var init_chain_state = __esm({
|
|
|
10366
10395
|
delete this.data[agentId];
|
|
10367
10396
|
this._scheduleWrite();
|
|
10368
10397
|
}
|
|
10369
|
-
applyAction(agentId, aNext, sessionId, isError = false, sourceAgent = "") {
|
|
10398
|
+
applyAction(agentId, aNext, sessionId, isError = false, sourceAgent = "", instanceId = "") {
|
|
10370
10399
|
const t = this.load(agentId) || new StatefulChainTracker(agentId);
|
|
10371
|
-
const r = t.advance({ aNext, sessionId, isError, agentId: sourceAgent });
|
|
10400
|
+
const r = t.advance({ aNext, sessionId, isError, agentId: sourceAgent, instanceId });
|
|
10372
10401
|
this.save(t);
|
|
10373
10402
|
return r;
|
|
10374
10403
|
}
|
|
@@ -10686,12 +10715,21 @@ async function runAnalysis(input) {
|
|
|
10686
10715
|
formalSessions.push({
|
|
10687
10716
|
sessionId: s.sessionId || "s",
|
|
10688
10717
|
...s.agentId ? { agentId: s.agentId } : {},
|
|
10718
|
+
...s.instanceId ? { instanceId: s.instanceId } : {},
|
|
10689
10719
|
actionHistory: s.actionHistory || []
|
|
10690
10720
|
});
|
|
10691
10721
|
}
|
|
10692
10722
|
}
|
|
10693
|
-
formalSessions.push({
|
|
10694
|
-
|
|
10723
|
+
formalSessions.push({
|
|
10724
|
+
sessionId: "current",
|
|
10725
|
+
agentId: input.agentId,
|
|
10726
|
+
instanceId: input.instanceId || "",
|
|
10727
|
+
actionHistory: input.actionHistory
|
|
10728
|
+
});
|
|
10729
|
+
const formalResult = formalEngine.verify(formalSessions, {
|
|
10730
|
+
...input.aNext,
|
|
10731
|
+
instanceId: input.instanceId || ""
|
|
10732
|
+
});
|
|
10695
10733
|
if (!formalResult.verified) {
|
|
10696
10734
|
const v = formalResult.violations[0];
|
|
10697
10735
|
if (isFormalObserveMode()) {
|
|
@@ -11062,6 +11100,8 @@ var AnalyzeRequestSchema = z.object({
|
|
|
11062
11100
|
session_id: z.string(),
|
|
11063
11101
|
/** 来源 agent(AgentGate 逐会话带上):记录在链路径里供告警/取证,不参与链匹配。 */
|
|
11064
11102
|
agent_id: z.string().optional(),
|
|
11103
|
+
/** 来源实例:仅用于展示层脱敏(同实例不隐藏),不参与链匹配。 */
|
|
11104
|
+
instance_id: z.string().optional(),
|
|
11065
11105
|
action_history: z.array(ActionItemSchema).default([])
|
|
11066
11106
|
})).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)."),
|
|
11067
11107
|
a_next: ActionItemSchema.describe("Next action to be executed"),
|
|
@@ -11069,6 +11109,7 @@ var AnalyzeRequestSchema = z.object({
|
|
|
11069
11109
|
os_type: z.string().default("").describe("OS type: 'linux', 'windows', or empty for auto-detect"),
|
|
11070
11110
|
cwd: z.string().default("").describe("Current working directory"),
|
|
11071
11111
|
agent_id: z.string().default("").describe("Caller agent identifier, e.g. 'xiaoo' / 'opencode' / 'opendesk'. Empty = generic mode (no agent-specific rules)."),
|
|
11112
|
+
instance_id: z.string().default("").describe("Agent installation/instance identifier. Used only for display-layer redaction: nodes from the same instance are returned unredacted. Does not affect detection."),
|
|
11072
11113
|
metadata: z.record(z.unknown()).optional().describe("Extended metadata")
|
|
11073
11114
|
});
|
|
11074
11115
|
var AnalyzeResponseSchema = z.object({
|
|
@@ -11106,7 +11147,9 @@ var AnalyzeResponseSchema = z.object({
|
|
|
11106
11147
|
// 节点在性质中的角色:source/carrier/sink(P2)或阶段名(P1)
|
|
11107
11148
|
role: z.string().optional(),
|
|
11108
11149
|
// 是否为违例见证节点(当前动作补全链 / 触发外传)
|
|
11109
|
-
witness: z.boolean().optional()
|
|
11150
|
+
witness: z.boolean().optional(),
|
|
11151
|
+
// 来源实例(仅展示层脱敏:同实例不隐藏)
|
|
11152
|
+
instance_id: z.string().optional()
|
|
11110
11153
|
})
|
|
11111
11154
|
),
|
|
11112
11155
|
edges: z.array(
|
|
@@ -11998,6 +12041,9 @@ async function analyzeRoute(c) {
|
|
|
11998
12041
|
`[AgentMoss] \u26A0\uFE0F \u8DE8\u4F1A\u8BDD\u6279\u91CF\u8BBF\u95EE: key=${_sweepKey} \u7A97\u53E3\u5185 ${_sweepN} \u4E2A\u4E0D\u540C session\uFF08\u9608\u503C ${sessionSweepThreshold()}\uFF09`
|
|
11999
12042
|
);
|
|
12000
12043
|
}
|
|
12044
|
+
const instanceId = String(
|
|
12045
|
+
req.instance_id || req.metadata?.instance_id || ""
|
|
12046
|
+
);
|
|
12001
12047
|
const result = await analyze({
|
|
12002
12048
|
sessionId: req.session_id,
|
|
12003
12049
|
promptSession: req.prompt_session,
|
|
@@ -12013,8 +12059,9 @@ async function analyzeRoute(c) {
|
|
|
12013
12059
|
})),
|
|
12014
12060
|
sessionHistory: (req.session_history || []).map((s) => ({
|
|
12015
12061
|
sessionId: s.session_id,
|
|
12016
|
-
// 来源 agent
|
|
12062
|
+
// 来源 agent/实例(AgentGate 逐会话带上,用于链路径取证/展示脱敏;不参与链匹配)
|
|
12017
12063
|
...s.agent_id ? { agentId: s.agent_id } : {},
|
|
12064
|
+
...s.instance_id ? { instanceId: s.instance_id } : {},
|
|
12018
12065
|
actionHistory: (s.action_history || []).map((h) => ({
|
|
12019
12066
|
actionType: h.action_type,
|
|
12020
12067
|
actionDetail: h.action_detail,
|
|
@@ -12038,11 +12085,13 @@ async function analyzeRoute(c) {
|
|
|
12038
12085
|
})),
|
|
12039
12086
|
aNext: {
|
|
12040
12087
|
actionType: req.a_next.action_type,
|
|
12041
|
-
actionDetail: req.a_next.action_detail
|
|
12088
|
+
actionDetail: req.a_next.action_detail,
|
|
12089
|
+
instanceId
|
|
12042
12090
|
},
|
|
12043
12091
|
reason: req.reason,
|
|
12044
12092
|
osType,
|
|
12045
12093
|
cwd: req.cwd,
|
|
12094
|
+
instanceId,
|
|
12046
12095
|
// agent_id:AgentGate V1 normalizer 历史上把 agent_type 塞 metadata,
|
|
12047
12096
|
// 顶层为空时兜底(OpenDesk 的 agent-moss 需 agent_id 加载专属规则)。
|
|
12048
12097
|
agentId,
|
|
@@ -12078,8 +12127,9 @@ async function analyzeRoute(c) {
|
|
|
12078
12127
|
{ actionType: req.a_next.action_type, actionDetail: req.a_next.action_detail },
|
|
12079
12128
|
req.session_id,
|
|
12080
12129
|
Boolean(meta.is_error),
|
|
12081
|
-
agentId
|
|
12130
|
+
agentId,
|
|
12082
12131
|
// 来源:真实 agent(桶 key 可能是 __system__)
|
|
12132
|
+
instanceId
|
|
12083
12133
|
);
|
|
12084
12134
|
const judgment = incMatchedToDeny(inc);
|
|
12085
12135
|
if (judgment) {
|
|
@@ -12100,8 +12150,8 @@ async function analyzeRoute(c) {
|
|
|
12100
12150
|
confidence: 90,
|
|
12101
12151
|
analysis_duration_ms: Math.round((performance.now() - t0) * 10) / 10,
|
|
12102
12152
|
// 跨会话节点脱敏(时间线按 agent_id 共享,原样返回等于泄露别人的命令原文)
|
|
12103
|
-
violation_chain: redactChain(judgment.violation_chain, req.session_id),
|
|
12104
|
-
violation_graph: redactGraph(judgment.violation_graph, req.session_id)
|
|
12153
|
+
violation_chain: redactChain(judgment.violation_chain, instanceId, req.session_id),
|
|
12154
|
+
violation_graph: redactGraph(judgment.violation_graph, instanceId, req.session_id)
|
|
12105
12155
|
})
|
|
12106
12156
|
);
|
|
12107
12157
|
}
|
|
@@ -12123,7 +12173,7 @@ async function analyzeRoute(c) {
|
|
|
12123
12173
|
confidence: result.confidence,
|
|
12124
12174
|
analysis_duration_ms: Math.round(durationMs * 10) / 10,
|
|
12125
12175
|
violation_chain: result.violation_chain ?? [],
|
|
12126
|
-
violation_graph: redactGraph(result.violation_graph, req.session_id)
|
|
12176
|
+
violation_graph: redactGraph(result.violation_graph, instanceId, req.session_id)
|
|
12127
12177
|
})
|
|
12128
12178
|
);
|
|
12129
12179
|
} catch (err) {
|