agentsafe-cli 0.1.1 → 0.3.1

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/README.md CHANGED
@@ -1,36 +1,207 @@
1
- # AgentSafe
1
+ # AgentSafe-CLI
2
2
 
3
- AgentSafe 是一个面向 AI 编程 Agent 使用场景的开源项目安装前安全体检 CLI。它只做静态扫描,不执行目标项目代码,默认在本地输出中文 Markdown 和 JSON 风险报告。
3
+ AgentSafe 是一个面向 AI 编程 Agent 使用场景的开源项目安装前安全体检 CLI。它在本地做静态扫描,不执行目标项目代码,默认不调用任何网络 API,并输出中文 Markdown、HTML 和 JSON 风险报告。
4
4
 
5
- ## 开发运行
5
+ 适用场景:
6
6
 
7
- ```powershell
8
- pnpm install
7
+ - 你准备把 GitHub/Gitee 项目交给 Cursor、Cline、Roo Code、Copilot、Codex 等 Agent 跑起来。
8
+ - 你想先确认 README、安装脚本、`package.json` 生命周期、Dockerfile、CI 配置里有没有高风险行为。
9
+ - 你希望生成一段可以直接贴给 AI Agent 的安全执行提示词,约束它不要盲目运行危险命令。
10
+
11
+ ## 当前版本
12
+
13
+ 当前源码版本:`0.3.1`
14
+
15
+ 已完成的升级点:
16
+
17
+ - `0.1.2`:同步 CLI/package 版本号,修正 README 调试脚本路径说明,明确 lockfile 当前只做文件收集和基础规则扫描,暂未做依赖信誉深度分析。
18
+ - `0.2.0`:新增 README 命令提取和 package scripts 执行链推断,可展示 `README -> npm install -> postinstall -> 脚本文件风险`。
19
+ - `0.2.1`:新增 `.agentsaferc.json` 配置,支持可信域名、忽略规则、忽略路径和严重度覆盖。
20
+ - `0.3.0`:新增 `report.html`,便于本地浏览、分享和给团队成员阅读。
21
+ - `0.3.1`:修复 HTML 报告中 Agent 执行提示词的字体颜色显示问题(改为易读的浅底黑字)。
22
+
23
+ ## 快速使用
24
+
25
+ 免安装运行:
26
+
27
+ ```bash
28
+ npx agentsafe-cli scan "/path/to/local/project" -o agentsafe-report
29
+ ```
30
+
31
+ 扫描远程 Git 仓库:
32
+
33
+ ```bash
34
+ npx agentsafe-cli scan "https://github.com/octocat/Spoon-Knife.git" -o agentsafe-report
35
+ ```
36
+
37
+ 全局安装:
38
+
39
+ ```bash
40
+ npm install -g agentsafe-cli
41
+ agentsafe scan "/path/to/local/project" -o agentsafe-report
42
+ ```
43
+
44
+ 扫描完成后会生成:
45
+
46
+ - `report.md`:中文 Markdown 风险报告。
47
+ - `report.html`:本地 HTML 可视化报告。
48
+ - `report.json`:结构化结果,适合接入 CI/CD 或其他工具。
49
+
50
+ ## CLI 参数
51
+
52
+ ```bash
53
+ agentsafe scan <本地目录或 Git URL> [options]
54
+ ```
55
+
56
+ 常用参数:
57
+
58
+ - `-o, --out-dir <dir>`:报告输出目录,默认 `agentsafe-report`。
59
+ - `-c, --config <path>`:指定 `.agentsaferc.json` 配置文件。
60
+ - `--allow-domain <domain...>`:加入可信域名白名单,可传多个;会和配置文件中的 `allowDomains` 合并。
61
+ - `--git-binary <path>`:手动指定 Git 可执行文件路径。
62
+
63
+ 退出码:
64
+
65
+ - `0`:未发现 high 或 block 风险。
66
+ - `1`:发现 high 风险。
67
+ - `2`:发现 block 阻断风险。
68
+
69
+ ## Agent 执行链推断
70
+
71
+ 从 `0.2.0` 开始,AgentSafe 不只展示单条规则命中,还会推断 AI Agent 可能执行的安装路径。
72
+
73
+ 例如 README 中存在:
74
+
75
+ ```bash
76
+ npm install
77
+ npm run dev
78
+ ```
79
+
80
+ 而 `package.json` 中存在:
81
+
82
+ ```json
83
+ {
84
+ "scripts": {
85
+ "postinstall": "bash install.sh",
86
+ "dev": "bash install.sh"
87
+ }
88
+ }
89
+ ```
90
+
91
+ 如果 `install.sh` 又命中读取 `.env`、`~/.ssh` 或外联上传规则,报告会展示类似链路:
92
+
93
+ ```text
94
+ README 安装命令 -> package.json scripts.postinstall -> install.sh -> 风险命中
95
+ README 运行命令 -> package.json scripts.dev -> install.sh -> 风险命中
96
+ ```
97
+
98
+ 同时报告会给出更安全的替代命令,例如:
99
+
100
+ ```bash
101
+ npm install --ignore-scripts
102
+ pnpm install --ignore-scripts
103
+ yarn install --ignore-scripts
104
+ ```
105
+
106
+ ## 配置文件
107
+
108
+ 你可以在被扫描项目根目录创建 `.agentsaferc.json`,也可以通过 `--config` 指定配置路径。
109
+
110
+ 示例:
111
+
112
+ ```json
113
+ {
114
+ "allowDomains": [
115
+ "registry.npmjs.org",
116
+ "*.mycorp.example"
117
+ ],
118
+ "ignoreRules": [
119
+ "github-action-unpinned"
120
+ ],
121
+ "ignorePaths": [
122
+ "docs/**",
123
+ "examples/legacy/**"
124
+ ],
125
+ "severityOverrides": {
126
+ "dockerfile-remote-add": "low"
127
+ }
128
+ }
129
+ ```
130
+
131
+ 字段说明:
132
+
133
+ - `allowDomains`:可信域名白名单。用于降低已知内网、私有 registry、公司服务域名的外联误报。
134
+ - `ignoreRules`:忽略指定规则 ID。
135
+ - `ignorePaths`:忽略指定文件路径,支持 glob,例如 `docs/**`。
136
+ - `severityOverrides`:覆盖规则严重度,适合团队内部策略调优。
137
+
138
+ 也可以使用仓库里的示例文件 `.agentsaferc.example.json` 作为模板。
139
+
140
+ ## HTML 报告
141
+
142
+ 从 `0.3.0` 开始,输出目录会额外生成 `report.html`。HTML 报告包含:
143
+
144
+ - 风险分和风险数量概览。
145
+ - 阻断/高风险明细。
146
+ - Agent 执行链推断。
147
+ - 建议替代命令。
148
+ - Agent 安全执行提示词。
149
+ - 生效配置摘要。
150
+
151
+ HTML 报告仍然是本地生成,不上传源码。
152
+
153
+ ## Lockfile 说明
154
+
155
+ 当前版本会收集并扫描 `package-lock.json`、`pnpm-lock.yaml`、`yarn.lock` 等 lockfile 中的基础文本风险,但暂未做深度依赖信誉分析,例如:
156
+
157
+ - npm 包下载量和发布时间。
158
+ - typosquatting 包名相似度。
159
+ - 维护者变更。
160
+ - 包版本近期异常发布。
161
+ - 第三方 registry 信誉。
162
+
163
+ 这类能力计划以显式开关形式加入,例如未来的 `--online-reputation`,默认仍保持离线扫描和隐私优先。
164
+
165
+ ## 本地开发
166
+
167
+ 安装依赖:
168
+
169
+ ```bash
170
+ pnpm install --ignore-scripts
171
+ ```
172
+
173
+ 运行测试:
174
+
175
+ ```bash
9
176
  pnpm test
177
+ ```
178
+
179
+ 构建:
180
+
181
+ ```bash
10
182
  pnpm build
11
- pnpm dev -- scan . -o agentsafe-report
12
183
  ```
13
184
 
14
- 如果当前终端没有 Node/pnpm,可以在 Codex 桌面环境中使用自带运行时:
185
+ 扫描内置风险样例:
15
186
 
16
- ```powershell
17
- & 'C:\Users\95365\.cache\codex-runtimes\codex-primary-runtime\dependencies\bin\pnpm.cmd' install
18
- & 'C:\Users\95365\.cache\codex-runtimes\codex-primary-runtime\dependencies\bin\pnpm.cmd' test
187
+ ```bash
188
+ pnpm scan:sample
19
189
  ```
20
190
 
21
- ## CLI
191
+ 调试脚本:
22
192
 
23
193
  ```powershell
24
- agentsafe scan <本地目录或 Git URL> -o agentsafe-report
194
+ powershell -ExecutionPolicy Bypass -File .\run-debug.ps1 -Mode all
195
+ powershell -ExecutionPolicy Bypass -File .\run-debug.ps1 -Mode scan-custom -Target "E:\your-project"
25
196
  ```
26
197
 
27
- 常用参数:
198
+ ## 防御边界
28
199
 
29
- - `-o, --out-dir <dir>`:报告输出目录,默认 `agentsafe-report`
30
- - `--allow-domain <domain...>`:把公司内网、私有 registry 等域名加入网络风险白名单
31
- - `--git-binary <path>`:指定 Git 可执行文件路径
200
+ AgentSafe 是防御性静态扫描工具,不是杀毒软件,也不会主动利用漏洞。它的目标是在用户把项目交给 AI Agent 自动运行前,提前发现高风险安装路径和可疑脚本行为。
32
201
 
33
- 输出文件:
202
+ 默认行为:
34
203
 
35
- - `report.md`:中文风险报告
36
- - `report.json`:结构化扫描结果
204
+ - 不执行目标项目代码。
205
+ - 不上传用户源码。
206
+ - 不绕过平台安全机制。
207
+ - 不对第三方项目直接定性为恶意,只报告“高风险行为”“阻断级风险”“需人工确认”。
@@ -0,0 +1,3 @@
1
+ import type { CollectedFile } from "./files.js";
2
+ import type { ExecutionChain, Finding } from "./types.js";
3
+ export declare function buildExecutionChains(files: CollectedFile[], findings: Finding[]): ExecutionChain[];
@@ -0,0 +1,275 @@
1
+ import path from "node:path";
2
+ import { severityRank } from "./config.js";
3
+ const lifecycleScripts = ["preinstall", "install", "postinstall", "prepare"];
4
+ export function buildExecutionChains(files, findings) {
5
+ const readmeCommands = files
6
+ .filter((file) => isReadme(file.relativePath))
7
+ .flatMap((file) => extractReadmeCommands(file.relativePath, file.content));
8
+ const packageScripts = files
9
+ .filter((file) => file.relativePath.endsWith("package.json"))
10
+ .flatMap((file) => extractPackageScripts(file.relativePath, file.content));
11
+ const filePaths = new Set(files.map((file) => file.relativePath));
12
+ const chains = [];
13
+ for (const command of readmeCommands) {
14
+ if (isPackageInstallCommand(command.command)) {
15
+ chains.push(...buildInstallChains({
16
+ command,
17
+ packageScripts,
18
+ findings,
19
+ filePaths
20
+ }));
21
+ continue;
22
+ }
23
+ const scriptName = extractPackageRunScriptName(command.command);
24
+ if (scriptName) {
25
+ chains.push(...buildRunScriptChains({
26
+ command,
27
+ scriptName,
28
+ packageScripts,
29
+ findings,
30
+ filePaths
31
+ }));
32
+ }
33
+ }
34
+ return dedupeChains(chains).sort((a, b) => {
35
+ const severityDelta = severityRank[b.risk] - severityRank[a.risk];
36
+ return severityDelta !== 0 ? severityDelta : a.title.localeCompare(b.title);
37
+ });
38
+ }
39
+ function buildInstallChains(input) {
40
+ const lifecycle = input.packageScripts.filter((script) => lifecycleScripts.includes(script.name));
41
+ if (!lifecycle.length) {
42
+ return [];
43
+ }
44
+ return lifecycle.map((script) => buildScriptChain({
45
+ idPrefix: "install",
46
+ title: `README 安装命令可能触发 ${script.name}`,
47
+ summary: `README 中的 ${input.command.command} 可能在安装阶段触发 package.json 的 ${script.name} 脚本。`,
48
+ command: input.command,
49
+ script,
50
+ findings: input.findings,
51
+ filePaths: input.filePaths,
52
+ safeCommand: safeInstallCommand(input.command.command),
53
+ recommendation: "先使用忽略生命周期脚本的安装命令,再人工审阅 package scripts 和关联脚本文件。"
54
+ }));
55
+ }
56
+ function buildRunScriptChains(input) {
57
+ return input.packageScripts
58
+ .filter((script) => script.name === input.scriptName)
59
+ .map((script) => buildScriptChain({
60
+ idPrefix: "run-script",
61
+ title: `README 命令会运行 npm script: ${script.name}`,
62
+ summary: `README 中的 ${input.command.command} 会进入 package.json 的 ${script.name} 脚本。`,
63
+ command: input.command,
64
+ script,
65
+ findings: input.findings,
66
+ filePaths: input.filePaths,
67
+ recommendation: "运行前先展开 npm script 的真实命令,并确认关联脚本没有读取凭据或外联上传。"
68
+ }));
69
+ }
70
+ function buildScriptChain(input) {
71
+ const nodes = [
72
+ {
73
+ kind: "readme-command",
74
+ label: "README 安装/运行命令",
75
+ filePath: input.command.filePath,
76
+ line: input.command.line,
77
+ command: input.command.command
78
+ },
79
+ {
80
+ kind: "package-script",
81
+ label: `package.json scripts.${input.script.name}`,
82
+ filePath: input.script.packagePath,
83
+ line: input.script.line,
84
+ command: input.script.command
85
+ }
86
+ ];
87
+ const scriptFiles = extractReferencedScriptFiles(input.script.command, input.script.packagePath, input.filePaths);
88
+ for (const scriptFile of scriptFiles) {
89
+ nodes.push({
90
+ kind: "script-file",
91
+ label: "关联脚本文件",
92
+ filePath: scriptFile,
93
+ line: 1
94
+ });
95
+ }
96
+ const chainFindings = input.findings.filter((finding) => {
97
+ if (finding.filePath === input.script.packagePath && Math.abs(finding.line - input.script.line) <= 1) {
98
+ return true;
99
+ }
100
+ return scriptFiles.includes(finding.filePath);
101
+ });
102
+ for (const finding of chainFindings.slice(0, 6)) {
103
+ nodes.push({
104
+ kind: "finding",
105
+ label: finding.title,
106
+ filePath: finding.filePath,
107
+ line: finding.line,
108
+ command: finding.snippet
109
+ });
110
+ }
111
+ return {
112
+ id: `${input.idPrefix}:${input.command.filePath}:${input.command.line}:${input.script.packagePath}:${input.script.name}`,
113
+ title: input.title,
114
+ risk: maxSeverity(chainFindings, input.script.name),
115
+ summary: input.summary,
116
+ nodes,
117
+ findings: chainFindings,
118
+ safeCommand: input.safeCommand,
119
+ recommendation: input.recommendation
120
+ };
121
+ }
122
+ function extractReadmeCommands(filePath, content) {
123
+ const lines = content.split(/\r?\n/);
124
+ const commands = [];
125
+ let inCodeBlock = false;
126
+ let codeFenceLanguage = "";
127
+ for (const [index, rawLine] of lines.entries()) {
128
+ const line = rawLine.trim();
129
+ const fence = /^```([A-Za-z0-9_-]*)/.exec(line);
130
+ if (fence) {
131
+ inCodeBlock = !inCodeBlock;
132
+ codeFenceLanguage = inCodeBlock ? fence[1].toLowerCase() : "";
133
+ continue;
134
+ }
135
+ if (!line || line.startsWith("#")) {
136
+ continue;
137
+ }
138
+ const command = normalizePromptPrefix(line);
139
+ if (inCodeBlock && isCommandLike(command, codeFenceLanguage)) {
140
+ commands.push({
141
+ filePath,
142
+ line: index + 1,
143
+ command
144
+ });
145
+ continue;
146
+ }
147
+ if (!inCodeBlock && /`[^`]*(npm|pnpm|yarn|bun|pip|docker)[^`]*`/.test(line)) {
148
+ const inlineCommands = [...line.matchAll(/`([^`]+)`/g)].map((match) => normalizePromptPrefix(match[1]));
149
+ for (const inlineCommand of inlineCommands) {
150
+ if (isCommandLike(inlineCommand, "")) {
151
+ commands.push({
152
+ filePath,
153
+ line: index + 1,
154
+ command: inlineCommand
155
+ });
156
+ }
157
+ }
158
+ }
159
+ }
160
+ return commands;
161
+ }
162
+ function extractPackageScripts(filePath, content) {
163
+ let parsed;
164
+ try {
165
+ parsed = JSON.parse(content);
166
+ }
167
+ catch {
168
+ return [];
169
+ }
170
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
171
+ return [];
172
+ }
173
+ const scripts = parsed.scripts;
174
+ if (!scripts || typeof scripts !== "object" || Array.isArray(scripts)) {
175
+ return [];
176
+ }
177
+ return Object.entries(scripts)
178
+ .filter((entry) => typeof entry[1] === "string")
179
+ .map(([name, command]) => ({
180
+ packagePath: filePath,
181
+ name,
182
+ command,
183
+ line: findJsonKeyLine(content, name)
184
+ }));
185
+ }
186
+ function isReadme(filePath) {
187
+ return path.basename(filePath).toLowerCase().startsWith("readme");
188
+ }
189
+ function normalizePromptPrefix(line) {
190
+ return line.replace(/^[$>]\s+/, "").trim();
191
+ }
192
+ function isCommandLike(command, language) {
193
+ if (language && !["bash", "shell", "sh", "zsh", "powershell", "ps1", "text", ""].includes(language)) {
194
+ return false;
195
+ }
196
+ return /^(npm|pnpm|yarn|bun|npx|pip|python|docker|docker-compose)\b/.test(command);
197
+ }
198
+ function isPackageInstallCommand(command) {
199
+ return /^(npm|pnpm)\s+(install|i)(\s|$)/.test(command) || /^yarn\s+(install)?(\s|$)/.test(command) || /^bun\s+install(\s|$)/.test(command);
200
+ }
201
+ function extractPackageRunScriptName(command) {
202
+ const npmMatch = /^(npm|pnpm)\s+run\s+([A-Za-z0-9:_-]+)/.exec(command);
203
+ if (npmMatch) {
204
+ return npmMatch[2];
205
+ }
206
+ const yarnMatch = /^yarn\s+([A-Za-z0-9:_-]+)/.exec(command);
207
+ if (yarnMatch && yarnMatch[1] !== "install") {
208
+ return yarnMatch[1];
209
+ }
210
+ return undefined;
211
+ }
212
+ function extractReferencedScriptFiles(command, packagePath, filePaths) {
213
+ const packageDir = path.posix.dirname(packagePath);
214
+ const candidates = [
215
+ ...command.matchAll(/\b(?:bash|sh|zsh|source|\.)\s+([^\s;&|]+\.sh)\b/g),
216
+ ...command.matchAll(/\bnode\s+([^\s;&|]+\.js)\b/g),
217
+ ...command.matchAll(/\bpython(?:3)?\s+([^\s;&|]+\.py)\b/g)
218
+ ].map((match) => normalizeRelativeScriptPath(packageDir, match[1]));
219
+ return [...new Set(candidates.filter((candidate) => filePaths.has(candidate)))];
220
+ }
221
+ function normalizeRelativeScriptPath(packageDir, scriptPath) {
222
+ const cleanPath = scriptPath.replace(/^['"]|['"]$/g, "");
223
+ if (packageDir === ".") {
224
+ return cleanPath.replace(/\\/g, "/").replace(/^\.\//, "");
225
+ }
226
+ return path.posix.normalize(path.posix.join(packageDir, cleanPath)).replace(/^\.\//, "");
227
+ }
228
+ function findJsonKeyLine(content, key) {
229
+ const lines = content.split(/\r?\n/);
230
+ const keyPattern = new RegExp(`"${escapeRegExp(key)}"\\s*:`);
231
+ for (const [index, line] of lines.entries()) {
232
+ if (keyPattern.test(line)) {
233
+ return index + 1;
234
+ }
235
+ }
236
+ return 1;
237
+ }
238
+ function safeInstallCommand(command) {
239
+ if (/^pnpm\s+/.test(command)) {
240
+ return "pnpm install --ignore-scripts";
241
+ }
242
+ if (/^yarn\s+/.test(command)) {
243
+ return "yarn install --ignore-scripts";
244
+ }
245
+ if (/^bun\s+/.test(command)) {
246
+ return "bun install --ignore-scripts";
247
+ }
248
+ if (/^npm\s+/.test(command)) {
249
+ return "npm install --ignore-scripts";
250
+ }
251
+ return undefined;
252
+ }
253
+ function maxSeverity(findings, scriptName) {
254
+ let max = lifecycleScripts.includes(scriptName) ? "high" : "medium";
255
+ for (const finding of findings) {
256
+ if (severityRank[finding.severity] > severityRank[max]) {
257
+ max = finding.severity;
258
+ }
259
+ }
260
+ return max;
261
+ }
262
+ function dedupeChains(chains) {
263
+ const seen = new Set();
264
+ return chains.filter((chain) => {
265
+ if (seen.has(chain.id)) {
266
+ return false;
267
+ }
268
+ seen.add(chain.id);
269
+ return true;
270
+ });
271
+ }
272
+ function escapeRegExp(value) {
273
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
274
+ }
275
+ //# sourceMappingURL=execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution.js","sourceRoot":"","sources":["../src/execution.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -6,16 +6,18 @@ import { writeReports } from "./report.js";
6
6
  import { loadRules } from "./rules.js";
7
7
  import { runScan } from "./scanner.js";
8
8
  import { resolveTarget } from "./target.js";
9
+ import { loadAgentSafeConfig } from "./user-config.js";
9
10
  const program = new Command();
10
11
  program
11
12
  .name("agentsafe")
12
13
  .description("AI Agent 开源项目安装前安全体检工具")
13
- .version("0.1.0");
14
+ .version("0.3.1");
14
15
  program
15
16
  .command("scan")
16
17
  .argument("<target>", "本地目录或 Git 仓库 URL")
17
18
  .option("-o, --out-dir <dir>", "报告输出目录", defaultReportDir)
18
19
  .option("--allow-domain <domain...>", "允许的可信域名,可传多个")
20
+ .option("-c, --config <path>", "指定 .agentsaferc.json 配置文件路径")
19
21
  .option("--git-binary <path>", "Git 可执行文件路径")
20
22
  .action(async (target, options) => {
21
23
  let cleanup;
@@ -23,17 +25,23 @@ program
23
25
  const resolved = await resolveTarget(target, options.gitBinary);
24
26
  cleanup = resolved.cleanup;
25
27
  const rules = await loadRules(defaultRulesPath);
28
+ const config = await loadAgentSafeConfig({
29
+ rootDir: resolved.rootDir,
30
+ configPath: options.config,
31
+ cliAllowDomains: options.allowDomain ?? []
32
+ });
26
33
  const report = await runScan({
27
34
  target: resolved.original,
28
35
  rootDir: resolved.rootDir,
29
36
  rules,
30
- allowDomains: options.allowDomain ?? []
37
+ config
31
38
  });
32
39
  const outDir = path.resolve(options.outDir);
33
40
  const paths = await writeReports(report, outDir);
34
41
  console.log(`AgentSafe 扫描完成:${report.summary.totalFindings} 个风险项,风险分 ${report.summary.score}/100`);
35
42
  console.log(`Markdown 报告:${paths.markdownPath}`);
36
43
  console.log(`JSON 报告:${paths.jsonPath}`);
44
+ console.log(`HTML 报告:${paths.htmlPath}`);
37
45
  if (report.summary.bySeverity.block > 0) {
38
46
  process.exitCode = 2;
39
47
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,wBAAwB,CAAC;KACrC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;KACxC,MAAM,CAAC,qBAAqB,EAAE,QAAQ,EAAE,gBAAgB,CAAC;KACzD,MAAM,CAAC,4BAA4B,EAAE,cAAc,CAAC;KACpD,MAAM,CAAC,qBAAqB,EAAE,aAAa,CAAC;KAC5C,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,OAI9B,EAAE,EAAE;IACH,IAAI,OAA0C,CAAC;IAE/C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAChE,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;QAE3B,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC;YAC3B,MAAM,EAAE,QAAQ,CAAC,QAAQ;YACzB,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,KAAK;YACL,YAAY,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE;SACxC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEjD,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,OAAO,CAAC,aAAa,aAAa,MAAM,CAAC,OAAO,CAAC,KAAK,MAAM,CAAC,CAAC;QACnG,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAEzC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;aAAM,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC9C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;QAC3C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,EAAE,CAAC;IACpB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/prompts.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import type { Finding } from "./types.js";
1
+ import type { ExecutionChain, Finding } from "./types.js";
2
2
  export declare function generateRecommendations(findings: Finding[]): string[];
3
- export declare function generateAgentPrompt(findings: Finding[]): string;
3
+ export declare function generateAgentPrompt(findings: Finding[], executionChains?: ExecutionChain[]): string;
package/dist/prompts.js CHANGED
@@ -18,7 +18,7 @@ export function generateRecommendations(findings) {
18
18
  recommendations.add("给 Agent 的执行权限应保持最小化:禁止自动运行 curl|bash、postinstall、未知脚本和需要 sudo 的命令。");
19
19
  return [...recommendations];
20
20
  }
21
- export function generateAgentPrompt(findings) {
21
+ export function generateAgentPrompt(findings, executionChains = []) {
22
22
  const blocked = findings.filter((finding) => finding.severity === "block");
23
23
  const high = findings.filter((finding) => finding.severity === "high");
24
24
  const riskyItems = [...blocked, ...high].slice(0, 8);
@@ -27,6 +27,12 @@ export function generateAgentPrompt(findings) {
27
27
  .map((finding) => `- ${finding.filePath}:${finding.line} 命中 ${finding.title},不要自动运行相关命令。`)
28
28
  .join("\n")
29
29
  : "- 暂未发现阻断/高风险命中,但仍需逐条解释命令后再请求用户确认。";
30
+ const chainText = executionChains.length
31
+ ? executionChains
32
+ .slice(0, 5)
33
+ .map((chain) => `- ${chain.title}:${chain.summary}`)
34
+ .join("\n")
35
+ : "- 暂未推断出 README 到 package scripts 的高风险执行链。";
30
36
  return [
31
37
  "你是 AI 编程 Agent。接下来处理该项目时必须遵守:",
32
38
  "",
@@ -36,7 +42,10 @@ export function generateAgentPrompt(findings) {
36
42
  "4. 如命令会访问 SSH、云厂商凭据、.env、浏览器目录或上传文件,必须停止并请求用户确认。",
37
43
  "",
38
44
  "本次扫描需特别注意:",
39
- riskyText
45
+ riskyText,
46
+ "",
47
+ "推断出的 Agent 执行链:",
48
+ chainText
40
49
  ].join("\n");
41
50
  }
42
51
  //# sourceMappingURL=prompts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,uBAAuB,CAAC,QAAmB;IACzD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE,CAAC;QAC7D,eAAe,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,mBAAmB,CAAC,EAAE,CAAC;QACzE,eAAe,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,sBAAsB,CAAC,EAAE,CAAC;QAC5E,eAAe,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,mBAAmB,CAAC,EAAE,CAAC;QACzE,eAAe,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrB,eAAe,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IAC9D,CAAC;IAED,eAAe,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;IAE1F,OAAO,CAAC,GAAG,eAAe,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAmB;IACrD,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC3E,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;IACvE,MAAM,UAAU,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM;QACjC,CAAC,CAAC,UAAU;aACT,GAAG,CACF,CAAC,OAAO,EAAE,EAAE,CACV,KAAK,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,OAAO,OAAO,CAAC,KAAK,cAAc,CAC1E;aACA,IAAI,CAAC,IAAI,CAAC;QACb,CAAC,CAAC,mCAAmC,CAAC;IAExC,OAAO;QACL,+BAA+B;QAC/B,EAAE;QACF,sFAAsF;QACtF,yCAAyC;QACzC,oCAAoC;QACpC,kDAAkD;QAClD,EAAE;QACF,YAAY;QACZ,SAAS;KACV,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,uBAAuB,CAAC,QAAmB;IACzD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAE1C,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE,CAAC;QAC7D,eAAe,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IAC/D,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,mBAAmB,CAAC,EAAE,CAAC;QACzE,eAAe,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,sBAAsB,CAAC,EAAE,CAAC;QAC5E,eAAe,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,mBAAmB,CAAC,EAAE,CAAC;QACzE,eAAe,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrB,eAAe,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;IAC9D,CAAC;IAED,eAAe,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;IAE1F,OAAO,CAAC,GAAG,eAAe,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAmB,EAAE,kBAAoC,EAAE;IAC7F,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC3E,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;IACvE,MAAM,UAAU,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM;QACjC,CAAC,CAAC,UAAU;aACT,GAAG,CACF,CAAC,OAAO,EAAE,EAAE,CACV,KAAK,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,OAAO,OAAO,CAAC,KAAK,cAAc,CAC1E;aACA,IAAI,CAAC,IAAI,CAAC;QACb,CAAC,CAAC,mCAAmC,CAAC;IACxC,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM;QACtC,CAAC,CAAC,eAAe;aACd,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;aACX,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;aACnD,IAAI,CAAC,IAAI,CAAC;QACb,CAAC,CAAC,2CAA2C,CAAC;IAEhD,OAAO;QACL,+BAA+B;QAC/B,EAAE;QACF,sFAAsF;QACtF,yCAAyC;QACzC,oCAAoC;QACpC,kDAAkD;QAClD,EAAE;QACF,YAAY;QACZ,SAAS;QACT,EAAE;QACF,iBAAiB;QACjB,SAAS;KACV,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
package/dist/report.d.ts CHANGED
@@ -2,5 +2,7 @@ import type { ScanReport } from "./types.js";
2
2
  export declare function writeReports(report: ScanReport, outDir: string): Promise<{
3
3
  markdownPath: string;
4
4
  jsonPath: string;
5
+ htmlPath: string;
5
6
  }>;
6
7
  export declare function renderMarkdownReport(report: ScanReport): string;
8
+ export declare function renderHtmlReport(report: ScanReport): string;
package/dist/report.js CHANGED
@@ -10,11 +10,14 @@ export async function writeReports(report, outDir) {
10
10
  await fs.mkdir(outDir, { recursive: true });
11
11
  const markdownPath = path.join(outDir, "report.md");
12
12
  const jsonPath = path.join(outDir, "report.json");
13
+ const htmlPath = path.join(outDir, "report.html");
13
14
  await fs.writeFile(markdownPath, renderMarkdownReport(report), "utf8");
14
15
  await fs.writeFile(jsonPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
16
+ await fs.writeFile(htmlPath, renderHtmlReport(report), "utf8");
15
17
  return {
16
18
  markdownPath,
17
- jsonPath
19
+ jsonPath,
20
+ htmlPath
18
21
  };
19
22
  }
20
23
  export function renderMarkdownReport(report) {
@@ -41,9 +44,18 @@ export function renderMarkdownReport(report) {
41
44
  "",
42
45
  ...report.recommendations.map((item) => `- ${item}`),
43
46
  "",
44
- "## 风险明细",
47
+ "## Agent 执行链推断",
45
48
  ""
46
49
  ];
50
+ if (!report.executionChains.length) {
51
+ lines.push("暂未推断出 README 到 package scripts 的执行链。", "");
52
+ }
53
+ else {
54
+ for (const chain of report.executionChains) {
55
+ lines.push(...renderExecutionChain(chain));
56
+ }
57
+ }
58
+ lines.push("## 风险明细", "");
47
59
  if (!report.findings.length) {
48
60
  lines.push("未发现内置规则命中的风险项。", "");
49
61
  }
@@ -52,9 +64,119 @@ export function renderMarkdownReport(report) {
52
64
  lines.push(...renderFinding(finding));
53
65
  }
54
66
  }
55
- lines.push("## 给 AI 编程 Agent 的安全执行提示", "", "```text", report.agentPrompt, "```", "", "## 已扫描文件", "", "| 文件 | 字节 | 命中数 |", "| --- | ---: | ---: |", ...report.scannedFiles.map((file) => `| ${file.path} | ${file.bytes} | ${file.matchedFindings} |`), "");
67
+ lines.push("## 给 AI 编程 Agent 的安全执行提示", "", "```text", report.agentPrompt, "```", "", "## 已扫描文件", "", "| 文件 | 字节 | 命中数 |", "| --- | ---: | ---: |", ...report.scannedFiles.map((file) => `| ${file.path} | ${file.bytes} | ${file.matchedFindings} |`), "", "## 生效配置", "", `- allowDomains:${report.config.allowDomains.length ? report.config.allowDomains.join(", ") : "无"}`, `- ignoreRules:${report.config.ignoreRules.length ? report.config.ignoreRules.join(", ") : "无"}`, `- ignorePaths:${report.config.ignorePaths.length ? report.config.ignorePaths.join(", ") : "无"}`, `- severityOverrides:${Object.keys(report.config.severityOverrides).length ? JSON.stringify(report.config.severityOverrides) : "无"}`, "");
56
68
  return lines.join("\n");
57
69
  }
70
+ export function renderHtmlReport(report) {
71
+ const findingRows = report.findings.length
72
+ ? report.findings.map((finding) => `
73
+ <article class="finding finding-${finding.severity}">
74
+ <div class="finding-head">
75
+ <span class="badge">${severityZh[finding.severity]}</span>
76
+ <h3>${escapeHtml(finding.title)}</h3>
77
+ </div>
78
+ <p class="meta">${escapeHtml(finding.filePath)}:${finding.line}:${finding.column} · ${escapeHtml(finding.ruleId)} · ${escapeHtml(finding.category)}</p>
79
+ <p>${escapeHtml(finding.explainZh)}</p>
80
+ <p class="advice">${escapeHtml(finding.safeFix)}</p>
81
+ <pre>${escapeHtml(finding.snippet)}</pre>
82
+ </article>`).join("\n")
83
+ : "<p>未发现内置规则命中的风险项。</p>";
84
+ const chainRows = report.executionChains.length
85
+ ? report.executionChains.map((chain) => `
86
+ <article class="chain chain-${chain.risk}">
87
+ <div class="finding-head">
88
+ <span class="badge">${severityZh[chain.risk]}</span>
89
+ <h3>${escapeHtml(chain.title)}</h3>
90
+ </div>
91
+ <p>${escapeHtml(chain.summary)}</p>
92
+ ${chain.safeCommand ? `<p class="safe-command">建议替代命令:<code>${escapeHtml(chain.safeCommand)}</code></p>` : ""}
93
+ <ol>
94
+ ${chain.nodes.map((node) => `<li><strong>${escapeHtml(node.label)}</strong> <span>${escapeHtml(node.filePath)}:${node.line}</span>${node.command ? `<pre>${escapeHtml(node.command)}</pre>` : ""}</li>`).join("\n")}
95
+ </ol>
96
+ <p class="advice">${escapeHtml(chain.recommendation)}</p>
97
+ </article>`).join("\n")
98
+ : "<p>暂未推断出 README 到 package scripts 的执行链。</p>";
99
+ return `<!doctype html>
100
+ <html lang="zh-CN">
101
+ <head>
102
+ <meta charset="utf-8">
103
+ <meta name="viewport" content="width=device-width, initial-scale=1">
104
+ <title>AgentSafe 风险报告</title>
105
+ <style>
106
+ :root { color-scheme: light; --text: #18212f; --muted: #5c6675; --line: #d9dee7; --bg: #f6f8fb; --panel: #ffffff; --block: #b42318; --high: #b54708; --medium: #175cd3; --low: #067647; }
107
+ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: var(--bg); color: var(--text); }
108
+ main { max-width: 1120px; margin: 0 auto; padding: 32px 20px 56px; }
109
+ header { border-bottom: 1px solid var(--line); padding-bottom: 20px; margin-bottom: 24px; }
110
+ h1 { margin: 0 0 12px; font-size: 32px; }
111
+ h2 { margin-top: 32px; font-size: 22px; }
112
+ h3 { margin: 0; font-size: 17px; }
113
+ .summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin: 20px 0; }
114
+ .metric, article, .prompt, .config { background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 16px; }
115
+ .metric strong { display: block; font-size: 28px; }
116
+ .muted, .meta { color: var(--muted); }
117
+ .finding, .chain { margin: 14px 0; }
118
+ .finding-head { display: flex; align-items: center; gap: 10px; }
119
+ .badge { color: #fff; border-radius: 999px; padding: 3px 9px; font-size: 12px; background: var(--medium); }
120
+ .finding-block .badge, .chain-block .badge { background: var(--block); }
121
+ .finding-high .badge, .chain-high .badge { background: var(--high); }
122
+ .finding-low .badge, .chain-low .badge { background: var(--low); }
123
+ pre { overflow: auto; white-space: pre-wrap; word-break: break-word; background: #111827; color: #f9fafb; border-radius: 6px; padding: 12px; }
124
+ .prompt { background: #f3f4f6; color: var(--text); font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace; }
125
+ code { background: #eef2f7; padding: 2px 5px; border-radius: 4px; }
126
+ .advice, .safe-command { font-weight: 600; }
127
+ ol { padding-left: 22px; }
128
+ li { margin: 10px 0; }
129
+ </style>
130
+ </head>
131
+ <body>
132
+ <main>
133
+ <header>
134
+ <h1>AgentSafe 风险报告</h1>
135
+ <p class="muted">${escapeHtml(report.target)} · ${escapeHtml(report.scannedAt)}</p>
136
+ </header>
137
+ <section class="summary">
138
+ <div class="metric"><span>风险分</span><strong>${report.summary.score}/100</strong></div>
139
+ <div class="metric"><span>风险项</span><strong>${report.summary.totalFindings}</strong></div>
140
+ <div class="metric"><span>阻断</span><strong>${report.summary.bySeverity.block}</strong></div>
141
+ <div class="metric"><span>高风险</span><strong>${report.summary.bySeverity.high}</strong></div>
142
+ <div class="metric"><span>扫描文件</span><strong>${report.summary.scannedFiles}</strong></div>
143
+ </section>
144
+ <h2>建议</h2>
145
+ <ul>${report.recommendations.map((item) => `<li>${escapeHtml(item)}</li>`).join("")}</ul>
146
+ <h2>Agent 执行链推断</h2>
147
+ ${chainRows}
148
+ <h2>风险明细</h2>
149
+ ${findingRows}
150
+ <h2>给 AI 编程 Agent 的安全执行提示</h2>
151
+ <pre class="prompt">${escapeHtml(report.agentPrompt)}</pre>
152
+ <h2>生效配置</h2>
153
+ <div class="config">
154
+ <p>allowDomains:${escapeHtml(report.config.allowDomains.join(", ") || "无")}</p>
155
+ <p>ignoreRules:${escapeHtml(report.config.ignoreRules.join(", ") || "无")}</p>
156
+ <p>ignorePaths:${escapeHtml(report.config.ignorePaths.join(", ") || "无")}</p>
157
+ <p>severityOverrides:${escapeHtml(JSON.stringify(report.config.severityOverrides))}</p>
158
+ </div>
159
+ </main>
160
+ </body>
161
+ </html>`;
162
+ }
163
+ function renderExecutionChain(chain) {
164
+ const lines = [
165
+ `### ${severityZh[chain.risk]}:${chain.title}`,
166
+ "",
167
+ `- 摘要:${chain.summary}`,
168
+ `- 建议:${chain.recommendation}`
169
+ ];
170
+ if (chain.safeCommand) {
171
+ lines.push(`- 建议替代命令:\`${chain.safeCommand}\``);
172
+ }
173
+ lines.push("", "| 步骤 | 位置 | 命令/内容 |", "| --- | --- | --- |");
174
+ for (const node of chain.nodes) {
175
+ lines.push(`| ${node.label} | ${node.filePath}:${node.line} | ${escapeMarkdownTable(node.command ?? "")} |`);
176
+ }
177
+ lines.push("");
178
+ return lines;
179
+ }
58
180
  function renderFinding(finding) {
59
181
  return [
60
182
  `### ${severityZh[finding.severity]}:${finding.title}`,
@@ -71,4 +193,14 @@ function renderFinding(finding) {
71
193
  ""
72
194
  ];
73
195
  }
196
+ function escapeMarkdownTable(value) {
197
+ return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
198
+ }
199
+ function escapeHtml(value) {
200
+ return value
201
+ .replace(/&/g, "&amp;")
202
+ .replace(/</g, "&lt;")
203
+ .replace(/>/g, "&gt;")
204
+ .replace(/"/g, "&quot;");
205
+ }
74
206
  //# sourceMappingURL=report.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
package/dist/scanner.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import type { Rule, ScanReport } from "./types.js";
1
+ import type { AgentSafeConfig, Rule, ScanReport } from "./types.js";
2
2
  export interface RunScanInput {
3
3
  target: string;
4
4
  rootDir: string;
5
5
  rules: Rule[];
6
6
  allowDomains?: string[];
7
+ config?: AgentSafeConfig;
7
8
  }
8
9
  export declare function runScan(input: RunScanInput): Promise<ScanReport>;
package/dist/scanner.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import picomatch from "picomatch";
2
2
  import { severityRank, severityWeight } from "./config.js";
3
3
  import { allMatchedDomainsAllowed } from "./domain.js";
4
+ import { buildExecutionChains } from "./execution.js";
4
5
  import { collectFiles } from "./files.js";
5
6
  import { generateAgentPrompt, generateRecommendations } from "./prompts.js";
6
7
  import { scanStructuredFile } from "./structured.js";
8
+ import { defaultAgentSafeConfig } from "./user-config.js";
7
9
  const emptySeverityCounts = {
8
10
  low: 0,
9
11
  medium: 0,
@@ -11,11 +13,12 @@ const emptySeverityCounts = {
11
13
  block: 0
12
14
  };
13
15
  export async function runScan(input) {
14
- const files = await collectFiles(input.rootDir);
16
+ const config = mergeScanConfig(input.config, input.allowDomains ?? []);
17
+ const files = (await collectFiles(input.rootDir)).filter((file) => !matchesAnyGlob(file.relativePath, config.ignorePaths));
15
18
  const findings = [];
16
19
  const scannedFiles = [];
17
20
  for (const file of files) {
18
- const fileFindings = [
21
+ const fileFindings = applyFindingConfig([
19
22
  ...scanStructuredFile({
20
23
  relativePath: file.relativePath,
21
24
  content: file.content,
@@ -25,9 +28,9 @@ export async function runScan(input) {
25
28
  relativePath: file.relativePath,
26
29
  content: file.content,
27
30
  rules: input.rules,
28
- allowDomains: input.allowDomains ?? []
31
+ allowDomains: config.allowDomains
29
32
  })
30
- ];
33
+ ], config);
31
34
  findings.push(...fileFindings);
32
35
  scannedFiles.push({
33
36
  path: file.relativePath,
@@ -36,6 +39,7 @@ export async function runScan(input) {
36
39
  });
37
40
  }
38
41
  const sortedFindings = sortFindings(findings);
42
+ const executionChains = buildExecutionChains(files, sortedFindings);
39
43
  const summary = summarize(sortedFindings, scannedFiles.length);
40
44
  return {
41
45
  target: input.target,
@@ -43,9 +47,11 @@ export async function runScan(input) {
43
47
  scannedAt: new Date().toISOString(),
44
48
  summary,
45
49
  findings: sortedFindings,
50
+ executionChains,
46
51
  scannedFiles,
47
52
  recommendations: generateRecommendations(sortedFindings),
48
- agentPrompt: generateAgentPrompt(sortedFindings)
53
+ agentPrompt: generateAgentPrompt(sortedFindings, executionChains),
54
+ config
49
55
  };
50
56
  }
51
57
  function scanContent(input) {
@@ -91,6 +97,25 @@ function scanContent(input) {
91
97
  function matchesAnyGlob(filePath, globs) {
92
98
  return globs.some((glob) => picomatch.isMatch(filePath, glob, { dot: true }));
93
99
  }
100
+ function mergeScanConfig(config, cliAllowDomains) {
101
+ return {
102
+ allowDomains: [
103
+ ...(config?.allowDomains ?? defaultAgentSafeConfig.allowDomains),
104
+ ...cliAllowDomains
105
+ ],
106
+ ignoreRules: config?.ignoreRules ?? defaultAgentSafeConfig.ignoreRules,
107
+ ignorePaths: config?.ignorePaths ?? defaultAgentSafeConfig.ignorePaths,
108
+ severityOverrides: config?.severityOverrides ?? defaultAgentSafeConfig.severityOverrides
109
+ };
110
+ }
111
+ function applyFindingConfig(findings, config) {
112
+ return findings
113
+ .filter((finding) => !config.ignoreRules.includes(finding.ruleId))
114
+ .map((finding) => ({
115
+ ...finding,
116
+ severity: config.severityOverrides[finding.ruleId] ?? finding.severity
117
+ }));
118
+ }
94
119
  function compactSnippet(line) {
95
120
  const normalized = line.trim().replace(/\s+/g, " ");
96
121
  return normalized.length > 240 ? `${normalized.slice(0, 237)}...` : normalized;
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -33,6 +33,29 @@ export interface Finding {
33
33
  explainZh: string;
34
34
  safeFix: string;
35
35
  }
36
+ export interface AgentSafeConfig {
37
+ allowDomains: string[];
38
+ ignoreRules: string[];
39
+ ignorePaths: string[];
40
+ severityOverrides: Partial<Record<string, Severity>>;
41
+ }
42
+ export interface ExecutionNode {
43
+ kind: "readme-command" | "package-script" | "script-file" | "finding";
44
+ label: string;
45
+ filePath: string;
46
+ line: number;
47
+ command?: string;
48
+ }
49
+ export interface ExecutionChain {
50
+ id: string;
51
+ title: string;
52
+ risk: Severity;
53
+ summary: string;
54
+ nodes: ExecutionNode[];
55
+ findings: Finding[];
56
+ safeCommand?: string;
57
+ recommendation: string;
58
+ }
36
59
  export interface ScannedFile {
37
60
  path: string;
38
61
  bytes: number;
@@ -50,15 +73,18 @@ export interface ScanReport {
50
73
  scannedAt: string;
51
74
  summary: ScanSummary;
52
75
  findings: Finding[];
76
+ executionChains: ExecutionChain[];
53
77
  scannedFiles: ScannedFile[];
54
78
  agentPrompt: string;
55
79
  recommendations: string[];
80
+ config: AgentSafeConfig;
56
81
  }
57
82
  export interface ScanOptions {
58
83
  target: string;
59
84
  outDir?: string;
60
85
  allowDomains?: string[];
61
86
  gitBinary?: string;
87
+ configPath?: string;
62
88
  }
63
89
  export interface ResolvedTarget {
64
90
  original: string;
@@ -0,0 +1,7 @@
1
+ import type { AgentSafeConfig } from "./types.js";
2
+ export declare const defaultAgentSafeConfig: AgentSafeConfig;
3
+ export declare function loadAgentSafeConfig(input: {
4
+ rootDir: string;
5
+ configPath?: string;
6
+ cliAllowDomains?: string[];
7
+ }): Promise<AgentSafeConfig>;
@@ -0,0 +1,58 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ export const defaultAgentSafeConfig = {
4
+ allowDomains: [],
5
+ ignoreRules: [],
6
+ ignorePaths: [],
7
+ severityOverrides: {}
8
+ };
9
+ export async function loadAgentSafeConfig(input) {
10
+ const resolvedConfigPath = input.configPath
11
+ ? path.resolve(input.configPath)
12
+ : path.join(input.rootDir, ".agentsaferc.json");
13
+ const raw = await readConfigFile(resolvedConfigPath);
14
+ return {
15
+ allowDomains: uniqueValues([
16
+ ...defaultAgentSafeConfig.allowDomains,
17
+ ...(raw?.allowDomains ?? []),
18
+ ...(input.cliAllowDomains ?? [])
19
+ ]),
20
+ ignoreRules: uniqueValues([
21
+ ...defaultAgentSafeConfig.ignoreRules,
22
+ ...(raw?.ignoreRules ?? [])
23
+ ]),
24
+ ignorePaths: uniqueValues([
25
+ ...defaultAgentSafeConfig.ignorePaths,
26
+ ...(raw?.ignorePaths ?? [])
27
+ ]),
28
+ severityOverrides: {
29
+ ...defaultAgentSafeConfig.severityOverrides,
30
+ ...(raw?.severityOverrides ?? {})
31
+ }
32
+ };
33
+ }
34
+ async function readConfigFile(configPath) {
35
+ const content = await fs.readFile(configPath, "utf8").catch((error) => {
36
+ if (isNotFound(error)) {
37
+ return undefined;
38
+ }
39
+ throw error;
40
+ });
41
+ if (!content) {
42
+ return undefined;
43
+ }
44
+ try {
45
+ return JSON.parse(content);
46
+ }
47
+ catch (error) {
48
+ const message = error instanceof Error ? error.message : String(error);
49
+ throw new Error(`配置文件解析失败 ${configPath}: ${message}`);
50
+ }
51
+ }
52
+ function uniqueValues(values) {
53
+ return [...new Set(values.filter(Boolean))];
54
+ }
55
+ function isNotFound(error) {
56
+ return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
57
+ }
58
+ //# sourceMappingURL=user-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-config.js","sourceRoot":"","sources":["../src/user-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAU7B,MAAM,CAAC,MAAM,sBAAsB,GAAoB;IACrD,YAAY,EAAE,EAAE;IAChB,WAAW,EAAE,EAAE;IACf,WAAW,EAAE,EAAE;IACf,iBAAiB,EAAE,EAAE;CACtB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,KAIzC;IACC,MAAM,kBAAkB,GAAG,KAAK,CAAC,UAAU;QACzC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC;QAChC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,kBAAkB,CAAC,CAAC;IAErD,OAAO;QACL,YAAY,EAAE,YAAY,CAAC;YACzB,GAAG,sBAAsB,CAAC,YAAY;YACtC,GAAG,CAAC,GAAG,EAAE,YAAY,IAAI,EAAE,CAAC;YAC5B,GAAG,CAAC,KAAK,CAAC,eAAe,IAAI,EAAE,CAAC;SACjC,CAAC;QACF,WAAW,EAAE,YAAY,CAAC;YACxB,GAAG,sBAAsB,CAAC,WAAW;YACrC,GAAG,CAAC,GAAG,EAAE,WAAW,IAAI,EAAE,CAAC;SAC5B,CAAC;QACF,WAAW,EAAE,YAAY,CAAC;YACxB,GAAG,sBAAsB,CAAC,WAAW;YACrC,GAAG,CAAC,GAAG,EAAE,WAAW,IAAI,EAAE,CAAC;SAC5B,CAAC;QACF,iBAAiB,EAAE;YACjB,GAAG,sBAAsB,CAAC,iBAAiB;YAC3C,GAAG,CAAC,GAAG,EAAE,iBAAiB,IAAI,EAAE,CAAC;SAClC;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,UAAkB;IAC9C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC7E,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAuB,CAAC;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,YAAY,UAAU,KAAK,OAAO,EAAE,CAAC,CAAC;IACxD,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,MAAgB;IACpC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,OAAO,OAAO,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;AACnG,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentsafe-cli",
3
- "version": "0.1.1",
3
+ "version": "0.3.1",
4
4
  "description": "AgentSafe: AI Agent 开源项目安装前安全体检 CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,4 +42,4 @@
42
42
  "node": ">=20"
43
43
  },
44
44
  "packageManager": "pnpm@11.7.0"
45
- }
45
+ }