shellward 0.6.7 → 0.6.8
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 +2 -0
- package/dist/cli.js +54 -1
- package/package.json +1 -1
- package/src/cli.ts +56 -1
package/README.md
CHANGED
|
@@ -37,6 +37,8 @@ npx shellward scan
|
|
|
37
37
|
合规得分: 63/100 [C]
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
+
想在浏览器里看?`npx shellward scan --open`(扫完直接打开报告)或 `--serve`(本地 http://localhost 提供报告)——**数据全程不出本机**。
|
|
41
|
+
|
|
40
42
|
`--json` 供 CI · `--ci` 发现 critical 时让构建失败 · `--html report.html` 导出可打印成 PDF 的报告(备案/审计存档)· 也可作 [GitHub Action](#github-action-pr-compliance-gate) 接入 PR 门禁。
|
|
41
43
|
|
|
42
44
|
> 检测重点:**境外大模型端点与 SDK 依赖(数据出境——中国独有、英文工具没有的概念)**、硬编码密钥、文件中的中文 PII、`.env` 暴露。扫到境外模型(如 `openai` 依赖)时,**直接给出境内合规替代**(通义千问 / DeepSeek / Kimi / 智谱)及其 OpenAI 兼容 `base_url`——多数迁移只需改一个 `base_url`。
|
package/dist/cli.js
CHANGED
|
@@ -8,8 +8,11 @@
|
|
|
8
8
|
// npx shellward --help
|
|
9
9
|
//
|
|
10
10
|
// 设计目标:30 秒、零配置、出一张可截图的「你的项目」合规风险报告。
|
|
11
|
-
import { resolve } from 'path';
|
|
11
|
+
import { resolve, join } from 'path';
|
|
12
12
|
import { writeFileSync } from 'fs';
|
|
13
|
+
import { tmpdir } from 'os';
|
|
14
|
+
import { createServer } from 'http';
|
|
15
|
+
import { spawn } from 'child_process';
|
|
13
16
|
import { ShellWard } from './core/engine.js';
|
|
14
17
|
import { runProjectComplianceAudit } from './compliance/audit.js';
|
|
15
18
|
import { renderComplianceReport, renderProjectFindings } from './compliance/report.js';
|
|
@@ -41,6 +44,8 @@ function runScan(args) {
|
|
|
41
44
|
const ci = args.includes('--ci');
|
|
42
45
|
const outPath = flagValue(args, '--out');
|
|
43
46
|
const htmlPath = flagValue(args, '--html');
|
|
47
|
+
const open = args.includes('--open');
|
|
48
|
+
const serve = args.includes('--serve');
|
|
44
49
|
const dirArg = args.find(a => !a.startsWith('-'));
|
|
45
50
|
const root = resolve(dirArg || process.cwd());
|
|
46
51
|
// 用环境变量解析 locale;layers/mode 用默认(代表「采用 ShellWard 默认部署」的合规覆盖)
|
|
@@ -52,6 +57,37 @@ function runScan(args) {
|
|
|
52
57
|
const locale = resolveLocale(guard.config);
|
|
53
58
|
const zh = locale === 'zh';
|
|
54
59
|
const { report, scan } = runProjectComplianceAudit(guard.config, root);
|
|
60
|
+
// ===== 本地 web 视图(方便看;数据全程不出本机)=====
|
|
61
|
+
if (serve) {
|
|
62
|
+
const html = renderHtmlReport(report, scan, locale, { root });
|
|
63
|
+
const port = Number(flagValue(args, '--serve') || flagValue(args, '--port')) || 7777;
|
|
64
|
+
const server = createServer((_req, res) => {
|
|
65
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
66
|
+
res.end(html);
|
|
67
|
+
});
|
|
68
|
+
server.on('error', (e) => {
|
|
69
|
+
console.error(zh ? `无法启动本地服务: ${e?.message}` : `Failed to start server: ${e?.message}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
});
|
|
72
|
+
server.listen(port, '127.0.0.1', () => {
|
|
73
|
+
const url = `http://localhost:${port}`;
|
|
74
|
+
process.stdout.write(zh
|
|
75
|
+
? `🌐 本地合规报告: ${url} (得分 ${report.score}/100 [${report.grade}],Ctrl+C 退出;数据不出本机)\n`
|
|
76
|
+
: `🌐 Local compliance report: ${url} (score ${report.score}/100 [${report.grade}]; Ctrl+C to stop; nothing leaves your machine)\n`);
|
|
77
|
+
openBrowser(url);
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (open) {
|
|
82
|
+
const html = renderHtmlReport(report, scan, locale, { root });
|
|
83
|
+
const file = join(tmpdir(), `shellward-report-${report.score}-${report.grade}.html`);
|
|
84
|
+
writeFileSync(file, html, 'utf-8');
|
|
85
|
+
process.stdout.write(zh
|
|
86
|
+
? `🌐 已在浏览器打开合规报告: ${file} (得分 ${report.score}/100 [${report.grade}];数据不出本机)\n`
|
|
87
|
+
: `🌐 Opened compliance report in browser: ${file} (score ${report.score}/100 [${report.grade}])\n`);
|
|
88
|
+
openBrowser(file);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
55
91
|
if (json) {
|
|
56
92
|
process.stdout.write(JSON.stringify({
|
|
57
93
|
root,
|
|
@@ -108,6 +144,19 @@ function runScan(args) {
|
|
|
108
144
|
process.exit(1);
|
|
109
145
|
}
|
|
110
146
|
}
|
|
147
|
+
/** 跨平台在默认浏览器打开 URL 或本地文件(失败静默,不影响主流程) */
|
|
148
|
+
function openBrowser(target) {
|
|
149
|
+
const cmd = process.platform === 'darwin' ? 'open'
|
|
150
|
+
: process.platform === 'win32' ? 'cmd'
|
|
151
|
+
: 'xdg-open';
|
|
152
|
+
const cmdArgs = process.platform === 'win32' ? ['/c', 'start', '', target] : [target];
|
|
153
|
+
try {
|
|
154
|
+
const child = spawn(cmd, cmdArgs, { stdio: 'ignore', detached: true });
|
|
155
|
+
child.on('error', () => { });
|
|
156
|
+
child.unref();
|
|
157
|
+
}
|
|
158
|
+
catch { /* 打开失败不影响 */ }
|
|
159
|
+
}
|
|
111
160
|
/** 取 `--flag value` 或 `--flag=value` 的值 */
|
|
112
161
|
function flagValue(args, flag) {
|
|
113
162
|
const i = args.indexOf(flag);
|
|
@@ -127,6 +176,8 @@ Usage:
|
|
|
127
176
|
shellward scan --ci Exit non-zero if critical findings
|
|
128
177
|
shellward scan --out f Export the full report to a Markdown file
|
|
129
178
|
shellward scan --html f Export a self-contained HTML report (print to PDF)
|
|
179
|
+
shellward scan --open Scan and open the report in your browser (local)
|
|
180
|
+
shellward scan --serve Scan and serve the report at http://localhost (local)
|
|
130
181
|
shellward mcp Start MCP server (stdio)
|
|
131
182
|
shellward --help
|
|
132
183
|
|
|
@@ -142,6 +193,8 @@ PII in files, .env permissions. Maps to CSL / PIPL / MLPS / cross-border / label
|
|
|
142
193
|
shellward scan --ci 有 critical 发现时非零退出
|
|
143
194
|
shellward scan --out 文件 导出完整报告为 Markdown(合规存档)
|
|
144
195
|
shellward scan --html 文件 导出自包含 HTML 报告(浏览器可打印成 PDF)
|
|
196
|
+
shellward scan --open 扫描并在浏览器打开报告(本地,方便看)
|
|
197
|
+
shellward scan --serve 扫描并在 http://localhost 提供报告(本地服务)
|
|
145
198
|
shellward mcp 启动 MCP 服务器(stdio)
|
|
146
199
|
shellward --help
|
|
147
200
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shellward",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.8",
|
|
4
4
|
"mcpName": "io.github.jnMetaCode/shellward",
|
|
5
5
|
"description": "AI agent security & MCP security middleware — prompt injection detection, AI firewall, runtime guardrails & data-loss prevention for LLM tool calls. 8-layer defense against data exfiltration & dangerous commands. Zero dependencies. SDK + OpenClaw plugin. Supports LangChain, AutoGPT, Claude Code, Cursor, OpenAI Agents, Hermes Agent.",
|
|
6
6
|
"keywords": [
|
package/src/cli.ts
CHANGED
|
@@ -9,8 +9,11 @@
|
|
|
9
9
|
//
|
|
10
10
|
// 设计目标:30 秒、零配置、出一张可截图的「你的项目」合规风险报告。
|
|
11
11
|
|
|
12
|
-
import { resolve } from 'path'
|
|
12
|
+
import { resolve, join } from 'path'
|
|
13
13
|
import { writeFileSync } from 'fs'
|
|
14
|
+
import { tmpdir } from 'os'
|
|
15
|
+
import { createServer } from 'http'
|
|
16
|
+
import { spawn } from 'child_process'
|
|
14
17
|
import { ShellWard } from './core/engine.js'
|
|
15
18
|
import { runProjectComplianceAudit } from './compliance/audit.js'
|
|
16
19
|
import { renderComplianceReport, renderProjectFindings } from './compliance/report.js'
|
|
@@ -48,6 +51,8 @@ function runScan(args: string[]) {
|
|
|
48
51
|
const ci = args.includes('--ci')
|
|
49
52
|
const outPath = flagValue(args, '--out')
|
|
50
53
|
const htmlPath = flagValue(args, '--html')
|
|
54
|
+
const open = args.includes('--open')
|
|
55
|
+
const serve = args.includes('--serve')
|
|
51
56
|
const dirArg = args.find(a => !a.startsWith('-'))
|
|
52
57
|
const root = resolve(dirArg || process.cwd())
|
|
53
58
|
|
|
@@ -62,6 +67,39 @@ function runScan(args: string[]) {
|
|
|
62
67
|
|
|
63
68
|
const { report, scan } = runProjectComplianceAudit(guard.config, root)
|
|
64
69
|
|
|
70
|
+
// ===== 本地 web 视图(方便看;数据全程不出本机)=====
|
|
71
|
+
if (serve) {
|
|
72
|
+
const html = renderHtmlReport(report, scan, locale, { root })
|
|
73
|
+
const port = Number(flagValue(args, '--serve') || flagValue(args, '--port')) || 7777
|
|
74
|
+
const server = createServer((_req, res) => {
|
|
75
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
|
|
76
|
+
res.end(html)
|
|
77
|
+
})
|
|
78
|
+
server.on('error', (e: any) => {
|
|
79
|
+
console.error(zh ? `无法启动本地服务: ${e?.message}` : `Failed to start server: ${e?.message}`)
|
|
80
|
+
process.exit(1)
|
|
81
|
+
})
|
|
82
|
+
server.listen(port, '127.0.0.1', () => {
|
|
83
|
+
const url = `http://localhost:${port}`
|
|
84
|
+
process.stdout.write(zh
|
|
85
|
+
? `🌐 本地合规报告: ${url} (得分 ${report.score}/100 [${report.grade}],Ctrl+C 退出;数据不出本机)\n`
|
|
86
|
+
: `🌐 Local compliance report: ${url} (score ${report.score}/100 [${report.grade}]; Ctrl+C to stop; nothing leaves your machine)\n`)
|
|
87
|
+
openBrowser(url)
|
|
88
|
+
})
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (open) {
|
|
93
|
+
const html = renderHtmlReport(report, scan, locale, { root })
|
|
94
|
+
const file = join(tmpdir(), `shellward-report-${report.score}-${report.grade}.html`)
|
|
95
|
+
writeFileSync(file, html, 'utf-8')
|
|
96
|
+
process.stdout.write(zh
|
|
97
|
+
? `🌐 已在浏览器打开合规报告: ${file} (得分 ${report.score}/100 [${report.grade}];数据不出本机)\n`
|
|
98
|
+
: `🌐 Opened compliance report in browser: ${file} (score ${report.score}/100 [${report.grade}])\n`)
|
|
99
|
+
openBrowser(file)
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
65
103
|
if (json) {
|
|
66
104
|
process.stdout.write(JSON.stringify({
|
|
67
105
|
root,
|
|
@@ -117,6 +155,19 @@ function runScan(args: string[]) {
|
|
|
117
155
|
}
|
|
118
156
|
}
|
|
119
157
|
|
|
158
|
+
/** 跨平台在默认浏览器打开 URL 或本地文件(失败静默,不影响主流程) */
|
|
159
|
+
function openBrowser(target: string): void {
|
|
160
|
+
const cmd = process.platform === 'darwin' ? 'open'
|
|
161
|
+
: process.platform === 'win32' ? 'cmd'
|
|
162
|
+
: 'xdg-open'
|
|
163
|
+
const cmdArgs = process.platform === 'win32' ? ['/c', 'start', '', target] : [target]
|
|
164
|
+
try {
|
|
165
|
+
const child = spawn(cmd, cmdArgs, { stdio: 'ignore', detached: true })
|
|
166
|
+
child.on('error', () => {})
|
|
167
|
+
child.unref()
|
|
168
|
+
} catch { /* 打开失败不影响 */ }
|
|
169
|
+
}
|
|
170
|
+
|
|
120
171
|
/** 取 `--flag value` 或 `--flag=value` 的值 */
|
|
121
172
|
function flagValue(args: string[], flag: string): string | undefined {
|
|
122
173
|
const i = args.indexOf(flag)
|
|
@@ -136,6 +187,8 @@ Usage:
|
|
|
136
187
|
shellward scan --ci Exit non-zero if critical findings
|
|
137
188
|
shellward scan --out f Export the full report to a Markdown file
|
|
138
189
|
shellward scan --html f Export a self-contained HTML report (print to PDF)
|
|
190
|
+
shellward scan --open Scan and open the report in your browser (local)
|
|
191
|
+
shellward scan --serve Scan and serve the report at http://localhost (local)
|
|
139
192
|
shellward mcp Start MCP server (stdio)
|
|
140
193
|
shellward --help
|
|
141
194
|
|
|
@@ -150,6 +203,8 @@ PII in files, .env permissions. Maps to CSL / PIPL / MLPS / cross-border / label
|
|
|
150
203
|
shellward scan --ci 有 critical 发现时非零退出
|
|
151
204
|
shellward scan --out 文件 导出完整报告为 Markdown(合规存档)
|
|
152
205
|
shellward scan --html 文件 导出自包含 HTML 报告(浏览器可打印成 PDF)
|
|
206
|
+
shellward scan --open 扫描并在浏览器打开报告(本地,方便看)
|
|
207
|
+
shellward scan --serve 扫描并在 http://localhost 提供报告(本地服务)
|
|
153
208
|
shellward mcp 启动 MCP 服务器(stdio)
|
|
154
209
|
shellward --help
|
|
155
210
|
|