@kenhkl/agent-moss 0.12.8 → 0.13.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/dist/agents/__pycache__/__init__.cpython-310.pyc +0 -0
- package/dist/agents/__pycache__/__init__.cpython-311.pyc +0 -0
- package/dist/agents/__pycache__/base.cpython-310.pyc +0 -0
- package/dist/agents/__pycache__/base.cpython-311.pyc +0 -0
- package/dist/cli.js +682 -119
- package/dist/cli.js.map +1 -1
- package/dist/engine/coordinator.js +678 -174
- package/dist/engine/coordinator.js.map +1 -1
- package/dist/rules/mc_rules.json +137 -0
- package/dist/rules/tool_registry.json +25 -0
- package/dist/scenarios/__init__.py +29 -0
- package/dist/scenarios/__pycache__/__init__.cpython-310.pyc +0 -0
- package/dist/scenarios/__pycache__/__init__.cpython-311.pyc +0 -0
- package/dist/scenarios/__pycache__/__init__.cpython-312.pyc +0 -0
- package/dist/server.js +752 -188
- package/dist/server.js.map +1 -1
- package/dist/static/index.html +85 -9
- package/package.json +1 -1
|
@@ -2,6 +2,12 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
6
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
7
|
+
}) : x)(function(x) {
|
|
8
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
9
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
10
|
+
});
|
|
5
11
|
var __esm = (fn, res) => function __init() {
|
|
6
12
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
13
|
};
|
|
@@ -127,6 +133,7 @@ __export(config_exports, {
|
|
|
127
133
|
getRetryConfig: () => getRetryConfig,
|
|
128
134
|
getTimeoutConfig: () => getTimeoutConfig,
|
|
129
135
|
isBrainEnabled: () => isBrainEnabled,
|
|
136
|
+
isFormalObserveMode: () => isFormalObserveMode,
|
|
130
137
|
isHeuristicEnabled: () => isHeuristicEnabled,
|
|
131
138
|
isLLMAvailable: () => isLLMAvailable,
|
|
132
139
|
isLogicRulesEnabled: () => isLogicRulesEnabled,
|
|
@@ -242,6 +249,7 @@ function getCustomRules() {
|
|
|
242
249
|
}
|
|
243
250
|
function isLLMAvailable() {
|
|
244
251
|
if (process.env.AGENT_MOSS_DISABLE_LLM === "1") return false;
|
|
252
|
+
if (!layerEnabledOrDefault("L3_llm_analysis")) return false;
|
|
245
253
|
return llmConfig.apiKey.length > 0;
|
|
246
254
|
}
|
|
247
255
|
async function probeLLMConnection(timeoutMs = 8e3) {
|
|
@@ -306,13 +314,26 @@ function getProviderHeaders(provider) {
|
|
|
306
314
|
return PROVIDER_HEADERS[provider] || {};
|
|
307
315
|
}
|
|
308
316
|
function isHeuristicEnabled() {
|
|
309
|
-
|
|
317
|
+
if (process.env.AGENT_MOSS_DISABLE_HEURISTIC === "1") return false;
|
|
318
|
+
return layerEnabledOrDefault("L1_heuristic");
|
|
319
|
+
}
|
|
320
|
+
function layerEnabledOrDefault(key) {
|
|
321
|
+
try {
|
|
322
|
+
const { isLayerEnabled: isLayerEnabled2 } = __require("../infra/runtime-config");
|
|
323
|
+
return isLayerEnabled2(key);
|
|
324
|
+
} catch {
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
310
327
|
}
|
|
311
328
|
function isBrainEnabled() {
|
|
312
329
|
return process.env.AGENT_MOSS_BRAIN_ENABLED === "1";
|
|
313
330
|
}
|
|
314
331
|
function isLogicRulesEnabled() {
|
|
315
|
-
|
|
332
|
+
if (process.env.AGENT_MOSS_DISABLE_LOGIC_RULES === "1") return false;
|
|
333
|
+
return layerEnabledOrDefault("L2_logic_rules");
|
|
334
|
+
}
|
|
335
|
+
function isFormalObserveMode() {
|
|
336
|
+
return process.env.AGENT_MOSS_FORMAL_OBSERVE === "1";
|
|
316
337
|
}
|
|
317
338
|
var timeoutConfig, retryConfig, llmConfig, __configModuleDir, USER_RULES_PATHS, customRules, PROVIDER_HEADERS;
|
|
318
339
|
var init_config = __esm({
|
|
@@ -570,8 +591,12 @@ var init_inline_analyzer = __esm({
|
|
|
570
591
|
|
|
571
592
|
// src/infra/rules-loader.ts
|
|
572
593
|
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
573
|
-
import { resolve, dirname } from "path";
|
|
594
|
+
import { resolve, dirname, join as join2 } from "path";
|
|
574
595
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
596
|
+
import { homedir as homedir2 } from "os";
|
|
597
|
+
function dataRootDir() {
|
|
598
|
+
return process.env.AGENT_MOSS_DATA_DIR || join2(homedir2(), ".config", "agentmoss");
|
|
599
|
+
}
|
|
575
600
|
function findRulesFile(name) {
|
|
576
601
|
for (const dir of RULES_DIR_CANDS) {
|
|
577
602
|
const p = resolve(dir, name);
|
|
@@ -597,6 +622,24 @@ function loadL2() {
|
|
|
597
622
|
function loadL3() {
|
|
598
623
|
return loadJson("l3_rules.json");
|
|
599
624
|
}
|
|
625
|
+
function loadMC() {
|
|
626
|
+
const mc = loadJson("mc_rules.json");
|
|
627
|
+
const rules = mc.rules || [];
|
|
628
|
+
try {
|
|
629
|
+
const rt = (init_runtime_config(), __toCommonJS(runtime_config_exports));
|
|
630
|
+
if (rules.length > 0 && typeof rt.hasRuntimeConfig === "function" && rt.hasRuntimeConfig()) {
|
|
631
|
+
const rtRules = rt.loadRuntimeConfig()?.L2_4?.ltl_rules?.rules || [];
|
|
632
|
+
const enabledById = {};
|
|
633
|
+
for (const r of rtRules) if (r?.id) enabledById[r.id] = r.enabled !== false;
|
|
634
|
+
for (const r of rules) if (r?.id && r.id in enabledById) r.enabled = enabledById[r.id];
|
|
635
|
+
}
|
|
636
|
+
} catch {
|
|
637
|
+
}
|
|
638
|
+
return mc;
|
|
639
|
+
}
|
|
640
|
+
function loadToolRegistry() {
|
|
641
|
+
return loadJson("tool_registry.json");
|
|
642
|
+
}
|
|
600
643
|
var __filename2, __dirname2, RULES_DIR_CANDS;
|
|
601
644
|
var init_rules_loader = __esm({
|
|
602
645
|
"src/infra/rules-loader.ts"() {
|
|
@@ -606,6 +649,10 @@ var init_rules_loader = __esm({
|
|
|
606
649
|
__dirname2 = dirname(__filename2);
|
|
607
650
|
RULES_DIR_CANDS = (() => {
|
|
608
651
|
const cands = [
|
|
652
|
+
// 用户数据目录覆盖优先(与 Python rules_loader._load_json 的
|
|
653
|
+
// <data_root>/rules/<name> 优先逻辑对齐)。用户安装 pip/npm 包后把自定义
|
|
654
|
+
// mc_rules.json 放到 <data_root>/rules/ 即可覆盖内置默认,无需改源码。
|
|
655
|
+
resolve(dataRootDir(), "rules"),
|
|
609
656
|
// dist: __dirname=dist/ → dist/rules;__dirname=dist/engine/ → dist/engine/../rules=dist/rules
|
|
610
657
|
resolve(__dirname2, "../rules"),
|
|
611
658
|
resolve(__dirname2, "rules"),
|
|
@@ -1343,6 +1390,7 @@ var init_skill_loader = __esm({
|
|
|
1343
1390
|
// src/infra/runtime-config.ts
|
|
1344
1391
|
var runtime_config_exports = {};
|
|
1345
1392
|
__export(runtime_config_exports, {
|
|
1393
|
+
DEFAULT_LAYERS: () => DEFAULT_LAYERS,
|
|
1346
1394
|
DENY_MODE_LABELS: () => DENY_MODE_LABELS,
|
|
1347
1395
|
addAgentRule: () => addAgentRule,
|
|
1348
1396
|
addCustomRule: () => addCustomRule,
|
|
@@ -1394,7 +1442,7 @@ __export(runtime_config_exports, {
|
|
|
1394
1442
|
updateSkillEnabled: () => updateSkillEnabled
|
|
1395
1443
|
});
|
|
1396
1444
|
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3 } from "fs";
|
|
1397
|
-
import { join as
|
|
1445
|
+
import { join as join3 } from "path";
|
|
1398
1446
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1399
1447
|
import { dirname as dirname3 } from "path";
|
|
1400
1448
|
function runtimeDir() {
|
|
@@ -1418,6 +1466,7 @@ function emptyRuntimeConfig() {
|
|
|
1418
1466
|
L1_rules: {},
|
|
1419
1467
|
L2_rules: {},
|
|
1420
1468
|
L3_skills: {},
|
|
1469
|
+
L2_4: {},
|
|
1421
1470
|
agent_rules: {},
|
|
1422
1471
|
scenario_rules: {}
|
|
1423
1472
|
};
|
|
@@ -1445,6 +1494,7 @@ function loadRuntimeConfig() {
|
|
|
1445
1494
|
L1_rules: merged.L1_rules || {},
|
|
1446
1495
|
L2_rules: merged.L2_rules || {},
|
|
1447
1496
|
L3_skills: merged.L3_skills || {},
|
|
1497
|
+
L2_4: merged.L2_4 || {},
|
|
1448
1498
|
agent_rules: merged.agent_rules || {},
|
|
1449
1499
|
scenario_rules: merged.scenario_rules || {}
|
|
1450
1500
|
};
|
|
@@ -1692,7 +1742,7 @@ function _scenarioRulesToDefaults() {
|
|
|
1692
1742
|
return out;
|
|
1693
1743
|
}
|
|
1694
1744
|
for (const scenarioId of entries) {
|
|
1695
|
-
const rulesFile =
|
|
1745
|
+
const rulesFile = join3(scenDir, scenarioId, "rules.json");
|
|
1696
1746
|
if (!existsSync4(rulesFile)) continue;
|
|
1697
1747
|
let data;
|
|
1698
1748
|
try {
|
|
@@ -1741,7 +1791,7 @@ function _agentRulesToDefaults() {
|
|
|
1741
1791
|
return out;
|
|
1742
1792
|
}
|
|
1743
1793
|
for (const agentId of entries) {
|
|
1744
|
-
const rulesFile =
|
|
1794
|
+
const rulesFile = join3(agentsDir, agentId, "rules.json");
|
|
1745
1795
|
if (!existsSync4(rulesFile)) continue;
|
|
1746
1796
|
let data;
|
|
1747
1797
|
try {
|
|
@@ -1782,7 +1832,7 @@ function _agentRulesToDefaults() {
|
|
|
1782
1832
|
function generateSourceDefaults() {
|
|
1783
1833
|
return {
|
|
1784
1834
|
version: 1,
|
|
1785
|
-
layers: {
|
|
1835
|
+
layers: { ...DEFAULT_LAYERS },
|
|
1786
1836
|
L1_rules: {
|
|
1787
1837
|
dangerous_commands: {
|
|
1788
1838
|
category_enabled: true,
|
|
@@ -1821,10 +1871,45 @@ function generateSourceDefaults() {
|
|
|
1821
1871
|
user_custom: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49 L2 \u903B\u8F91\u89C4\u5219", rules: [] }
|
|
1822
1872
|
},
|
|
1823
1873
|
L3_skills: _l3SkillsToRules(),
|
|
1874
|
+
L2_4: _ltlRulesToRuntime(),
|
|
1824
1875
|
agent_rules: _agentRulesToDefaults(),
|
|
1825
1876
|
scenario_rules: _scenarioRulesToDefaults()
|
|
1826
1877
|
};
|
|
1827
1878
|
}
|
|
1879
|
+
function _ltlRulesToRuntime() {
|
|
1880
|
+
const cands = [
|
|
1881
|
+
join3(__dirname4, "..", "rules"),
|
|
1882
|
+
join3(__dirname4, "..", "..", "..", "agent_moss", "rules"),
|
|
1883
|
+
join3(process.cwd(), "agent_moss", "rules")
|
|
1884
|
+
];
|
|
1885
|
+
let mc = {};
|
|
1886
|
+
for (const dir of cands) {
|
|
1887
|
+
const p = join3(dir, "mc_rules.json");
|
|
1888
|
+
if (existsSync4(p)) {
|
|
1889
|
+
try {
|
|
1890
|
+
mc = JSON.parse(readFileSync4(p, "utf-8")) || {};
|
|
1891
|
+
} catch {
|
|
1892
|
+
mc = {};
|
|
1893
|
+
}
|
|
1894
|
+
break;
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
const rules = mc.rules || [];
|
|
1898
|
+
return {
|
|
1899
|
+
ltl_rules: {
|
|
1900
|
+
category_enabled: true,
|
|
1901
|
+
category_desc: "LTL \u653B\u51FB\u6A21\u5F0F\u89C4\u5219\uFF08\u65F6\u5E8F\u653B\u51FB\u68C0\u6D4B\uFF0C\u5148 A \u540E B\uFF09",
|
|
1902
|
+
rules: rules.map((r) => ({
|
|
1903
|
+
id: r.id,
|
|
1904
|
+
reason: r.reason || "",
|
|
1905
|
+
risk_level: r.risk_level || "high",
|
|
1906
|
+
action: r.action || "block",
|
|
1907
|
+
enabled: true,
|
|
1908
|
+
builtin: true
|
|
1909
|
+
}))
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1828
1913
|
function normalizePatternForFingerprint(pattern) {
|
|
1829
1914
|
return pattern.replace(/\\\//g, "/");
|
|
1830
1915
|
}
|
|
@@ -1974,6 +2059,7 @@ function mergeConfig(userCfg, srcDefaults) {
|
|
|
1974
2059
|
);
|
|
1975
2060
|
_mergeRuleCategories(cfg, srcDefaults, "L1_rules");
|
|
1976
2061
|
_mergeRuleCategories(cfg, srcDefaults, "L2_rules");
|
|
2062
|
+
_mergeRuleCategories(cfg, srcDefaults, "L2_4");
|
|
1977
2063
|
_mergeSkillCategories(cfg, srcDefaults, "L3_skills");
|
|
1978
2064
|
_mergeAgentRules(cfg, srcDefaults);
|
|
1979
2065
|
_mergeAgentRules(cfg, srcDefaults, "scenario_rules");
|
|
@@ -2166,12 +2252,12 @@ function deleteCustomRule(layer, category, ruleId) {
|
|
|
2166
2252
|
function addCustomSkill(skillId, category, keywords, content) {
|
|
2167
2253
|
_validateSkillId(skillId);
|
|
2168
2254
|
const runtime = loadRuntimeConfig();
|
|
2169
|
-
const skillsDir =
|
|
2255
|
+
const skillsDir = join3(RUNTIME_CONFIG_DIR, "agent_moss_skills");
|
|
2170
2256
|
try {
|
|
2171
2257
|
mkdirSync(skillsDir, { recursive: true });
|
|
2172
2258
|
} catch {
|
|
2173
2259
|
}
|
|
2174
|
-
writeFileSync(
|
|
2260
|
+
writeFileSync(join3(skillsDir, `${skillId}.md`), content, "utf-8");
|
|
2175
2261
|
const l3 = runtime.L3_skills || (runtime.L3_skills = {});
|
|
2176
2262
|
const cat = l3[category] || (l3[category] = { category_enabled: true, category_desc: "", skills: [] });
|
|
2177
2263
|
(cat.skills || (cat.skills = [])).push({ id: skillId, keywords, enabled: true, builtin: false });
|
|
@@ -2186,7 +2272,7 @@ function deleteCustomSkill(skillId, category) {
|
|
|
2186
2272
|
if (idx >= 0) {
|
|
2187
2273
|
if (skills[idx].builtin) return null;
|
|
2188
2274
|
skills.splice(idx, 1);
|
|
2189
|
-
const skillPath =
|
|
2275
|
+
const skillPath = join3(RUNTIME_CONFIG_DIR, "agent_moss_skills", `${skillId}.md`);
|
|
2190
2276
|
try {
|
|
2191
2277
|
if (existsSync4(skillPath)) unlinkSync(skillPath);
|
|
2192
2278
|
} catch {
|
|
@@ -2380,7 +2466,7 @@ function updateScenarioCategoryEnabled(scenarioId, category, enabled) {
|
|
|
2380
2466
|
saveRuntimeConfig(runtime);
|
|
2381
2467
|
return runtime;
|
|
2382
2468
|
}
|
|
2383
|
-
var __dirname4, ENV_RUNTIME_CONFIG_PATH, RUNTIME_CONFIG_DIR, RUNTIME_CONFIG_PATH, LAYER_DISABLE_ENV, DENY_MODE_LABELS, _AGENTS_DIR_PROD, _AGENTS_DIR_DEV, _SCENARIOS_DIR_PROD, _SCENARIOS_DIR_DEV, SKILL_ID_RE;
|
|
2469
|
+
var __dirname4, ENV_RUNTIME_CONFIG_PATH, RUNTIME_CONFIG_DIR, RUNTIME_CONFIG_PATH, LAYER_DISABLE_ENV, DEFAULT_LAYERS, DENY_MODE_LABELS, _AGENTS_DIR_PROD, _AGENTS_DIR_DEV, _SCENARIOS_DIR_PROD, _SCENARIOS_DIR_DEV, SKILL_ID_RE;
|
|
2384
2470
|
var init_runtime_config = __esm({
|
|
2385
2471
|
"src/infra/runtime-config.ts"() {
|
|
2386
2472
|
"use strict";
|
|
@@ -2392,21 +2478,28 @@ var init_runtime_config = __esm({
|
|
|
2392
2478
|
__dirname4 = dirname3(fileURLToPath5(import.meta.url));
|
|
2393
2479
|
ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
|
|
2394
2480
|
RUNTIME_CONFIG_DIR = runtimeDir();
|
|
2395
|
-
RUNTIME_CONFIG_PATH =
|
|
2481
|
+
RUNTIME_CONFIG_PATH = join3(RUNTIME_CONFIG_DIR, "agent_moss_runtime.json");
|
|
2396
2482
|
LAYER_DISABLE_ENV = {
|
|
2397
2483
|
L1_heuristic: "AGENT_MOSS_DISABLE_HEURISTIC",
|
|
2398
2484
|
L2_logic_rules: "AGENT_MOSS_DISABLE_LOGIC_RULES",
|
|
2399
2485
|
L3_llm_analysis: "AGENT_MOSS_DISABLE_LLM"
|
|
2400
2486
|
};
|
|
2487
|
+
DEFAULT_LAYERS = {
|
|
2488
|
+
L1_heuristic: true,
|
|
2489
|
+
L2_logic_rules: true,
|
|
2490
|
+
L3_llm_analysis: true,
|
|
2491
|
+
agent_rules_enabled: true,
|
|
2492
|
+
scenario_rules_enabled: true
|
|
2493
|
+
};
|
|
2401
2494
|
DENY_MODE_LABELS = {
|
|
2402
2495
|
deny_write: "\u4EC5\u62E6\u622A\u5199\u5165",
|
|
2403
2496
|
deny_read: "\u4EC5\u62E6\u622A\u8BFB\u53D6",
|
|
2404
2497
|
deny_both: "\u8BFB\u5199\u5747\u62E6\u622A"
|
|
2405
2498
|
};
|
|
2406
|
-
_AGENTS_DIR_PROD =
|
|
2407
|
-
_AGENTS_DIR_DEV =
|
|
2408
|
-
_SCENARIOS_DIR_PROD =
|
|
2409
|
-
_SCENARIOS_DIR_DEV =
|
|
2499
|
+
_AGENTS_DIR_PROD = join3(__dirname4, "agents");
|
|
2500
|
+
_AGENTS_DIR_DEV = join3(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
2501
|
+
_SCENARIOS_DIR_PROD = join3(__dirname4, "scenarios");
|
|
2502
|
+
_SCENARIOS_DIR_DEV = join3(__dirname4, "..", "..", "..", "agent_moss", "scenarios");
|
|
2410
2503
|
SKILL_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
2411
2504
|
}
|
|
2412
2505
|
});
|
|
@@ -2544,11 +2637,21 @@ function getScenarioExtensions(scenarioId) {
|
|
|
2544
2637
|
);
|
|
2545
2638
|
return ext;
|
|
2546
2639
|
}
|
|
2640
|
+
function getScenarioExtensionsMulti(scenarioSpec) {
|
|
2641
|
+
if (!scenarioSpec) return null;
|
|
2642
|
+
const ids = scenarioSpec.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2643
|
+
if (ids.length === 0) return null;
|
|
2644
|
+
const exts = ids.map((id) => getScenarioExtensions(id));
|
|
2645
|
+
const nonNull = exts.filter((e) => e !== null);
|
|
2646
|
+
if (nonNull.length === 0) return null;
|
|
2647
|
+
return mergeAgentExtensions(...nonNull);
|
|
2648
|
+
}
|
|
2547
2649
|
var __filename5, __dirname6, SCENARIOS_DIR_PROD, SCENARIOS_DIR_DEV_FALLBACK, cache2;
|
|
2548
2650
|
var init_scenarios = __esm({
|
|
2549
2651
|
"src/scenarios/index.ts"() {
|
|
2550
2652
|
"use strict";
|
|
2551
2653
|
init_esm_shims();
|
|
2654
|
+
init_agents();
|
|
2552
2655
|
__filename5 = fileURLToPath7(import.meta.url);
|
|
2553
2656
|
__dirname6 = dirname5(__filename5);
|
|
2554
2657
|
SCENARIOS_DIR_PROD = resolve4(__dirname6, "scenarios");
|
|
@@ -2597,8 +2700,8 @@ function runHeuristicCheck(input) {
|
|
|
2597
2700
|
}
|
|
2598
2701
|
highestRiskType = topRiskType || highestRiskType;
|
|
2599
2702
|
const agentExt = mergeAgentExtensions(
|
|
2600
|
-
getAgentExtensions(input.agentId),
|
|
2601
|
-
|
|
2703
|
+
isLayerEnabled("agent_rules_enabled") ? getAgentExtensions(input.agentId) : null,
|
|
2704
|
+
isLayerEnabled("scenario_rules_enabled") ? getScenarioExtensionsMulti(input.scenarioId || process.env.AGENT_MOSS_SCENARIO || "") : null
|
|
2602
2705
|
);
|
|
2603
2706
|
if (agentExt?.extra_command_patterns) {
|
|
2604
2707
|
for (const rule of agentExt.extra_command_patterns) {
|
|
@@ -3043,6 +3146,7 @@ var init_heuristic = __esm({
|
|
|
3043
3146
|
init_config();
|
|
3044
3147
|
init_agents();
|
|
3045
3148
|
init_scenarios();
|
|
3149
|
+
init_runtime_config();
|
|
3046
3150
|
init_rules_loader();
|
|
3047
3151
|
init_logic_rules();
|
|
3048
3152
|
INJECTION_KEYWORDS = (() => {
|
|
@@ -3242,6 +3346,112 @@ var init_token_stats = __esm({
|
|
|
3242
3346
|
}
|
|
3243
3347
|
});
|
|
3244
3348
|
|
|
3349
|
+
// src/engine/formal-engine/decode.ts
|
|
3350
|
+
var decode_exports = {};
|
|
3351
|
+
__export(decode_exports, {
|
|
3352
|
+
allCandidates: () => allCandidates,
|
|
3353
|
+
decodeBase64Literals: () => decodeBase64Literals,
|
|
3354
|
+
decodeUrlAndNumeric: () => decodeUrlAndNumeric,
|
|
3355
|
+
matchStageAny: () => matchStageAny
|
|
3356
|
+
});
|
|
3357
|
+
function isValidBase64Token(tok) {
|
|
3358
|
+
if (tok.length < 8) return false;
|
|
3359
|
+
if (!(tok.length % 4 === 0 || tok.endsWith("==") || tok.endsWith("="))) return false;
|
|
3360
|
+
return true;
|
|
3361
|
+
}
|
|
3362
|
+
function isPrintable(s) {
|
|
3363
|
+
for (let i = 0; i < s.length; i++) {
|
|
3364
|
+
const c = s.charCodeAt(i);
|
|
3365
|
+
if (c < 32 || c > 126) return false;
|
|
3366
|
+
}
|
|
3367
|
+
return true;
|
|
3368
|
+
}
|
|
3369
|
+
function decodeBase64Literals(text) {
|
|
3370
|
+
const out = [];
|
|
3371
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3372
|
+
for (const m of text.matchAll(B64_TOKEN_RE)) {
|
|
3373
|
+
const tok = m[0];
|
|
3374
|
+
if (!isValidBase64Token(tok)) continue;
|
|
3375
|
+
if (!/[A-Z]/.test(tok) || !/[a-z]/.test(tok)) continue;
|
|
3376
|
+
try {
|
|
3377
|
+
const padded = tok + "=".repeat((4 - tok.length % 4) % 4);
|
|
3378
|
+
const bin = Buffer.from(padded, "base64");
|
|
3379
|
+
const s = bin.toString("utf8");
|
|
3380
|
+
if (s && isPrintable(s) && !seen.has(s)) {
|
|
3381
|
+
seen.add(s);
|
|
3382
|
+
out.push(s);
|
|
3383
|
+
}
|
|
3384
|
+
} catch {
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
return out;
|
|
3388
|
+
}
|
|
3389
|
+
function decodeUrlAndNumeric(text) {
|
|
3390
|
+
const out = [];
|
|
3391
|
+
let s = text;
|
|
3392
|
+
for (let i = 0; i < 3; i++) {
|
|
3393
|
+
let nxt = s;
|
|
3394
|
+
try {
|
|
3395
|
+
nxt = decodeURIComponent(s);
|
|
3396
|
+
} catch {
|
|
3397
|
+
break;
|
|
3398
|
+
}
|
|
3399
|
+
if (nxt === s) break;
|
|
3400
|
+
s = nxt;
|
|
3401
|
+
}
|
|
3402
|
+
if (s !== text) out.push(s);
|
|
3403
|
+
if (/\\[0-7]{3}/.test(text)) {
|
|
3404
|
+
let expanded = "";
|
|
3405
|
+
try {
|
|
3406
|
+
expanded = text.replace(/\\[0-7]{3}/g, (m) => String.fromCharCode(parseInt(m.slice(1), 8)));
|
|
3407
|
+
} catch {
|
|
3408
|
+
}
|
|
3409
|
+
if (expanded && expanded !== text) out.push(expanded);
|
|
3410
|
+
}
|
|
3411
|
+
if (/\\x[0-9a-fA-F]{2}/.test(text)) {
|
|
3412
|
+
let expanded = "";
|
|
3413
|
+
try {
|
|
3414
|
+
expanded = text.replace(/\\x[0-9a-fA-F]{2}/g, (m) => String.fromCharCode(parseInt(m.slice(2), 16)));
|
|
3415
|
+
} catch {
|
|
3416
|
+
}
|
|
3417
|
+
if (expanded && expanded !== text) out.push(expanded);
|
|
3418
|
+
}
|
|
3419
|
+
return out;
|
|
3420
|
+
}
|
|
3421
|
+
function allCandidates(detail, max = 8) {
|
|
3422
|
+
const cands = [detail];
|
|
3423
|
+
cands.push(...decodeBase64Literals(detail));
|
|
3424
|
+
cands.push(...decodeUrlAndNumeric(detail));
|
|
3425
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3426
|
+
const out = [];
|
|
3427
|
+
for (const c of cands) {
|
|
3428
|
+
if (seen.has(c) || c.length > 4096) continue;
|
|
3429
|
+
seen.add(c);
|
|
3430
|
+
out.push(c);
|
|
3431
|
+
if (out.length >= max) break;
|
|
3432
|
+
}
|
|
3433
|
+
return out;
|
|
3434
|
+
}
|
|
3435
|
+
function matchStageAny(detail, stages) {
|
|
3436
|
+
for (const cand of allCandidates(detail)) {
|
|
3437
|
+
for (const [name, pats] of Object.entries(stages)) {
|
|
3438
|
+
for (const p of pats) {
|
|
3439
|
+
p.lastIndex = 0;
|
|
3440
|
+
if (p.test(cand)) return name;
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
return "";
|
|
3445
|
+
}
|
|
3446
|
+
var B64_TOKEN_RE;
|
|
3447
|
+
var init_decode = __esm({
|
|
3448
|
+
"src/engine/formal-engine/decode.ts"() {
|
|
3449
|
+
"use strict";
|
|
3450
|
+
init_esm_shims();
|
|
3451
|
+
B64_TOKEN_RE = /[A-Za-z0-9+/]+={0,2}/g;
|
|
3452
|
+
}
|
|
3453
|
+
});
|
|
3454
|
+
|
|
3245
3455
|
// src/engine/coordinator.ts
|
|
3246
3456
|
init_esm_shims();
|
|
3247
3457
|
init_heuristic();
|
|
@@ -3286,7 +3496,7 @@ function loadTemplates() {
|
|
|
3286
3496
|
// src/engine/script-analyzer.ts
|
|
3287
3497
|
init_esm_shims();
|
|
3288
3498
|
import { readFileSync as readFileSync8 } from "fs";
|
|
3289
|
-
import { resolve as resolve6, join as
|
|
3499
|
+
import { resolve as resolve6, join as join4 } from "path";
|
|
3290
3500
|
var SUSPICIOUS_PATTERNS = [
|
|
3291
3501
|
// Network exfiltration (curl/wget POST in scripts is almost never legitimate)
|
|
3292
3502
|
{ name: "curl POST", pattern: /curl\s+(.*\s)?-X\s+POST/i },
|
|
@@ -3419,7 +3629,7 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
3419
3629
|
}
|
|
3420
3630
|
function readScriptContent(scriptPath, maxLines = 500) {
|
|
3421
3631
|
try {
|
|
3422
|
-
const expandedPath = scriptPath.startsWith("~") ?
|
|
3632
|
+
const expandedPath = scriptPath.startsWith("~") ? join4(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve6(scriptPath);
|
|
3423
3633
|
const raw = readFileSync8(expandedPath, "utf-8");
|
|
3424
3634
|
const lines = raw.split("\n").slice(0, maxLines);
|
|
3425
3635
|
return { content: lines.join("\n"), lineCount: lines.length, error: "" };
|
|
@@ -3475,8 +3685,8 @@ init_esm_shims();
|
|
|
3475
3685
|
init_heuristic();
|
|
3476
3686
|
init_logic_rules();
|
|
3477
3687
|
import { statSync as statSync2, existsSync as existsSync9 } from "fs";
|
|
3478
|
-
import { resolve as resolve8, join as
|
|
3479
|
-
import { homedir as
|
|
3688
|
+
import { resolve as resolve8, join as join6, isAbsolute as isAbsolute2 } from "path";
|
|
3689
|
+
import { homedir as homedir4 } from "os";
|
|
3480
3690
|
|
|
3481
3691
|
// src/engine/script-engine/tracker.ts
|
|
3482
3692
|
init_esm_shims();
|
|
@@ -5121,7 +5331,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
5121
5331
|
function resolvePath2(p) {
|
|
5122
5332
|
let expanded = p;
|
|
5123
5333
|
if (expanded.startsWith("~/") || expanded === "~") {
|
|
5124
|
-
expanded =
|
|
5334
|
+
expanded = join6(homedir4(), expanded.slice(1));
|
|
5125
5335
|
}
|
|
5126
5336
|
return resolve8(expanded);
|
|
5127
5337
|
}
|
|
@@ -5202,7 +5412,7 @@ function analyzeScriptContent2(input) {
|
|
|
5202
5412
|
isInline = true;
|
|
5203
5413
|
}
|
|
5204
5414
|
if (resolvedPath && !isAbsolute2(resolvedPath) && !resolvedPath.startsWith("~/")) {
|
|
5205
|
-
resolvedPath =
|
|
5415
|
+
resolvedPath = join6(input.cwd || process.cwd(), resolvedPath);
|
|
5206
5416
|
}
|
|
5207
5417
|
const l1Adapter = (content) => {
|
|
5208
5418
|
const virtualInput = {
|
|
@@ -5513,6 +5723,7 @@ async function analyzeWithLLM(prompt, config) {
|
|
|
5513
5723
|
|
|
5514
5724
|
// src/engine/coordinator.ts
|
|
5515
5725
|
init_config();
|
|
5726
|
+
init_runtime_config();
|
|
5516
5727
|
init_agents();
|
|
5517
5728
|
init_scenarios();
|
|
5518
5729
|
|
|
@@ -5522,9 +5733,9 @@ init_esm_shims();
|
|
|
5522
5733
|
// src/brain/rule-store.ts
|
|
5523
5734
|
init_esm_shims();
|
|
5524
5735
|
import { existsSync as existsSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
5525
|
-
import { join as
|
|
5526
|
-
import { homedir as
|
|
5527
|
-
var DEFAULT_RULES_PATH =
|
|
5736
|
+
import { join as join7 } from "path";
|
|
5737
|
+
import { homedir as homedir5 } from "os";
|
|
5738
|
+
var DEFAULT_RULES_PATH = join7(homedir5(), ".agentmoss", "brain", "rules.json");
|
|
5528
5739
|
var ENV_RULES_PATH = "AGENT_MOSS_BRAIN_RULES_PATH";
|
|
5529
5740
|
var STATUS_DRAFT = "draft";
|
|
5530
5741
|
var STATUS_APPROVED = "approved";
|
|
@@ -6050,98 +6261,132 @@ init_esm_shims();
|
|
|
6050
6261
|
// src/engine/formal-engine/builder.ts
|
|
6051
6262
|
init_esm_shims();
|
|
6052
6263
|
init_rules_loader();
|
|
6264
|
+
init_decode();
|
|
6053
6265
|
|
|
6054
|
-
// src/engine/formal-engine/
|
|
6266
|
+
// src/engine/formal-engine/ltl.ts
|
|
6055
6267
|
init_esm_shims();
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
const c = s.charCodeAt(i);
|
|
6065
|
-
if (c < 32 || c > 126) return false;
|
|
6066
|
-
}
|
|
6067
|
-
return true;
|
|
6268
|
+
init_rules_loader();
|
|
6269
|
+
|
|
6270
|
+
// src/engine/formal-engine/ir.ts
|
|
6271
|
+
init_esm_shims();
|
|
6272
|
+
function allNodes(mg) {
|
|
6273
|
+
const out = [];
|
|
6274
|
+
for (const s of mg.sessions) out.push(...s.nodes);
|
|
6275
|
+
return out;
|
|
6068
6276
|
}
|
|
6069
|
-
function
|
|
6277
|
+
function allEdges(mg) {
|
|
6070
6278
|
const out = [];
|
|
6071
|
-
const
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6279
|
+
for (const s of mg.sessions) out.push(...s.edges);
|
|
6280
|
+
out.push(...mg.crossEdges);
|
|
6281
|
+
return out;
|
|
6282
|
+
}
|
|
6283
|
+
function emptyVerificationResult() {
|
|
6284
|
+
return { verified: true, violations: [] };
|
|
6285
|
+
}
|
|
6286
|
+
|
|
6287
|
+
// src/engine/formal-engine/ltl.ts
|
|
6288
|
+
var AP_RE = null;
|
|
6289
|
+
function compileAps(apPatterns) {
|
|
6290
|
+
if (AP_RE) return;
|
|
6291
|
+
AP_RE = {};
|
|
6292
|
+
for (const [name, pats] of Object.entries(apPatterns || {})) {
|
|
6293
|
+
AP_RE[name] = pats.map((p) => new RegExp(p, "i"));
|
|
6294
|
+
}
|
|
6295
|
+
}
|
|
6296
|
+
function labelEvent(actionDetail) {
|
|
6297
|
+
if (!AP_RE) compileAps(loadMC().ap_patterns || {});
|
|
6298
|
+
let candidates = [actionDetail];
|
|
6299
|
+
try {
|
|
6300
|
+
candidates = (init_decode(), __toCommonJS(decode_exports)).allCandidates(actionDetail);
|
|
6301
|
+
} catch {
|
|
6302
|
+
}
|
|
6303
|
+
const hits = /* @__PURE__ */ new Set();
|
|
6304
|
+
for (const [name, pats] of Object.entries(AP_RE || {})) {
|
|
6305
|
+
for (const c of candidates) {
|
|
6306
|
+
const m = pats.some((p) => p.test(c));
|
|
6307
|
+
if (m) {
|
|
6308
|
+
hits.add(name);
|
|
6309
|
+
break;
|
|
6083
6310
|
}
|
|
6084
|
-
} catch {
|
|
6085
6311
|
}
|
|
6086
6312
|
}
|
|
6087
|
-
return
|
|
6313
|
+
return hits;
|
|
6088
6314
|
}
|
|
6089
|
-
function
|
|
6090
|
-
const
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6315
|
+
function evaluateLTL(formula, trace, pos) {
|
|
6316
|
+
const op = formula[0];
|
|
6317
|
+
switch (op) {
|
|
6318
|
+
case "ap":
|
|
6319
|
+
return trace[pos].has(formula[1]);
|
|
6320
|
+
case "!":
|
|
6321
|
+
return !evaluateLTL(formula[1], trace, pos);
|
|
6322
|
+
case "&":
|
|
6323
|
+
return evaluateLTL(formula[1], trace, pos) && evaluateLTL(formula[2], trace, pos);
|
|
6324
|
+
case "|":
|
|
6325
|
+
return evaluateLTL(formula[1], trace, pos) || evaluateLTL(formula[2], trace, pos);
|
|
6326
|
+
case "->":
|
|
6327
|
+
return !evaluateLTL(formula[1], trace, pos) || evaluateLTL(formula[2], trace, pos);
|
|
6328
|
+
case "X":
|
|
6329
|
+
return pos + 1 < trace.length && evaluateLTL(formula[1], trace, pos + 1);
|
|
6330
|
+
case "G": {
|
|
6331
|
+
for (let j = pos; j < trace.length; j++) {
|
|
6332
|
+
if (!evaluateLTL(formula[1], trace, j)) return false;
|
|
6333
|
+
}
|
|
6334
|
+
return true;
|
|
6098
6335
|
}
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
let expanded = "";
|
|
6105
|
-
try {
|
|
6106
|
-
expanded = text.replace(/\\[0-7]{3}/g, (m) => String.fromCharCode(parseInt(m.slice(1), 8)));
|
|
6107
|
-
} catch {
|
|
6336
|
+
case "F": {
|
|
6337
|
+
for (let j = pos; j < trace.length; j++) {
|
|
6338
|
+
if (evaluateLTL(formula[1], trace, j)) return true;
|
|
6339
|
+
}
|
|
6340
|
+
return false;
|
|
6108
6341
|
}
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6342
|
+
case "U": {
|
|
6343
|
+
for (let j = pos; j < trace.length; j++) {
|
|
6344
|
+
if (evaluateLTL(formula[2], trace, j)) {
|
|
6345
|
+
for (let k = pos; k < j; k++) {
|
|
6346
|
+
if (!evaluateLTL(formula[1], trace, k)) return false;
|
|
6347
|
+
}
|
|
6348
|
+
return true;
|
|
6349
|
+
}
|
|
6350
|
+
}
|
|
6351
|
+
return false;
|
|
6116
6352
|
}
|
|
6117
|
-
|
|
6353
|
+
default:
|
|
6354
|
+
return false;
|
|
6118
6355
|
}
|
|
6119
|
-
return out;
|
|
6120
6356
|
}
|
|
6121
|
-
function
|
|
6122
|
-
const
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
if (
|
|
6129
|
-
seen.add(c);
|
|
6130
|
-
out.push(c);
|
|
6131
|
-
if (out.length >= max) break;
|
|
6357
|
+
function ruleViolates(rule, traceWith, witnessMode) {
|
|
6358
|
+
const formula = rule?.formula;
|
|
6359
|
+
if (!Array.isArray(formula) || formula.length === 0) return false;
|
|
6360
|
+
const satWith = evaluateLTL(formula, traceWith, 0);
|
|
6361
|
+
if (!satWith) return false;
|
|
6362
|
+
if (witnessMode && traceWith.length > 1) {
|
|
6363
|
+
const traceWithout = traceWith.slice(0, -1);
|
|
6364
|
+
if (evaluateLTL(formula, traceWithout, 0)) return false;
|
|
6132
6365
|
}
|
|
6133
|
-
return
|
|
6366
|
+
return true;
|
|
6134
6367
|
}
|
|
6135
|
-
function
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6368
|
+
function checkMCRules(graph) {
|
|
6369
|
+
const violations = [];
|
|
6370
|
+
const nodes = allNodes(graph);
|
|
6371
|
+
if (nodes.length === 0) return violations;
|
|
6372
|
+
const mc = loadMC();
|
|
6373
|
+
const rules = mc.rules || [];
|
|
6374
|
+
if (rules.length === 0) return violations;
|
|
6375
|
+
const trace = nodes.map((n) => labelEvent(n.actionDetail));
|
|
6376
|
+
const witnessMode = graph.witnessIdx !== void 0;
|
|
6377
|
+
for (const rule of rules) {
|
|
6378
|
+
if (rule?.type !== "ltl" || !(rule.enabled !== false)) continue;
|
|
6379
|
+
if (ruleViolates(rule, trace, witnessMode)) {
|
|
6380
|
+
violations.push({
|
|
6381
|
+
propertyId: String(rule.id || "mc-ltl"),
|
|
6382
|
+
reason: String(rule.reason || "L2.2 \u6A21\u578B\u68C0\u6D4B\u89C4\u5219\u547D\u4E2D"),
|
|
6383
|
+
riskLevel: String(rule.risk_level || "high"),
|
|
6384
|
+
path: nodes.filter((n) => labelEvent(n.actionDetail).size > 0).slice(-3).map((n) => ({ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) }))
|
|
6385
|
+
});
|
|
6386
|
+
if (witnessMode) return violations;
|
|
6142
6387
|
}
|
|
6143
6388
|
}
|
|
6144
|
-
return
|
|
6389
|
+
return violations;
|
|
6145
6390
|
}
|
|
6146
6391
|
|
|
6147
6392
|
// src/engine/formal-engine/builder.ts
|
|
@@ -6172,6 +6417,26 @@ function extractResources(actionDetail) {
|
|
|
6172
6417
|
function markStage(actionDetail) {
|
|
6173
6418
|
return matchStageAny(actionDetail, loadStages());
|
|
6174
6419
|
}
|
|
6420
|
+
function markIntegrity(actionDetail) {
|
|
6421
|
+
const aps = labelEvent(actionDetail);
|
|
6422
|
+
if (aps.has("download_file") || aps.has("prompt_injection")) {
|
|
6423
|
+
return { integrity: "low", isLowSource: true };
|
|
6424
|
+
}
|
|
6425
|
+
return { integrity: "medium", isLowSource: false };
|
|
6426
|
+
}
|
|
6427
|
+
function initNode(sessionId, seq, actionType, actionDetail) {
|
|
6428
|
+
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
6429
|
+
return {
|
|
6430
|
+
sessionId,
|
|
6431
|
+
seq,
|
|
6432
|
+
actionType,
|
|
6433
|
+
actionDetail,
|
|
6434
|
+
stage: markStage(actionDetail),
|
|
6435
|
+
resources: extractResources(actionDetail),
|
|
6436
|
+
integrity,
|
|
6437
|
+
isLowSource
|
|
6438
|
+
};
|
|
6439
|
+
}
|
|
6175
6440
|
function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
6176
6441
|
const nodes = [];
|
|
6177
6442
|
const edges = [];
|
|
@@ -6185,17 +6450,9 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
|
6185
6450
|
details.push({ actionType: String(aNext.actionType || ""), actionDetail: String(aNext.actionDetail || "") });
|
|
6186
6451
|
}
|
|
6187
6452
|
details.forEach((d, seq) => {
|
|
6188
|
-
const
|
|
6189
|
-
const node = {
|
|
6190
|
-
sessionId,
|
|
6191
|
-
seq,
|
|
6192
|
-
actionType: d.actionType,
|
|
6193
|
-
actionDetail: d.actionDetail,
|
|
6194
|
-
stage,
|
|
6195
|
-
resources: extractResources(d.actionDetail)
|
|
6196
|
-
};
|
|
6453
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail);
|
|
6197
6454
|
nodes.push(node);
|
|
6198
|
-
if (stage) stageFlags.add(stage);
|
|
6455
|
+
if (node.stage) stageFlags.add(node.stage);
|
|
6199
6456
|
});
|
|
6200
6457
|
for (let i = 0; i < nodes.length - 1; i++) {
|
|
6201
6458
|
edges.push({ src: i, dst: i + 1, kind: "next" });
|
|
@@ -6215,15 +6472,12 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
6215
6472
|
if (aNext) {
|
|
6216
6473
|
const last = mg.sessions[mg.sessions.length - 1];
|
|
6217
6474
|
if (last.sessionId === "current") {
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
stage,
|
|
6225
|
-
resources: extractResources(String(aNext.actionDetail || ""))
|
|
6226
|
-
});
|
|
6475
|
+
last.nodes.push(initNode(
|
|
6476
|
+
last.sessionId,
|
|
6477
|
+
last.nodes.length,
|
|
6478
|
+
String(aNext.actionType || ""),
|
|
6479
|
+
String(aNext.actionDetail || "")
|
|
6480
|
+
));
|
|
6227
6481
|
if (last.nodes.length > 1) {
|
|
6228
6482
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
6229
6483
|
}
|
|
@@ -6237,11 +6491,25 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
6237
6491
|
function addCrossDataEdges(mg) {
|
|
6238
6492
|
const nodes = allNodesFlat(mg);
|
|
6239
6493
|
if (nodes.length < 2) return;
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
const
|
|
6244
|
-
if (
|
|
6494
|
+
const resIndex = /* @__PURE__ */ new Map();
|
|
6495
|
+
nodes.forEach((n, i) => {
|
|
6496
|
+
for (const r of n.resources) {
|
|
6497
|
+
const list = resIndex.get(r);
|
|
6498
|
+
if (list) list.push(i);
|
|
6499
|
+
else resIndex.set(r, [i]);
|
|
6500
|
+
}
|
|
6501
|
+
});
|
|
6502
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6503
|
+
for (const idxs of resIndex.values()) {
|
|
6504
|
+
if (idxs.length < 2) continue;
|
|
6505
|
+
for (let a = 0; a < idxs.length; a++) {
|
|
6506
|
+
const i = idxs[a];
|
|
6507
|
+
for (let b = a + 1; b < idxs.length; b++) {
|
|
6508
|
+
const j = idxs[b];
|
|
6509
|
+
if (nodes[i].sessionId === nodes[j].sessionId) continue;
|
|
6510
|
+
const key = `${i}:${j}`;
|
|
6511
|
+
if (seen.has(key)) continue;
|
|
6512
|
+
seen.add(key);
|
|
6245
6513
|
mg.crossEdges.push({ src: i, dst: j, kind: "data" });
|
|
6246
6514
|
}
|
|
6247
6515
|
}
|
|
@@ -6252,28 +6520,6 @@ function allNodesFlat(mg) {
|
|
|
6252
6520
|
for (const s of mg.sessions) out.push(...s.nodes);
|
|
6253
6521
|
return out;
|
|
6254
6522
|
}
|
|
6255
|
-
function intersect(a, b) {
|
|
6256
|
-
const out = /* @__PURE__ */ new Set();
|
|
6257
|
-
for (const v of a) if (b.has(v)) out.add(v);
|
|
6258
|
-
return out;
|
|
6259
|
-
}
|
|
6260
|
-
|
|
6261
|
-
// src/engine/formal-engine/ir.ts
|
|
6262
|
-
init_esm_shims();
|
|
6263
|
-
function allNodes(mg) {
|
|
6264
|
-
const out = [];
|
|
6265
|
-
for (const s of mg.sessions) out.push(...s.nodes);
|
|
6266
|
-
return out;
|
|
6267
|
-
}
|
|
6268
|
-
function allEdges(mg) {
|
|
6269
|
-
const out = [];
|
|
6270
|
-
for (const s of mg.sessions) out.push(...s.edges);
|
|
6271
|
-
out.push(...mg.crossEdges);
|
|
6272
|
-
return out;
|
|
6273
|
-
}
|
|
6274
|
-
function emptyVerificationResult() {
|
|
6275
|
-
return { verified: true, violations: [] };
|
|
6276
|
-
}
|
|
6277
6523
|
|
|
6278
6524
|
// src/engine/formal-engine/properties.ts
|
|
6279
6525
|
init_esm_shims();
|
|
@@ -6296,27 +6542,50 @@ function checkCrossSessionChain(graph) {
|
|
|
6296
6542
|
const violations = [];
|
|
6297
6543
|
const nodes = allNodes(graph);
|
|
6298
6544
|
if (nodes.length === 0) return violations;
|
|
6545
|
+
const witness = graph.witnessIdx;
|
|
6299
6546
|
for (const chain of loadCrossSessionChains()) {
|
|
6300
6547
|
const stages = chain.stages;
|
|
6301
6548
|
if (!stages.length) continue;
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6549
|
+
if (witness !== void 0) {
|
|
6550
|
+
if (nodes[witness].stage !== stages[stages.length - 1]) continue;
|
|
6551
|
+
let matched = 0;
|
|
6552
|
+
const path5 = [];
|
|
6553
|
+
for (let k = 0; k < witness; k++) {
|
|
6554
|
+
const n = nodes[k];
|
|
6555
|
+
if (matched < stages.length - 1 && n.stage === stages[matched]) {
|
|
6556
|
+
matched += 1;
|
|
6557
|
+
path5.push({ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) });
|
|
6558
|
+
}
|
|
6311
6559
|
}
|
|
6312
|
-
|
|
6313
|
-
|
|
6560
|
+
if (matched < stages.length - 1) continue;
|
|
6561
|
+
path5.push({ sessionId: nodes[witness].sessionId, seq: nodes[witness].seq, detail: nodes[witness].actionDetail.slice(0, 60) });
|
|
6314
6562
|
violations.push({
|
|
6315
6563
|
propertyId: "cross-" + chain.id,
|
|
6316
6564
|
reason: chain.reason,
|
|
6317
6565
|
riskLevel: chain.riskLevel,
|
|
6318
6566
|
path: path5
|
|
6319
6567
|
});
|
|
6568
|
+
return violations;
|
|
6569
|
+
} else {
|
|
6570
|
+
let matched = 0;
|
|
6571
|
+
let stageIdx = 0;
|
|
6572
|
+
const path5 = [];
|
|
6573
|
+
for (const n of nodes) {
|
|
6574
|
+
if (stageIdx < stages.length && n.stage === stages[stageIdx]) {
|
|
6575
|
+
matched += 1;
|
|
6576
|
+
path5.push({ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) });
|
|
6577
|
+
stageIdx += 1;
|
|
6578
|
+
if (matched >= stages.length) break;
|
|
6579
|
+
}
|
|
6580
|
+
}
|
|
6581
|
+
if (matched >= stages.length) {
|
|
6582
|
+
violations.push({
|
|
6583
|
+
propertyId: "cross-" + chain.id,
|
|
6584
|
+
reason: chain.reason,
|
|
6585
|
+
riskLevel: chain.riskLevel,
|
|
6586
|
+
path: path5
|
|
6587
|
+
});
|
|
6588
|
+
}
|
|
6320
6589
|
}
|
|
6321
6590
|
}
|
|
6322
6591
|
return violations;
|
|
@@ -6351,7 +6620,10 @@ function checkSensitiveDataFlow(graph) {
|
|
|
6351
6620
|
}
|
|
6352
6621
|
}
|
|
6353
6622
|
}
|
|
6354
|
-
|
|
6623
|
+
const witness = graph.witnessIdx;
|
|
6624
|
+
const candidates = witness !== void 0 ? [witness] : nodes.map((_, i) => i);
|
|
6625
|
+
for (const i of candidates) {
|
|
6626
|
+
const n = nodes[i];
|
|
6355
6627
|
if (tainted.has(i) && EXFIL_RE.test(n.actionDetail)) {
|
|
6356
6628
|
violations.push({
|
|
6357
6629
|
propertyId: "sensitive-data-exfil",
|
|
@@ -6359,6 +6631,7 @@ function checkSensitiveDataFlow(graph) {
|
|
|
6359
6631
|
riskLevel: "critical",
|
|
6360
6632
|
path: [{ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) }]
|
|
6361
6633
|
});
|
|
6634
|
+
if (witness !== void 0) return violations;
|
|
6362
6635
|
}
|
|
6363
6636
|
}
|
|
6364
6637
|
return violations;
|
|
@@ -6389,6 +6662,32 @@ function checkNeverExfilAfterPrivesc(graph) {
|
|
|
6389
6662
|
const violations = [];
|
|
6390
6663
|
const nodes = allNodes(graph);
|
|
6391
6664
|
if (nodes.length < 2) return violations;
|
|
6665
|
+
const witness = graph.witnessIdx;
|
|
6666
|
+
if (witness !== void 0) {
|
|
6667
|
+
const evIdx = [];
|
|
6668
|
+
nodes.forEach((n, i) => {
|
|
6669
|
+
if ((i === witness || n.sessionId === "ebpf-evidence") && isExfilNode(n)) evIdx.push(i);
|
|
6670
|
+
});
|
|
6671
|
+
if (evIdx.length === 0) return violations;
|
|
6672
|
+
const firstEv = Math.min(...evIdx);
|
|
6673
|
+
let pre = null;
|
|
6674
|
+
for (let i = 0; i < firstEv; i++) {
|
|
6675
|
+
if (isPrivescNode(nodes[i])) pre = nodes[i];
|
|
6676
|
+
}
|
|
6677
|
+
if (pre) {
|
|
6678
|
+
const post = nodes[firstEv];
|
|
6679
|
+
return [{
|
|
6680
|
+
propertyId: "no-privesc-then-exfil",
|
|
6681
|
+
reason: "\u63D0\u6743\u540E\u51FA\u73B0\u5916\u4F20\uFF1A\u63D0\u6743(\u524D) \u2192 \u5916\u4F20(\u540E)\uFF0C\u8FDD\u53CD \u25A1(PRIVESC\u2192\xAC\u25C7EXFIL)",
|
|
6682
|
+
riskLevel: "critical",
|
|
6683
|
+
path: [
|
|
6684
|
+
{ sessionId: pre.sessionId, seq: pre.seq, detail: pre.actionDetail.slice(0, 60) },
|
|
6685
|
+
{ sessionId: post.sessionId, seq: post.seq, detail: post.actionDetail.slice(0, 60) }
|
|
6686
|
+
]
|
|
6687
|
+
}];
|
|
6688
|
+
}
|
|
6689
|
+
return violations;
|
|
6690
|
+
}
|
|
6392
6691
|
for (let i = 0; i < nodes.length; i++) {
|
|
6393
6692
|
if (!isPrivescNode(nodes[i])) continue;
|
|
6394
6693
|
for (let j = i + 1; j < nodes.length; j++) {
|
|
@@ -6412,6 +6711,32 @@ function checkNeverExfilAfterCred(graph) {
|
|
|
6412
6711
|
const violations = [];
|
|
6413
6712
|
const nodes = allNodes(graph);
|
|
6414
6713
|
if (nodes.length < 2) return violations;
|
|
6714
|
+
const witness = graph.witnessIdx;
|
|
6715
|
+
if (witness !== void 0) {
|
|
6716
|
+
const evIdx = [];
|
|
6717
|
+
nodes.forEach((n, i) => {
|
|
6718
|
+
if ((i === witness || n.sessionId === "ebpf-evidence") && isExfilNode(n)) evIdx.push(i);
|
|
6719
|
+
});
|
|
6720
|
+
if (evIdx.length === 0) return violations;
|
|
6721
|
+
const firstEv = Math.min(...evIdx);
|
|
6722
|
+
let pre = null;
|
|
6723
|
+
for (let i = 0; i < firstEv; i++) {
|
|
6724
|
+
if (isCredNode(nodes[i])) pre = nodes[i];
|
|
6725
|
+
}
|
|
6726
|
+
if (pre) {
|
|
6727
|
+
const post = nodes[firstEv];
|
|
6728
|
+
return [{
|
|
6729
|
+
propertyId: "no-cred-then-exfil",
|
|
6730
|
+
reason: "\u8BFB\u53D6\u51ED\u636E\u540E\u51FA\u73B0\u5916\u4F20\uFF0C\u8FDD\u53CD \u25A1(CRED\u2192\xAC\u25C7EXFIL)",
|
|
6731
|
+
riskLevel: "critical",
|
|
6732
|
+
path: [
|
|
6733
|
+
{ sessionId: pre.sessionId, seq: pre.seq, detail: pre.actionDetail.slice(0, 60) },
|
|
6734
|
+
{ sessionId: post.sessionId, seq: post.seq, detail: post.actionDetail.slice(0, 60) }
|
|
6735
|
+
]
|
|
6736
|
+
}];
|
|
6737
|
+
}
|
|
6738
|
+
return violations;
|
|
6739
|
+
}
|
|
6415
6740
|
for (let i = 0; i < nodes.length; i++) {
|
|
6416
6741
|
if (!isCredNode(nodes[i])) continue;
|
|
6417
6742
|
for (let j = i + 1; j < nodes.length; j++) {
|
|
@@ -6431,11 +6756,172 @@ function checkNeverExfilAfterCred(graph) {
|
|
|
6431
6756
|
}
|
|
6432
6757
|
return violations;
|
|
6433
6758
|
}
|
|
6759
|
+
var TOOL_REGISTRY = null;
|
|
6760
|
+
function getToolRegistry() {
|
|
6761
|
+
if (TOOL_REGISTRY) return TOOL_REGISTRY;
|
|
6762
|
+
TOOL_REGISTRY = loadToolRegistry().tools || {};
|
|
6763
|
+
return TOOL_REGISTRY;
|
|
6764
|
+
}
|
|
6765
|
+
function lookupToolClass(actionType) {
|
|
6766
|
+
const entry = getToolRegistry()[actionType] || {};
|
|
6767
|
+
return entry.actionClass;
|
|
6768
|
+
}
|
|
6769
|
+
var COMPUTE_RE = /subprocess|os\.system|shell\s*=\s*True|\beval\(|\bexec\(|bash\s+[^\s]|sh\s+-c|python3?\s+|node\s+|\btimeout\s+|nohup\s+|\b\.\/[\w./-]+/i;
|
|
6770
|
+
var STRONG_COMPUTE_TYPES = /* @__PURE__ */ new Set(["python", "node", "exec", "terminal", "cmd"]);
|
|
6771
|
+
function isComputeNode(n) {
|
|
6772
|
+
if (STRONG_COMPUTE_TYPES.has(n.actionType.toLowerCase())) return true;
|
|
6773
|
+
const cls = lookupToolClass(n.actionType);
|
|
6774
|
+
if (cls === "read" || cls === "write" || cls === "network_egress" || cls === "message_egress") return false;
|
|
6775
|
+
return COMPUTE_RE.test(n.actionDetail);
|
|
6776
|
+
}
|
|
6777
|
+
function checkLowIntegrityCommandExec(graph) {
|
|
6778
|
+
const violations = [];
|
|
6779
|
+
const nodes = allNodes(graph);
|
|
6780
|
+
if (nodes.length === 0) return violations;
|
|
6781
|
+
const witness = graph.witnessIdx;
|
|
6782
|
+
const lowResources = /* @__PURE__ */ new Set();
|
|
6783
|
+
const lowAt = /* @__PURE__ */ new Map();
|
|
6784
|
+
nodes.forEach((n, i) => {
|
|
6785
|
+
if (n.isLowSource) {
|
|
6786
|
+
lowAt.set(i, n.actionDetail.slice(0, 60));
|
|
6787
|
+
for (const r of n.resources) lowResources.add(r);
|
|
6788
|
+
}
|
|
6789
|
+
});
|
|
6790
|
+
let changed = true;
|
|
6791
|
+
while (changed) {
|
|
6792
|
+
changed = false;
|
|
6793
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
6794
|
+
if (lowAt.has(i)) continue;
|
|
6795
|
+
let shared = "";
|
|
6796
|
+
for (const r of nodes[i].resources) {
|
|
6797
|
+
if (lowResources.has(r)) {
|
|
6798
|
+
shared = r;
|
|
6799
|
+
break;
|
|
6800
|
+
}
|
|
6801
|
+
}
|
|
6802
|
+
if (shared) {
|
|
6803
|
+
lowAt.set(i, `\u7EE7\u627F\u81EA ${shared}`);
|
|
6804
|
+
for (const r of nodes[i].resources) lowResources.add(r);
|
|
6805
|
+
changed = true;
|
|
6806
|
+
}
|
|
6807
|
+
}
|
|
6808
|
+
}
|
|
6809
|
+
if (lowAt.size === 0) return violations;
|
|
6810
|
+
const candidates = witness !== void 0 ? [witness] : nodes.map((_, i) => i);
|
|
6811
|
+
for (const i of candidates) {
|
|
6812
|
+
const n = nodes[i];
|
|
6813
|
+
if (lowAt.has(i) && isComputeNode(n)) {
|
|
6814
|
+
violations.push({
|
|
6815
|
+
propertyId: "low-integrity-controls-command-exec",
|
|
6816
|
+
reason: `\u4F4E\u5B8C\u6574\u6027\u6570\u636E\u63A7\u5236\u547D\u4EE4\u6267\u884C\uFF1A${lowAt.get(i)} \u2192 ${n.sessionId}#${n.seq} \u6267\u884C\u4E0D\u53EF\u4FE1\u5185\u5BB9`,
|
|
6817
|
+
riskLevel: "critical",
|
|
6818
|
+
path: [{ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) }]
|
|
6819
|
+
});
|
|
6820
|
+
if (witness !== void 0) return violations;
|
|
6821
|
+
}
|
|
6822
|
+
}
|
|
6823
|
+
return violations;
|
|
6824
|
+
}
|
|
6825
|
+
var DL_OR_LOW_RE = /curl\s+.*-o\b|wget\s+.*\s+-O\b|curl\s+.*\|\s*(bash|sh|python)|wget\s+.*\|\s*(bash|sh|python)|git\s+clone|docker\s+pull|pip\s+install|npm\s+install|base64\s+-d/i;
|
|
6826
|
+
function checkCrossSessionReachability(graph) {
|
|
6827
|
+
const violations = [];
|
|
6828
|
+
const nodes = allNodes(graph);
|
|
6829
|
+
if (nodes.length === 0) return violations;
|
|
6830
|
+
const witness = graph.witnessIdx;
|
|
6831
|
+
const sources = /* @__PURE__ */ new Set();
|
|
6832
|
+
nodes.forEach((n, i) => {
|
|
6833
|
+
if (n.isLowSource || DL_OR_LOW_RE.test(n.actionDetail)) sources.add(i);
|
|
6834
|
+
});
|
|
6835
|
+
if (sources.size === 0) return violations;
|
|
6836
|
+
const reached = new Set(sources);
|
|
6837
|
+
let changed = true;
|
|
6838
|
+
while (changed) {
|
|
6839
|
+
changed = false;
|
|
6840
|
+
for (const e of allEdges(graph)) {
|
|
6841
|
+
if (reached.has(e.src) && !reached.has(e.dst)) {
|
|
6842
|
+
const srcRes = nodes[e.src].resources;
|
|
6843
|
+
const dstRes = nodes[e.dst].resources;
|
|
6844
|
+
for (const r of srcRes) {
|
|
6845
|
+
if (dstRes.has(r)) {
|
|
6846
|
+
reached.add(e.dst);
|
|
6847
|
+
changed = true;
|
|
6848
|
+
break;
|
|
6849
|
+
}
|
|
6850
|
+
}
|
|
6851
|
+
}
|
|
6852
|
+
}
|
|
6853
|
+
}
|
|
6854
|
+
const candidates = witness !== void 0 ? [witness] : nodes.map((_, i) => i);
|
|
6855
|
+
for (const i of candidates) {
|
|
6856
|
+
const n = nodes[i];
|
|
6857
|
+
if (sources.has(i)) continue;
|
|
6858
|
+
if (reached.has(i)) {
|
|
6859
|
+
const srcIdx = Math.min(...sources);
|
|
6860
|
+
const srcDesc = nodes[srcIdx].actionDetail.slice(0, 40);
|
|
6861
|
+
violations.push({
|
|
6862
|
+
propertyId: "cross-session-reachability",
|
|
6863
|
+
reason: `\u4F4E\u5B8C\u6574\u6027\u6E90\u7ECF\u8DE8 session \u6570\u636E\u94FE\u591A\u8DF3\u5230\u8FBE\u5F53\u524D\u6267\u884C\uFF08\u6E90: ${srcDesc} \u2192 ${n.sessionId}#${n.seq}\uFF09`,
|
|
6864
|
+
riskLevel: "high",
|
|
6865
|
+
path: nodes.slice(-3).map((m) => ({ sessionId: m.sessionId, seq: m.seq, detail: m.actionDetail.slice(0, 60) }))
|
|
6866
|
+
});
|
|
6867
|
+
if (witness !== void 0) return violations;
|
|
6868
|
+
}
|
|
6869
|
+
}
|
|
6870
|
+
return violations;
|
|
6871
|
+
}
|
|
6872
|
+
function checkSensitiveDataAggregation(graph) {
|
|
6873
|
+
const violations = [];
|
|
6874
|
+
const nodes = allNodes(graph);
|
|
6875
|
+
if (nodes.length < 2) return violations;
|
|
6876
|
+
const witness = graph.witnessIdx;
|
|
6877
|
+
const resIndex = /* @__PURE__ */ new Map();
|
|
6878
|
+
nodes.forEach((n, i) => {
|
|
6879
|
+
for (const r of n.resources) {
|
|
6880
|
+
const list = resIndex.get(r);
|
|
6881
|
+
if (list) list.push(i);
|
|
6882
|
+
else resIndex.set(r, [i]);
|
|
6883
|
+
}
|
|
6884
|
+
});
|
|
6885
|
+
const sourcesFor = (exfilIdx) => {
|
|
6886
|
+
const srcs = /* @__PURE__ */ new Set();
|
|
6887
|
+
const n = nodes[exfilIdx];
|
|
6888
|
+
for (const r of n.resources) {
|
|
6889
|
+
for (const j of resIndex.get(r) || []) {
|
|
6890
|
+
if (j === exfilIdx) continue;
|
|
6891
|
+
srcs.add(`${nodes[j].sessionId}#${nodes[j].seq}`);
|
|
6892
|
+
}
|
|
6893
|
+
}
|
|
6894
|
+
return srcs;
|
|
6895
|
+
};
|
|
6896
|
+
const candidates = witness !== void 0 ? [witness] : nodes.map((_, i) => i);
|
|
6897
|
+
for (const i of candidates) {
|
|
6898
|
+
const n = nodes[i];
|
|
6899
|
+
if (!isExfilNode(n)) continue;
|
|
6900
|
+
const srcs = sourcesFor(i);
|
|
6901
|
+
if (srcs.size >= 2) {
|
|
6902
|
+
violations.push({
|
|
6903
|
+
propertyId: "sensitive-data-aggregation",
|
|
6904
|
+
reason: `\u654F\u611F\u6570\u636E\u805A\u5408\u5916\u4F20\uFF1Aegress \u805A\u5408 ${srcs.size} \u4E2A\u4E8B\u4EF6\u6E90\u6570\u636E\uFF08Rule 12\uFF09`,
|
|
6905
|
+
riskLevel: "critical",
|
|
6906
|
+
path: [{ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) }]
|
|
6907
|
+
});
|
|
6908
|
+
if (witness !== void 0) return violations;
|
|
6909
|
+
}
|
|
6910
|
+
}
|
|
6911
|
+
return violations;
|
|
6912
|
+
}
|
|
6434
6913
|
var ALL_PROPERTIES = [
|
|
6435
6914
|
{ id: "cross-session-chain", check: checkCrossSessionChain },
|
|
6436
6915
|
{ id: "sensitive-data-flow", check: checkSensitiveDataFlow },
|
|
6916
|
+
{ id: "cross-session-reachability", check: checkCrossSessionReachability },
|
|
6437
6917
|
{ id: "no-privesc-then-exfil", check: checkNeverExfilAfterPrivesc },
|
|
6438
|
-
{ id: "no-cred-then-exfil", check: checkNeverExfilAfterCred }
|
|
6918
|
+
{ id: "no-cred-then-exfil", check: checkNeverExfilAfterCred },
|
|
6919
|
+
// L2.2 模型检测(通用 LTL 求值器,mc_rules.json 单一事实源;witness 语义见 ltl.ts)
|
|
6920
|
+
{ id: "mc-ltl-rules", check: checkMCRules },
|
|
6921
|
+
// Rule 5 低完整性控制命令执行(integrity 维度,站点 L2.1 最有区分度的检测之一)
|
|
6922
|
+
{ id: "low-integrity-command-exec", check: checkLowIntegrityCommandExec },
|
|
6923
|
+
// Rule 12 敏感数据聚合外传(egress 聚合 ≥2 事件源)
|
|
6924
|
+
{ id: "sensitive-data-aggregation", check: checkSensitiveDataAggregation }
|
|
6439
6925
|
];
|
|
6440
6926
|
|
|
6441
6927
|
// src/engine/formal-engine/engine.ts
|
|
@@ -6467,6 +6953,9 @@ var FormalEngine = class {
|
|
|
6467
6953
|
});
|
|
6468
6954
|
}
|
|
6469
6955
|
const graph = buildMultiSessionGraph(all, aNext);
|
|
6956
|
+
if (aNext) {
|
|
6957
|
+
graph.witnessIdx = allNodes(graph).length - 1;
|
|
6958
|
+
}
|
|
6470
6959
|
const result = emptyVerificationResult();
|
|
6471
6960
|
for (const prop of this.properties) {
|
|
6472
6961
|
let violations;
|
|
@@ -6495,6 +6984,7 @@ var FormalEngine = class {
|
|
|
6495
6984
|
// src/engine/formal-engine/stateful.ts
|
|
6496
6985
|
init_esm_shims();
|
|
6497
6986
|
init_rules_loader();
|
|
6987
|
+
init_decode();
|
|
6498
6988
|
|
|
6499
6989
|
// src/engine/formal-engine/chain_state.ts
|
|
6500
6990
|
init_esm_shims();
|
|
@@ -6607,6 +7097,7 @@ function _resetBrainForTest() {
|
|
|
6607
7097
|
}
|
|
6608
7098
|
var formalEngine = new FormalEngine();
|
|
6609
7099
|
async function runAnalysis(input) {
|
|
7100
|
+
const observedFormalLayers = [];
|
|
6610
7101
|
const heuristicResult = isHeuristicEnabled() ? runHeuristicCheck(input) : null;
|
|
6611
7102
|
const isInlineScriptCmd = isInlineScriptCommand(input.aNext.actionDetail.toLowerCase());
|
|
6612
7103
|
const isLiteralTextCmd = isLiteralTextCommand(input.aNext.actionDetail.toLowerCase());
|
|
@@ -6661,8 +7152,8 @@ async function runAnalysis(input) {
|
|
|
6661
7152
|
const rawDetail = extractRawCommand(input.aNext.actionDetail);
|
|
6662
7153
|
const lowerDetail = rawDetail.toLowerCase();
|
|
6663
7154
|
const agentExt = mergeAgentExtensions(
|
|
6664
|
-
getAgentExtensions(input.agentId),
|
|
6665
|
-
|
|
7155
|
+
isLayerEnabled("agent_rules_enabled") ? getAgentExtensions(input.agentId) : null,
|
|
7156
|
+
isLayerEnabled("scenario_rules_enabled") ? getScenarioExtensionsMulti(input.scenarioId || process.env.AGENT_MOSS_SCENARIO || "") : null
|
|
6666
7157
|
);
|
|
6667
7158
|
if (FULLY_SAFE_TOOLS.has(actionType)) {
|
|
6668
7159
|
return {
|
|
@@ -6779,15 +7270,22 @@ async function runAnalysis(input) {
|
|
|
6779
7270
|
const formalResult = formalEngine.verify(formalSessions, input.aNext);
|
|
6780
7271
|
if (!formalResult.verified) {
|
|
6781
7272
|
const v = formalResult.violations[0];
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
7273
|
+
if (isFormalObserveMode()) {
|
|
7274
|
+
console.warn(
|
|
7275
|
+
`[AgentMoss] \u5F62\u5F0F\u5316\u9A8C\u8BC1 observe\uFF08\u53EA\u8BB0\u5F55\u4E0D\u62E6\u622A\uFF09: property=${v?.propertyId ?? "?"} risk=${v?.riskLevel ?? "?"} path_len=${v?.path?.length ?? 0} reason=${(v?.reason ?? "?").slice(0, 200)}`
|
|
7276
|
+
);
|
|
7277
|
+
observedFormalLayers.push("2.4");
|
|
7278
|
+
} else {
|
|
7279
|
+
return {
|
|
7280
|
+
allowed: false,
|
|
7281
|
+
reason: v ? v.reason : "\u5F62\u5F0F\u5316\u9A8C\u8BC1\u672A\u901A\u8FC7\uFF08\u884C\u4E3A\u6027\u8D28\u8FDD\u53CD\uFF09",
|
|
7282
|
+
riskLevel: v ? v.riskLevel : "high",
|
|
7283
|
+
riskType: "formal_verification",
|
|
7284
|
+
confidence: 90,
|
|
7285
|
+
source: "formal_engine",
|
|
7286
|
+
violatedLayers: ["2.4"]
|
|
7287
|
+
};
|
|
7288
|
+
}
|
|
6791
7289
|
}
|
|
6792
7290
|
}
|
|
6793
7291
|
if (scriptChain && scriptChain.nodes.length > 0 && isLogicRulesEnabled()) {
|
|
@@ -6834,7 +7332,7 @@ async function runAnalysis(input) {
|
|
|
6834
7332
|
riskType: "",
|
|
6835
7333
|
confidence: 85,
|
|
6836
7334
|
source: "heuristic_and_logic_only",
|
|
6837
|
-
violatedLayers: []
|
|
7335
|
+
violatedLayers: observedFormalLayers.length > 0 ? [...observedFormalLayers] : []
|
|
6838
7336
|
};
|
|
6839
7337
|
}
|
|
6840
7338
|
let skipL3Hints = "\u65E0\uFF08\u5F53\u524D\u65E0\u7981\u7528\u89C4\u5219\u547D\u4E2D\uFF09";
|
|
@@ -6879,7 +7377,7 @@ async function runAnalysis(input) {
|
|
|
6879
7377
|
riskType: "",
|
|
6880
7378
|
confidence: 50,
|
|
6881
7379
|
source: "llm_failure_fallback",
|
|
6882
|
-
violatedLayers: []
|
|
7380
|
+
violatedLayers: observedFormalLayers.length > 0 ? [...observedFormalLayers] : []
|
|
6883
7381
|
};
|
|
6884
7382
|
}
|
|
6885
7383
|
return {
|
|
@@ -6906,6 +7404,9 @@ async function runAnalysis(input) {
|
|
|
6906
7404
|
} catch {
|
|
6907
7405
|
}
|
|
6908
7406
|
}
|
|
7407
|
+
if (observedFormalLayers.length > 0 && llmResult.allowed) {
|
|
7408
|
+
llmResult.violatedLayers = Array.from(/* @__PURE__ */ new Set([...observedFormalLayers, ...llmResult.violatedLayers || []]));
|
|
7409
|
+
}
|
|
6909
7410
|
return llmResult;
|
|
6910
7411
|
}
|
|
6911
7412
|
export {
|
|
@@ -6913,4 +7414,7 @@ export {
|
|
|
6913
7414
|
_resetBrainForTest,
|
|
6914
7415
|
runAnalysis
|
|
6915
7416
|
};
|
|
7417
|
+
//! 顺序即 fail-closed 短路优先级:verify 逐个执行,首个返回违规的性质成为
|
|
7418
|
+
//! first_violation,后续不再评估。调整顺序影响判定归属,须与 Python
|
|
7419
|
+
//! properties.py ALL_PROPERTIES 保持一致并双端测试确认。
|
|
6916
7420
|
//# sourceMappingURL=coordinator.js.map
|