@kenhkl/agent-moss 0.16.14 → 0.17.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 +1124 -343
- package/dist/engine/coordinator.js +333 -158
- package/dist/rules/l1_rules.json +51 -2
- package/dist/rules/l2_rules.json +2 -1
- package/dist/server.js +1083 -302
- package/package.json +1 -1
|
@@ -25,6 +25,10 @@ var init_esm_shims = __esm({
|
|
|
25
25
|
import { join } from "path";
|
|
26
26
|
import { homedir } from "os";
|
|
27
27
|
import { readFileSync } from "fs";
|
|
28
|
+
function isSafeId(value) {
|
|
29
|
+
if (!value || value.length > ID_MAX_LEN) return false;
|
|
30
|
+
return ID_PATTERN.test(value);
|
|
31
|
+
}
|
|
28
32
|
function getRulesRoot() {
|
|
29
33
|
const raw = (process.env[ENV_RULES_ROOT] ?? "").trim();
|
|
30
34
|
return raw ? raw : null;
|
|
@@ -98,7 +102,7 @@ function getTokenStatsPath() {
|
|
|
98
102
|
}
|
|
99
103
|
return join(getDataRoot(), "agent_moss_token_stats.json");
|
|
100
104
|
}
|
|
101
|
-
var ENV_DATA_ROOT, ENV_INSTANCE, DEFAULT_DATA_ROOT, ENV_RULES_ROOT;
|
|
105
|
+
var ENV_DATA_ROOT, ENV_INSTANCE, DEFAULT_DATA_ROOT, ENV_RULES_ROOT, ID_MAX_LEN, ID_PATTERN;
|
|
102
106
|
var init_paths = __esm({
|
|
103
107
|
"src/infra/paths.ts"() {
|
|
104
108
|
"use strict";
|
|
@@ -107,6 +111,8 @@ var init_paths = __esm({
|
|
|
107
111
|
ENV_INSTANCE = "AGENT_MOSS_INSTANCE";
|
|
108
112
|
DEFAULT_DATA_ROOT = join(homedir(), ".config", "agentmoss");
|
|
109
113
|
ENV_RULES_ROOT = "AGENT_MOSS_RULES_ROOT";
|
|
114
|
+
ID_MAX_LEN = 64;
|
|
115
|
+
ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
110
116
|
}
|
|
111
117
|
});
|
|
112
118
|
|
|
@@ -228,7 +234,7 @@ function parseDirEnv(envName) {
|
|
|
228
234
|
function rulesDirs() {
|
|
229
235
|
if (isBuiltinOnly()) return [];
|
|
230
236
|
const dirs = [];
|
|
231
|
-
for (const
|
|
237
|
+
for (const env2 of RULES_DIR_ENVS) dirs.push(...parseDirEnv(env2));
|
|
232
238
|
dirs.push(resolve(dataRootDir(), "rules"));
|
|
233
239
|
return [...new Set(dirs)];
|
|
234
240
|
}
|
|
@@ -273,6 +279,7 @@ function loadJson(name) {
|
|
|
273
279
|
}
|
|
274
280
|
}
|
|
275
281
|
function resolveScenarioRulesFile(scenarioId) {
|
|
282
|
+
if (!isSafeId(scenarioId)) return null;
|
|
276
283
|
const rel = join2("scenarios", scenarioId, "rules.json");
|
|
277
284
|
for (const dir of rulesDirs()) {
|
|
278
285
|
const p = resolve(dir, rel);
|
|
@@ -1282,7 +1289,7 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
|
|
|
1282
1289
|
targetPaths.push(...segPathsFiltered);
|
|
1283
1290
|
}
|
|
1284
1291
|
}
|
|
1285
|
-
const uniqueTargetPaths = [...new Set(targetPaths)];
|
|
1292
|
+
const uniqueTargetPaths = [...new Set(targetPaths)].filter((p) => !PSEUDO_FS_PREFIXES.some((pfx) => p.startsWith(pfx)));
|
|
1286
1293
|
if (uniqueTargetPaths.length === 0) return null;
|
|
1287
1294
|
const historyReadPaths = /* @__PURE__ */ new Set();
|
|
1288
1295
|
for (const action of actionHistory) {
|
|
@@ -1461,7 +1468,7 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd, osType) {
|
|
|
1461
1468
|
violatedLayers: ["L2.1"]
|
|
1462
1469
|
};
|
|
1463
1470
|
}
|
|
1464
|
-
var _LOGIC, _HEURISTIC, EXCLUDED_PREFIXES, TEMP_DIRS, ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, ROOT_SENSITIVE_PATHS_WINDOWS, HOME_SENSITIVE_PATHS_WINDOWS, CREDENTIAL_PATHS_WINDOWS, ROOT_SENSITIVE_PATHS_MACOS, HOME_SENSITIVE_PATHS_MACOS, CREDENTIAL_PATHS_MACOS, ROOT_SENSITIVE_PATHS_HARMONY, HOME_SENSITIVE_PATHS_HARMONY, CREDENTIAL_PATHS_HARMONY, _scopeIndex, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, WRITE_KEYWORDS, SED_INPLACE_RE, DEVNULL_REDIRECT_RE, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, COMBO_STAGES, COMBO_CHAINS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW, _IFA, IFA_READ_KEYWORDS, IFA_WRITE_KEYWORDS, IFA_EXEC_KEYWORDS, IFA_OPEN_KEYWORDS;
|
|
1471
|
+
var _LOGIC, _HEURISTIC, EXCLUDED_PREFIXES, TEMP_DIRS, ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, ROOT_SENSITIVE_PATHS_WINDOWS, HOME_SENSITIVE_PATHS_WINDOWS, CREDENTIAL_PATHS_WINDOWS, ROOT_SENSITIVE_PATHS_MACOS, HOME_SENSITIVE_PATHS_MACOS, CREDENTIAL_PATHS_MACOS, ROOT_SENSITIVE_PATHS_HARMONY, HOME_SENSITIVE_PATHS_HARMONY, CREDENTIAL_PATHS_HARMONY, _scopeIndex, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, PSEUDO_FS_PREFIXES, WRITE_KEYWORDS, SED_INPLACE_RE, DEVNULL_REDIRECT_RE, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, COMBO_STAGES, COMBO_CHAINS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW, _IFA, IFA_READ_KEYWORDS, IFA_WRITE_KEYWORDS, IFA_EXEC_KEYWORDS, IFA_OPEN_KEYWORDS;
|
|
1465
1472
|
var init_logic_rules = __esm({
|
|
1466
1473
|
"src/engine/logic-rules.ts"() {
|
|
1467
1474
|
"use strict";
|
|
@@ -1508,6 +1515,7 @@ var init_logic_rules = __esm({
|
|
|
1508
1515
|
"cat"
|
|
1509
1516
|
]);
|
|
1510
1517
|
NON_WRITE_TOOL_PREFIXES = _LOGIC.non_write_tool_prefixes ?? [];
|
|
1518
|
+
PSEUDO_FS_PREFIXES = ["/sys/", "/proc/", "/dev/", "/run/"];
|
|
1511
1519
|
WRITE_KEYWORDS = ["write", "\u5199\u5165", "save", "\u4FDD\u5B58", "modify", "\u4FEE\u6539", "update", "\u66F4\u65B0", "delete", "\u5220\u9664", "remove", "\u79FB\u9664", "create", "\u521B\u5EFA", "append", "\u8FFD\u52A0", "truncate", "\u622A\u65AD", "overwrite", "\u8986\u76D6", "replace", "\u66FF\u6362", "edit"];
|
|
1512
1520
|
SED_INPLACE_RE = /\bsed\s+(?:-\S+\s+)*(?:-[a-zA-Z]*i[a-zA-Z]*|--in-place)\b/i;
|
|
1513
1521
|
DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/g;
|
|
@@ -2122,7 +2130,7 @@ function _l2SensitivePathsToRules() {
|
|
|
2122
2130
|
const all = [...root, ...home, ...credential];
|
|
2123
2131
|
for (const sp of all) {
|
|
2124
2132
|
const os3 = String(sp.os || "linux").toLowerCase();
|
|
2125
|
-
const denyMode = _deriveDenyMode({
|
|
2133
|
+
const denyMode = sp.denyMode || _deriveDenyMode({
|
|
2126
2134
|
deny_mode: sp.deny_mode,
|
|
2127
2135
|
credential: sp.credential,
|
|
2128
2136
|
read_only: sp.read_only
|
|
@@ -3509,6 +3517,11 @@ function resolveAgentsDir() {
|
|
|
3509
3517
|
}
|
|
3510
3518
|
function getAgentExtensions(agentId) {
|
|
3511
3519
|
if (!agentId) return null;
|
|
3520
|
+
if (!isSafeId(agentId)) {
|
|
3521
|
+
console.warn(`[AgentMoss agents] \u975E\u6CD5 agent_id \u5DF2\u5FFD\u7565\uFF08\u542B\u8DEF\u5F84\u5B57\u7B26\u6216\u8D85\u957F\uFF09: ${agentId.slice(0, 120)}`);
|
|
3522
|
+
return null;
|
|
3523
|
+
}
|
|
3524
|
+
if (cache.size >= CACHE_MAX) cache.clear();
|
|
3512
3525
|
const fp = getRuleSourceFingerprint();
|
|
3513
3526
|
const cached2 = cache.get(agentId);
|
|
3514
3527
|
if (cached2 && cached2.fp === fp) return cached2.ext;
|
|
@@ -3561,7 +3574,7 @@ function mergeAgentExtensions(...exts) {
|
|
|
3561
3574
|
extra_skills: nonNull.flatMap((e) => e.extra_skills || [])
|
|
3562
3575
|
};
|
|
3563
3576
|
}
|
|
3564
|
-
var __filename4, __dirname5, AGENTS_DIR_PROD, AGENTS_DIR_DEV_FALLBACK, cache;
|
|
3577
|
+
var __filename4, __dirname5, AGENTS_DIR_PROD, AGENTS_DIR_DEV_FALLBACK, cache, CACHE_MAX;
|
|
3565
3578
|
var init_agents = __esm({
|
|
3566
3579
|
"src/agents/index.ts"() {
|
|
3567
3580
|
"use strict";
|
|
@@ -3573,6 +3586,7 @@ var init_agents = __esm({
|
|
|
3573
3586
|
AGENTS_DIR_PROD = resolve4(__dirname5, "agents");
|
|
3574
3587
|
AGENTS_DIR_DEV_FALLBACK = resolve4(__dirname5, "../../../agent_moss/agents");
|
|
3575
3588
|
cache = /* @__PURE__ */ new Map();
|
|
3589
|
+
CACHE_MAX = 512;
|
|
3576
3590
|
}
|
|
3577
3591
|
});
|
|
3578
3592
|
|
|
@@ -3589,6 +3603,11 @@ function resolveScenariosDir() {
|
|
|
3589
3603
|
}
|
|
3590
3604
|
function getScenarioExtensions(scenarioId) {
|
|
3591
3605
|
if (!scenarioId) return null;
|
|
3606
|
+
if (!isSafeId(scenarioId)) {
|
|
3607
|
+
console.warn(`[AgentMoss scenarios] \u975E\u6CD5 scenario_id \u5DF2\u5FFD\u7565\uFF08\u542B\u8DEF\u5F84\u5B57\u7B26\u6216\u8D85\u957F\uFF09: ${scenarioId.slice(0, 120)}`);
|
|
3608
|
+
return null;
|
|
3609
|
+
}
|
|
3610
|
+
if (cache2.size >= CACHE_MAX2) cache2.clear();
|
|
3592
3611
|
const fp = getRuleSourceFingerprint();
|
|
3593
3612
|
const cached2 = cache2.get(scenarioId);
|
|
3594
3613
|
if (cached2 && cached2.fp === fp) return cached2.ext;
|
|
@@ -3658,7 +3677,7 @@ function getScenarioExtensionsMulti(scenarioSpec) {
|
|
|
3658
3677
|
if (nonNull.length === 0) return null;
|
|
3659
3678
|
return mergeAgentExtensions(...nonNull);
|
|
3660
3679
|
}
|
|
3661
|
-
var __filename5, __dirname6, SCENARIOS_DIR_PROD, SCENARIOS_DIR_DEV_FALLBACK, cache2;
|
|
3680
|
+
var __filename5, __dirname6, SCENARIOS_DIR_PROD, SCENARIOS_DIR_DEV_FALLBACK, cache2, CACHE_MAX2;
|
|
3662
3681
|
var init_scenarios = __esm({
|
|
3663
3682
|
"src/scenarios/index.ts"() {
|
|
3664
3683
|
"use strict";
|
|
@@ -3672,6 +3691,7 @@ var init_scenarios = __esm({
|
|
|
3672
3691
|
SCENARIOS_DIR_PROD = resolve5(__dirname6, "scenarios");
|
|
3673
3692
|
SCENARIOS_DIR_DEV_FALLBACK = resolve5(__dirname6, "../../../agent_moss/scenarios");
|
|
3674
3693
|
cache2 = /* @__PURE__ */ new Map();
|
|
3694
|
+
CACHE_MAX2 = 512;
|
|
3675
3695
|
}
|
|
3676
3696
|
});
|
|
3677
3697
|
|
|
@@ -4560,16 +4580,16 @@ __export(token_stats_exports, {
|
|
|
4560
4580
|
recordTokenUsage: () => recordTokenUsage,
|
|
4561
4581
|
resetTokenStats: () => resetTokenStats
|
|
4562
4582
|
});
|
|
4563
|
-
import { readFileSync as
|
|
4583
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync2, existsSync as existsSync12, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
4564
4584
|
function getStatsPath() {
|
|
4565
4585
|
const envPath = process.env[ENV_STATS_PATH];
|
|
4566
4586
|
if (envPath) return envPath;
|
|
4567
4587
|
return getTokenStatsPath();
|
|
4568
4588
|
}
|
|
4569
4589
|
function loadAllRecords(statsPath) {
|
|
4570
|
-
if (!
|
|
4590
|
+
if (!existsSync12(statsPath)) return [];
|
|
4571
4591
|
try {
|
|
4572
|
-
const data = JSON.parse(
|
|
4592
|
+
const data = JSON.parse(readFileSync12(statsPath, "utf-8"));
|
|
4573
4593
|
if (Array.isArray(data)) return data;
|
|
4574
4594
|
if (data && Array.isArray(data.records)) return data.records;
|
|
4575
4595
|
return [];
|
|
@@ -4580,7 +4600,7 @@ function loadAllRecords(statsPath) {
|
|
|
4580
4600
|
function saveRecords(statsPath, records) {
|
|
4581
4601
|
try {
|
|
4582
4602
|
const dir = statsPath.substring(0, statsPath.lastIndexOf("/"));
|
|
4583
|
-
if (dir && !
|
|
4603
|
+
if (dir && !existsSync12(dir)) mkdirSync3(dir, { recursive: true });
|
|
4584
4604
|
writeFileSync2(statsPath, JSON.stringify(records, null, 2), "utf-8");
|
|
4585
4605
|
} catch (e) {
|
|
4586
4606
|
}
|
|
@@ -4707,7 +4727,7 @@ function getTokenTrend(days = 0, startDate, endDate) {
|
|
|
4707
4727
|
}
|
|
4708
4728
|
function resetTokenStats() {
|
|
4709
4729
|
const statsPath = getStatsPath();
|
|
4710
|
-
if (
|
|
4730
|
+
if (existsSync12(statsPath)) {
|
|
4711
4731
|
try {
|
|
4712
4732
|
unlinkSync2(statsPath);
|
|
4713
4733
|
} catch {
|
|
@@ -4735,17 +4755,113 @@ init_inline_analyzer();
|
|
|
4735
4755
|
|
|
4736
4756
|
// src/engine/llm-analyzer.ts
|
|
4737
4757
|
init_esm_shims();
|
|
4758
|
+
|
|
4759
|
+
// src/infra/security-policy.ts
|
|
4760
|
+
init_esm_shims();
|
|
4761
|
+
init_paths();
|
|
4762
|
+
import { chmodSync, closeSync, existsSync as existsSync8, lstatSync, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync7, readSync, realpathSync, writeSync } from "fs";
|
|
4763
|
+
import { homedir as homedir2, tmpdir } from "os";
|
|
4764
|
+
import { basename, isAbsolute, join as join7, relative, resolve as resolve6, dirname as dirname6 } from "path";
|
|
4765
|
+
var TRUTHY2 = ["1", "true", "yes", "on"];
|
|
4766
|
+
function env(name, dflt = "") {
|
|
4767
|
+
return (process.env[name] ?? dflt).trim();
|
|
4768
|
+
}
|
|
4769
|
+
function splitList(raw) {
|
|
4770
|
+
return raw.replace(/;/g, ",").split(",").map((x) => x.trim()).filter(Boolean);
|
|
4771
|
+
}
|
|
4772
|
+
function homeDir() {
|
|
4773
|
+
try {
|
|
4774
|
+
return homedir2();
|
|
4775
|
+
} catch {
|
|
4776
|
+
return tmpdir();
|
|
4777
|
+
}
|
|
4778
|
+
}
|
|
4779
|
+
function logRoots() {
|
|
4780
|
+
const raw = env("AGENT_MOSS_LOG_ROOTS");
|
|
4781
|
+
if (raw) return splitList(raw);
|
|
4782
|
+
return [.../* @__PURE__ */ new Set([homeDir(), "/tmp", tmpdir()])];
|
|
4783
|
+
}
|
|
4784
|
+
function realpathLoose(p) {
|
|
4785
|
+
const abs = resolve6(p.replace(/^~(?=$|\/)/, homeDir()));
|
|
4786
|
+
try {
|
|
4787
|
+
return realpathSync(abs);
|
|
4788
|
+
} catch {
|
|
4789
|
+
}
|
|
4790
|
+
const parts = [];
|
|
4791
|
+
let cur = abs;
|
|
4792
|
+
for (; ; ) {
|
|
4793
|
+
const parent = dirname6(cur);
|
|
4794
|
+
if (parent === cur) return null;
|
|
4795
|
+
parts.unshift(basename(cur));
|
|
4796
|
+
cur = parent;
|
|
4797
|
+
try {
|
|
4798
|
+
return join7(realpathSync(cur), ...parts);
|
|
4799
|
+
} catch {
|
|
4800
|
+
}
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
function pathWithin(p, roots) {
|
|
4804
|
+
if (!p) return true;
|
|
4805
|
+
const target = realpathLoose(p);
|
|
4806
|
+
if (target === null) return false;
|
|
4807
|
+
for (const root of roots) {
|
|
4808
|
+
const rootReal = realpathLoose(root);
|
|
4809
|
+
if (rootReal === null) continue;
|
|
4810
|
+
const rel = relative(rootReal, target);
|
|
4811
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute(rel)) return true;
|
|
4812
|
+
}
|
|
4813
|
+
return false;
|
|
4814
|
+
}
|
|
4815
|
+
var BLOCKED_HOSTS = ["169.254.169.254", "metadata.google.internal", "metadata.tencentyun.com"];
|
|
4816
|
+
function validateLlmBaseUrl(url, allowPrivate) {
|
|
4817
|
+
if (!url) return [true, ""];
|
|
4818
|
+
let u;
|
|
4819
|
+
try {
|
|
4820
|
+
u = new URL(url);
|
|
4821
|
+
} catch {
|
|
4822
|
+
return [false, "baseUrl \u4E0D\u662F\u5408\u6CD5 URL"];
|
|
4823
|
+
}
|
|
4824
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") {
|
|
4825
|
+
return [false, `baseUrl \u534F\u8BAE\u4E0D\u53D7\u652F\u6301: ${u.protocol}`];
|
|
4826
|
+
}
|
|
4827
|
+
const host = (u.hostname || "").toLowerCase();
|
|
4828
|
+
if (!host) return [false, "baseUrl \u7F3A\u5C11\u4E3B\u673A\u540D"];
|
|
4829
|
+
if (BLOCKED_HOSTS.includes(host)) return [false, `baseUrl \u6307\u5411\u4E91\u5143\u6570\u636E\u5730\u5740\uFF0C\u5DF2\u62D2\u7EDD: ${host}`];
|
|
4830
|
+
if (/^169\.254\.\d{1,3}\.\d{1,3}$/.test(host)) {
|
|
4831
|
+
return [false, `baseUrl \u6307\u5411\u94FE\u8DEF\u672C\u5730\u5730\u5740\uFF0C\u5DF2\u62D2\u7EDD: ${host}`];
|
|
4832
|
+
}
|
|
4833
|
+
const allowlist = splitList(env("AGENT_MOSS_LLM_HOST_ALLOWLIST")).map((h) => h.toLowerCase());
|
|
4834
|
+
if (allowlist.length && !allowlist.includes(host)) {
|
|
4835
|
+
return [false, `baseUrl \u4E3B\u673A\u4E0D\u5728\u5141\u8BB8\u5217\u8868: ${host}`];
|
|
4836
|
+
}
|
|
4837
|
+
if (allowPrivate === void 0) {
|
|
4838
|
+
allowPrivate = TRUTHY2.includes(env("AGENT_MOSS_TRUST_PRIVATE_LLM", "1").toLowerCase());
|
|
4839
|
+
}
|
|
4840
|
+
if (!allowPrivate) {
|
|
4841
|
+
if (host === "localhost" || host === "::1") return [false, "baseUrl \u6307\u5411\u672C\u673A\uFF0C\u5DF2\u62D2\u7EDD"];
|
|
4842
|
+
const m = host.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
|
|
4843
|
+
if (m) {
|
|
4844
|
+
const [a, b] = [Number(m[1]), Number(m[2])];
|
|
4845
|
+
if (a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 127 || a === 169 && b === 254) {
|
|
4846
|
+
return [false, `baseUrl \u6307\u5411\u5185\u7F51\u5730\u5740\uFF0C\u5DF2\u62D2\u7EDD: ${host}`];
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
}
|
|
4850
|
+
return [true, ""];
|
|
4851
|
+
}
|
|
4852
|
+
|
|
4853
|
+
// src/engine/llm-analyzer.ts
|
|
4738
4854
|
init_config();
|
|
4739
4855
|
init_skill_loader();
|
|
4740
4856
|
|
|
4741
4857
|
// src/engine/template-loader.ts
|
|
4742
4858
|
init_esm_shims();
|
|
4743
4859
|
init_asset_dir();
|
|
4744
|
-
import { readFileSync as
|
|
4745
|
-
import { resolve as
|
|
4860
|
+
import { readFileSync as readFileSync8, existsSync as existsSync9 } from "fs";
|
|
4861
|
+
import { resolve as resolve7, dirname as dirname7 } from "path";
|
|
4746
4862
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
4747
4863
|
var __filename6 = fileURLToPath8(import.meta.url);
|
|
4748
|
-
var __dirname7 =
|
|
4864
|
+
var __dirname7 = dirname7(__filename6);
|
|
4749
4865
|
var TEMPLATE_FILES = ["prompt1_template.txt", "prompt2_template.txt", "security_judge_template.txt"];
|
|
4750
4866
|
var cachedTemplates = null;
|
|
4751
4867
|
function loadTemplates() {
|
|
@@ -4758,10 +4874,10 @@ function loadTemplates() {
|
|
|
4758
4874
|
return cachedTemplates;
|
|
4759
4875
|
}
|
|
4760
4876
|
for (const file of TEMPLATE_FILES) {
|
|
4761
|
-
const filePath =
|
|
4762
|
-
if (
|
|
4877
|
+
const filePath = resolve7(dir, file);
|
|
4878
|
+
if (existsSync9(filePath)) {
|
|
4763
4879
|
const key = file.replace(".txt", "").replace("_template", "");
|
|
4764
|
-
cachedTemplates[key] =
|
|
4880
|
+
cachedTemplates[key] = readFileSync8(filePath, "utf-8");
|
|
4765
4881
|
}
|
|
4766
4882
|
}
|
|
4767
4883
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates from ${dir}`);
|
|
@@ -4771,8 +4887,8 @@ function loadTemplates() {
|
|
|
4771
4887
|
// src/engine/script-analyzer.ts
|
|
4772
4888
|
init_esm_shims();
|
|
4773
4889
|
init_rules_loader();
|
|
4774
|
-
import { readFileSync as
|
|
4775
|
-
import { resolve as
|
|
4890
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
4891
|
+
import { resolve as resolve8, join as join8 } from "path";
|
|
4776
4892
|
var SCRIPT_RULES = loadScriptRules();
|
|
4777
4893
|
if (!SCRIPT_RULES || Object.keys(SCRIPT_RULES).length === 0) {
|
|
4778
4894
|
console.error(
|
|
@@ -4842,8 +4958,8 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
4842
4958
|
}
|
|
4843
4959
|
function readScriptContent(scriptPath, maxLines = 500) {
|
|
4844
4960
|
try {
|
|
4845
|
-
const expandedPath = scriptPath === "~" || scriptPath.startsWith("~/") ?
|
|
4846
|
-
const raw =
|
|
4961
|
+
const expandedPath = scriptPath === "~" || scriptPath.startsWith("~/") ? join8(process.env.HOME || "/home/user", scriptPath.slice(1)) : resolve8(scriptPath);
|
|
4962
|
+
const raw = readFileSync9(expandedPath, "utf-8");
|
|
4847
4963
|
const lines = raw.split("\n").slice(0, maxLines);
|
|
4848
4964
|
return { content: lines.join("\n"), lineCount: lines.length, error: "" };
|
|
4849
4965
|
} catch (e) {
|
|
@@ -4899,9 +5015,9 @@ init_heuristic();
|
|
|
4899
5015
|
init_config();
|
|
4900
5016
|
init_logic_rules();
|
|
4901
5017
|
init_inline_analyzer();
|
|
4902
|
-
import { statSync as statSync4, existsSync as
|
|
4903
|
-
import { resolve as
|
|
4904
|
-
import { homedir as
|
|
5018
|
+
import { statSync as statSync4, existsSync as existsSync11 } from "fs";
|
|
5019
|
+
import { resolve as resolve10, join as join10, isAbsolute as isAbsolute3 } from "path";
|
|
5020
|
+
import { homedir as homedir4 } from "os";
|
|
4905
5021
|
|
|
4906
5022
|
// src/engine/script-engine/tracker.ts
|
|
4907
5023
|
init_esm_shims();
|
|
@@ -5011,14 +5127,14 @@ function isSysArgv(node) {
|
|
|
5011
5127
|
const prop = node.getChild("PropertyName");
|
|
5012
5128
|
return prop !== null && srcSlice(prop) === "argv";
|
|
5013
5129
|
}
|
|
5014
|
-
function evalExpr(node,
|
|
5130
|
+
function evalExpr(node, env2) {
|
|
5015
5131
|
if (!node) return null;
|
|
5016
5132
|
const name = node.name;
|
|
5017
5133
|
if (name === "String") return stringValue(srcSlice(node));
|
|
5018
5134
|
if (name === "Number") return srcSlice(node);
|
|
5019
5135
|
if (name === "VariableName") {
|
|
5020
5136
|
const id = srcSlice(node);
|
|
5021
|
-
return id in
|
|
5137
|
+
return id in env2.vars ? env2.vars[id] : null;
|
|
5022
5138
|
}
|
|
5023
5139
|
if (name === "MemberExpression") {
|
|
5024
5140
|
const bracket = node.getChild("[");
|
|
@@ -5028,13 +5144,13 @@ function evalExpr(node, env) {
|
|
|
5028
5144
|
const idxNode = bracket.nextSibling;
|
|
5029
5145
|
if (idxNode && idxNode.name === "Number") {
|
|
5030
5146
|
const idx = parseInt(srcSlice(idxNode), 10);
|
|
5031
|
-
if (idx >= 1 && idx <=
|
|
5147
|
+
if (idx >= 1 && idx <= env2.argv.length) return env2.argv[idx - 1];
|
|
5032
5148
|
return null;
|
|
5033
5149
|
}
|
|
5034
5150
|
}
|
|
5035
5151
|
return null;
|
|
5036
5152
|
}
|
|
5037
|
-
if (isSysArgv(node)) return
|
|
5153
|
+
if (isSysArgv(node)) return env2.argv[0] ?? null;
|
|
5038
5154
|
return null;
|
|
5039
5155
|
}
|
|
5040
5156
|
if (name === "CallExpression") {
|
|
@@ -5042,7 +5158,7 @@ function evalExpr(node, env) {
|
|
|
5042
5158
|
if (func && func.name === "VariableName" && srcSlice(func) === "len") {
|
|
5043
5159
|
const argList = node.getChild("ArgList");
|
|
5044
5160
|
const inner = argList ? firstNamedChild(argList) : null;
|
|
5045
|
-
if (inner && isSysArgv(inner)) return String(
|
|
5161
|
+
if (inner && isSysArgv(inner)) return String(env2.argv.length + 1);
|
|
5046
5162
|
}
|
|
5047
5163
|
return null;
|
|
5048
5164
|
}
|
|
@@ -5054,16 +5170,16 @@ function evalExpr(node, env) {
|
|
|
5054
5170
|
const condNode = ifKw.nextSibling;
|
|
5055
5171
|
const orelseNode = elseKw.nextSibling;
|
|
5056
5172
|
if (!thenNode || !condNode || !orelseNode) return null;
|
|
5057
|
-
const cond = evalCondition(condNode,
|
|
5058
|
-
if (cond === true) return evalExpr(thenNode,
|
|
5059
|
-
if (cond === false) return evalExpr(orelseNode,
|
|
5173
|
+
const cond = evalCondition(condNode, env2);
|
|
5174
|
+
if (cond === true) return evalExpr(thenNode, env2);
|
|
5175
|
+
if (cond === false) return evalExpr(orelseNode, env2);
|
|
5060
5176
|
return null;
|
|
5061
5177
|
}
|
|
5062
5178
|
if (name === "BinaryExpression") {
|
|
5063
5179
|
const op = findOp(node);
|
|
5064
5180
|
if (op === "+") {
|
|
5065
|
-
const left = evalExpr(node.firstChild,
|
|
5066
|
-
const right = evalExpr(lastNamedChild(node),
|
|
5181
|
+
const left = evalExpr(node.firstChild, env2);
|
|
5182
|
+
const right = evalExpr(lastNamedChild(node), env2);
|
|
5067
5183
|
if (left !== null && right !== null) return left + right;
|
|
5068
5184
|
}
|
|
5069
5185
|
return null;
|
|
@@ -5096,7 +5212,7 @@ function findOp(node) {
|
|
|
5096
5212
|
}
|
|
5097
5213
|
return null;
|
|
5098
5214
|
}
|
|
5099
|
-
function evalCondition(node,
|
|
5215
|
+
function evalCondition(node, env2) {
|
|
5100
5216
|
if (!node) return null;
|
|
5101
5217
|
const name = node.name;
|
|
5102
5218
|
if (name === "Boolean") {
|
|
@@ -5107,7 +5223,7 @@ function evalCondition(node, env) {
|
|
|
5107
5223
|
const op = findOp(node);
|
|
5108
5224
|
if (op === "and" || op === "or") {
|
|
5109
5225
|
const parts2 = namedChildren(node);
|
|
5110
|
-
const vals = parts2.map((p) => evalCondition(p,
|
|
5226
|
+
const vals = parts2.map((p) => evalCondition(p, env2));
|
|
5111
5227
|
if (op === "and") {
|
|
5112
5228
|
if (vals.some((v) => v === false)) return false;
|
|
5113
5229
|
if (vals.every((v) => v === true)) return true;
|
|
@@ -5121,13 +5237,13 @@ function evalCondition(node, env) {
|
|
|
5121
5237
|
if (parts.length !== 3) return null;
|
|
5122
5238
|
const [left, opNode, right] = parts;
|
|
5123
5239
|
const opText = srcSlice(opNode).trim();
|
|
5124
|
-
return evalCompare(left, opText, right,
|
|
5240
|
+
return evalCompare(left, opText, right, env2);
|
|
5125
5241
|
}
|
|
5126
5242
|
if (name === "UnaryExpression") {
|
|
5127
5243
|
const kw = node.getChild("not");
|
|
5128
5244
|
if (kw) {
|
|
5129
5245
|
const operand = kw.nextSibling;
|
|
5130
|
-
const v = evalCondition(operand,
|
|
5246
|
+
const v = evalCondition(operand, env2);
|
|
5131
5247
|
return v === null ? null : !v;
|
|
5132
5248
|
}
|
|
5133
5249
|
return null;
|
|
@@ -5148,39 +5264,39 @@ function namedChildren(node) {
|
|
|
5148
5264
|
}
|
|
5149
5265
|
return out;
|
|
5150
5266
|
}
|
|
5151
|
-
function evalCompare(left, opText, right,
|
|
5267
|
+
function evalCompare(left, opText, right, env2) {
|
|
5152
5268
|
if (opText === "==" && left.name === "VariableName" && srcSlice(left) === "__name__") {
|
|
5153
|
-
const rv = evalExpr(right,
|
|
5269
|
+
const rv = evalExpr(right, env2);
|
|
5154
5270
|
if (rv !== null) return rv === "__main__";
|
|
5155
5271
|
return null;
|
|
5156
5272
|
}
|
|
5157
5273
|
if (opText === "==" || opText === "!=") {
|
|
5158
|
-
const lv = evalExpr(left,
|
|
5159
|
-
const rv = evalExpr(right,
|
|
5274
|
+
const lv = evalExpr(left, env2);
|
|
5275
|
+
const rv = evalExpr(right, env2);
|
|
5160
5276
|
if (lv !== null && rv !== null) {
|
|
5161
5277
|
return opText === "==" ? lv === rv : lv !== rv;
|
|
5162
5278
|
}
|
|
5163
5279
|
return null;
|
|
5164
5280
|
}
|
|
5165
5281
|
if (opText === "in") {
|
|
5166
|
-
const lv = evalExpr(left,
|
|
5282
|
+
const lv = evalExpr(left, env2);
|
|
5167
5283
|
if (lv === null) return null;
|
|
5168
5284
|
const rightName = right.name;
|
|
5169
5285
|
if (rightName === "TupleExpression" || rightName === "ArrayExpression" || rightName === "SetExpression" || rightName === "ParenthesizedExpression") {
|
|
5170
5286
|
const container = rightName === "ParenthesizedExpression" && right.firstChild && right.firstChild.name === "TupleExpression" ? right.firstChild : right;
|
|
5171
5287
|
for (const elt of namedChildren(container)) {
|
|
5172
|
-
const ev = evalExpr(elt,
|
|
5288
|
+
const ev = evalExpr(elt, env2);
|
|
5173
5289
|
if (ev !== null && ev === lv) return true;
|
|
5174
5290
|
}
|
|
5175
5291
|
return false;
|
|
5176
5292
|
}
|
|
5177
|
-
const rv = evalExpr(right,
|
|
5293
|
+
const rv = evalExpr(right, env2);
|
|
5178
5294
|
if (rv !== null) return rv.includes(lv);
|
|
5179
5295
|
return null;
|
|
5180
5296
|
}
|
|
5181
5297
|
if (opText === ">" || opText === ">=" || opText === "<" || opText === "<=") {
|
|
5182
|
-
const lv = evalExpr(left,
|
|
5183
|
-
const rv = evalExpr(right,
|
|
5298
|
+
const lv = evalExpr(left, env2);
|
|
5299
|
+
const rv = evalExpr(right, env2);
|
|
5184
5300
|
if (lv === null || rv === null) return null;
|
|
5185
5301
|
const ln = parseInt(lv, 10);
|
|
5186
5302
|
const rn = parseInt(rv, 10);
|
|
@@ -5192,71 +5308,71 @@ function evalCompare(left, opText, right, env) {
|
|
|
5192
5308
|
}
|
|
5193
5309
|
return null;
|
|
5194
5310
|
}
|
|
5195
|
-
function processStmts(stmts,
|
|
5196
|
-
for (const s of stmts) processStmt(s,
|
|
5311
|
+
function processStmts(stmts, env2, lineStarts, lines, branches) {
|
|
5312
|
+
for (const s of stmts) processStmt(s, env2, lineStarts, lines, branches);
|
|
5197
5313
|
}
|
|
5198
|
-
function invalidateEnvOnCalls(node,
|
|
5314
|
+
function invalidateEnvOnCalls(node, env2) {
|
|
5199
5315
|
const cursor = node.cursor();
|
|
5200
5316
|
cursor.iterate((n) => {
|
|
5201
5317
|
const nd = n.node;
|
|
5202
5318
|
if (nd.name !== "CallExpression") return true;
|
|
5203
5319
|
const func = nd.firstChild;
|
|
5204
5320
|
if (func && func.name === "VariableName" && !PURE_BUILTINS.has(srcSlice(func))) {
|
|
5205
|
-
for (const k of Object.keys(
|
|
5321
|
+
for (const k of Object.keys(env2.vars)) env2.vars[k] = null;
|
|
5206
5322
|
return false;
|
|
5207
5323
|
}
|
|
5208
5324
|
return true;
|
|
5209
5325
|
});
|
|
5210
5326
|
}
|
|
5211
|
-
function processStmt(stmt,
|
|
5327
|
+
function processStmt(stmt, env2, lineStarts, lines, branches) {
|
|
5212
5328
|
const name = stmt.name;
|
|
5213
5329
|
if (name === "AssignStatement") {
|
|
5214
5330
|
const target = stmt.firstChild;
|
|
5215
5331
|
if (target && target.name === "VariableName") {
|
|
5216
5332
|
const valNode = target.nextSibling ? target.nextSibling.nextSibling : null;
|
|
5217
|
-
invalidateEnvOnCalls(stmt,
|
|
5218
|
-
const val = evalExpr(valNode,
|
|
5219
|
-
|
|
5333
|
+
invalidateEnvOnCalls(stmt, env2);
|
|
5334
|
+
const val = evalExpr(valNode, env2);
|
|
5335
|
+
env2.vars[srcSlice(target)] = val;
|
|
5220
5336
|
}
|
|
5221
5337
|
markNodeLines(stmt, lines, lineStarts);
|
|
5222
5338
|
return;
|
|
5223
5339
|
}
|
|
5224
5340
|
if (name === "UpdateStatement") {
|
|
5225
5341
|
const target = stmt.firstChild;
|
|
5226
|
-
if (target && target.name === "VariableName")
|
|
5227
|
-
invalidateEnvOnCalls(stmt,
|
|
5342
|
+
if (target && target.name === "VariableName") env2.vars[srcSlice(target)] = null;
|
|
5343
|
+
invalidateEnvOnCalls(stmt, env2);
|
|
5228
5344
|
markNodeLines(stmt, lines, lineStarts);
|
|
5229
5345
|
return;
|
|
5230
5346
|
}
|
|
5231
5347
|
if (name === "IfStatement") {
|
|
5232
|
-
processIf(stmt,
|
|
5348
|
+
processIf(stmt, env2, lineStarts, lines, branches);
|
|
5233
5349
|
return;
|
|
5234
5350
|
}
|
|
5235
5351
|
if (name === "ForStatement" || name === "WhileStatement") {
|
|
5236
5352
|
markNodeLines(stmt, lines, lineStarts);
|
|
5237
5353
|
for (const body of stmt.getChildren("Body")) {
|
|
5238
|
-
processStmts(bodyStmts(body), { argv:
|
|
5354
|
+
processStmts(bodyStmts(body), { argv: env2.argv, vars: { ...env2.vars } }, lineStarts, lines, branches);
|
|
5239
5355
|
}
|
|
5240
5356
|
return;
|
|
5241
5357
|
}
|
|
5242
5358
|
if (name === "TryStatement") {
|
|
5243
5359
|
markNodeLines(stmt, lines, lineStarts);
|
|
5244
5360
|
for (const body of stmt.getChildren("Body")) {
|
|
5245
|
-
processStmts(bodyStmts(body), { argv:
|
|
5361
|
+
processStmts(bodyStmts(body), { argv: env2.argv, vars: { ...env2.vars } }, lineStarts, lines, branches);
|
|
5246
5362
|
}
|
|
5247
5363
|
return;
|
|
5248
5364
|
}
|
|
5249
5365
|
if (name === "WithStatement") {
|
|
5250
5366
|
markNodeLines(stmt, lines, lineStarts);
|
|
5251
5367
|
const body = stmt.getChild("Body");
|
|
5252
|
-
if (body) processStmts(bodyStmts(body), { argv:
|
|
5368
|
+
if (body) processStmts(bodyStmts(body), { argv: env2.argv, vars: { ...env2.vars } }, lineStarts, lines, branches);
|
|
5253
5369
|
return;
|
|
5254
5370
|
}
|
|
5255
5371
|
if (name === "MatchStatement") {
|
|
5256
5372
|
markNodeLines(stmt, lines, lineStarts);
|
|
5257
5373
|
for (const clause of stmt.getChildren("MatchClause")) {
|
|
5258
5374
|
const body = clause.getChild("Body");
|
|
5259
|
-
if (body) processStmts(bodyStmts(body), { argv:
|
|
5375
|
+
if (body) processStmts(bodyStmts(body), { argv: env2.argv, vars: { ...env2.vars } }, lineStarts, lines, branches);
|
|
5260
5376
|
}
|
|
5261
5377
|
return;
|
|
5262
5378
|
}
|
|
@@ -5265,7 +5381,7 @@ function processStmt(stmt, env, lineStarts, lines, branches) {
|
|
|
5265
5381
|
return;
|
|
5266
5382
|
}
|
|
5267
5383
|
if (name === "ExpressionStatement") {
|
|
5268
|
-
invalidateEnvOnCalls(stmt,
|
|
5384
|
+
invalidateEnvOnCalls(stmt, env2);
|
|
5269
5385
|
}
|
|
5270
5386
|
markNodeLines(stmt, lines, lineStarts);
|
|
5271
5387
|
}
|
|
@@ -5285,7 +5401,7 @@ function bodyStmts(body) {
|
|
|
5285
5401
|
}
|
|
5286
5402
|
return out;
|
|
5287
5403
|
}
|
|
5288
|
-
function processIf(stmt,
|
|
5404
|
+
function processIf(stmt, env2, lineStarts, lines, branches) {
|
|
5289
5405
|
const sections = [];
|
|
5290
5406
|
let c = stmt.firstChild;
|
|
5291
5407
|
while (c) {
|
|
@@ -5300,17 +5416,17 @@ function processIf(stmt, env, lineStarts, lines, branches) {
|
|
|
5300
5416
|
}
|
|
5301
5417
|
c = c.nextSibling;
|
|
5302
5418
|
}
|
|
5303
|
-
processIfSections(stmt, sections, 0,
|
|
5419
|
+
processIfSections(stmt, sections, 0, env2, lineStarts, lines, branches);
|
|
5304
5420
|
}
|
|
5305
|
-
function processIfSections(_stmt, sections, idx,
|
|
5421
|
+
function processIfSections(_stmt, sections, idx, env2, lineStarts, lines, branches) {
|
|
5306
5422
|
if (idx >= sections.length) return;
|
|
5307
5423
|
const s = sections[idx];
|
|
5308
5424
|
if (s.cond) markNodeLines(s.cond, lines, lineStarts);
|
|
5309
5425
|
if (s.isElse) {
|
|
5310
|
-
if (s.body) processStmts(bodyStmts(s.body),
|
|
5426
|
+
if (s.body) processStmts(bodyStmts(s.body), env2, lineStarts, lines, branches);
|
|
5311
5427
|
return;
|
|
5312
5428
|
}
|
|
5313
|
-
const cond = s.cond ? evalCondition(s.cond,
|
|
5429
|
+
const cond = s.cond ? evalCondition(s.cond, env2) : null;
|
|
5314
5430
|
branches.push({
|
|
5315
5431
|
kind: "if",
|
|
5316
5432
|
label: s.cond ? srcSlice(s.cond) : "",
|
|
@@ -5318,18 +5434,18 @@ function processIfSections(_stmt, sections, idx, env, lineStarts, lines, branche
|
|
|
5318
5434
|
reachable: cond !== false
|
|
5319
5435
|
});
|
|
5320
5436
|
if (cond === true) {
|
|
5321
|
-
if (s.body) processStmts(bodyStmts(s.body),
|
|
5437
|
+
if (s.body) processStmts(bodyStmts(s.body), env2, lineStarts, lines, branches);
|
|
5322
5438
|
return;
|
|
5323
5439
|
}
|
|
5324
5440
|
if (cond === false) {
|
|
5325
|
-
processIfSections(_stmt, sections, idx + 1,
|
|
5441
|
+
processIfSections(_stmt, sections, idx + 1, env2, lineStarts, lines, branches);
|
|
5326
5442
|
return;
|
|
5327
5443
|
}
|
|
5328
|
-
if (s.body) processStmts(bodyStmts(s.body),
|
|
5444
|
+
if (s.body) processStmts(bodyStmts(s.body), env2, lineStarts, lines, branches);
|
|
5329
5445
|
for (let j = idx + 1; j < sections.length; j++) {
|
|
5330
5446
|
const sj = sections[j];
|
|
5331
5447
|
if (sj.cond) markNodeLines(sj.cond, lines, lineStarts);
|
|
5332
|
-
if (sj.body) processStmts(bodyStmts(sj.body),
|
|
5448
|
+
if (sj.body) processStmts(bodyStmts(sj.body), env2, lineStarts, lines, branches);
|
|
5333
5449
|
}
|
|
5334
5450
|
}
|
|
5335
5451
|
function parseShellString(s) {
|
|
@@ -5452,7 +5568,7 @@ var PythonBackend = class {
|
|
|
5452
5568
|
SOURCE = c;
|
|
5453
5569
|
const sourceLines = c.split("\n");
|
|
5454
5570
|
const lineStarts = buildLineStarts(c);
|
|
5455
|
-
const
|
|
5571
|
+
const env2 = makeEnv(entryArgs || []);
|
|
5456
5572
|
const lines = /* @__PURE__ */ new Set();
|
|
5457
5573
|
const branches = [];
|
|
5458
5574
|
if (sourceLines.length > MAX_LINES) {
|
|
@@ -5479,7 +5595,7 @@ var PythonBackend = class {
|
|
|
5479
5595
|
};
|
|
5480
5596
|
}
|
|
5481
5597
|
const stmts = bodyStmts(tree);
|
|
5482
|
-
processStmts(stmts,
|
|
5598
|
+
processStmts(stmts, env2, lineStarts, lines, branches);
|
|
5483
5599
|
const reachable = reconstruct(sourceLines, lines);
|
|
5484
5600
|
let calls = extractCallsFromTree(tree, lines);
|
|
5485
5601
|
if (calls.length === 0) calls = extractCallsRegex(c);
|
|
@@ -5729,7 +5845,7 @@ function tokenize(content) {
|
|
|
5729
5845
|
return stmts;
|
|
5730
5846
|
}
|
|
5731
5847
|
var EXPR_SPLIT_RE = /(\$\{[^}]*\}|\$[A-Za-z_][A-Za-z0-9_]*|\$\d+)/;
|
|
5732
|
-
function evalExpr2(text,
|
|
5848
|
+
function evalExpr2(text, env2) {
|
|
5733
5849
|
const isSingleQuoted = text.length >= 2 && text[0] === "'" && text[text.length - 1] === "'";
|
|
5734
5850
|
if (text.length >= 2 && (text[0] === '"' || text[0] === "'") && text[text.length - 1] === text[0]) {
|
|
5735
5851
|
text = text.slice(1, -1);
|
|
@@ -5745,19 +5861,19 @@ function evalExpr2(text, env) {
|
|
|
5745
5861
|
const dm = inner.match(/^([A-Za-z_][A-Za-z0-9_]*|\d+):?-(.*)$/s);
|
|
5746
5862
|
if (dm) {
|
|
5747
5863
|
const key = /^\d+$/.test(dm[1]) ? `$${dm[1]}` : dm[1];
|
|
5748
|
-
const bound =
|
|
5864
|
+
const bound = env2.get(key);
|
|
5749
5865
|
if (bound && !(bound.kind === "concrete" && !bound.value)) {
|
|
5750
5866
|
result.push(bound);
|
|
5751
5867
|
} else {
|
|
5752
|
-
result.push(evalExpr2(dm[2],
|
|
5868
|
+
result.push(evalExpr2(dm[2], env2));
|
|
5753
5869
|
}
|
|
5754
5870
|
continue;
|
|
5755
5871
|
}
|
|
5756
5872
|
if (/^\d+$/.test(inner)) {
|
|
5757
|
-
const v =
|
|
5873
|
+
const v = env2.get(`$${inner}`);
|
|
5758
5874
|
result.push(v || svalSym(`$${inner}`));
|
|
5759
5875
|
} else {
|
|
5760
|
-
const v =
|
|
5876
|
+
const v = env2.get(inner);
|
|
5761
5877
|
result.push(v || svalSym(inner));
|
|
5762
5878
|
}
|
|
5763
5879
|
continue;
|
|
@@ -5766,7 +5882,7 @@ function evalExpr2(text, env) {
|
|
|
5766
5882
|
if (bare) {
|
|
5767
5883
|
const varName = bare[1];
|
|
5768
5884
|
const key = /^\d+$/.test(varName) ? `$${varName}` : varName;
|
|
5769
|
-
const v =
|
|
5885
|
+
const v = env2.get(key);
|
|
5770
5886
|
result.push(v || svalSym(p));
|
|
5771
5887
|
continue;
|
|
5772
5888
|
}
|
|
@@ -5776,13 +5892,13 @@ function evalExpr2(text, env) {
|
|
|
5776
5892
|
return fold(svalExpr(result));
|
|
5777
5893
|
}
|
|
5778
5894
|
function initEnv(entryArgs) {
|
|
5779
|
-
const
|
|
5895
|
+
const env2 = /* @__PURE__ */ new Map();
|
|
5780
5896
|
if (entryArgs && entryArgs.length) {
|
|
5781
|
-
entryArgs.forEach((a, idx) =>
|
|
5782
|
-
|
|
5783
|
-
|
|
5897
|
+
entryArgs.forEach((a, idx) => env2.set(`$${idx + 1}`, svalConc(a)));
|
|
5898
|
+
env2.set("$@", svalConc(entryArgs.join(" ")));
|
|
5899
|
+
env2.set("$*", svalConc(entryArgs.join(" ")));
|
|
5784
5900
|
}
|
|
5785
|
-
return
|
|
5901
|
+
return env2;
|
|
5786
5902
|
}
|
|
5787
5903
|
var HAS_GLOB = /[*?[]/;
|
|
5788
5904
|
function globToRegex(pattern) {
|
|
@@ -5841,12 +5957,12 @@ function evalNumericCompare(op, left, right) {
|
|
|
5841
5957
|
return null;
|
|
5842
5958
|
}
|
|
5843
5959
|
}
|
|
5844
|
-
function resolveVarSide(tok,
|
|
5960
|
+
function resolveVarSide(tok, env2) {
|
|
5845
5961
|
if (!tok.startsWith("$")) return tok;
|
|
5846
|
-
const ev = evalExpr2(tok,
|
|
5962
|
+
const ev = evalExpr2(tok, env2);
|
|
5847
5963
|
return ev.kind === "concrete" ? ev.value : null;
|
|
5848
5964
|
}
|
|
5849
|
-
function evalCondition2(cond,
|
|
5965
|
+
function evalCondition2(cond, env2) {
|
|
5850
5966
|
let inner = cond.trim().replace(/^\[\[?|\]\]?$/g, "").trim();
|
|
5851
5967
|
if (/^-[A-Za-z]\s/.test(inner) || inner.startsWith("-d") || inner.startsWith("-f")) return null;
|
|
5852
5968
|
const innerQ = inner.replace(/"/g, "").replace(/'/g, "");
|
|
@@ -5856,8 +5972,8 @@ function evalCondition2(cond, env) {
|
|
|
5856
5972
|
if (!opm) continue;
|
|
5857
5973
|
const left2 = innerQ.slice(0, opm.index).trim();
|
|
5858
5974
|
const right2 = innerQ.slice(opm.index + opm[0].length).trim();
|
|
5859
|
-
const lv2 = resolveVarSide(left2,
|
|
5860
|
-
const rv2 = resolveVarSide(right2,
|
|
5975
|
+
const lv2 = resolveVarSide(left2, env2);
|
|
5976
|
+
const rv2 = resolveVarSide(right2, env2);
|
|
5861
5977
|
if (lv2 === null || rv2 === null) return null;
|
|
5862
5978
|
return evalNumericCompare(op2, lv2, rv2);
|
|
5863
5979
|
}
|
|
@@ -5868,7 +5984,7 @@ function evalCondition2(cond, env) {
|
|
|
5868
5984
|
let right = sm[3].trim();
|
|
5869
5985
|
if (op === "=~") {
|
|
5870
5986
|
if (right.startsWith("/") && right.endsWith("/")) right = right.slice(1, -1);
|
|
5871
|
-
const lv2 = resolveVarSide(left,
|
|
5987
|
+
const lv2 = resolveVarSide(left, env2);
|
|
5872
5988
|
if (lv2 === null) return null;
|
|
5873
5989
|
try {
|
|
5874
5990
|
return new RegExp(right).test(lv2);
|
|
@@ -5876,8 +5992,8 @@ function evalCondition2(cond, env) {
|
|
|
5876
5992
|
return null;
|
|
5877
5993
|
}
|
|
5878
5994
|
}
|
|
5879
|
-
const lv = resolveVarSide(left,
|
|
5880
|
-
const rv = resolveVarSide(right,
|
|
5995
|
+
const lv = resolveVarSide(left, env2);
|
|
5996
|
+
const rv = resolveVarSide(right, env2);
|
|
5881
5997
|
if (lv === null || rv === null) return null;
|
|
5882
5998
|
if (op === "!=") return lv !== rv;
|
|
5883
5999
|
return lv === rv;
|
|
@@ -5887,7 +6003,7 @@ function symbolicProcess(content, entryArgs) {
|
|
|
5887
6003
|
const stmts = tokenize(content);
|
|
5888
6004
|
if (!stmts.some((s) => s.kind === "case" || s.kind === "if" || s.kind === "assign")) return null;
|
|
5889
6005
|
if (stmts.some((s) => !s.modelable)) return null;
|
|
5890
|
-
const
|
|
6006
|
+
const env2 = initEnv(entryArgs);
|
|
5891
6007
|
let linesBudget = 0;
|
|
5892
6008
|
let branchesBudget = 0;
|
|
5893
6009
|
let modelable = false;
|
|
@@ -5897,9 +6013,9 @@ function symbolicProcess(content, entryArgs) {
|
|
|
5897
6013
|
if (linesBudget > MAX_LINES2) return null;
|
|
5898
6014
|
if (s.kind === "assign") {
|
|
5899
6015
|
modelable = true;
|
|
5900
|
-
if (
|
|
5901
|
-
const v = evalExpr2(s.rhs,
|
|
5902
|
-
|
|
6016
|
+
if (env2.size >= MAX_VARS) return null;
|
|
6017
|
+
const v = evalExpr2(s.rhs, env2);
|
|
6018
|
+
env2.set(s.name, fold(v));
|
|
5903
6019
|
out.push(s.line);
|
|
5904
6020
|
continue;
|
|
5905
6021
|
}
|
|
@@ -5907,7 +6023,7 @@ function symbolicProcess(content, entryArgs) {
|
|
|
5907
6023
|
modelable = true;
|
|
5908
6024
|
branchesBudget += s.branches.length;
|
|
5909
6025
|
if (branchesBudget > MAX_BRANCHES) return null;
|
|
5910
|
-
const selVal = fold(evalExpr2(s.selector,
|
|
6026
|
+
const selVal = fold(evalExpr2(s.selector, env2));
|
|
5911
6027
|
if (selVal.kind !== "concrete") return null;
|
|
5912
6028
|
const concrete = selVal.value || "";
|
|
5913
6029
|
let selected = null;
|
|
@@ -5934,7 +6050,7 @@ esac`);
|
|
|
5934
6050
|
modelable = true;
|
|
5935
6051
|
branchesBudget++;
|
|
5936
6052
|
if (branchesBudget > MAX_BRANCHES) return null;
|
|
5937
|
-
const truth = evalCondition2(s.cond,
|
|
6053
|
+
const truth = evalCondition2(s.cond, env2);
|
|
5938
6054
|
if (truth === null) return null;
|
|
5939
6055
|
const chosen = truth ? s.thenBody : s.elseBody;
|
|
5940
6056
|
if (chosen === null) return null;
|
|
@@ -6539,7 +6655,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
6539
6655
|
if (looksLikeScriptPath(tok)) {
|
|
6540
6656
|
try {
|
|
6541
6657
|
const resolved = resolvePath2(tok.replace(/^['"]|['"]$/g, ""));
|
|
6542
|
-
if (
|
|
6658
|
+
if (existsSync11(resolved)) {
|
|
6543
6659
|
const stat = statSync4(resolved);
|
|
6544
6660
|
if (stat.isFile()) return resolved;
|
|
6545
6661
|
}
|
|
@@ -6553,7 +6669,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
6553
6669
|
const p = m[1];
|
|
6554
6670
|
try {
|
|
6555
6671
|
const resolved = resolvePath2(p);
|
|
6556
|
-
if (
|
|
6672
|
+
if (existsSync11(resolved)) {
|
|
6557
6673
|
const stat = statSync4(resolved);
|
|
6558
6674
|
if (stat.isFile()) return resolved;
|
|
6559
6675
|
}
|
|
@@ -6569,7 +6685,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
6569
6685
|
let resolved;
|
|
6570
6686
|
try {
|
|
6571
6687
|
resolved = resolvePath2(p);
|
|
6572
|
-
if (
|
|
6688
|
+
if (existsSync11(resolved)) {
|
|
6573
6689
|
const stat = statSync4(resolved);
|
|
6574
6690
|
if (stat.isFile()) return resolved;
|
|
6575
6691
|
}
|
|
@@ -6610,9 +6726,9 @@ function shlexSplit(s) {
|
|
|
6610
6726
|
function resolvePath2(p) {
|
|
6611
6727
|
let expanded = p;
|
|
6612
6728
|
if (expanded.startsWith("~/") || expanded === "~") {
|
|
6613
|
-
expanded =
|
|
6729
|
+
expanded = join10(homedir4(), expanded.slice(1));
|
|
6614
6730
|
}
|
|
6615
|
-
return
|
|
6731
|
+
return resolve10(expanded);
|
|
6616
6732
|
}
|
|
6617
6733
|
function scanExtensionPatterns(ext, content) {
|
|
6618
6734
|
const pats = ext?.extra_command_patterns;
|
|
@@ -6733,8 +6849,8 @@ function analyzeScriptContent2(input, ext) {
|
|
|
6733
6849
|
resolvedPath = inline;
|
|
6734
6850
|
isInline = true;
|
|
6735
6851
|
}
|
|
6736
|
-
if (resolvedPath && !
|
|
6737
|
-
resolvedPath =
|
|
6852
|
+
if (resolvedPath && !isAbsolute3(resolvedPath) && !resolvedPath.startsWith("~/")) {
|
|
6853
|
+
resolvedPath = join10(input.cwd || process.cwd(), resolvedPath);
|
|
6738
6854
|
}
|
|
6739
6855
|
const l1Adapter = (content) => {
|
|
6740
6856
|
const j = scanDangerousCommandPatterns("bash", content, input.osType);
|
|
@@ -6821,7 +6937,7 @@ ${contentPreview}
|
|
|
6821
6937
|
}
|
|
6822
6938
|
|
|
6823
6939
|
// src/engine/llm-analyzer.ts
|
|
6824
|
-
import {
|
|
6940
|
+
import { openSync as openSync2, writeSync as writeSync2, closeSync as closeSync2, constants as fsConstants } from "fs";
|
|
6825
6941
|
import OpenAI from "openai";
|
|
6826
6942
|
var llmCache = /* @__PURE__ */ new Map();
|
|
6827
6943
|
var LLM_CACHE_MAX = 200;
|
|
@@ -6839,7 +6955,15 @@ async function runLLMAnalysis(input, previous) {
|
|
|
6839
6955
|
};
|
|
6840
6956
|
}
|
|
6841
6957
|
const globalConfig = getLLMConfig();
|
|
6842
|
-
|
|
6958
|
+
let perRequest = input.llmConfig;
|
|
6959
|
+
if (perRequest?.apiKey) {
|
|
6960
|
+
const [okUrl, why] = validateLlmBaseUrl(String(perRequest.baseUrl || ""));
|
|
6961
|
+
if (!okUrl) {
|
|
6962
|
+
console.warn("[AgentMoss] \u5FFD\u7565\u4E0D\u88AB\u5141\u8BB8\u7684 per-request llmConfig.baseUrl:", why);
|
|
6963
|
+
perRequest = { ...perRequest, baseUrl: void 0 };
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
const config = perRequest?.apiKey ? { ...globalConfig, ...perRequest } : globalConfig;
|
|
6843
6967
|
const rawDetail = input.aNext.actionDetail.replace(/^terminal-\w+:\s*command=([^,]+).*/, "$1").trim();
|
|
6844
6968
|
const cacheKey = `${input.aNext.actionType}:${rawDetail || input.aNext.actionDetail}`;
|
|
6845
6969
|
const cached2 = llmCache.get(cacheKey);
|
|
@@ -6868,6 +6992,10 @@ async function runLLMAnalysis(input, previous) {
|
|
|
6868
6992
|
}
|
|
6869
6993
|
function logPrompt(prompt, aNext, logPath) {
|
|
6870
6994
|
if (!logPath) return;
|
|
6995
|
+
if (!pathWithin(logPath, logRoots())) {
|
|
6996
|
+
console.warn("[AgentMoss] \u5FFD\u7565\u8D8A\u754C\u7684 llm_log_path\uFF08\u4E0D\u5728\u5141\u8BB8\u6839\u76EE\u5F55\u5185\uFF09:", logPath);
|
|
6997
|
+
return;
|
|
6998
|
+
}
|
|
6871
6999
|
try {
|
|
6872
7000
|
const actionType = aNext.actionType || "unknown";
|
|
6873
7001
|
const actionDetail = (aNext.actionDetail || "").slice(0, 100);
|
|
@@ -6875,7 +7003,14 @@ function logPrompt(prompt, aNext, logPath) {
|
|
|
6875
7003
|
${prompt}
|
|
6876
7004
|
--- END PROMPT ---
|
|
6877
7005
|
`;
|
|
6878
|
-
|
|
7006
|
+
let flags = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_APPEND;
|
|
7007
|
+
if (fsConstants.O_NOFOLLOW) flags |= fsConstants.O_NOFOLLOW;
|
|
7008
|
+
const fd = openSync2(logPath, flags, 384);
|
|
7009
|
+
try {
|
|
7010
|
+
writeSync2(fd, line);
|
|
7011
|
+
} finally {
|
|
7012
|
+
closeSync2(fd);
|
|
7013
|
+
}
|
|
6879
7014
|
} catch (e) {
|
|
6880
7015
|
console.warn("[AgentMoss] Failed to write LLM prompt to log:", e);
|
|
6881
7016
|
}
|
|
@@ -7034,7 +7169,7 @@ async function analyzeWithLLM(prompt, config) {
|
|
|
7034
7169
|
}
|
|
7035
7170
|
if (attempt < maxRetries) {
|
|
7036
7171
|
console.error(`[AgentMoss] LLM call failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${retryCfg.retryInterval}s:`, err.message);
|
|
7037
|
-
await new Promise((
|
|
7172
|
+
await new Promise((resolve11) => setTimeout(resolve11, retryCfg.retryInterval * 1e3));
|
|
7038
7173
|
} else {
|
|
7039
7174
|
clearTimeout(totalTimeoutTimer);
|
|
7040
7175
|
console.error("[AgentMoss] LLM call failed after all retries:", err.message);
|
|
@@ -7057,10 +7192,10 @@ init_esm_shims();
|
|
|
7057
7192
|
|
|
7058
7193
|
// src/brain/rule-store.ts
|
|
7059
7194
|
init_esm_shims();
|
|
7060
|
-
import { existsSync as
|
|
7061
|
-
import { join as
|
|
7062
|
-
import { homedir as
|
|
7063
|
-
var DEFAULT_RULES_PATH =
|
|
7195
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "fs";
|
|
7196
|
+
import { join as join11 } from "path";
|
|
7197
|
+
import { homedir as homedir5 } from "os";
|
|
7198
|
+
var DEFAULT_RULES_PATH = join11(homedir5(), ".agentmoss", "brain", "rules.json");
|
|
7064
7199
|
var ENV_RULES_PATH = "AGENT_MOSS_BRAIN_RULES_PATH";
|
|
7065
7200
|
var STATUS_DRAFT = "draft";
|
|
7066
7201
|
var STATUS_APPROVED = "approved";
|
|
@@ -7089,11 +7224,11 @@ var BrainRuleStore = class {
|
|
|
7089
7224
|
this.data = this.load();
|
|
7090
7225
|
}
|
|
7091
7226
|
load() {
|
|
7092
|
-
if (!
|
|
7227
|
+
if (!existsSync13(this.path)) {
|
|
7093
7228
|
return { version: 1, rules: [], pattern_candidates: [] };
|
|
7094
7229
|
}
|
|
7095
7230
|
try {
|
|
7096
|
-
const raw = JSON.parse(
|
|
7231
|
+
const raw = JSON.parse(readFileSync13(this.path, "utf-8"));
|
|
7097
7232
|
return {
|
|
7098
7233
|
version: raw.version || 1,
|
|
7099
7234
|
rules: raw.rules || [],
|
|
@@ -7105,7 +7240,7 @@ var BrainRuleStore = class {
|
|
|
7105
7240
|
}
|
|
7106
7241
|
save() {
|
|
7107
7242
|
const dir = this.path.substring(0, this.path.lastIndexOf("/"));
|
|
7108
|
-
if (dir)
|
|
7243
|
+
if (dir) mkdirSync4(dir, { recursive: true });
|
|
7109
7244
|
writeFileSync3(this.path, JSON.stringify(this.data, null, 2), "utf-8");
|
|
7110
7245
|
}
|
|
7111
7246
|
addRule(rule) {
|
|
@@ -7673,11 +7808,11 @@ function parseReview(content) {
|
|
|
7673
7808
|
|
|
7674
7809
|
// src/brain/skill-manager.ts
|
|
7675
7810
|
init_esm_shims();
|
|
7676
|
-
import { existsSync as
|
|
7677
|
-
import { homedir as
|
|
7678
|
-
import { join as
|
|
7811
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync5, readFileSync as readFileSync14, renameSync, writeFileSync as writeFileSync4 } from "fs";
|
|
7812
|
+
import { homedir as homedir6 } from "os";
|
|
7813
|
+
import { join as join12 } from "path";
|
|
7679
7814
|
import { randomUUID } from "crypto";
|
|
7680
|
-
var DEFAULT_SKILL_META_PATH =
|
|
7815
|
+
var DEFAULT_SKILL_META_PATH = join12(homedir6(), ".agentmoss", "brain", "skill_meta.json");
|
|
7681
7816
|
var ENV_SKILL_META_PATH = "AGENT_MOSS_BRAIN_SKILL_META_PATH";
|
|
7682
7817
|
function getMetaPath(override) {
|
|
7683
7818
|
return override || process.env[ENV_SKILL_META_PATH] || DEFAULT_SKILL_META_PATH;
|
|
@@ -7687,7 +7822,7 @@ var BrainSkillManager = class {
|
|
|
7687
7822
|
this.skillsDir = skillsDir;
|
|
7688
7823
|
this.metaPath = getMetaPath(metaPath);
|
|
7689
7824
|
try {
|
|
7690
|
-
|
|
7825
|
+
mkdirSync5(join12(this.metaPath, ".."), { recursive: true });
|
|
7691
7826
|
} catch {
|
|
7692
7827
|
}
|
|
7693
7828
|
this.load();
|
|
@@ -7697,9 +7832,9 @@ var BrainSkillManager = class {
|
|
|
7697
7832
|
skills = [];
|
|
7698
7833
|
metaPath;
|
|
7699
7834
|
load() {
|
|
7700
|
-
if (!
|
|
7835
|
+
if (!existsSync14(this.metaPath)) return;
|
|
7701
7836
|
try {
|
|
7702
|
-
const data = JSON.parse(
|
|
7837
|
+
const data = JSON.parse(readFileSync14(this.metaPath, "utf-8"));
|
|
7703
7838
|
this.skills = data.skills || [];
|
|
7704
7839
|
} catch {
|
|
7705
7840
|
this.skills = [];
|
|
@@ -7722,7 +7857,7 @@ var BrainSkillManager = class {
|
|
|
7722
7857
|
let changed = false;
|
|
7723
7858
|
for (const sk of this.skills) {
|
|
7724
7859
|
if (sk.status !== "active") continue;
|
|
7725
|
-
if (!
|
|
7860
|
+
if (!existsSync14(join12(this.skillsDir, `${sk.name}.md`))) {
|
|
7726
7861
|
sk.status = "stale";
|
|
7727
7862
|
changed = true;
|
|
7728
7863
|
}
|
|
@@ -7733,9 +7868,9 @@ var BrainSkillManager = class {
|
|
|
7733
7868
|
addSkill(skill) {
|
|
7734
7869
|
const id = skill.id || randomUUID();
|
|
7735
7870
|
const name = skill.name || `brain_${id.slice(0, 8)}`;
|
|
7736
|
-
if (!
|
|
7737
|
-
const mdPath =
|
|
7738
|
-
if (
|
|
7871
|
+
if (!existsSync14(this.skillsDir)) return "";
|
|
7872
|
+
const mdPath = join12(this.skillsDir, `${name}.md`);
|
|
7873
|
+
if (existsSync14(mdPath)) return "";
|
|
7739
7874
|
try {
|
|
7740
7875
|
writeFileSync4(mdPath, skill.content, "utf-8");
|
|
7741
7876
|
} catch {
|
|
@@ -7784,12 +7919,12 @@ var BrainSkillManager = class {
|
|
|
7784
7919
|
const out = [];
|
|
7785
7920
|
for (const sk of this.skills) {
|
|
7786
7921
|
if (sk.origin_node !== "local" || sk.status !== "active") continue;
|
|
7787
|
-
const mdPath =
|
|
7788
|
-
if (!
|
|
7922
|
+
const mdPath = join12(this.skillsDir, `${sk.name}.md`);
|
|
7923
|
+
if (!existsSync14(mdPath)) continue;
|
|
7789
7924
|
out.push({
|
|
7790
7925
|
name: sk.name,
|
|
7791
7926
|
category: sk.category || "",
|
|
7792
|
-
content:
|
|
7927
|
+
content: readFileSync14(mdPath, "utf-8"),
|
|
7793
7928
|
keywords: sk.keywords || []
|
|
7794
7929
|
});
|
|
7795
7930
|
}
|
|
@@ -7870,9 +8005,9 @@ var BrainCurator = class {
|
|
|
7870
8005
|
// src/brain/contributor.ts
|
|
7871
8006
|
init_esm_shims();
|
|
7872
8007
|
init_asset_dir();
|
|
7873
|
-
import { dirname as
|
|
8008
|
+
import { dirname as dirname10 } from "path";
|
|
7874
8009
|
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
7875
|
-
var __dirname8 =
|
|
8010
|
+
var __dirname8 = dirname10(fileURLToPath9(import.meta.url));
|
|
7876
8011
|
|
|
7877
8012
|
// src/brain/index.ts
|
|
7878
8013
|
function checkBrainRules(store, opts) {
|
|
@@ -8225,7 +8360,7 @@ function markIntegrity(actionDetail) {
|
|
|
8225
8360
|
}
|
|
8226
8361
|
return { integrity: "medium", isLowSource: false };
|
|
8227
8362
|
}
|
|
8228
|
-
function initNode(sessionId, seq, actionType, actionDetail) {
|
|
8363
|
+
function initNode(sessionId, seq, actionType, actionDetail, timestamp) {
|
|
8229
8364
|
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
8230
8365
|
return {
|
|
8231
8366
|
sessionId,
|
|
@@ -8235,7 +8370,8 @@ function initNode(sessionId, seq, actionType, actionDetail) {
|
|
|
8235
8370
|
stage: markStage(actionDetail),
|
|
8236
8371
|
resources: extractResources(actionDetail),
|
|
8237
8372
|
integrity,
|
|
8238
|
-
isLowSource
|
|
8373
|
+
isLowSource,
|
|
8374
|
+
timestamp: timestamp || void 0
|
|
8239
8375
|
};
|
|
8240
8376
|
}
|
|
8241
8377
|
function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
@@ -8245,13 +8381,21 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
|
8245
8381
|
const details = [];
|
|
8246
8382
|
for (const a of actionHistory) {
|
|
8247
8383
|
const ad = String(a.actionDetail || "");
|
|
8248
|
-
if (ad) details.push({
|
|
8384
|
+
if (ad) details.push({
|
|
8385
|
+
actionType: String(a.actionType || ""),
|
|
8386
|
+
actionDetail: ad,
|
|
8387
|
+
calledAt: a.calledAt || void 0
|
|
8388
|
+
});
|
|
8249
8389
|
}
|
|
8250
8390
|
if (aNext) {
|
|
8251
|
-
details.push({
|
|
8391
|
+
details.push({
|
|
8392
|
+
actionType: String(aNext.actionType || ""),
|
|
8393
|
+
actionDetail: String(aNext.actionDetail || ""),
|
|
8394
|
+
calledAt: aNext.calledAt || void 0
|
|
8395
|
+
});
|
|
8252
8396
|
}
|
|
8253
8397
|
details.forEach((d, seq) => {
|
|
8254
|
-
const node = initNode(sessionId, seq, d.actionType, d.actionDetail);
|
|
8398
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt);
|
|
8255
8399
|
nodes.push(node);
|
|
8256
8400
|
if (node.stage) stageFlags.add(node.stage);
|
|
8257
8401
|
});
|
|
@@ -8277,7 +8421,8 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
8277
8421
|
last.sessionId,
|
|
8278
8422
|
last.nodes.length,
|
|
8279
8423
|
String(aNext.actionType || ""),
|
|
8280
|
-
String(aNext.actionDetail || "")
|
|
8424
|
+
String(aNext.actionDetail || ""),
|
|
8425
|
+
aNext.calledAt || void 0
|
|
8281
8426
|
));
|
|
8282
8427
|
if (last.nodes.length > 1) {
|
|
8283
8428
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
@@ -8325,6 +8470,27 @@ function allNodesFlat(mg) {
|
|
|
8325
8470
|
// src/engine/formal-engine/properties.ts
|
|
8326
8471
|
init_esm_shims();
|
|
8327
8472
|
init_rules_loader();
|
|
8473
|
+
function parseTs(ts) {
|
|
8474
|
+
if (!ts) return null;
|
|
8475
|
+
const t = Date.parse(String(ts).trim());
|
|
8476
|
+
return Number.isFinite(t) ? t : null;
|
|
8477
|
+
}
|
|
8478
|
+
function privescExfilWindowSec() {
|
|
8479
|
+
const raw = (process.env.AGENT_MOSS_PRIVESC_EXFIL_WINDOW_SEC || "").trim();
|
|
8480
|
+
if (!raw) return 1800;
|
|
8481
|
+
const n = parseInt(raw, 10);
|
|
8482
|
+
return Number.isFinite(n) ? Math.max(0, n) : 1800;
|
|
8483
|
+
}
|
|
8484
|
+
function privescInWindow(nodes, indexes, exfilIdx, windowSec) {
|
|
8485
|
+
const before = indexes.filter((i) => i < exfilIdx);
|
|
8486
|
+
if (windowSec <= 0) return before;
|
|
8487
|
+
const exfilTs = parseTs(nodes[exfilIdx].timestamp);
|
|
8488
|
+
if (exfilTs === null) return before;
|
|
8489
|
+
return before.filter((i) => {
|
|
8490
|
+
const ts = parseTs(nodes[i].timestamp);
|
|
8491
|
+
return ts === null || exfilTs - ts <= windowSec * 1e3;
|
|
8492
|
+
});
|
|
8493
|
+
}
|
|
8328
8494
|
var CROSS_SESSION_CHAINS = null;
|
|
8329
8495
|
function loadCrossSessionChains() {
|
|
8330
8496
|
if (CROSS_SESSION_CHAINS) return CROSS_SESSION_CHAINS;
|
|
@@ -8527,6 +8693,7 @@ function checkNeverExfilAfterPrivesc(graph) {
|
|
|
8527
8693
|
const nodes = allNodes(graph);
|
|
8528
8694
|
if (nodes.length < 2) return violations;
|
|
8529
8695
|
const witness = graph.witnessIdx;
|
|
8696
|
+
const windowSec = privescExfilWindowSec();
|
|
8530
8697
|
if (witness !== void 0) {
|
|
8531
8698
|
const evIdx = [];
|
|
8532
8699
|
nodes.forEach((n, i) => {
|
|
@@ -8534,15 +8701,17 @@ function checkNeverExfilAfterPrivesc(graph) {
|
|
|
8534
8701
|
});
|
|
8535
8702
|
if (evIdx.length === 0) return violations;
|
|
8536
8703
|
const firstEv = Math.min(...evIdx);
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
if (isPrivescNode(
|
|
8540
|
-
}
|
|
8541
|
-
|
|
8704
|
+
const privescIdx = [];
|
|
8705
|
+
nodes.forEach((n, i) => {
|
|
8706
|
+
if (isPrivescNode(n)) privescIdx.push(i);
|
|
8707
|
+
});
|
|
8708
|
+
const candidates = privescInWindow(nodes, privescIdx, firstEv, windowSec);
|
|
8709
|
+
if (candidates.length > 0) {
|
|
8710
|
+
const pre = nodes[candidates[candidates.length - 1]];
|
|
8542
8711
|
const post = nodes[firstEv];
|
|
8543
8712
|
return [{
|
|
8544
8713
|
propertyId: "no-exfil-after-privesc",
|
|
8545
|
-
reason: "\u63D0\u6743\u540E\u51FA\u73B0\u5916\u4F20\uFF1A\u63D0\u6743(\u524D) \u2192 \u5916\u4F20(\u540E)\uFF0C\u8FDD\u53CD \u25A1(PRIVESC\u2192\
|
|
8714
|
+
reason: "\u63D0\u6743\u540E\u51FA\u73B0\u5916\u4F20\uFF1A\u63D0\u6743(\u524D) \u2192 \u5916\u4F20(\u540E)\uFF0C\u8FDD\u53CD \u25A1(PRIVESC\u2192\u25C7EXFIL) \u7A97\u53E3\u7EA6\u675F",
|
|
8546
8715
|
riskLevel: "critical",
|
|
8547
8716
|
path: [
|
|
8548
8717
|
{ sessionId: pre.sessionId, seq: pre.seq, detail: pre.actionDetail.slice(0, 60) },
|
|
@@ -8555,18 +8724,18 @@ function checkNeverExfilAfterPrivesc(graph) {
|
|
|
8555
8724
|
for (let i = 0; i < nodes.length; i++) {
|
|
8556
8725
|
if (!isPrivescNode(nodes[i])) continue;
|
|
8557
8726
|
for (let j = i + 1; j < nodes.length; j++) {
|
|
8558
|
-
if (isExfilNode(nodes[j]))
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
]
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8727
|
+
if (!isExfilNode(nodes[j])) continue;
|
|
8728
|
+
if (privescInWindow(nodes, [i], j, windowSec).length === 0) continue;
|
|
8729
|
+
violations.push({
|
|
8730
|
+
propertyId: "no-exfil-after-privesc",
|
|
8731
|
+
reason: "\u63D0\u6743\u540E\u51FA\u73B0\u5916\u4F20\uFF1A\u63D0\u6743(\u524D) \u2192 \u5916\u4F20(\u540E)\uFF0C\u8FDD\u53CD \u25A1(PRIVESC\u2192\u25C7EXFIL) \u7A97\u53E3\u7EA6\u675F",
|
|
8732
|
+
riskLevel: "critical",
|
|
8733
|
+
path: [
|
|
8734
|
+
{ sessionId: nodes[i].sessionId, seq: nodes[i].seq, detail: nodes[i].actionDetail.slice(0, 60) },
|
|
8735
|
+
{ sessionId: nodes[j].sessionId, seq: nodes[j].seq, detail: nodes[j].actionDetail.slice(0, 60) }
|
|
8736
|
+
]
|
|
8737
|
+
});
|
|
8738
|
+
return violations;
|
|
8570
8739
|
}
|
|
8571
8740
|
}
|
|
8572
8741
|
return violations;
|
|
@@ -8733,6 +8902,11 @@ function checkCrossSessionReachability(graph) {
|
|
|
8733
8902
|
}
|
|
8734
8903
|
return violations;
|
|
8735
8904
|
}
|
|
8905
|
+
var DATA_SOURCE_READ_RE = /\b(?:cat|head|tail|less|more|sed|awk|grep|strings|base64|xxd|od|dd)\b|\b(?:open|read_text|read_bytes)\s*\(/i;
|
|
8906
|
+
function isDataSourceNode(n) {
|
|
8907
|
+
if (n.stage === "CRED" || n.isLowSource) return true;
|
|
8908
|
+
return DATA_SOURCE_READ_RE.test(n.actionDetail);
|
|
8909
|
+
}
|
|
8736
8910
|
function checkSensitiveDataAggregation(graph) {
|
|
8737
8911
|
const violations = [];
|
|
8738
8912
|
const nodes = allNodes(graph);
|
|
@@ -8752,6 +8926,7 @@ function checkSensitiveDataAggregation(graph) {
|
|
|
8752
8926
|
for (const r of n.resources) {
|
|
8753
8927
|
for (const j of resIndex.get(r) || []) {
|
|
8754
8928
|
if (j === exfilIdx) continue;
|
|
8929
|
+
if (!isDataSourceNode(nodes[j])) continue;
|
|
8755
8930
|
srcs.add(`${nodes[j].sessionId}#${nodes[j].seq}`);
|
|
8756
8931
|
}
|
|
8757
8932
|
}
|