dsh-jev-guard 0.5.2 → 0.5.3
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/CHANGELOG.md +18 -0
- package/CHANGELOG.zh-CN.md +18 -0
- package/DEPLOY.md +3 -1
- package/DEPLOY.zh-CN.md +3 -1
- package/README.md +2 -1
- package/README.zh-CN.md +2 -1
- package/adapters/dsh/index.js +16 -0
- package/bin/guard.mjs +11 -5
- package/docs/AGENT-TASK-dsh.md +2 -9
- package/docs/AGENT-TASK-dsh.zh-CN.md +2 -9
- package/docs/DECISIONS.md +34 -3
- package/docs/DECISIONS.zh-CN.md +29 -3
- package/docs/DSH-INTEGRATION.md +7 -1
- package/docs/DSH-INTEGRATION.zh-CN.md +6 -1
- package/docs/MEASUREMENTS.md +23 -2
- package/docs/MEASUREMENTS.zh-CN.md +21 -2
- package/docs/VERIFICATION.md +5 -4
- package/docs/VERIFICATION.zh-CN.md +5 -4
- package/lib/gate.js +68 -4
- package/lib/i18n.js +14 -0
- package/lib/quota.js +71 -5
- package/package.json +2 -2
- package/tools/check-doc-pairs.mjs +1 -0
- package/tools/selftest-quota.mjs +164 -4
- package/tools/smoke-dsh-adapter.mjs +42 -1
- package/tools/smoke-dsh-pipeline.mjs +39 -7
|
@@ -7,11 +7,24 @@
|
|
|
7
7
|
* (pre-execute → guards → execute → post-execute → result),看最终给出的
|
|
8
8
|
* `ToolExecutionResult` 是不是我们要的拒绝/放行。
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* 运行方式:这个测试只依赖两件事,而它们必须**同时**成立
|
|
11
|
+
* ① 裸 `@deepseek-ai/*` 能解析 —— 注意 ESM 是按**文件自身所在目录**向上找 node_modules 的(不是
|
|
12
|
+
* cwd),所以在 pnpm 工作区检出里必须让本文件待在**包目录**里(如 `apps/cli`);
|
|
13
|
+
* ② `./packages/util/values/lib/index.js` 存在(第 6 项拿 DSH 自己的 `snapshotJsonValue` 校验
|
|
14
|
+
* notice 形状,那是 `Session.append` 之前的一步)—— 这一条按 **cwd** 算,只有检出**根**满足。
|
|
15
|
+
* 检出的两个目录各满足一条,所以做法是搭一个临时目录把两者接过来(2026-09-23 实测:6/6;带密钥 7/7):
|
|
11
16
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
17
|
+
* H=<DSH 检出>; T=/tmp/jev-guard-pipeline; rm -rf $T; mkdir -p $T/node_modules/@deepseek-ai
|
|
18
|
+
* for p in cordis dsh-tools dsh-session dsh-system-prompt; do
|
|
19
|
+
* ln -s $H/apps/cli/node_modules/@deepseek-ai/$p $T/node_modules/@deepseek-ai/$p; done
|
|
20
|
+
* ln -s $H/packages $T/packages
|
|
21
|
+
* cp <本文件> $T/ && cd $T && JEV_GUARD_ROOT=/mnt/t/jev-guard node smoke-dsh-pipeline.mjs
|
|
22
|
+
* # 加 TYPESAFE_API_KEY 则第 4 项会真的走一次联网判定(7/7)
|
|
23
|
+
*
|
|
24
|
+
* 三个**别照抄**的旧配方:从检出根直接跑会以 `ERR_MODULE_NOT_FOUND` 崩在下面的 import 上;
|
|
25
|
+
* 从 `packages/core/agent-loop` 跑则第 6 项会假报 FAIL(那个 cwd 下没有 `./packages/...`);
|
|
26
|
+
* 用绝对路径跑本文件(不复制)同样在 import 那一步就崩 —— 裸说明符不认 cwd。
|
|
27
|
+
* 测试自身不写真实 `~/.jev-guard/`:日志与降级状态都钉在临时目录里(与 `smoke-dsh-adapter` 同规矩)。
|
|
15
28
|
*
|
|
16
29
|
* @module jev-guard/tools/smoke-dsh-pipeline
|
|
17
30
|
*/
|
|
@@ -20,11 +33,17 @@ import { Context } from '@deepseek-ai/cordis'
|
|
|
20
33
|
import ToolRuntime, { defineContentToolFixture } from '@deepseek-ai/dsh-tools'
|
|
21
34
|
import SessionStore from '@deepseek-ai/dsh-session'
|
|
22
35
|
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
|
|
36
|
+
import { mkdtemp, rm } from 'node:fs/promises'
|
|
37
|
+
import { tmpdir } from 'node:os'
|
|
38
|
+
import { join } from 'node:path'
|
|
23
39
|
import { pathToFileURL } from 'node:url'
|
|
24
40
|
|
|
25
41
|
const ROOT = process.env.JEV_GUARD_ROOT ?? '/mnt/t/dsh-jev-guard'
|
|
26
42
|
const mod = await import(`${ROOT}/adapters/dsh/index.js`)
|
|
27
43
|
|
|
44
|
+
/** 审计日志与降级状态都落在这里 —— 跑测试不该改动本机真实的阀门状态。 */
|
|
45
|
+
const SANDBOX = await mkdtemp(join(tmpdir(), 'jev-guard-pipeline-'))
|
|
46
|
+
|
|
28
47
|
let failures = 0
|
|
29
48
|
let checks = 0
|
|
30
49
|
|
|
@@ -86,9 +105,11 @@ function expect(label, actual, wantError, needles = []) {
|
|
|
86
105
|
|
|
87
106
|
async function main() {
|
|
88
107
|
const hasKey = Boolean(process.env.TYPESAFE_API_KEY)
|
|
89
|
-
process.stdout.write(`DSH 工具管线集成测试 root=${ROOT} ${hasKey ? '(含联网)' : '(无密钥)'}\n\n`)
|
|
108
|
+
process.stdout.write(`DSH 工具管线集成测试 root=${ROOT} sandbox=${SANDBOX} ${hasKey ? '(含联网)' : '(无密钥)'}\n\n`)
|
|
90
109
|
|
|
91
|
-
|
|
110
|
+
// 日志/状态钉在临时目录:真实 `~/.jev-guard/` 不该因为跑一次测试而被写入(与 smoke-dsh-adapter 同规矩)。
|
|
111
|
+
const paths = { logPath: join(SANDBOX, 'guard.log'), degradedPath: join(SANDBOX, 'degraded.json') }
|
|
112
|
+
const ctx = await harness({ tools: ['bash'], inlineScripts: false, ...paths })
|
|
92
113
|
|
|
93
114
|
// 1. 只读命令:预筛放行 → 假工具真的被执行
|
|
94
115
|
expect('ls -la → 真的执行(管线走通)', await run(ctx, 'ls -la'), false, ['RAN: ls -la'])
|
|
@@ -115,7 +136,7 @@ async function main() {
|
|
|
115
136
|
}
|
|
116
137
|
|
|
117
138
|
// 5. 非目标工具不受影响
|
|
118
|
-
const ctx2 = await harness({ tools: ['read'], inlineScripts: false })
|
|
139
|
+
const ctx2 = await harness({ tools: ['read'], inlineScripts: false, ...paths })
|
|
119
140
|
expect('tools 不匹配 → 放行', await run(ctx2, 'ls -la'), false, ['RAN: ls -la'])
|
|
120
141
|
|
|
121
142
|
// 6. 会话内 notice 的形状:交给 DSH 自己的 JSON 快照校验(真实 Session.append 之前那一步)
|
|
@@ -139,6 +160,17 @@ async function main() {
|
|
|
139
160
|
if (!noticeOk) failures += 1
|
|
140
161
|
process.stdout.write(`${noticeOk ? 'ok ' : 'FAIL'} notice 通过 DSH 自己的 snapshotJsonValue(Session.append 之前那一步)\n ${noticeWhy}\n`)
|
|
141
162
|
|
|
163
|
+
// 收尾与 smoke-dsh-adapter 同规矩:先等审计队列落盘(record() 是 fire-and-forget,
|
|
164
|
+
// 不等它 process.exit 会丢尾部记录),再把整个临时目录删掉。
|
|
165
|
+
// 审计模块从 ROOT 动态导入 —— 本文件可能被复制到临时目录里运行,相对路径在那里是无效的。
|
|
166
|
+
try {
|
|
167
|
+
const audit = await import(`${ROOT}/lib/audit.js`)
|
|
168
|
+
await audit.flush()
|
|
169
|
+
} catch {
|
|
170
|
+
// 清理失败不该改变测试结论
|
|
171
|
+
}
|
|
172
|
+
await rm(SANDBOX, { recursive: true, force: true }).catch(() => {})
|
|
173
|
+
|
|
142
174
|
process.stdout.write(`\n${failures === 0 ? `全部通过(${checks} 组断言)` : `${failures} 组失败 / 共 ${checks} 组`}\n`)
|
|
143
175
|
process.exit(failures === 0 ? 0 : 1)
|
|
144
176
|
}
|