@kenhkl/agent-moss 0.12.9 → 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/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-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
package/dist/cli.js
CHANGED
|
@@ -138,6 +138,7 @@ __export(config_exports, {
|
|
|
138
138
|
getRetryConfig: () => getRetryConfig,
|
|
139
139
|
getTimeoutConfig: () => getTimeoutConfig,
|
|
140
140
|
isBrainEnabled: () => isBrainEnabled,
|
|
141
|
+
isFormalObserveMode: () => isFormalObserveMode,
|
|
141
142
|
isHeuristicEnabled: () => isHeuristicEnabled,
|
|
142
143
|
isLLMAvailable: () => isLLMAvailable,
|
|
143
144
|
isLogicRulesEnabled: () => isLogicRulesEnabled,
|
|
@@ -253,6 +254,7 @@ function getCustomRules() {
|
|
|
253
254
|
}
|
|
254
255
|
function isLLMAvailable() {
|
|
255
256
|
if (process.env.AGENT_MOSS_DISABLE_LLM === "1") return false;
|
|
257
|
+
if (!layerEnabledOrDefault("L3_llm_analysis")) return false;
|
|
256
258
|
return llmConfig.apiKey.length > 0;
|
|
257
259
|
}
|
|
258
260
|
async function probeLLMConnection(timeoutMs = 8e3) {
|
|
@@ -317,13 +319,26 @@ function getProviderHeaders(provider) {
|
|
|
317
319
|
return PROVIDER_HEADERS[provider] || {};
|
|
318
320
|
}
|
|
319
321
|
function isHeuristicEnabled() {
|
|
320
|
-
|
|
322
|
+
if (process.env.AGENT_MOSS_DISABLE_HEURISTIC === "1") return false;
|
|
323
|
+
return layerEnabledOrDefault("L1_heuristic");
|
|
324
|
+
}
|
|
325
|
+
function layerEnabledOrDefault(key) {
|
|
326
|
+
try {
|
|
327
|
+
const { isLayerEnabled: isLayerEnabled2 } = __require("../infra/runtime-config");
|
|
328
|
+
return isLayerEnabled2(key);
|
|
329
|
+
} catch {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
321
332
|
}
|
|
322
333
|
function isBrainEnabled() {
|
|
323
334
|
return process.env.AGENT_MOSS_BRAIN_ENABLED === "1";
|
|
324
335
|
}
|
|
325
336
|
function isLogicRulesEnabled() {
|
|
326
|
-
|
|
337
|
+
if (process.env.AGENT_MOSS_DISABLE_LOGIC_RULES === "1") return false;
|
|
338
|
+
return layerEnabledOrDefault("L2_logic_rules");
|
|
339
|
+
}
|
|
340
|
+
function isFormalObserveMode() {
|
|
341
|
+
return process.env.AGENT_MOSS_FORMAL_OBSERVE === "1";
|
|
327
342
|
}
|
|
328
343
|
var timeoutConfig, retryConfig, llmConfig, __configModuleDir, USER_RULES_PATHS, customRules, PROVIDER_HEADERS;
|
|
329
344
|
var init_config = __esm({
|
|
@@ -581,8 +596,12 @@ var init_inline_analyzer = __esm({
|
|
|
581
596
|
|
|
582
597
|
// src/infra/rules-loader.ts
|
|
583
598
|
import { readFileSync as readFileSync2, existsSync } from "fs";
|
|
584
|
-
import { resolve, dirname } from "path";
|
|
599
|
+
import { resolve, dirname, join as join2 } from "path";
|
|
585
600
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
601
|
+
import { homedir as homedir2 } from "os";
|
|
602
|
+
function dataRootDir() {
|
|
603
|
+
return process.env.AGENT_MOSS_DATA_DIR || join2(homedir2(), ".config", "agentmoss");
|
|
604
|
+
}
|
|
586
605
|
function findRulesFile(name) {
|
|
587
606
|
for (const dir of RULES_DIR_CANDS) {
|
|
588
607
|
const p = resolve(dir, name);
|
|
@@ -608,6 +627,24 @@ function loadL2() {
|
|
|
608
627
|
function loadL3() {
|
|
609
628
|
return loadJson("l3_rules.json");
|
|
610
629
|
}
|
|
630
|
+
function loadMC() {
|
|
631
|
+
const mc = loadJson("mc_rules.json");
|
|
632
|
+
const rules = mc.rules || [];
|
|
633
|
+
try {
|
|
634
|
+
const rt = (init_runtime_config(), __toCommonJS(runtime_config_exports));
|
|
635
|
+
if (rules.length > 0 && typeof rt.hasRuntimeConfig === "function" && rt.hasRuntimeConfig()) {
|
|
636
|
+
const rtRules = rt.loadRuntimeConfig()?.L2_4?.ltl_rules?.rules || [];
|
|
637
|
+
const enabledById = {};
|
|
638
|
+
for (const r of rtRules) if (r?.id) enabledById[r.id] = r.enabled !== false;
|
|
639
|
+
for (const r of rules) if (r?.id && r.id in enabledById) r.enabled = enabledById[r.id];
|
|
640
|
+
}
|
|
641
|
+
} catch {
|
|
642
|
+
}
|
|
643
|
+
return mc;
|
|
644
|
+
}
|
|
645
|
+
function loadToolRegistry() {
|
|
646
|
+
return loadJson("tool_registry.json");
|
|
647
|
+
}
|
|
611
648
|
var __filename2, __dirname2, RULES_DIR_CANDS;
|
|
612
649
|
var init_rules_loader = __esm({
|
|
613
650
|
"src/infra/rules-loader.ts"() {
|
|
@@ -617,6 +654,10 @@ var init_rules_loader = __esm({
|
|
|
617
654
|
__dirname2 = dirname(__filename2);
|
|
618
655
|
RULES_DIR_CANDS = (() => {
|
|
619
656
|
const cands = [
|
|
657
|
+
// 用户数据目录覆盖优先(与 Python rules_loader._load_json 的
|
|
658
|
+
// <data_root>/rules/<name> 优先逻辑对齐)。用户安装 pip/npm 包后把自定义
|
|
659
|
+
// mc_rules.json 放到 <data_root>/rules/ 即可覆盖内置默认,无需改源码。
|
|
660
|
+
resolve(dataRootDir(), "rules"),
|
|
620
661
|
// dist: __dirname=dist/ → dist/rules;__dirname=dist/engine/ → dist/engine/../rules=dist/rules
|
|
621
662
|
resolve(__dirname2, "../rules"),
|
|
622
663
|
resolve(__dirname2, "rules"),
|
|
@@ -1354,6 +1395,7 @@ var init_skill_loader = __esm({
|
|
|
1354
1395
|
// src/infra/runtime-config.ts
|
|
1355
1396
|
var runtime_config_exports = {};
|
|
1356
1397
|
__export(runtime_config_exports, {
|
|
1398
|
+
DEFAULT_LAYERS: () => DEFAULT_LAYERS,
|
|
1357
1399
|
DENY_MODE_LABELS: () => DENY_MODE_LABELS,
|
|
1358
1400
|
addAgentRule: () => addAgentRule,
|
|
1359
1401
|
addCustomRule: () => addCustomRule,
|
|
@@ -1405,7 +1447,7 @@ __export(runtime_config_exports, {
|
|
|
1405
1447
|
updateSkillEnabled: () => updateSkillEnabled
|
|
1406
1448
|
});
|
|
1407
1449
|
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync4, mkdirSync, unlinkSync, readdirSync as readdirSync3 } from "fs";
|
|
1408
|
-
import { join as
|
|
1450
|
+
import { join as join3 } from "path";
|
|
1409
1451
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1410
1452
|
import { dirname as dirname3 } from "path";
|
|
1411
1453
|
function runtimeDir() {
|
|
@@ -1429,6 +1471,7 @@ function emptyRuntimeConfig() {
|
|
|
1429
1471
|
L1_rules: {},
|
|
1430
1472
|
L2_rules: {},
|
|
1431
1473
|
L3_skills: {},
|
|
1474
|
+
L2_4: {},
|
|
1432
1475
|
agent_rules: {},
|
|
1433
1476
|
scenario_rules: {}
|
|
1434
1477
|
};
|
|
@@ -1456,6 +1499,7 @@ function loadRuntimeConfig() {
|
|
|
1456
1499
|
L1_rules: merged.L1_rules || {},
|
|
1457
1500
|
L2_rules: merged.L2_rules || {},
|
|
1458
1501
|
L3_skills: merged.L3_skills || {},
|
|
1502
|
+
L2_4: merged.L2_4 || {},
|
|
1459
1503
|
agent_rules: merged.agent_rules || {},
|
|
1460
1504
|
scenario_rules: merged.scenario_rules || {}
|
|
1461
1505
|
};
|
|
@@ -1703,7 +1747,7 @@ function _scenarioRulesToDefaults() {
|
|
|
1703
1747
|
return out;
|
|
1704
1748
|
}
|
|
1705
1749
|
for (const scenarioId of entries) {
|
|
1706
|
-
const rulesFile =
|
|
1750
|
+
const rulesFile = join3(scenDir, scenarioId, "rules.json");
|
|
1707
1751
|
if (!existsSync4(rulesFile)) continue;
|
|
1708
1752
|
let data;
|
|
1709
1753
|
try {
|
|
@@ -1752,7 +1796,7 @@ function _agentRulesToDefaults() {
|
|
|
1752
1796
|
return out;
|
|
1753
1797
|
}
|
|
1754
1798
|
for (const agentId of entries) {
|
|
1755
|
-
const rulesFile =
|
|
1799
|
+
const rulesFile = join3(agentsDir, agentId, "rules.json");
|
|
1756
1800
|
if (!existsSync4(rulesFile)) continue;
|
|
1757
1801
|
let data;
|
|
1758
1802
|
try {
|
|
@@ -1793,7 +1837,7 @@ function _agentRulesToDefaults() {
|
|
|
1793
1837
|
function generateSourceDefaults() {
|
|
1794
1838
|
return {
|
|
1795
1839
|
version: 1,
|
|
1796
|
-
layers: {
|
|
1840
|
+
layers: { ...DEFAULT_LAYERS },
|
|
1797
1841
|
L1_rules: {
|
|
1798
1842
|
dangerous_commands: {
|
|
1799
1843
|
category_enabled: true,
|
|
@@ -1832,10 +1876,45 @@ function generateSourceDefaults() {
|
|
|
1832
1876
|
user_custom: { category_enabled: true, category_desc: "\u7528\u6237\u81EA\u5B9A\u4E49 L2 \u903B\u8F91\u89C4\u5219", rules: [] }
|
|
1833
1877
|
},
|
|
1834
1878
|
L3_skills: _l3SkillsToRules(),
|
|
1879
|
+
L2_4: _ltlRulesToRuntime(),
|
|
1835
1880
|
agent_rules: _agentRulesToDefaults(),
|
|
1836
1881
|
scenario_rules: _scenarioRulesToDefaults()
|
|
1837
1882
|
};
|
|
1838
1883
|
}
|
|
1884
|
+
function _ltlRulesToRuntime() {
|
|
1885
|
+
const cands = [
|
|
1886
|
+
join3(__dirname4, "..", "rules"),
|
|
1887
|
+
join3(__dirname4, "..", "..", "..", "agent_moss", "rules"),
|
|
1888
|
+
join3(process.cwd(), "agent_moss", "rules")
|
|
1889
|
+
];
|
|
1890
|
+
let mc = {};
|
|
1891
|
+
for (const dir of cands) {
|
|
1892
|
+
const p = join3(dir, "mc_rules.json");
|
|
1893
|
+
if (existsSync4(p)) {
|
|
1894
|
+
try {
|
|
1895
|
+
mc = JSON.parse(readFileSync4(p, "utf-8")) || {};
|
|
1896
|
+
} catch {
|
|
1897
|
+
mc = {};
|
|
1898
|
+
}
|
|
1899
|
+
break;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
const rules = mc.rules || [];
|
|
1903
|
+
return {
|
|
1904
|
+
ltl_rules: {
|
|
1905
|
+
category_enabled: true,
|
|
1906
|
+
category_desc: "LTL \u653B\u51FB\u6A21\u5F0F\u89C4\u5219\uFF08\u65F6\u5E8F\u653B\u51FB\u68C0\u6D4B\uFF0C\u5148 A \u540E B\uFF09",
|
|
1907
|
+
rules: rules.map((r) => ({
|
|
1908
|
+
id: r.id,
|
|
1909
|
+
reason: r.reason || "",
|
|
1910
|
+
risk_level: r.risk_level || "high",
|
|
1911
|
+
action: r.action || "block",
|
|
1912
|
+
enabled: true,
|
|
1913
|
+
builtin: true
|
|
1914
|
+
}))
|
|
1915
|
+
}
|
|
1916
|
+
};
|
|
1917
|
+
}
|
|
1839
1918
|
function normalizePatternForFingerprint(pattern) {
|
|
1840
1919
|
return pattern.replace(/\\\//g, "/");
|
|
1841
1920
|
}
|
|
@@ -1985,6 +2064,7 @@ function mergeConfig(userCfg, srcDefaults) {
|
|
|
1985
2064
|
);
|
|
1986
2065
|
_mergeRuleCategories(cfg, srcDefaults, "L1_rules");
|
|
1987
2066
|
_mergeRuleCategories(cfg, srcDefaults, "L2_rules");
|
|
2067
|
+
_mergeRuleCategories(cfg, srcDefaults, "L2_4");
|
|
1988
2068
|
_mergeSkillCategories(cfg, srcDefaults, "L3_skills");
|
|
1989
2069
|
_mergeAgentRules(cfg, srcDefaults);
|
|
1990
2070
|
_mergeAgentRules(cfg, srcDefaults, "scenario_rules");
|
|
@@ -2177,12 +2257,12 @@ function deleteCustomRule(layer, category, ruleId) {
|
|
|
2177
2257
|
function addCustomSkill(skillId, category, keywords, content) {
|
|
2178
2258
|
_validateSkillId(skillId);
|
|
2179
2259
|
const runtime = loadRuntimeConfig();
|
|
2180
|
-
const skillsDir =
|
|
2260
|
+
const skillsDir = join3(RUNTIME_CONFIG_DIR, "agent_moss_skills");
|
|
2181
2261
|
try {
|
|
2182
2262
|
mkdirSync(skillsDir, { recursive: true });
|
|
2183
2263
|
} catch {
|
|
2184
2264
|
}
|
|
2185
|
-
writeFileSync(
|
|
2265
|
+
writeFileSync(join3(skillsDir, `${skillId}.md`), content, "utf-8");
|
|
2186
2266
|
const l3 = runtime.L3_skills || (runtime.L3_skills = {});
|
|
2187
2267
|
const cat = l3[category] || (l3[category] = { category_enabled: true, category_desc: "", skills: [] });
|
|
2188
2268
|
(cat.skills || (cat.skills = [])).push({ id: skillId, keywords, enabled: true, builtin: false });
|
|
@@ -2197,7 +2277,7 @@ function deleteCustomSkill(skillId, category) {
|
|
|
2197
2277
|
if (idx >= 0) {
|
|
2198
2278
|
if (skills[idx].builtin) return null;
|
|
2199
2279
|
skills.splice(idx, 1);
|
|
2200
|
-
const skillPath =
|
|
2280
|
+
const skillPath = join3(RUNTIME_CONFIG_DIR, "agent_moss_skills", `${skillId}.md`);
|
|
2201
2281
|
try {
|
|
2202
2282
|
if (existsSync4(skillPath)) unlinkSync(skillPath);
|
|
2203
2283
|
} catch {
|
|
@@ -2391,7 +2471,7 @@ function updateScenarioCategoryEnabled(scenarioId, category, enabled) {
|
|
|
2391
2471
|
saveRuntimeConfig(runtime);
|
|
2392
2472
|
return runtime;
|
|
2393
2473
|
}
|
|
2394
|
-
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;
|
|
2474
|
+
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;
|
|
2395
2475
|
var init_runtime_config = __esm({
|
|
2396
2476
|
"src/infra/runtime-config.ts"() {
|
|
2397
2477
|
"use strict";
|
|
@@ -2403,21 +2483,28 @@ var init_runtime_config = __esm({
|
|
|
2403
2483
|
__dirname4 = dirname3(fileURLToPath5(import.meta.url));
|
|
2404
2484
|
ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
|
|
2405
2485
|
RUNTIME_CONFIG_DIR = runtimeDir();
|
|
2406
|
-
RUNTIME_CONFIG_PATH =
|
|
2486
|
+
RUNTIME_CONFIG_PATH = join3(RUNTIME_CONFIG_DIR, "agent_moss_runtime.json");
|
|
2407
2487
|
LAYER_DISABLE_ENV = {
|
|
2408
2488
|
L1_heuristic: "AGENT_MOSS_DISABLE_HEURISTIC",
|
|
2409
2489
|
L2_logic_rules: "AGENT_MOSS_DISABLE_LOGIC_RULES",
|
|
2410
2490
|
L3_llm_analysis: "AGENT_MOSS_DISABLE_LLM"
|
|
2411
2491
|
};
|
|
2492
|
+
DEFAULT_LAYERS = {
|
|
2493
|
+
L1_heuristic: true,
|
|
2494
|
+
L2_logic_rules: true,
|
|
2495
|
+
L3_llm_analysis: true,
|
|
2496
|
+
agent_rules_enabled: true,
|
|
2497
|
+
scenario_rules_enabled: true
|
|
2498
|
+
};
|
|
2412
2499
|
DENY_MODE_LABELS = {
|
|
2413
2500
|
deny_write: "\u4EC5\u62E6\u622A\u5199\u5165",
|
|
2414
2501
|
deny_read: "\u4EC5\u62E6\u622A\u8BFB\u53D6",
|
|
2415
2502
|
deny_both: "\u8BFB\u5199\u5747\u62E6\u622A"
|
|
2416
2503
|
};
|
|
2417
|
-
_AGENTS_DIR_PROD =
|
|
2418
|
-
_AGENTS_DIR_DEV =
|
|
2419
|
-
_SCENARIOS_DIR_PROD =
|
|
2420
|
-
_SCENARIOS_DIR_DEV =
|
|
2504
|
+
_AGENTS_DIR_PROD = join3(__dirname4, "agents");
|
|
2505
|
+
_AGENTS_DIR_DEV = join3(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
2506
|
+
_SCENARIOS_DIR_PROD = join3(__dirname4, "scenarios");
|
|
2507
|
+
_SCENARIOS_DIR_DEV = join3(__dirname4, "..", "..", "..", "agent_moss", "scenarios");
|
|
2421
2508
|
SKILL_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
2422
2509
|
}
|
|
2423
2510
|
});
|
|
@@ -2555,11 +2642,21 @@ function getScenarioExtensions(scenarioId) {
|
|
|
2555
2642
|
);
|
|
2556
2643
|
return ext;
|
|
2557
2644
|
}
|
|
2645
|
+
function getScenarioExtensionsMulti(scenarioSpec) {
|
|
2646
|
+
if (!scenarioSpec) return null;
|
|
2647
|
+
const ids = scenarioSpec.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2648
|
+
if (ids.length === 0) return null;
|
|
2649
|
+
const exts = ids.map((id) => getScenarioExtensions(id));
|
|
2650
|
+
const nonNull = exts.filter((e) => e !== null);
|
|
2651
|
+
if (nonNull.length === 0) return null;
|
|
2652
|
+
return mergeAgentExtensions(...nonNull);
|
|
2653
|
+
}
|
|
2558
2654
|
var __filename5, __dirname6, SCENARIOS_DIR_PROD, SCENARIOS_DIR_DEV_FALLBACK, cache2;
|
|
2559
2655
|
var init_scenarios = __esm({
|
|
2560
2656
|
"src/scenarios/index.ts"() {
|
|
2561
2657
|
"use strict";
|
|
2562
2658
|
init_esm_shims();
|
|
2659
|
+
init_agents();
|
|
2563
2660
|
__filename5 = fileURLToPath7(import.meta.url);
|
|
2564
2661
|
__dirname6 = dirname5(__filename5);
|
|
2565
2662
|
SCENARIOS_DIR_PROD = resolve4(__dirname6, "scenarios");
|
|
@@ -2608,8 +2705,8 @@ function runHeuristicCheck(input) {
|
|
|
2608
2705
|
}
|
|
2609
2706
|
highestRiskType = topRiskType || highestRiskType;
|
|
2610
2707
|
const agentExt = mergeAgentExtensions(
|
|
2611
|
-
getAgentExtensions(input.agentId),
|
|
2612
|
-
|
|
2708
|
+
isLayerEnabled("agent_rules_enabled") ? getAgentExtensions(input.agentId) : null,
|
|
2709
|
+
isLayerEnabled("scenario_rules_enabled") ? getScenarioExtensionsMulti(input.scenarioId || process.env.AGENT_MOSS_SCENARIO || "") : null
|
|
2613
2710
|
);
|
|
2614
2711
|
if (agentExt?.extra_command_patterns) {
|
|
2615
2712
|
for (const rule of agentExt.extra_command_patterns) {
|
|
@@ -3054,6 +3151,7 @@ var init_heuristic = __esm({
|
|
|
3054
3151
|
init_config();
|
|
3055
3152
|
init_agents();
|
|
3056
3153
|
init_scenarios();
|
|
3154
|
+
init_runtime_config();
|
|
3057
3155
|
init_rules_loader();
|
|
3058
3156
|
init_logic_rules();
|
|
3059
3157
|
INJECTION_KEYWORDS = (() => {
|
|
@@ -3116,7 +3214,7 @@ var init_template_loader = __esm({
|
|
|
3116
3214
|
|
|
3117
3215
|
// src/engine/script-analyzer.ts
|
|
3118
3216
|
import { readFileSync as readFileSync8 } from "fs";
|
|
3119
|
-
import { resolve as resolve6, join as
|
|
3217
|
+
import { resolve as resolve6, join as join4 } from "path";
|
|
3120
3218
|
function emptyResult() {
|
|
3121
3219
|
return { scriptPath: "", scriptContent: "", matchedKeywords: [], lineCount: 0, isSuspicious: false, error: "", riskLevel: "", riskReason: "" };
|
|
3122
3220
|
}
|
|
@@ -3169,7 +3267,7 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
3169
3267
|
}
|
|
3170
3268
|
function readScriptContent(scriptPath, maxLines = 500) {
|
|
3171
3269
|
try {
|
|
3172
|
-
const expandedPath = scriptPath.startsWith("~") ?
|
|
3270
|
+
const expandedPath = scriptPath.startsWith("~") ? join4(process.env.HOME || "/home/user", scriptPath.slice(2)) : resolve6(scriptPath);
|
|
3173
3271
|
const raw = readFileSync8(expandedPath, "utf-8");
|
|
3174
3272
|
const lines = raw.split("\n").slice(0, maxLines);
|
|
3175
3273
|
return { content: lines.join("\n"), lineCount: lines.length, error: "" };
|
|
@@ -4803,8 +4901,8 @@ var init_tracker = __esm({
|
|
|
4803
4901
|
|
|
4804
4902
|
// src/engine/script-content-analyzer.ts
|
|
4805
4903
|
import { statSync as statSync2, existsSync as existsSync9 } from "fs";
|
|
4806
|
-
import { resolve as resolve8, join as
|
|
4807
|
-
import { homedir as
|
|
4904
|
+
import { resolve as resolve8, join as join6, isAbsolute as isAbsolute2 } from "path";
|
|
4905
|
+
import { homedir as homedir4 } from "os";
|
|
4808
4906
|
function emptyChain() {
|
|
4809
4907
|
return {
|
|
4810
4908
|
nodes: [],
|
|
@@ -4902,7 +5000,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
4902
5000
|
function resolvePath2(p) {
|
|
4903
5001
|
let expanded = p;
|
|
4904
5002
|
if (expanded.startsWith("~/") || expanded === "~") {
|
|
4905
|
-
expanded =
|
|
5003
|
+
expanded = join6(homedir4(), expanded.slice(1));
|
|
4906
5004
|
}
|
|
4907
5005
|
return resolve8(expanded);
|
|
4908
5006
|
}
|
|
@@ -4983,7 +5081,7 @@ function analyzeScriptContent2(input) {
|
|
|
4983
5081
|
isInline = true;
|
|
4984
5082
|
}
|
|
4985
5083
|
if (resolvedPath && !isAbsolute2(resolvedPath) && !resolvedPath.startsWith("~/")) {
|
|
4986
|
-
resolvedPath =
|
|
5084
|
+
resolvedPath = join6(input.cwd || process.cwd(), resolvedPath);
|
|
4987
5085
|
}
|
|
4988
5086
|
const l1Adapter = (content) => {
|
|
4989
5087
|
const virtualInput = {
|
|
@@ -5573,8 +5671,8 @@ var init_llm_analyzer = __esm({
|
|
|
5573
5671
|
|
|
5574
5672
|
// src/brain/rule-store.ts
|
|
5575
5673
|
import { existsSync as existsSync11, readFileSync as readFileSync12, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
5576
|
-
import { join as
|
|
5577
|
-
import { homedir as
|
|
5674
|
+
import { join as join7 } from "path";
|
|
5675
|
+
import { homedir as homedir5 } from "os";
|
|
5578
5676
|
function getRulesPath() {
|
|
5579
5677
|
const envPath = process.env[ENV_RULES_PATH];
|
|
5580
5678
|
if (envPath) return envPath;
|
|
@@ -5592,7 +5690,7 @@ var init_rule_store = __esm({
|
|
|
5592
5690
|
"src/brain/rule-store.ts"() {
|
|
5593
5691
|
"use strict";
|
|
5594
5692
|
init_esm_shims();
|
|
5595
|
-
DEFAULT_RULES_PATH =
|
|
5693
|
+
DEFAULT_RULES_PATH = join7(homedir5(), ".agentmoss", "brain", "rules.json");
|
|
5596
5694
|
ENV_RULES_PATH = "AGENT_MOSS_BRAIN_RULES_PATH";
|
|
5597
5695
|
STATUS_DRAFT = "draft";
|
|
5598
5696
|
STATUS_APPROVED = "approved";
|
|
@@ -6122,6 +6220,13 @@ var init_brain = __esm({
|
|
|
6122
6220
|
});
|
|
6123
6221
|
|
|
6124
6222
|
// src/engine/formal-engine/decode.ts
|
|
6223
|
+
var decode_exports = {};
|
|
6224
|
+
__export(decode_exports, {
|
|
6225
|
+
allCandidates: () => allCandidates,
|
|
6226
|
+
decodeBase64Literals: () => decodeBase64Literals,
|
|
6227
|
+
decodeUrlAndNumeric: () => decodeUrlAndNumeric,
|
|
6228
|
+
matchStageAny: () => matchStageAny
|
|
6229
|
+
});
|
|
6125
6230
|
function isValidBase64Token(tok) {
|
|
6126
6231
|
if (tok.length < 8) return false;
|
|
6127
6232
|
if (!(tok.length % 4 === 0 || tok.endsWith("==") || tok.endsWith("="))) return false;
|
|
@@ -6220,6 +6325,142 @@ var init_decode = __esm({
|
|
|
6220
6325
|
}
|
|
6221
6326
|
});
|
|
6222
6327
|
|
|
6328
|
+
// src/engine/formal-engine/ir.ts
|
|
6329
|
+
function allNodes(mg) {
|
|
6330
|
+
const out = [];
|
|
6331
|
+
for (const s of mg.sessions) out.push(...s.nodes);
|
|
6332
|
+
return out;
|
|
6333
|
+
}
|
|
6334
|
+
function allEdges(mg) {
|
|
6335
|
+
const out = [];
|
|
6336
|
+
for (const s of mg.sessions) out.push(...s.edges);
|
|
6337
|
+
out.push(...mg.crossEdges);
|
|
6338
|
+
return out;
|
|
6339
|
+
}
|
|
6340
|
+
function emptyVerificationResult() {
|
|
6341
|
+
return { verified: true, violations: [] };
|
|
6342
|
+
}
|
|
6343
|
+
var init_ir = __esm({
|
|
6344
|
+
"src/engine/formal-engine/ir.ts"() {
|
|
6345
|
+
"use strict";
|
|
6346
|
+
init_esm_shims();
|
|
6347
|
+
}
|
|
6348
|
+
});
|
|
6349
|
+
|
|
6350
|
+
// src/engine/formal-engine/ltl.ts
|
|
6351
|
+
function compileAps(apPatterns) {
|
|
6352
|
+
if (AP_RE) return;
|
|
6353
|
+
AP_RE = {};
|
|
6354
|
+
for (const [name, pats] of Object.entries(apPatterns || {})) {
|
|
6355
|
+
AP_RE[name] = pats.map((p) => new RegExp(p, "i"));
|
|
6356
|
+
}
|
|
6357
|
+
}
|
|
6358
|
+
function labelEvent(actionDetail) {
|
|
6359
|
+
if (!AP_RE) compileAps(loadMC().ap_patterns || {});
|
|
6360
|
+
let candidates = [actionDetail];
|
|
6361
|
+
try {
|
|
6362
|
+
candidates = (init_decode(), __toCommonJS(decode_exports)).allCandidates(actionDetail);
|
|
6363
|
+
} catch {
|
|
6364
|
+
}
|
|
6365
|
+
const hits = /* @__PURE__ */ new Set();
|
|
6366
|
+
for (const [name, pats] of Object.entries(AP_RE || {})) {
|
|
6367
|
+
for (const c of candidates) {
|
|
6368
|
+
const m = pats.some((p) => p.test(c));
|
|
6369
|
+
if (m) {
|
|
6370
|
+
hits.add(name);
|
|
6371
|
+
break;
|
|
6372
|
+
}
|
|
6373
|
+
}
|
|
6374
|
+
}
|
|
6375
|
+
return hits;
|
|
6376
|
+
}
|
|
6377
|
+
function evaluateLTL(formula, trace, pos) {
|
|
6378
|
+
const op = formula[0];
|
|
6379
|
+
switch (op) {
|
|
6380
|
+
case "ap":
|
|
6381
|
+
return trace[pos].has(formula[1]);
|
|
6382
|
+
case "!":
|
|
6383
|
+
return !evaluateLTL(formula[1], trace, pos);
|
|
6384
|
+
case "&":
|
|
6385
|
+
return evaluateLTL(formula[1], trace, pos) && evaluateLTL(formula[2], trace, pos);
|
|
6386
|
+
case "|":
|
|
6387
|
+
return evaluateLTL(formula[1], trace, pos) || evaluateLTL(formula[2], trace, pos);
|
|
6388
|
+
case "->":
|
|
6389
|
+
return !evaluateLTL(formula[1], trace, pos) || evaluateLTL(formula[2], trace, pos);
|
|
6390
|
+
case "X":
|
|
6391
|
+
return pos + 1 < trace.length && evaluateLTL(formula[1], trace, pos + 1);
|
|
6392
|
+
case "G": {
|
|
6393
|
+
for (let j = pos; j < trace.length; j++) {
|
|
6394
|
+
if (!evaluateLTL(formula[1], trace, j)) return false;
|
|
6395
|
+
}
|
|
6396
|
+
return true;
|
|
6397
|
+
}
|
|
6398
|
+
case "F": {
|
|
6399
|
+
for (let j = pos; j < trace.length; j++) {
|
|
6400
|
+
if (evaluateLTL(formula[1], trace, j)) return true;
|
|
6401
|
+
}
|
|
6402
|
+
return false;
|
|
6403
|
+
}
|
|
6404
|
+
case "U": {
|
|
6405
|
+
for (let j = pos; j < trace.length; j++) {
|
|
6406
|
+
if (evaluateLTL(formula[2], trace, j)) {
|
|
6407
|
+
for (let k = pos; k < j; k++) {
|
|
6408
|
+
if (!evaluateLTL(formula[1], trace, k)) return false;
|
|
6409
|
+
}
|
|
6410
|
+
return true;
|
|
6411
|
+
}
|
|
6412
|
+
}
|
|
6413
|
+
return false;
|
|
6414
|
+
}
|
|
6415
|
+
default:
|
|
6416
|
+
return false;
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
function ruleViolates(rule, traceWith, witnessMode) {
|
|
6420
|
+
const formula = rule?.formula;
|
|
6421
|
+
if (!Array.isArray(formula) || formula.length === 0) return false;
|
|
6422
|
+
const satWith = evaluateLTL(formula, traceWith, 0);
|
|
6423
|
+
if (!satWith) return false;
|
|
6424
|
+
if (witnessMode && traceWith.length > 1) {
|
|
6425
|
+
const traceWithout = traceWith.slice(0, -1);
|
|
6426
|
+
if (evaluateLTL(formula, traceWithout, 0)) return false;
|
|
6427
|
+
}
|
|
6428
|
+
return true;
|
|
6429
|
+
}
|
|
6430
|
+
function checkMCRules(graph) {
|
|
6431
|
+
const violations = [];
|
|
6432
|
+
const nodes = allNodes(graph);
|
|
6433
|
+
if (nodes.length === 0) return violations;
|
|
6434
|
+
const mc = loadMC();
|
|
6435
|
+
const rules = mc.rules || [];
|
|
6436
|
+
if (rules.length === 0) return violations;
|
|
6437
|
+
const trace = nodes.map((n) => labelEvent(n.actionDetail));
|
|
6438
|
+
const witnessMode = graph.witnessIdx !== void 0;
|
|
6439
|
+
for (const rule of rules) {
|
|
6440
|
+
if (rule?.type !== "ltl" || !(rule.enabled !== false)) continue;
|
|
6441
|
+
if (ruleViolates(rule, trace, witnessMode)) {
|
|
6442
|
+
violations.push({
|
|
6443
|
+
propertyId: String(rule.id || "mc-ltl"),
|
|
6444
|
+
reason: String(rule.reason || "L2.2 \u6A21\u578B\u68C0\u6D4B\u89C4\u5219\u547D\u4E2D"),
|
|
6445
|
+
riskLevel: String(rule.risk_level || "high"),
|
|
6446
|
+
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) }))
|
|
6447
|
+
});
|
|
6448
|
+
if (witnessMode) return violations;
|
|
6449
|
+
}
|
|
6450
|
+
}
|
|
6451
|
+
return violations;
|
|
6452
|
+
}
|
|
6453
|
+
var AP_RE;
|
|
6454
|
+
var init_ltl = __esm({
|
|
6455
|
+
"src/engine/formal-engine/ltl.ts"() {
|
|
6456
|
+
"use strict";
|
|
6457
|
+
init_esm_shims();
|
|
6458
|
+
init_rules_loader();
|
|
6459
|
+
init_ir();
|
|
6460
|
+
AP_RE = null;
|
|
6461
|
+
}
|
|
6462
|
+
});
|
|
6463
|
+
|
|
6223
6464
|
// src/engine/formal-engine/builder.ts
|
|
6224
6465
|
function loadStages() {
|
|
6225
6466
|
if (COMBO_STAGES2) return COMBO_STAGES2;
|
|
@@ -6246,6 +6487,26 @@ function extractResources(actionDetail) {
|
|
|
6246
6487
|
function markStage(actionDetail) {
|
|
6247
6488
|
return matchStageAny(actionDetail, loadStages());
|
|
6248
6489
|
}
|
|
6490
|
+
function markIntegrity(actionDetail) {
|
|
6491
|
+
const aps = labelEvent(actionDetail);
|
|
6492
|
+
if (aps.has("download_file") || aps.has("prompt_injection")) {
|
|
6493
|
+
return { integrity: "low", isLowSource: true };
|
|
6494
|
+
}
|
|
6495
|
+
return { integrity: "medium", isLowSource: false };
|
|
6496
|
+
}
|
|
6497
|
+
function initNode(sessionId, seq, actionType, actionDetail) {
|
|
6498
|
+
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
6499
|
+
return {
|
|
6500
|
+
sessionId,
|
|
6501
|
+
seq,
|
|
6502
|
+
actionType,
|
|
6503
|
+
actionDetail,
|
|
6504
|
+
stage: markStage(actionDetail),
|
|
6505
|
+
resources: extractResources(actionDetail),
|
|
6506
|
+
integrity,
|
|
6507
|
+
isLowSource
|
|
6508
|
+
};
|
|
6509
|
+
}
|
|
6249
6510
|
function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
6250
6511
|
const nodes = [];
|
|
6251
6512
|
const edges = [];
|
|
@@ -6259,17 +6520,9 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
|
6259
6520
|
details.push({ actionType: String(aNext.actionType || ""), actionDetail: String(aNext.actionDetail || "") });
|
|
6260
6521
|
}
|
|
6261
6522
|
details.forEach((d, seq) => {
|
|
6262
|
-
const
|
|
6263
|
-
const node = {
|
|
6264
|
-
sessionId,
|
|
6265
|
-
seq,
|
|
6266
|
-
actionType: d.actionType,
|
|
6267
|
-
actionDetail: d.actionDetail,
|
|
6268
|
-
stage,
|
|
6269
|
-
resources: extractResources(d.actionDetail)
|
|
6270
|
-
};
|
|
6523
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail);
|
|
6271
6524
|
nodes.push(node);
|
|
6272
|
-
if (stage) stageFlags.add(stage);
|
|
6525
|
+
if (node.stage) stageFlags.add(node.stage);
|
|
6273
6526
|
});
|
|
6274
6527
|
for (let i = 0; i < nodes.length - 1; i++) {
|
|
6275
6528
|
edges.push({ src: i, dst: i + 1, kind: "next" });
|
|
@@ -6289,15 +6542,12 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
6289
6542
|
if (aNext) {
|
|
6290
6543
|
const last = mg.sessions[mg.sessions.length - 1];
|
|
6291
6544
|
if (last.sessionId === "current") {
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
stage,
|
|
6299
|
-
resources: extractResources(String(aNext.actionDetail || ""))
|
|
6300
|
-
});
|
|
6545
|
+
last.nodes.push(initNode(
|
|
6546
|
+
last.sessionId,
|
|
6547
|
+
last.nodes.length,
|
|
6548
|
+
String(aNext.actionType || ""),
|
|
6549
|
+
String(aNext.actionDetail || "")
|
|
6550
|
+
));
|
|
6301
6551
|
if (last.nodes.length > 1) {
|
|
6302
6552
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
6303
6553
|
}
|
|
@@ -6311,11 +6561,25 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
6311
6561
|
function addCrossDataEdges(mg) {
|
|
6312
6562
|
const nodes = allNodesFlat(mg);
|
|
6313
6563
|
if (nodes.length < 2) return;
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6317
|
-
const
|
|
6318
|
-
if (
|
|
6564
|
+
const resIndex = /* @__PURE__ */ new Map();
|
|
6565
|
+
nodes.forEach((n, i) => {
|
|
6566
|
+
for (const r of n.resources) {
|
|
6567
|
+
const list = resIndex.get(r);
|
|
6568
|
+
if (list) list.push(i);
|
|
6569
|
+
else resIndex.set(r, [i]);
|
|
6570
|
+
}
|
|
6571
|
+
});
|
|
6572
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6573
|
+
for (const idxs of resIndex.values()) {
|
|
6574
|
+
if (idxs.length < 2) continue;
|
|
6575
|
+
for (let a = 0; a < idxs.length; a++) {
|
|
6576
|
+
const i = idxs[a];
|
|
6577
|
+
for (let b = a + 1; b < idxs.length; b++) {
|
|
6578
|
+
const j = idxs[b];
|
|
6579
|
+
if (nodes[i].sessionId === nodes[j].sessionId) continue;
|
|
6580
|
+
const key = `${i}:${j}`;
|
|
6581
|
+
if (seen.has(key)) continue;
|
|
6582
|
+
seen.add(key);
|
|
6319
6583
|
mg.crossEdges.push({ src: i, dst: j, kind: "data" });
|
|
6320
6584
|
}
|
|
6321
6585
|
}
|
|
@@ -6326,11 +6590,6 @@ function allNodesFlat(mg) {
|
|
|
6326
6590
|
for (const s of mg.sessions) out.push(...s.nodes);
|
|
6327
6591
|
return out;
|
|
6328
6592
|
}
|
|
6329
|
-
function intersect(a, b) {
|
|
6330
|
-
const out = /* @__PURE__ */ new Set();
|
|
6331
|
-
for (const v of a) if (b.has(v)) out.add(v);
|
|
6332
|
-
return out;
|
|
6333
|
-
}
|
|
6334
6593
|
var COMBO_STAGES2, PATH_RE;
|
|
6335
6594
|
var init_builder = __esm({
|
|
6336
6595
|
"src/engine/formal-engine/builder.ts"() {
|
|
@@ -6338,33 +6597,12 @@ var init_builder = __esm({
|
|
|
6338
6597
|
init_esm_shims();
|
|
6339
6598
|
init_rules_loader();
|
|
6340
6599
|
init_decode();
|
|
6600
|
+
init_ltl();
|
|
6341
6601
|
COMBO_STAGES2 = null;
|
|
6342
6602
|
PATH_RE = /(?:^|\s|[@=])((?:\/|~\/)[\w./~-]+)/g;
|
|
6343
6603
|
}
|
|
6344
6604
|
});
|
|
6345
6605
|
|
|
6346
|
-
// src/engine/formal-engine/ir.ts
|
|
6347
|
-
function allNodes(mg) {
|
|
6348
|
-
const out = [];
|
|
6349
|
-
for (const s of mg.sessions) out.push(...s.nodes);
|
|
6350
|
-
return out;
|
|
6351
|
-
}
|
|
6352
|
-
function allEdges(mg) {
|
|
6353
|
-
const out = [];
|
|
6354
|
-
for (const s of mg.sessions) out.push(...s.edges);
|
|
6355
|
-
out.push(...mg.crossEdges);
|
|
6356
|
-
return out;
|
|
6357
|
-
}
|
|
6358
|
-
function emptyVerificationResult() {
|
|
6359
|
-
return { verified: true, violations: [] };
|
|
6360
|
-
}
|
|
6361
|
-
var init_ir = __esm({
|
|
6362
|
-
"src/engine/formal-engine/ir.ts"() {
|
|
6363
|
-
"use strict";
|
|
6364
|
-
init_esm_shims();
|
|
6365
|
-
}
|
|
6366
|
-
});
|
|
6367
|
-
|
|
6368
6606
|
// src/engine/formal-engine/properties.ts
|
|
6369
6607
|
function loadCrossSessionChains() {
|
|
6370
6608
|
if (CROSS_SESSION_CHAINS) return CROSS_SESSION_CHAINS;
|
|
@@ -6381,27 +6619,50 @@ function checkCrossSessionChain(graph) {
|
|
|
6381
6619
|
const violations = [];
|
|
6382
6620
|
const nodes = allNodes(graph);
|
|
6383
6621
|
if (nodes.length === 0) return violations;
|
|
6622
|
+
const witness = graph.witnessIdx;
|
|
6384
6623
|
for (const chain of loadCrossSessionChains()) {
|
|
6385
6624
|
const stages = chain.stages;
|
|
6386
6625
|
if (!stages.length) continue;
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6626
|
+
if (witness !== void 0) {
|
|
6627
|
+
if (nodes[witness].stage !== stages[stages.length - 1]) continue;
|
|
6628
|
+
let matched = 0;
|
|
6629
|
+
const path6 = [];
|
|
6630
|
+
for (let k = 0; k < witness; k++) {
|
|
6631
|
+
const n = nodes[k];
|
|
6632
|
+
if (matched < stages.length - 1 && n.stage === stages[matched]) {
|
|
6633
|
+
matched += 1;
|
|
6634
|
+
path6.push({ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) });
|
|
6635
|
+
}
|
|
6396
6636
|
}
|
|
6397
|
-
|
|
6398
|
-
|
|
6637
|
+
if (matched < stages.length - 1) continue;
|
|
6638
|
+
path6.push({ sessionId: nodes[witness].sessionId, seq: nodes[witness].seq, detail: nodes[witness].actionDetail.slice(0, 60) });
|
|
6399
6639
|
violations.push({
|
|
6400
6640
|
propertyId: "cross-" + chain.id,
|
|
6401
6641
|
reason: chain.reason,
|
|
6402
6642
|
riskLevel: chain.riskLevel,
|
|
6403
6643
|
path: path6
|
|
6404
6644
|
});
|
|
6645
|
+
return violations;
|
|
6646
|
+
} else {
|
|
6647
|
+
let matched = 0;
|
|
6648
|
+
let stageIdx = 0;
|
|
6649
|
+
const path6 = [];
|
|
6650
|
+
for (const n of nodes) {
|
|
6651
|
+
if (stageIdx < stages.length && n.stage === stages[stageIdx]) {
|
|
6652
|
+
matched += 1;
|
|
6653
|
+
path6.push({ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) });
|
|
6654
|
+
stageIdx += 1;
|
|
6655
|
+
if (matched >= stages.length) break;
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
if (matched >= stages.length) {
|
|
6659
|
+
violations.push({
|
|
6660
|
+
propertyId: "cross-" + chain.id,
|
|
6661
|
+
reason: chain.reason,
|
|
6662
|
+
riskLevel: chain.riskLevel,
|
|
6663
|
+
path: path6
|
|
6664
|
+
});
|
|
6665
|
+
}
|
|
6405
6666
|
}
|
|
6406
6667
|
}
|
|
6407
6668
|
return violations;
|
|
@@ -6436,7 +6697,10 @@ function checkSensitiveDataFlow(graph) {
|
|
|
6436
6697
|
}
|
|
6437
6698
|
}
|
|
6438
6699
|
}
|
|
6439
|
-
|
|
6700
|
+
const witness = graph.witnessIdx;
|
|
6701
|
+
const candidates = witness !== void 0 ? [witness] : nodes.map((_, i) => i);
|
|
6702
|
+
for (const i of candidates) {
|
|
6703
|
+
const n = nodes[i];
|
|
6440
6704
|
if (tainted.has(i) && EXFIL_RE.test(n.actionDetail)) {
|
|
6441
6705
|
violations.push({
|
|
6442
6706
|
propertyId: "sensitive-data-exfil",
|
|
@@ -6444,6 +6708,7 @@ function checkSensitiveDataFlow(graph) {
|
|
|
6444
6708
|
riskLevel: "critical",
|
|
6445
6709
|
path: [{ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) }]
|
|
6446
6710
|
});
|
|
6711
|
+
if (witness !== void 0) return violations;
|
|
6447
6712
|
}
|
|
6448
6713
|
}
|
|
6449
6714
|
return violations;
|
|
@@ -6469,6 +6734,32 @@ function checkNeverExfilAfterPrivesc(graph) {
|
|
|
6469
6734
|
const violations = [];
|
|
6470
6735
|
const nodes = allNodes(graph);
|
|
6471
6736
|
if (nodes.length < 2) return violations;
|
|
6737
|
+
const witness = graph.witnessIdx;
|
|
6738
|
+
if (witness !== void 0) {
|
|
6739
|
+
const evIdx = [];
|
|
6740
|
+
nodes.forEach((n, i) => {
|
|
6741
|
+
if ((i === witness || n.sessionId === "ebpf-evidence") && isExfilNode(n)) evIdx.push(i);
|
|
6742
|
+
});
|
|
6743
|
+
if (evIdx.length === 0) return violations;
|
|
6744
|
+
const firstEv = Math.min(...evIdx);
|
|
6745
|
+
let pre = null;
|
|
6746
|
+
for (let i = 0; i < firstEv; i++) {
|
|
6747
|
+
if (isPrivescNode(nodes[i])) pre = nodes[i];
|
|
6748
|
+
}
|
|
6749
|
+
if (pre) {
|
|
6750
|
+
const post = nodes[firstEv];
|
|
6751
|
+
return [{
|
|
6752
|
+
propertyId: "no-privesc-then-exfil",
|
|
6753
|
+
reason: "\u63D0\u6743\u540E\u51FA\u73B0\u5916\u4F20\uFF1A\u63D0\u6743(\u524D) \u2192 \u5916\u4F20(\u540E)\uFF0C\u8FDD\u53CD \u25A1(PRIVESC\u2192\xAC\u25C7EXFIL)",
|
|
6754
|
+
riskLevel: "critical",
|
|
6755
|
+
path: [
|
|
6756
|
+
{ sessionId: pre.sessionId, seq: pre.seq, detail: pre.actionDetail.slice(0, 60) },
|
|
6757
|
+
{ sessionId: post.sessionId, seq: post.seq, detail: post.actionDetail.slice(0, 60) }
|
|
6758
|
+
]
|
|
6759
|
+
}];
|
|
6760
|
+
}
|
|
6761
|
+
return violations;
|
|
6762
|
+
}
|
|
6472
6763
|
for (let i = 0; i < nodes.length; i++) {
|
|
6473
6764
|
if (!isPrivescNode(nodes[i])) continue;
|
|
6474
6765
|
for (let j = i + 1; j < nodes.length; j++) {
|
|
@@ -6492,6 +6783,32 @@ function checkNeverExfilAfterCred(graph) {
|
|
|
6492
6783
|
const violations = [];
|
|
6493
6784
|
const nodes = allNodes(graph);
|
|
6494
6785
|
if (nodes.length < 2) return violations;
|
|
6786
|
+
const witness = graph.witnessIdx;
|
|
6787
|
+
if (witness !== void 0) {
|
|
6788
|
+
const evIdx = [];
|
|
6789
|
+
nodes.forEach((n, i) => {
|
|
6790
|
+
if ((i === witness || n.sessionId === "ebpf-evidence") && isExfilNode(n)) evIdx.push(i);
|
|
6791
|
+
});
|
|
6792
|
+
if (evIdx.length === 0) return violations;
|
|
6793
|
+
const firstEv = Math.min(...evIdx);
|
|
6794
|
+
let pre = null;
|
|
6795
|
+
for (let i = 0; i < firstEv; i++) {
|
|
6796
|
+
if (isCredNode(nodes[i])) pre = nodes[i];
|
|
6797
|
+
}
|
|
6798
|
+
if (pre) {
|
|
6799
|
+
const post = nodes[firstEv];
|
|
6800
|
+
return [{
|
|
6801
|
+
propertyId: "no-cred-then-exfil",
|
|
6802
|
+
reason: "\u8BFB\u53D6\u51ED\u636E\u540E\u51FA\u73B0\u5916\u4F20\uFF0C\u8FDD\u53CD \u25A1(CRED\u2192\xAC\u25C7EXFIL)",
|
|
6803
|
+
riskLevel: "critical",
|
|
6804
|
+
path: [
|
|
6805
|
+
{ sessionId: pre.sessionId, seq: pre.seq, detail: pre.actionDetail.slice(0, 60) },
|
|
6806
|
+
{ sessionId: post.sessionId, seq: post.seq, detail: post.actionDetail.slice(0, 60) }
|
|
6807
|
+
]
|
|
6808
|
+
}];
|
|
6809
|
+
}
|
|
6810
|
+
return violations;
|
|
6811
|
+
}
|
|
6495
6812
|
for (let i = 0; i < nodes.length; i++) {
|
|
6496
6813
|
if (!isCredNode(nodes[i])) continue;
|
|
6497
6814
|
for (let j = i + 1; j < nodes.length; j++) {
|
|
@@ -6511,13 +6828,164 @@ function checkNeverExfilAfterCred(graph) {
|
|
|
6511
6828
|
}
|
|
6512
6829
|
return violations;
|
|
6513
6830
|
}
|
|
6514
|
-
|
|
6831
|
+
function getToolRegistry() {
|
|
6832
|
+
if (TOOL_REGISTRY) return TOOL_REGISTRY;
|
|
6833
|
+
TOOL_REGISTRY = loadToolRegistry().tools || {};
|
|
6834
|
+
return TOOL_REGISTRY;
|
|
6835
|
+
}
|
|
6836
|
+
function lookupToolClass(actionType) {
|
|
6837
|
+
const entry = getToolRegistry()[actionType] || {};
|
|
6838
|
+
return entry.actionClass;
|
|
6839
|
+
}
|
|
6840
|
+
function isComputeNode(n) {
|
|
6841
|
+
if (STRONG_COMPUTE_TYPES.has(n.actionType.toLowerCase())) return true;
|
|
6842
|
+
const cls = lookupToolClass(n.actionType);
|
|
6843
|
+
if (cls === "read" || cls === "write" || cls === "network_egress" || cls === "message_egress") return false;
|
|
6844
|
+
return COMPUTE_RE.test(n.actionDetail);
|
|
6845
|
+
}
|
|
6846
|
+
function checkLowIntegrityCommandExec(graph) {
|
|
6847
|
+
const violations = [];
|
|
6848
|
+
const nodes = allNodes(graph);
|
|
6849
|
+
if (nodes.length === 0) return violations;
|
|
6850
|
+
const witness = graph.witnessIdx;
|
|
6851
|
+
const lowResources = /* @__PURE__ */ new Set();
|
|
6852
|
+
const lowAt = /* @__PURE__ */ new Map();
|
|
6853
|
+
nodes.forEach((n, i) => {
|
|
6854
|
+
if (n.isLowSource) {
|
|
6855
|
+
lowAt.set(i, n.actionDetail.slice(0, 60));
|
|
6856
|
+
for (const r of n.resources) lowResources.add(r);
|
|
6857
|
+
}
|
|
6858
|
+
});
|
|
6859
|
+
let changed = true;
|
|
6860
|
+
while (changed) {
|
|
6861
|
+
changed = false;
|
|
6862
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
6863
|
+
if (lowAt.has(i)) continue;
|
|
6864
|
+
let shared = "";
|
|
6865
|
+
for (const r of nodes[i].resources) {
|
|
6866
|
+
if (lowResources.has(r)) {
|
|
6867
|
+
shared = r;
|
|
6868
|
+
break;
|
|
6869
|
+
}
|
|
6870
|
+
}
|
|
6871
|
+
if (shared) {
|
|
6872
|
+
lowAt.set(i, `\u7EE7\u627F\u81EA ${shared}`);
|
|
6873
|
+
for (const r of nodes[i].resources) lowResources.add(r);
|
|
6874
|
+
changed = true;
|
|
6875
|
+
}
|
|
6876
|
+
}
|
|
6877
|
+
}
|
|
6878
|
+
if (lowAt.size === 0) return violations;
|
|
6879
|
+
const candidates = witness !== void 0 ? [witness] : nodes.map((_, i) => i);
|
|
6880
|
+
for (const i of candidates) {
|
|
6881
|
+
const n = nodes[i];
|
|
6882
|
+
if (lowAt.has(i) && isComputeNode(n)) {
|
|
6883
|
+
violations.push({
|
|
6884
|
+
propertyId: "low-integrity-controls-command-exec",
|
|
6885
|
+
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`,
|
|
6886
|
+
riskLevel: "critical",
|
|
6887
|
+
path: [{ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) }]
|
|
6888
|
+
});
|
|
6889
|
+
if (witness !== void 0) return violations;
|
|
6890
|
+
}
|
|
6891
|
+
}
|
|
6892
|
+
return violations;
|
|
6893
|
+
}
|
|
6894
|
+
function checkCrossSessionReachability(graph) {
|
|
6895
|
+
const violations = [];
|
|
6896
|
+
const nodes = allNodes(graph);
|
|
6897
|
+
if (nodes.length === 0) return violations;
|
|
6898
|
+
const witness = graph.witnessIdx;
|
|
6899
|
+
const sources = /* @__PURE__ */ new Set();
|
|
6900
|
+
nodes.forEach((n, i) => {
|
|
6901
|
+
if (n.isLowSource || DL_OR_LOW_RE.test(n.actionDetail)) sources.add(i);
|
|
6902
|
+
});
|
|
6903
|
+
if (sources.size === 0) return violations;
|
|
6904
|
+
const reached = new Set(sources);
|
|
6905
|
+
let changed = true;
|
|
6906
|
+
while (changed) {
|
|
6907
|
+
changed = false;
|
|
6908
|
+
for (const e of allEdges(graph)) {
|
|
6909
|
+
if (reached.has(e.src) && !reached.has(e.dst)) {
|
|
6910
|
+
const srcRes = nodes[e.src].resources;
|
|
6911
|
+
const dstRes = nodes[e.dst].resources;
|
|
6912
|
+
for (const r of srcRes) {
|
|
6913
|
+
if (dstRes.has(r)) {
|
|
6914
|
+
reached.add(e.dst);
|
|
6915
|
+
changed = true;
|
|
6916
|
+
break;
|
|
6917
|
+
}
|
|
6918
|
+
}
|
|
6919
|
+
}
|
|
6920
|
+
}
|
|
6921
|
+
}
|
|
6922
|
+
const candidates = witness !== void 0 ? [witness] : nodes.map((_, i) => i);
|
|
6923
|
+
for (const i of candidates) {
|
|
6924
|
+
const n = nodes[i];
|
|
6925
|
+
if (sources.has(i)) continue;
|
|
6926
|
+
if (reached.has(i)) {
|
|
6927
|
+
const srcIdx = Math.min(...sources);
|
|
6928
|
+
const srcDesc = nodes[srcIdx].actionDetail.slice(0, 40);
|
|
6929
|
+
violations.push({
|
|
6930
|
+
propertyId: "cross-session-reachability",
|
|
6931
|
+
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`,
|
|
6932
|
+
riskLevel: "high",
|
|
6933
|
+
path: nodes.slice(-3).map((m) => ({ sessionId: m.sessionId, seq: m.seq, detail: m.actionDetail.slice(0, 60) }))
|
|
6934
|
+
});
|
|
6935
|
+
if (witness !== void 0) return violations;
|
|
6936
|
+
}
|
|
6937
|
+
}
|
|
6938
|
+
return violations;
|
|
6939
|
+
}
|
|
6940
|
+
function checkSensitiveDataAggregation(graph) {
|
|
6941
|
+
const violations = [];
|
|
6942
|
+
const nodes = allNodes(graph);
|
|
6943
|
+
if (nodes.length < 2) return violations;
|
|
6944
|
+
const witness = graph.witnessIdx;
|
|
6945
|
+
const resIndex = /* @__PURE__ */ new Map();
|
|
6946
|
+
nodes.forEach((n, i) => {
|
|
6947
|
+
for (const r of n.resources) {
|
|
6948
|
+
const list = resIndex.get(r);
|
|
6949
|
+
if (list) list.push(i);
|
|
6950
|
+
else resIndex.set(r, [i]);
|
|
6951
|
+
}
|
|
6952
|
+
});
|
|
6953
|
+
const sourcesFor = (exfilIdx) => {
|
|
6954
|
+
const srcs = /* @__PURE__ */ new Set();
|
|
6955
|
+
const n = nodes[exfilIdx];
|
|
6956
|
+
for (const r of n.resources) {
|
|
6957
|
+
for (const j of resIndex.get(r) || []) {
|
|
6958
|
+
if (j === exfilIdx) continue;
|
|
6959
|
+
srcs.add(`${nodes[j].sessionId}#${nodes[j].seq}`);
|
|
6960
|
+
}
|
|
6961
|
+
}
|
|
6962
|
+
return srcs;
|
|
6963
|
+
};
|
|
6964
|
+
const candidates = witness !== void 0 ? [witness] : nodes.map((_, i) => i);
|
|
6965
|
+
for (const i of candidates) {
|
|
6966
|
+
const n = nodes[i];
|
|
6967
|
+
if (!isExfilNode(n)) continue;
|
|
6968
|
+
const srcs = sourcesFor(i);
|
|
6969
|
+
if (srcs.size >= 2) {
|
|
6970
|
+
violations.push({
|
|
6971
|
+
propertyId: "sensitive-data-aggregation",
|
|
6972
|
+
reason: `\u654F\u611F\u6570\u636E\u805A\u5408\u5916\u4F20\uFF1Aegress \u805A\u5408 ${srcs.size} \u4E2A\u4E8B\u4EF6\u6E90\u6570\u636E\uFF08Rule 12\uFF09`,
|
|
6973
|
+
riskLevel: "critical",
|
|
6974
|
+
path: [{ sessionId: n.sessionId, seq: n.seq, detail: n.actionDetail.slice(0, 60) }]
|
|
6975
|
+
});
|
|
6976
|
+
if (witness !== void 0) return violations;
|
|
6977
|
+
}
|
|
6978
|
+
}
|
|
6979
|
+
return violations;
|
|
6980
|
+
}
|
|
6981
|
+
var CROSS_SESSION_CHAINS, CRED_FILE_RE, EXFIL_RE, EBPF_NET_RE, REMOTE_RE, PRIVESC_RE, EXFIL_ACTION_RE, CRED_STRICT_RE, TOOL_REGISTRY, COMPUTE_RE, STRONG_COMPUTE_TYPES, DL_OR_LOW_RE, ALL_PROPERTIES;
|
|
6515
6982
|
var init_properties = __esm({
|
|
6516
6983
|
"src/engine/formal-engine/properties.ts"() {
|
|
6517
6984
|
"use strict";
|
|
6518
6985
|
init_esm_shims();
|
|
6519
6986
|
init_rules_loader();
|
|
6520
6987
|
init_ir();
|
|
6988
|
+
init_ltl();
|
|
6521
6989
|
CROSS_SESSION_CHAINS = null;
|
|
6522
6990
|
CRED_FILE_RE = /(known_hosts|\.ssh|id_rsa|\/etc\/shadow|\/etc\/passwd|credentials)/i;
|
|
6523
6991
|
EXFIL_RE = /https?:\/\/|scp\s+.*@|rsync\s+.*@/i;
|
|
@@ -6526,11 +6994,22 @@ var init_properties = __esm({
|
|
|
6526
6994
|
PRIVESC_RE = /\bsudo\b|\bsu\b|chmod\s+u\s*\+\s*s|pkexec|setuid/i;
|
|
6527
6995
|
EXFIL_ACTION_RE = /\bcurl\b|\bwget\b|\bscp\b|\brsync\b|\brclone\b|\bftp\b|connect\s+.*\d+\.\d+\.\d+\.\d+|open\s+.*tcp|base64\s+.*\-o/i;
|
|
6528
6996
|
CRED_STRICT_RE = /(known_hosts|\.ssh|id_rsa|\.pem|\b\.key\b|\/etc\/shadow|\/etc\/passwd|\.aws\/credentials|credentials\.json|netrc|password|secrets?\.ya?ml|credentials?\s*(file|path)?\s*(=|\:)|\bconfig.*(password|token))/i;
|
|
6997
|
+
TOOL_REGISTRY = null;
|
|
6998
|
+
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;
|
|
6999
|
+
STRONG_COMPUTE_TYPES = /* @__PURE__ */ new Set(["python", "node", "exec", "terminal", "cmd"]);
|
|
7000
|
+
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;
|
|
6529
7001
|
ALL_PROPERTIES = [
|
|
6530
7002
|
{ id: "cross-session-chain", check: checkCrossSessionChain },
|
|
6531
7003
|
{ id: "sensitive-data-flow", check: checkSensitiveDataFlow },
|
|
7004
|
+
{ id: "cross-session-reachability", check: checkCrossSessionReachability },
|
|
6532
7005
|
{ id: "no-privesc-then-exfil", check: checkNeverExfilAfterPrivesc },
|
|
6533
|
-
{ id: "no-cred-then-exfil", check: checkNeverExfilAfterCred }
|
|
7006
|
+
{ id: "no-cred-then-exfil", check: checkNeverExfilAfterCred },
|
|
7007
|
+
// L2.2 模型检测(通用 LTL 求值器,mc_rules.json 单一事实源;witness 语义见 ltl.ts)
|
|
7008
|
+
{ id: "mc-ltl-rules", check: checkMCRules },
|
|
7009
|
+
// Rule 5 低完整性控制命令执行(integrity 维度,站点 L2.1 最有区分度的检测之一)
|
|
7010
|
+
{ id: "low-integrity-command-exec", check: checkLowIntegrityCommandExec },
|
|
7011
|
+
// Rule 12 敏感数据聚合外传(egress 聚合 ≥2 事件源)
|
|
7012
|
+
{ id: "sensitive-data-aggregation", check: checkSensitiveDataAggregation }
|
|
6534
7013
|
];
|
|
6535
7014
|
}
|
|
6536
7015
|
});
|
|
@@ -6572,6 +7051,9 @@ var init_engine = __esm({
|
|
|
6572
7051
|
});
|
|
6573
7052
|
}
|
|
6574
7053
|
const graph = buildMultiSessionGraph(all, aNext);
|
|
7054
|
+
if (aNext) {
|
|
7055
|
+
graph.witnessIdx = allNodes(graph).length - 1;
|
|
7056
|
+
}
|
|
6575
7057
|
const result = emptyVerificationResult();
|
|
6576
7058
|
for (const prop of this.properties) {
|
|
6577
7059
|
let violations;
|
|
@@ -7083,6 +7565,7 @@ function _resetBrainForTest() {
|
|
|
7083
7565
|
_brainInitialized = false;
|
|
7084
7566
|
}
|
|
7085
7567
|
async function runAnalysis(input) {
|
|
7568
|
+
const observedFormalLayers = [];
|
|
7086
7569
|
const heuristicResult = isHeuristicEnabled() ? runHeuristicCheck(input) : null;
|
|
7087
7570
|
const isInlineScriptCmd = isInlineScriptCommand(input.aNext.actionDetail.toLowerCase());
|
|
7088
7571
|
const isLiteralTextCmd = isLiteralTextCommand(input.aNext.actionDetail.toLowerCase());
|
|
@@ -7137,8 +7620,8 @@ async function runAnalysis(input) {
|
|
|
7137
7620
|
const rawDetail = extractRawCommand(input.aNext.actionDetail);
|
|
7138
7621
|
const lowerDetail = rawDetail.toLowerCase();
|
|
7139
7622
|
const agentExt = mergeAgentExtensions(
|
|
7140
|
-
getAgentExtensions(input.agentId),
|
|
7141
|
-
|
|
7623
|
+
isLayerEnabled("agent_rules_enabled") ? getAgentExtensions(input.agentId) : null,
|
|
7624
|
+
isLayerEnabled("scenario_rules_enabled") ? getScenarioExtensionsMulti(input.scenarioId || process.env.AGENT_MOSS_SCENARIO || "") : null
|
|
7142
7625
|
);
|
|
7143
7626
|
if (FULLY_SAFE_TOOLS.has(actionType)) {
|
|
7144
7627
|
return {
|
|
@@ -7255,15 +7738,22 @@ async function runAnalysis(input) {
|
|
|
7255
7738
|
const formalResult = formalEngine.verify(formalSessions, input.aNext);
|
|
7256
7739
|
if (!formalResult.verified) {
|
|
7257
7740
|
const v = formalResult.violations[0];
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7741
|
+
if (isFormalObserveMode()) {
|
|
7742
|
+
console.warn(
|
|
7743
|
+
`[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)}`
|
|
7744
|
+
);
|
|
7745
|
+
observedFormalLayers.push("2.4");
|
|
7746
|
+
} else {
|
|
7747
|
+
return {
|
|
7748
|
+
allowed: false,
|
|
7749
|
+
reason: v ? v.reason : "\u5F62\u5F0F\u5316\u9A8C\u8BC1\u672A\u901A\u8FC7\uFF08\u884C\u4E3A\u6027\u8D28\u8FDD\u53CD\uFF09",
|
|
7750
|
+
riskLevel: v ? v.riskLevel : "high",
|
|
7751
|
+
riskType: "formal_verification",
|
|
7752
|
+
confidence: 90,
|
|
7753
|
+
source: "formal_engine",
|
|
7754
|
+
violatedLayers: ["2.4"]
|
|
7755
|
+
};
|
|
7756
|
+
}
|
|
7267
7757
|
}
|
|
7268
7758
|
}
|
|
7269
7759
|
if (scriptChain && scriptChain.nodes.length > 0 && isLogicRulesEnabled()) {
|
|
@@ -7310,7 +7800,7 @@ async function runAnalysis(input) {
|
|
|
7310
7800
|
riskType: "",
|
|
7311
7801
|
confidence: 85,
|
|
7312
7802
|
source: "heuristic_and_logic_only",
|
|
7313
|
-
violatedLayers: []
|
|
7803
|
+
violatedLayers: observedFormalLayers.length > 0 ? [...observedFormalLayers] : []
|
|
7314
7804
|
};
|
|
7315
7805
|
}
|
|
7316
7806
|
let skipL3Hints = "\u65E0\uFF08\u5F53\u524D\u65E0\u7981\u7528\u89C4\u5219\u547D\u4E2D\uFF09";
|
|
@@ -7355,7 +7845,7 @@ async function runAnalysis(input) {
|
|
|
7355
7845
|
riskType: "",
|
|
7356
7846
|
confidence: 50,
|
|
7357
7847
|
source: "llm_failure_fallback",
|
|
7358
|
-
violatedLayers: []
|
|
7848
|
+
violatedLayers: observedFormalLayers.length > 0 ? [...observedFormalLayers] : []
|
|
7359
7849
|
};
|
|
7360
7850
|
}
|
|
7361
7851
|
return {
|
|
@@ -7382,6 +7872,9 @@ async function runAnalysis(input) {
|
|
|
7382
7872
|
} catch {
|
|
7383
7873
|
}
|
|
7384
7874
|
}
|
|
7875
|
+
if (observedFormalLayers.length > 0 && llmResult.allowed) {
|
|
7876
|
+
llmResult.violatedLayers = Array.from(/* @__PURE__ */ new Set([...observedFormalLayers, ...llmResult.violatedLayers || []]));
|
|
7877
|
+
}
|
|
7385
7878
|
return llmResult;
|
|
7386
7879
|
}
|
|
7387
7880
|
var FULLY_SAFE_TOOLS, TRUSTED_SKILLS_BASE, READONLY_SENSITIVE_TOOLS, FULLY_SAFE_BASH_PATTERNS, READONLY_SENSITIVE_BASH_PATTERNS, _brainStore, _brainExtractor, _brainInitialized, formalEngine;
|
|
@@ -7395,6 +7888,7 @@ var init_coordinator = __esm({
|
|
|
7395
7888
|
init_llm_analyzer();
|
|
7396
7889
|
init_script_content_analyzer();
|
|
7397
7890
|
init_config();
|
|
7891
|
+
init_runtime_config();
|
|
7398
7892
|
init_agents();
|
|
7399
7893
|
init_scenarios();
|
|
7400
7894
|
init_brain();
|
|
@@ -7556,7 +8050,7 @@ var require_bindings = __commonJS({
|
|
|
7556
8050
|
var fs7 = __require("fs");
|
|
7557
8051
|
var path6 = __require("path");
|
|
7558
8052
|
var fileURLToPath11 = require_file_uri_to_path();
|
|
7559
|
-
var
|
|
8053
|
+
var join11 = path6.join;
|
|
7560
8054
|
var dirname11 = path6.dirname;
|
|
7561
8055
|
var exists = fs7.accessSync && function(path7) {
|
|
7562
8056
|
try {
|
|
@@ -7616,7 +8110,7 @@ var require_bindings = __commonJS({
|
|
|
7616
8110
|
var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
7617
8111
|
var tries = [], i = 0, l = opts.try.length, n, b, err;
|
|
7618
8112
|
for (; i < l; i++) {
|
|
7619
|
-
n =
|
|
8113
|
+
n = join11.apply(
|
|
7620
8114
|
null,
|
|
7621
8115
|
opts.try[i].map(function(p) {
|
|
7622
8116
|
return opts[p] || p;
|
|
@@ -7677,7 +8171,7 @@ var require_bindings = __commonJS({
|
|
|
7677
8171
|
if (dir === ".") {
|
|
7678
8172
|
dir = process.cwd();
|
|
7679
8173
|
}
|
|
7680
|
-
if (exists(
|
|
8174
|
+
if (exists(join11(dir, "package.json")) || exists(join11(dir, "node_modules"))) {
|
|
7681
8175
|
return dir;
|
|
7682
8176
|
}
|
|
7683
8177
|
if (prev === dir) {
|
|
@@ -7686,7 +8180,7 @@ var require_bindings = __commonJS({
|
|
|
7686
8180
|
);
|
|
7687
8181
|
}
|
|
7688
8182
|
prev = dir;
|
|
7689
|
-
dir =
|
|
8183
|
+
dir = join11(dir, "..");
|
|
7690
8184
|
}
|
|
7691
8185
|
};
|
|
7692
8186
|
}
|
|
@@ -8846,12 +9340,13 @@ init_esm_shims();
|
|
|
8846
9340
|
init_esm_shims();
|
|
8847
9341
|
init_runtime_config();
|
|
8848
9342
|
init_token_stats();
|
|
9343
|
+
init_rules_loader();
|
|
8849
9344
|
import { Hono } from "hono";
|
|
8850
9345
|
import { readFileSync as readFileSync15, existsSync as existsSync14 } from "fs";
|
|
8851
|
-
import { join as
|
|
9346
|
+
import { join as join10, dirname as dirname10 } from "path";
|
|
8852
9347
|
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
8853
9348
|
var __dirname8 = dirname10(fileURLToPath9(import.meta.url));
|
|
8854
|
-
var STATIC_DIR =
|
|
9349
|
+
var STATIC_DIR = join10(__dirname8, "static");
|
|
8855
9350
|
var CONSOLE_TOKEN_ENV = "AGENT_MOSS_CONSOLE_TOKEN";
|
|
8856
9351
|
function getConsoleToken() {
|
|
8857
9352
|
return process.env[CONSOLE_TOKEN_ENV] || "";
|
|
@@ -8875,7 +9370,7 @@ function createConsoleRouter() {
|
|
|
8875
9370
|
const console2 = new Hono();
|
|
8876
9371
|
console2.use("/api/*", authMiddleware());
|
|
8877
9372
|
const serveIndex = (c) => {
|
|
8878
|
-
const indexFile =
|
|
9373
|
+
const indexFile = join10(STATIC_DIR, "index.html");
|
|
8879
9374
|
if (existsSync14(indexFile)) {
|
|
8880
9375
|
return c.html(readFileSync15(indexFile, "utf-8"));
|
|
8881
9376
|
}
|
|
@@ -8892,24 +9387,89 @@ function createConsoleRouter() {
|
|
|
8892
9387
|
const rc = updateLayerEnabled(body.layer_key, body.enabled);
|
|
8893
9388
|
return c.json({ layers: rc.layers, env_overrides: getEnvOverrides() });
|
|
8894
9389
|
});
|
|
9390
|
+
function getL24View() {
|
|
9391
|
+
const ltlHuman = {
|
|
9392
|
+
"mc-ltl-001": "\u5148\u8BFB\u53D6\u4E86\u51ED\u636E/\u5BC6\u94A5\uFF0C\u4E4B\u540E\u51FA\u73B0\u7F51\u7EDC\u5916\u4F20",
|
|
9393
|
+
"mc-ltl-002": "\u5148\u4E0B\u8F7D/\u83B7\u53D6\u4E86\u6587\u4EF6\uFF0C\u4E4B\u540E\u6267\u884C\u4E86\u6587\u4EF6",
|
|
9394
|
+
"mc-ltl-003": "\u5148\u7981\u7528\u4E86\u5B89\u5168\u9632\u62A4\uFF0C\u4E4B\u540E\u51FA\u73B0\u7834\u574F\u6027\u64CD\u4F5C\uFF08\u6267\u884C/\u5220\u9664/\u63D0\u6743\uFF09",
|
|
9395
|
+
"mc-ltl-004": "\u5148\u51FA\u73B0\u63D0\u793A\u8BCD\u6CE8\u5165\uFF0C\u4E4B\u540E\u51FA\u73B0\u654F\u611F\u64CD\u4F5C\uFF08\u5916\u4F20/\u5199\u6587\u4EF6/\u6267\u884C\uFF09",
|
|
9396
|
+
"mc-ltl-005": "\u5148\u8BFB\u53D6\u51ED\u636E\uFF0C\u4E4B\u540E\u51FA\u73B0\u6A2A\u5411\u79FB\u52A8\uFF08ssh/scp \u5230\u8FDC\u7A0B\uFF09",
|
|
9397
|
+
"mc-ltl-006": "\u5148\u63A5\u89E6\u654F\u611F\u6570\u636E\uFF0C\u4E4B\u540E\u6E05\u9664\u65E5\u5FD7",
|
|
9398
|
+
"mc-ltl-007": "\u5148\u63D0\u6743\uFF0C\u4E4B\u540E\u5B89\u88C5\u6301\u4E45\u5316\u540E\u95E8",
|
|
9399
|
+
"mc-ltl-008": "\u5148\u4E0B\u8F7D\u6587\u4EF6\uFF0C\u4E4B\u540E\u5B89\u88C5\u6301\u4E45\u5316\u540E\u95E8",
|
|
9400
|
+
"mc-ltl-009": "\u5148\u63A5\u89E6\u654F\u611F\u6570\u636E \u2192 \u6253\u5305\u538B\u7F29 \u2192 \u7F51\u7EDC\u5916\u4F20",
|
|
9401
|
+
"mc-ltl-010": "\u5B89\u88C5\u4E86\u6301\u4E45\u5316\u673A\u5236\uFF08crontab/systemd/.bashrc \u7B49\uFF09\uFF0C\u9700\u5BA1\u6279",
|
|
9402
|
+
"mc-ctl-001": "\u4EFB\u4F55\u60C5\u51B5\u4E0B\u4E0D\u5141\u8BB8\u6E05\u9664\u65E5\u5FD7\uFF08\u5B89\u5168\u5E95\u7EBF\uFF09"
|
|
9403
|
+
};
|
|
9404
|
+
const mc = loadMC();
|
|
9405
|
+
const rules = mc.rules || [];
|
|
9406
|
+
return {
|
|
9407
|
+
enabled_via: "L2_logic_rules",
|
|
9408
|
+
description: "\u65F6\u5E8F\u4E0E\u6570\u636E\u6D41\u653B\u51FB\u68C0\u6D4B\uFF08L2.2 \u6A21\u578B\u68C0\u6D4B\uFF09",
|
|
9409
|
+
ltl_rules: rules.map((r) => ({
|
|
9410
|
+
id: r.id,
|
|
9411
|
+
type: r.type,
|
|
9412
|
+
formula: Array.isArray(r.formula) ? "<\u516C\u5F0F>" : r.formula,
|
|
9413
|
+
reason: r.reason,
|
|
9414
|
+
risk_level: r.risk_level,
|
|
9415
|
+
action: r.action,
|
|
9416
|
+
enabled: r.enabled !== false,
|
|
9417
|
+
human: ltlHuman[r.id] || r.reason || ""
|
|
9418
|
+
}))
|
|
9419
|
+
};
|
|
9420
|
+
}
|
|
9421
|
+
function withL24View(rc) {
|
|
9422
|
+
if (rc && rc.L2_4 && typeof rc.L2_4 === "object" && !Array.isArray(rc.L2_4)) {
|
|
9423
|
+
const cat = rc.L2_4.ltl_rules;
|
|
9424
|
+
const rls = cat && cat.rules || [];
|
|
9425
|
+
const ltlHumanLocal = {
|
|
9426
|
+
"mc-ltl-001": "\u5148\u8BFB\u53D6\u4E86\u51ED\u636E/\u5BC6\u94A5\uFF0C\u4E4B\u540E\u51FA\u73B0\u7F51\u7EDC\u5916\u4F20",
|
|
9427
|
+
"mc-ltl-002": "\u5148\u4E0B\u8F7D/\u83B7\u53D6\u4E86\u6587\u4EF6\uFF0C\u4E4B\u540E\u6267\u884C\u4E86\u6587\u4EF6",
|
|
9428
|
+
"mc-ltl-003": "\u5148\u7981\u7528\u4E86\u5B89\u5168\u9632\u62A4\uFF0C\u4E4B\u540E\u51FA\u73B0\u7834\u574F\u6027\u64CD\u4F5C\uFF08\u6267\u884C/\u5220\u9664/\u63D0\u6743\uFF09",
|
|
9429
|
+
"mc-ltl-004": "\u5148\u51FA\u73B0\u63D0\u793A\u8BCD\u6CE8\u5165\uFF0C\u4E4B\u540E\u51FA\u73B0\u654F\u611F\u64CD\u4F5C\uFF08\u5916\u4F20/\u5199\u6587\u4EF6/\u6267\u884C\uFF09",
|
|
9430
|
+
"mc-ltl-005": "\u5148\u8BFB\u53D6\u51ED\u636E\uFF0C\u4E4B\u540E\u51FA\u73B0\u6A2A\u5411\u79FB\u52A8\uFF08ssh/scp \u5230\u8FDC\u7A0B\uFF09",
|
|
9431
|
+
"mc-ltl-006": "\u5148\u63A5\u89E6\u654F\u611F\u6570\u636E\uFF0C\u4E4B\u540E\u6E05\u9664\u65E5\u5FD7",
|
|
9432
|
+
"mc-ltl-007": "\u5148\u63D0\u6743\uFF0C\u4E4B\u540E\u5B89\u88C5\u6301\u4E45\u5316\u540E\u95E8",
|
|
9433
|
+
"mc-ltl-008": "\u5148\u4E0B\u8F7D\u6587\u4EF6\uFF0C\u4E4B\u540E\u5B89\u88C5\u6301\u4E45\u5316\u540E\u95E8",
|
|
9434
|
+
"mc-ltl-009": "\u5148\u63A5\u89E6\u654F\u611F\u6570\u636E \u2192 \u6253\u5305\u538B\u7F29 \u2192 \u7F51\u7EDC\u5916\u4F20",
|
|
9435
|
+
"mc-ltl-010": "\u5B89\u88C5\u4E86\u6301\u4E45\u5316\u673A\u5236\uFF08crontab/systemd/.bashrc \u7B49\uFF09\uFF0C\u9700\u5BA1\u6279",
|
|
9436
|
+
"mc-ctl-001": "\u4EFB\u4F55\u60C5\u51B5\u4E0B\u4E0D\u5141\u8BB8\u6E05\u9664\u65E5\u5FD7\uFF08\u5B89\u5168\u5E95\u7EBF\uFF09"
|
|
9437
|
+
};
|
|
9438
|
+
rc.L2_4 = {
|
|
9439
|
+
enabled_via: "L2_logic_rules",
|
|
9440
|
+
description: "\u65F6\u5E8F\u4E0E\u6570\u636E\u6D41\u653B\u51FB\u68C0\u6D4B\uFF08L2.2 \u6A21\u578B\u68C0\u6D4B\uFF09",
|
|
9441
|
+
ltl_rules: rls.map((r) => ({
|
|
9442
|
+
id: r.id,
|
|
9443
|
+
type: "ltl",
|
|
9444
|
+
formula: "<\u516C\u5F0F>",
|
|
9445
|
+
reason: r.reason || "",
|
|
9446
|
+
risk_level: r.risk_level || "high",
|
|
9447
|
+
action: r.action || "block",
|
|
9448
|
+
enabled: r.enabled !== false,
|
|
9449
|
+
human: ltlHumanLocal[r.id] || r.reason || ""
|
|
9450
|
+
}))
|
|
9451
|
+
};
|
|
9452
|
+
}
|
|
9453
|
+
return rc;
|
|
9454
|
+
}
|
|
8895
9455
|
console2.get("/api/rules", (c) => {
|
|
8896
9456
|
const rc = loadRuntimeConfig();
|
|
8897
|
-
return c.json({ L1_rules: rc.L1_rules, L2_rules: rc.L2_rules });
|
|
9457
|
+
return c.json({ L1_rules: rc.L1_rules, L2_rules: rc.L2_rules, L2_4: getL24View() });
|
|
8898
9458
|
});
|
|
8899
9459
|
console2.put("/api/rules/enabled", async (c) => {
|
|
8900
9460
|
const b = await c.req.json();
|
|
8901
9461
|
const rc = updateRuleEnabled(b.layer, b.category, b.rule_id, b.enabled);
|
|
8902
|
-
return c.json(rc);
|
|
9462
|
+
return c.json(withL24View(rc));
|
|
8903
9463
|
});
|
|
8904
9464
|
console2.put("/api/rules/deny_mode", async (c) => {
|
|
8905
9465
|
const b = await c.req.json();
|
|
8906
9466
|
const rc = updateRuleDenyMode(b.layer, b.category, b.rule_id, b.deny_mode);
|
|
8907
|
-
return c.json(rc);
|
|
9467
|
+
return c.json(withL24View(rc));
|
|
8908
9468
|
});
|
|
8909
9469
|
console2.put("/api/rules/skip_l3", async (c) => {
|
|
8910
9470
|
const b = await c.req.json();
|
|
8911
9471
|
const rc = updateRuleSkipL3(b.layer, b.category, b.rule_id, b.skip_l3_on_disabled);
|
|
8912
|
-
return c.json(rc);
|
|
9472
|
+
return c.json(withL24View(rc));
|
|
8913
9473
|
});
|
|
8914
9474
|
console2.put("/api/categories/enabled", async (c) => {
|
|
8915
9475
|
const b = await c.req.json();
|
|
@@ -8968,9 +9528,9 @@ function createConsoleRouter() {
|
|
|
8968
9528
|
if (!/^[A-Za-z0-9_-]+$/.test(skillId)) {
|
|
8969
9529
|
return c.json({ error: "invalid skill_id" }, 400);
|
|
8970
9530
|
}
|
|
8971
|
-
const skillPath =
|
|
9531
|
+
const skillPath = join10(dirname10(getRuntimeConfigPath()), "agent_moss_skills", `${skillId}.md`);
|
|
8972
9532
|
if (!existsSync14(skillPath)) {
|
|
8973
|
-
const builtinPath =
|
|
9533
|
+
const builtinPath = join10(__dirname8, "..", "..", "agent_moss", "skills", `${skillId}.md`);
|
|
8974
9534
|
if (existsSync14(builtinPath)) return c.text(readFileSync15(builtinPath, "utf-8"));
|
|
8975
9535
|
return c.json({ error: "skill not found" }, 404);
|
|
8976
9536
|
}
|
|
@@ -9059,7 +9619,7 @@ function createConsoleRouter() {
|
|
|
9059
9619
|
});
|
|
9060
9620
|
console2.get("/api/config", (c) => {
|
|
9061
9621
|
const rc = loadRuntimeConfig();
|
|
9062
|
-
return c.json(rc);
|
|
9622
|
+
return c.json({ ...rc, L2_4: getL24View() });
|
|
9063
9623
|
});
|
|
9064
9624
|
console2.get("/api/env-overrides", (c) => {
|
|
9065
9625
|
return c.json({ overrides: getEnvOverrides() });
|
|
@@ -9396,4 +9956,7 @@ if (isMain) {
|
|
|
9396
9956
|
process.exit(1);
|
|
9397
9957
|
});
|
|
9398
9958
|
}
|
|
9959
|
+
//! 顺序即 fail-closed 短路优先级:verify 逐个执行,首个返回违规的性质成为
|
|
9960
|
+
//! first_violation,后续不再评估。调整顺序影响判定归属,须与 Python
|
|
9961
|
+
//! properties.py ALL_PROPERTIES 保持一致并双端测试确认。
|
|
9399
9962
|
//# sourceMappingURL=cli.js.map
|