@lixiangzhong/dsh-shell-secrets 0.1.0 → 0.1.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 +153 -237
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,307 +1,223 @@
|
|
|
1
1
|
# @lixiangzhong/dsh-shell-secrets
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@lixiangzhong/dsh-shell-secrets)
|
|
4
|
+
[](./LICENSE)
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
> 这个插件**有意绕过** harness 的凭证 scrub。启用之后,匹配到的变量会进入**每一个**
|
|
9
|
-
> bash 子进程 —— 包括 `npm install` 的 postinstall、以及模型运行的任意第三方二进制。
|
|
10
|
-
> 只要模型执行 `env`,这些值就会出现在 tool result(也就是会话日志和模型上下文)里。
|
|
11
|
-
>
|
|
12
|
-
> 请在**受信 workspace + 受信会话**里使用;不要把值直接 `echo`/`env` 到会被记录的输出里
|
|
13
|
-
> (验证时用 `env | cut -d= -f1 | grep ...` 只列名字)。插件本身无法对输出脱敏。
|
|
6
|
+
一个 [dsh](https://www.npmjs.com/package/@deepseek-ai/dsh)(DeepSeek Harness)插件:把**启动 dsh 时环境里**
|
|
7
|
+
名字匹配 `KEY` / `PASSWORD` / `SECRET` / `TOKEN` 的变量,以**原始变量名**注入 bash 工具的子进程。
|
|
14
8
|
|
|
15
9
|
```bash
|
|
16
10
|
export GITHUB_TOKEN=ghp_xxx PGPASSWORD=secret
|
|
17
11
|
dsh web
|
|
18
|
-
# 之后模型通过 bash 工具执行:
|
|
19
|
-
# gh auth status # 直接读 $GITHUB_TOKEN,无需改写
|
|
20
|
-
# psql -h db -U app # 直接读 $PGPASSWORD
|
|
21
12
|
```
|
|
22
13
|
|
|
23
|
-
|
|
14
|
+
之后模型通过 bash 工具执行命令时,`gh`、`psql`、`aws`、`curl` 这类自己读环境变量的 CLI **无需改写**:
|
|
24
15
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
scrubbedParentEnv() // 剔除 /KEY|PASSWORD|SECRET|TOKEN/i 以及所有 DSH_*
|
|
29
|
-
childEnv(extra) = { ...scrubbedParentEnv(), ...extra } // extra 不再过滤
|
|
16
|
+
```bash
|
|
17
|
+
gh auth status # 直接读 $GITHUB_TOKEN
|
|
18
|
+
psql -h db -U app # 直接读 $PGPASSWORD
|
|
30
19
|
```
|
|
31
20
|
|
|
32
|
-
|
|
33
|
-
只能注册 `DSH_*` 键(命令里得写 `$DSH_GITHUB_TOKEN`),`gh`/`mysql`/`aws` 这类自己读
|
|
34
|
-
环境变量的 CLI 就用不上。本插件改为接管 `ctx.shell`,往文档化的
|
|
35
|
-
`ShellExecSpec.env`("merged after the credential scrub")里注入原始变量名。
|
|
21
|
+
---
|
|
36
22
|
|
|
37
|
-
##
|
|
23
|
+
## ⚠️ 安全须知
|
|
38
24
|
|
|
39
|
-
|
|
25
|
+
> 这个插件**有意绕过** dsh 的凭证隔离机制。启用之后,匹配到的变量会进入**每一个** bash 子进程 ——
|
|
26
|
+
> 包括 `npm install` 的 postinstall 脚本,以及模型运行的任意第三方二进制。
|
|
27
|
+
>
|
|
28
|
+
> 只要模型执行 `env`,这些值就会出现在工具结果里,也就是**会话日志与模型上下文**里。插件无法对
|
|
29
|
+
> 输出做脱敏,也无法撤回已经写进日志的值。
|
|
30
|
+
>
|
|
31
|
+
> 建议:
|
|
32
|
+
>
|
|
33
|
+
> - 只在**受信的 workspace 和会话**里使用;
|
|
34
|
+
> - 验证时只列变量名,不要打印值:`env | cut -d= -f1 | grep -E '_TOKEN$|PASSWORD$|_KEY$'`;
|
|
35
|
+
> - 一旦有值进了日志又不想留,**直接轮换该密钥**。
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
---
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
`dsh.profile.bundles` 层,不需要手改 profile 的任何 YAML:
|
|
39
|
+
## 为什么需要它
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
dsh plugin --profile web update @lixiangzhong/dsh-shell-secrets # 升级
|
|
41
|
+
dsh 在启动子进程前会做一次固定的凭证清理:名字匹配 `/KEY|PASSWORD|SECRET|TOKEN/i` 的变量、
|
|
42
|
+
以及所有 `DSH_*`,都不会传给 bash 子进程。因此即使用户在自己的 shell 里 `export GITHUB_TOKEN=...`,
|
|
43
|
+
模型执行的命令里也读不到它。
|
|
50
44
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
dsh plugin --profile web add file:./dsh-shell-secrets-0.1.0.tgz
|
|
45
|
+
dsh 官方提供的插件接缝 `ctx.shellEnv` 只能注册 `DSH_*` 前缀的变量,命令里得写成
|
|
46
|
+
`$DSH_GITHUB_TOKEN`,对 `gh`、`psql` 这类直接读 `GITHUB_TOKEN` / `PGPASSWORD` 的 CLI 没用。
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
本插件改为接管 shell 执行器,把同一批变量以**原始名字**放回子进程环境 —— 走的仍是 dsh
|
|
49
|
+
文档化的落点(`ShellExecSpec.env`,语义是"在凭证清理之后合并")。
|
|
57
50
|
|
|
58
|
-
|
|
59
|
-
dsh plugin --profile web remove @lixiangzhong/dsh-shell-secrets && \
|
|
60
|
-
dsh plugin --profile web add file:/Users/lxz/gopath/src/github.com/lixiangzhong/dsh-shell-secrets
|
|
51
|
+
## 安装
|
|
61
52
|
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
**环境要求**:已安装 `dsh` CLI(本插件在 dsh 进程内运行,Node 版本要求 ≥ 22);用 `dsh plugin`
|
|
54
|
+
管理插件时需要 `pnpm`(dsh 自身用 pnpm 管理 profile 依赖)。
|
|
64
55
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
- 从 npm 装的是**版本化的 registry 依赖**,`dsh plugin … update` 就能升级;本地 `file:` 目录
|
|
68
|
-
依赖没有版本概念,升级=remove + add(见下一条)。
|
|
69
|
-
- **本地安装必须用 `file:`,不能用 `link:`**。`link:` 会把包软链到源码目录,Node 按 realpath
|
|
70
|
-
解析 `@deepseek-ai/dsh-bash-sandbox` 时会从源码目录向上找而失败(实测 `MODULE_NOT_FOUND`);
|
|
71
|
-
`file:` 是真实目录(pnpm 硬链接),realpath 落在 `~/.dsh/profiles` 内,能解析到 harness
|
|
72
|
-
自己那份模块(实测 hoisted 与 `.pnpm` 两种布局都解析到 npx 安装目录)。
|
|
73
|
-
- 目录依赖是**硬链接**:原地修改源码会立刻反映到已安装副本;但编辑器"写临时文件再 rename"
|
|
74
|
-
的保存方式会换 inode 断链,所以**刷新请用上面的 remove + add**(实测 `pnpm update` 与
|
|
75
|
-
`pnpm install --force` 对目录依赖都会报 "Already up to date" 而不重新拷贝)。
|
|
76
|
-
- `bundle` 列表在 **dsh 启动时**读取,装/卸之后要重启 dsh 才生效。
|
|
77
|
-
- **pnpm 版本/store 必须与 profile 现有的 `node_modules` 匹配**。`dsh plugin` 只是转发给
|
|
78
|
-
PATH 上的 `pnpm`;如果 profile 的 `node_modules` 是用另一个大版本的 pnpm 装的,会直接失败:
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
ERR_PNPM_UNEXPECTED_STORE Unexpected store location
|
|
82
|
-
The dependencies at "~/.dsh/profiles/web/node_modules" are currently linked from the store at
|
|
83
|
-
"~/.dsh/Library/pnpm/store/v11"; pnpm now wants to use the store at ".../store/v10"
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
两条出路:把匹配的 pnpm 放到 PATH 前面(本机 store v11 ↔ `~/Library/pnpm/bin/pnpm` 11.8.0):
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
PATH="$HOME/Library/pnpm/bin:$PATH" dsh plugin --profile web add file:<此目录>
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
或者在 profile 目录里用当前的 pnpm 重建一次 `node_modules`(`cd ~/.dsh/profiles/web && pnpm install`)。
|
|
93
|
-
- 从 npm 装时,**pnpm 也要指对 registry**:本机全局 registry 是腾讯镜像(`npm_config_registry`
|
|
94
|
-
环境变量,优先级高于 `~/.npmrc`),刚发布的包在镜像上通常还没同步,会 `404`。给这条命令显式指定:
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
PATH="$HOME/Library/pnpm/bin:$PATH" dsh plugin --profile web add @lixiangzhong/dsh-shell-secrets \
|
|
98
|
-
--registry=https://registry.npmjs.org
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
(`dsh plugin` 会把参数原样转发给 pnpm,所以 pnpm 自己的 flag 也能直接写。)
|
|
102
|
-
- 包里的 `peerDependencies` 把 harness 包声明为**可选** peer:只为表达耦合关系,配合 profile
|
|
103
|
-
自带的 `autoInstallPeers: false`,pnpm 不会偷偷装第二份 harness 包(否则会出现两个 cordis /
|
|
104
|
-
两个 `Service` 实例,服务注册行为会错乱)。
|
|
105
|
-
- 装好后 `dsh.profile.bundles` 会变成 `['@deepseek-ai/dsh-base', '@deepseek-ai/dsh-web-app',
|
|
106
|
-
'dsh-shell-secrets']`,profile 的 `cordis.patch.yml` 应保持干净的 `[]`。
|
|
107
|
-
|
|
108
|
-
### 方式 B:deploy.mjs(拷贝 + 手工挂载,不依赖 pnpm)
|
|
109
|
-
|
|
110
|
-
适合不想让 pnpm 参与、或要装进多个 profile 的场景:
|
|
56
|
+
### 从 npm 安装(推荐)
|
|
111
57
|
|
|
112
58
|
```bash
|
|
113
|
-
|
|
114
|
-
node deploy.mjs --check # dsh --profile web --dump-config 校验挂载结果
|
|
115
|
-
node deploy.mjs --remove # 回滚:移除挂载行 + 删除插件目录
|
|
116
|
-
PROFILE=tui node deploy.mjs # 换 profile(默认 web)
|
|
59
|
+
dsh plugin --profile web add @lixiangzhong/dsh-shell-secrets
|
|
117
60
|
```
|
|
118
61
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
1. **拷贝**(不是软链)插件到 `~/.dsh/profiles/<profile>/plugins/dsh-shell-secrets/`。
|
|
122
|
-
必须是拷贝:`@deepseek-ai/dsh-bash-sandbox` 要从 `~/.dsh/profiles/node_modules`(指向
|
|
123
|
-
npx 安装目录的软链)解析到 harness **同一份模块实例**,软链会让 Node 按 realpath 从
|
|
124
|
-
工作区向上找包而失败,两个模块实例混用会出问题。
|
|
125
|
-
2. 在 `~/.dsh/profiles/<profile>/cordis.patch.yml` 的 `# >>> dsh-shell-secrets` /
|
|
126
|
-
`# <<< dsh-shell-secrets` 标记段内写入:
|
|
127
|
-
|
|
128
|
-
```yaml
|
|
129
|
-
- id: bash-sandbox
|
|
130
|
-
disabled: true # 不关掉官方行就会有两个 shell 服务,cordis 会大声报重复服务
|
|
131
|
-
- insert:
|
|
132
|
-
- id: shell-secrets
|
|
133
|
-
name: ./plugins/dsh-shell-secrets/lib/index.js
|
|
134
|
-
config:
|
|
135
|
-
timeoutMs: 60000 # 与官方 bash-sandbox 行同值
|
|
136
|
-
disabled: !!js process.platform === 'win32'
|
|
137
|
-
```
|
|
62
|
+
`dsh plugin` 会把包装进 `~/.dsh/profiles/<profile>/node_modules`,并把包名追加到
|
|
63
|
+
`dsh.profile.bundles` 层(因为包里声明了 `dsh.bundle.patch`),**不需要手改任何 YAML**。
|
|
138
64
|
|
|
139
|
-
|
|
65
|
+
`--profile` 按需替换(`web` / `tui` / `headless` …)。装好后**重启 dsh** 才会生效。
|
|
140
66
|
|
|
141
|
-
|
|
67
|
+
### 从源码或离线 tarball 安装
|
|
142
68
|
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
config:
|
|
150
|
-
timeoutMs: 60000
|
|
151
|
-
disabled: !!js process.platform === 'win32'
|
|
69
|
+
```bash
|
|
70
|
+
# 目录形式
|
|
71
|
+
dsh plugin --profile web add file:/path/to/dsh-shell-secrets
|
|
72
|
+
|
|
73
|
+
# tarball 形式(npm pack 产物)
|
|
74
|
+
dsh plugin --profile web add file:./lixiangzhong-dsh-shell-secrets-0.1.0.tgz
|
|
152
75
|
```
|
|
153
76
|
|
|
154
|
-
|
|
77
|
+
本地安装必须使用 `file:`(会落成真实目录),**不要用 `link:`**:软链会让 Node 按真实路径去
|
|
78
|
+
源码目录解析 dsh 自身的包,从而加载到**两份** harness 模块实例,服务注册会出问题。
|
|
155
79
|
|
|
156
|
-
|
|
157
|
-
| --- | --- | --- |
|
|
158
|
-
| `DSH_SHELL_SECRETS_PATTERN` | `KEY\|PASSWORD\|SECRET\|TOKEN`(i) | 自定义匹配正则(与 scrub 同语义是刻意的) |
|
|
159
|
-
| `DSH_SHELL_SECRETS_INCLUDE` | 空 | 逗号分隔 glob(`*`/`?`),**优先于** pattern,如 `*_TOKEN,AWS_*` |
|
|
160
|
-
| `DSH_SHELL_SECRETS_EXCLUDE` | 空 | 逗号分隔 glob 排除项,如 `MONKEY,KEYBOARD_*`(修子串误伤) |
|
|
161
|
-
| `DSH_SHELL_SECRETS_MAX_BYTES` | `8192` | 单值上限,超长跳过 |
|
|
162
|
-
| `DSH_SHELL_SECRETS_DISABLE` | 空 | 非空即停用注入(不卸载插件) |
|
|
80
|
+
### 升级与卸载
|
|
163
81
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
-
|
|
168
|
-
|
|
169
|
-
- 未命中的变量不会进日志(否则整个环境变量表都会变成噪音)。
|
|
82
|
+
```bash
|
|
83
|
+
dsh plugin --profile web update @lixiangzhong/dsh-shell-secrets # 升级到最新版
|
|
84
|
+
dsh plugin --profile web add @lixiangzhong/dsh-shell-secrets@0.1.0 # 或指定版本
|
|
85
|
+
dsh plugin --profile web remove @lixiangzhong/dsh-shell-secrets # 卸载(依赖 + bundle 层一起移除)
|
|
86
|
+
```
|
|
170
87
|
|
|
171
|
-
|
|
88
|
+
升级/卸载后同样**需要重启 dsh**。
|
|
172
89
|
|
|
173
|
-
|
|
90
|
+
### 生效时机
|
|
174
91
|
|
|
175
|
-
|
|
|
92
|
+
| 改动 | 生效方式 |
|
|
176
93
|
| --- | --- |
|
|
177
94
|
| 启动环境里的密钥变量 | 重启 dsh |
|
|
178
95
|
| `DSH_SHELL_SECRETS_*` 配置 | 重启 dsh |
|
|
179
|
-
|
|
|
180
|
-
|
|
96
|
+
| 插件版本(安装 / 升级 / 卸载) | 重启 dsh |
|
|
97
|
+
|
|
98
|
+
变量与配置都来自 **dsh 启动时的那个环境**,进程启动后不再变化。
|
|
99
|
+
|
|
100
|
+
## 配置
|
|
101
|
+
|
|
102
|
+
全部通过环境变量(在**启动 dsh 之前**设置):
|
|
103
|
+
|
|
104
|
+
| 变量 | 默认 | 说明 |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `DSH_SHELL_SECRETS_PATTERN` | `KEY\|PASSWORD\|SECRET\|TOKEN`(忽略大小写) | 自定义匹配正则。默认值与 dsh 自身的凭证清理规则一致,保证"被清掉的正好被补回来" |
|
|
107
|
+
| `DSH_SHELL_SECRETS_INCLUDE` | 空 | 逗号分隔的 glob(`*` / `?`),**优先于** `PATTERN`,例如 `*_TOKEN,AWS_*` |
|
|
108
|
+
| `DSH_SHELL_SECRETS_EXCLUDE` | 空 | 逗号分隔的 glob 排除项,例如 `MONKEY,KEYBOARD_*`(修掉子串误伤) |
|
|
109
|
+
| `DSH_SHELL_SECRETS_MAX_BYTES` | `8192` | 单个值的长度上限,超长跳过 |
|
|
110
|
+
| `DSH_SHELL_SECRETS_DISABLE` | 空 | 设为任意非空值即停用注入(不必卸载插件) |
|
|
111
|
+
|
|
112
|
+
规则细节:
|
|
181
113
|
|
|
182
|
-
|
|
114
|
+
- **`DSH_*` 永不注入**:保持 dsh "外部传入的 `DSH_*` 会被丢弃" 的既有约定,避免伪造框架自身的事实。
|
|
115
|
+
- 默认规则是**子串匹配**,因此 `MONKEY`、`KEYBOARD_LAYOUT` 这类名字也会命中 —— 用 `EXCLUDE` 排除即可。
|
|
116
|
+
- 空值、纯空白、超长值会被跳过;含换行的值仍会注入(保真优先),但会在装载日志里提示。
|
|
117
|
+
- 配置非法(正则写错、上限非正整数)会让**插件装载失败并报错**:宁可启动时报错,也不要静默不注入。
|
|
118
|
+
- 装载日志只打印**变量名与原因,绝不打印值**。
|
|
183
119
|
|
|
184
|
-
##
|
|
120
|
+
## 快速验证
|
|
185
121
|
|
|
186
122
|
```bash
|
|
187
|
-
#
|
|
188
|
-
export MY_TEST_PASSWORD=probe-ok
|
|
123
|
+
# 1) 在启动 dsh 的 shell 里设置一个测试变量,然后启动 dsh
|
|
124
|
+
export MY_TEST_PASSWORD=probe-ok
|
|
189
125
|
dsh web
|
|
190
126
|
```
|
|
191
127
|
|
|
192
|
-
之后在 bash 工具里:
|
|
193
|
-
|
|
194
128
|
```bash
|
|
195
|
-
|
|
196
|
-
#
|
|
129
|
+
# 2) 在 dsh 的 bash 工具里执行
|
|
130
|
+
echo "${MY_TEST_PASSWORD-unset}" # → probe-ok(原始名字可用)
|
|
131
|
+
|
|
132
|
+
# 只列名字,不要打印值
|
|
197
133
|
env | cut -d= -f1 | grep -E '_TOKEN$|PASSWORD$|SECRET$|_KEY$' | sort
|
|
198
|
-
env | cut -d= -f1 | grep '^DSH_'
|
|
134
|
+
env | cut -d= -f1 | grep '^DSH_' # 应只有 DSH_HOME / DSH_SHELL / DSH_SESSION_ID / DSH_WEB_URL
|
|
199
135
|
```
|
|
200
136
|
|
|
201
|
-
|
|
137
|
+
## 已知限制
|
|
202
138
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
139
|
+
- **只处理 bash 执行器**。使用持久 PTY shell 的场景(`minimal` agent preset、`sdk-minimal` profile)
|
|
140
|
+
走的是另一套 `terminals` 服务,不在覆盖范围内。
|
|
141
|
+
- **Windows 的 pwsh 未覆盖**(机制上可同构补充,尚未实现)。
|
|
142
|
+
- **只从启动环境读取**,不读文件;dsh 启动之后才 export 的变量不会生效。
|
|
143
|
+
- 变量集合在插件装载时确定一次,运行期不再刷新。
|
|
206
144
|
|
|
207
|
-
##
|
|
145
|
+
## 兼容性
|
|
208
146
|
|
|
209
|
-
|
|
210
|
-
Proxy,方法调用时 `this` 被替换成 shadow 代理,私有字段的 brand 校验会直接失败:
|
|
211
|
-
`Error: Receiver must be an instance of class SecretsBashExecutor`,且每个命令都失败。
|
|
212
|
-
官方服务一律用普通字段/方法,照做即可(本插件用 `this.secrets` + `mergeSecrets()`)。
|
|
213
|
-
- **挂载会在运行中的 dsh 上热生效**(web profile 是 `patchReload: live`)。如果新代码有致命
|
|
214
|
-
缺陷,这个会话的 bash 会立刻不可用;实测**把标记段删掉不足以卸载**已挂载的执行器
|
|
215
|
-
(服务行的卸载不会自动回滚),此时只能重启 dsh 恢复。所以:改执行器代码后建议先重启再挂载,
|
|
216
|
-
或者接受一次"重启即恢复"的窗口。
|
|
217
|
-
- 插件 JS 改动受 ESM 模块缓存影响,**同一个进程内换文件内容不会重新导入**(同 URL 命中缓存)。
|
|
147
|
+
本插件通过覆写 shell 执行器实现,因此绑定了 dsh 的内部接口:
|
|
218
148
|
|
|
219
|
-
|
|
149
|
+
- `@deepseek-ai/dsh-bash-sandbox` 导出的 `SandboxBashExecutor`,及其 `resolve` / `run` / `start` 方法;
|
|
150
|
+
- `ShellExecSpec.env` 的合并语义(在凭证清理之后合并);
|
|
151
|
+
- `ctx.shell` 服务名与 `bash-sandbox` 配置行。
|
|
220
152
|
|
|
221
|
-
|
|
153
|
+
为了尽早暴露不兼容,插件装载时会做一次自检,并在 dsh 日志里以 `error` 级别报告(**不阻断启动**,
|
|
154
|
+
以免误报导致 dsh 起不来):
|
|
222
155
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
| `SandboxBashExecutor` 是否仍是类,且带 `resolve/run/start` | `logger.error` 报警(不阻断启动) |
|
|
226
|
-
| 本插件解析到的 `@deepseek-ai/dsh-bash-sandbox` 与 harness 自己用的是否**同一份**(防止 profile 装出第二份 harness 包 → 两个 cordis 实例) | `logger.error` 报警(不阻断启动) |
|
|
156
|
+
- 基类是否仍提供 `resolve` / `run` / `start`;
|
|
157
|
+
- 插件解析到的 harness 包与 dsh 自身使用的是否是**同一份**(避免 profile 里装出第二份 harness 包)。
|
|
227
158
|
|
|
228
|
-
|
|
229
|
-
真正的致命问题(导出的不是类)会在 import 期直接炸。
|
|
230
|
-
|
|
231
|
-
已实测环境:
|
|
159
|
+
**已测试环境**
|
|
232
160
|
|
|
233
161
|
| dsh | Node | 平台 | 结果 |
|
|
234
|
-
|
|
235
|
-
| 0.1.5-rc.1
|
|
236
|
-
|
|
237
|
-
未覆盖:`minimal` 预设 / `sdk-minimal` profile 的持久 PTY shell;Windows pwsh。
|
|
162
|
+
| --- | --- | --- | --- |
|
|
163
|
+
| 0.1.5-rc.1 | 26.x | macOS | 前台与后台任务路径均注入成功,单元测试 13/13 |
|
|
238
164
|
|
|
239
|
-
dsh
|
|
165
|
+
其它版本/平台(尤其 Windows)尚未验证,欢迎反馈。dsh 升级后建议确认一次:
|
|
240
166
|
|
|
241
167
|
```bash
|
|
242
|
-
|
|
243
|
-
env | cut -d= -f1 | grep -E '_TOKEN$|PASSWORD$|SECRET$|_KEY$'
|
|
168
|
+
echo "${GITHUB_TOKEN-unset}" # 或任一敏感变量
|
|
169
|
+
env | cut -d= -f1 | grep -E '_TOKEN$|PASSWORD$|SECRET$|_KEY$' # 只列名字
|
|
244
170
|
```
|
|
245
171
|
|
|
246
|
-
##
|
|
172
|
+
## 常见问题
|
|
173
|
+
|
|
174
|
+
**装了但命令里读不到变量**
|
|
175
|
+
|
|
176
|
+
1. 变量是在**启动 dsh 的那个 shell** 里 export 的吗?(`.zshrc` 里 export 也可以,但要重启 dsh)
|
|
177
|
+
2. 装/改配置之后**重启 dsh** 了吗?
|
|
178
|
+
3. 用 `env | cut -d= -f1 | grep '^DSH_'` 之外的方式确认名字是否在注入清单里;装载日志会打印
|
|
179
|
+
`可注入密钥变量 N 个: ...`,若为 0 并伴随警告,说明启动环境里没有匹配项或 `PATTERN` 写错了。
|
|
180
|
+
|
|
181
|
+
**`dsh plugin add` 报 `ERR_PNPM_UNEXPECTED_STORE`**
|
|
182
|
+
|
|
183
|
+
profile 的 `node_modules` 与当前 `pnpm` 的大版本不一致(store 版本不同)。两种处理:使用与
|
|
184
|
+
profile 一致的 pnpm 版本重建一次(`cd ~/.dsh/profiles/<profile> && pnpm install`),或者统一
|
|
185
|
+
本机的 pnpm 版本。
|
|
186
|
+
|
|
187
|
+
**`dsh plugin add` 报 404 / 找不到包**
|
|
188
|
+
|
|
189
|
+
使用了企业或国内镜像,而镜像尚未同步新包。显式指定官方 registry:
|
|
247
190
|
|
|
248
191
|
```bash
|
|
249
|
-
|
|
250
|
-
npm publish # publishConfig 已固定 registry=npmjs、access=public
|
|
192
|
+
dsh plugin --profile web add @lixiangzhong/dsh-shell-secrets --registry=https://registry.npmjs.org
|
|
251
193
|
```
|
|
252
194
|
|
|
253
|
-
|
|
254
|
-
`npm login` 会打到镜像上并报 `E409 ... user registration disabled`。二选一:
|
|
255
|
-
|
|
256
|
-
```bash
|
|
257
|
-
# a) 用 npmjs 的 Access Token(推荐,尤其是账号开了 2FA 时)
|
|
258
|
-
# 在 https://www.npmjs.com/settings/<用户名>/tokens 生成 Granular Access Token(Read and write),
|
|
259
|
-
# 然后写进 ~/.npmrc(token 按 host 存,不受 registry 配置影响):
|
|
260
|
-
# //registry.npmjs.org/:_authToken=npm_xxxxxxxx
|
|
261
|
-
npm whoami --registry=https://registry.npmjs.org # 应输出你的用户名
|
|
262
|
-
|
|
263
|
-
# b) 或者直接登录 npmjs(npm 11 默认 web 登录;也可加 --auth-type=legacy 走用户名/密码/OTP)
|
|
264
|
-
npm login --registry=https://registry.npmjs.org
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
注意:环境变量 `npm_config_registry` 优先级高于 project/user `.npmrc`,所以"在项目里放
|
|
268
|
-
`.npmrc` 改 registry"在这里**无效**,只能用 CLI flag 或按 host 存的 token。
|
|
269
|
-
- `publishConfig.registry` 显式指向 `https://registry.npmjs.org`:本机 `npm_config_registry`
|
|
270
|
-
是只读镜像时,不加这个会发布失败。
|
|
271
|
-
- 发布前自查:`npm pack --dry-run`(应只含 `lib/`、`cordis.patch.yml`、`README.md`、`LICENSE`、
|
|
272
|
-
`package.json`)、`node --test`。
|
|
273
|
-
- 发布后把安装方式切到 registry 版本(pnpm 也要指 registry,见上文;镜像对新包有同步延迟):
|
|
274
|
-
|
|
275
|
-
```bash
|
|
276
|
-
PATH="$HOME/Library/pnpm/bin:$PATH" dsh plugin --profile web remove @lixiangzhong/dsh-shell-secrets
|
|
277
|
-
PATH="$HOME/Library/pnpm/bin:$PATH" dsh plugin --profile web add @lixiangzhong/dsh-shell-secrets \
|
|
278
|
-
--registry=https://registry.npmjs.org
|
|
279
|
-
npm view @lixiangzhong/dsh-shell-secrets version --registry=https://registry.npmjs.org
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
## 风险与边界
|
|
283
|
-
|
|
284
|
-
1. **这是有意绕过凭证 scrub**:匹配到的变量会进入**每一个** bash 子进程,包括
|
|
285
|
-
`npm install` 的 postinstall 与任意第三方二进制。只在受信 workspace 使用。
|
|
286
|
-
2. 值会随命令输出进入模型可见的 tool result(例如模型跑 `env`)。插件无法对输出脱敏。
|
|
287
|
-
3. 绑定了 harness 内部结构:`SandboxBashExecutor` 默认导出、`run`/`start` 语义、
|
|
288
|
-
`ShellExecSpec.env` 的"scrub 之后再合并"约定、`bash-sandbox` 行的存在,
|
|
289
|
-
以及 `ctx.shell` 服务名。dsh 升级后请重新跑一遍:
|
|
290
|
-
```bash
|
|
291
|
-
node --test && node deploy.mjs --check
|
|
292
|
-
```
|
|
293
|
-
并确认 `env` 里密钥仍在。
|
|
294
|
-
4. 若将来 harness 给 `ShellExecSpec` 增加了插件级 env 贡献接缝,应迁移过去并删掉
|
|
295
|
-
执行器替换(少一层内部耦合)。
|
|
296
|
-
5. **不覆盖**:`minimal` 预设 / `sdk-minimal` profile 的持久 PTY shell(走 `terminals`
|
|
297
|
-
服务,不经 `ctx.shell`);Windows 的 pwsh(`SandboxPwshExecutor` 同样已导出,可同构补充)。
|
|
298
|
-
|
|
299
|
-
## 目录
|
|
195
|
+
**误把值打印出来了**
|
|
300
196
|
|
|
197
|
+
无法撤回,请轮换该密钥;后续验证只列名字。
|
|
198
|
+
|
|
199
|
+
## 工作原理(简述)
|
|
200
|
+
|
|
201
|
+
1. 插件在装载时读一次启动环境,按配置挑出需要注入的变量(纯函数逻辑,见 `lib/secrets.js`);
|
|
202
|
+
2. 用 `SecretsBashExecutor` 接管 dsh 的 shell 执行器(覆写 `run` 与 `start` 两个方法);
|
|
203
|
+
3. 每次执行前把这些变量并入 `ShellExecSpec.env` —— 该字段由 dsh 在凭证清理**之后**合并,
|
|
204
|
+
因此原始变量名能进入子进程环境,同时不会覆盖 dsh 自己注入的 `DSH_*`(那些走另一个字段)。
|
|
205
|
+
|
|
206
|
+
插件只做"把已有变量放回去",不读文件、不访问网络、不做持久化。
|
|
207
|
+
|
|
208
|
+
## 开发
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
node --test # 单元测试(纯逻辑,零依赖)
|
|
212
|
+
npm pack --dry-run # 查看发布产物
|
|
301
213
|
```
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
214
|
+
|
|
215
|
+
本地联调:把仓库目录以 `file:` 方式装进 profile(见上文),改完代码后重新
|
|
216
|
+
`dsh plugin remove && add` 并重启 dsh。仓库内的 `deploy.mjs` 提供了不依赖 pnpm 的
|
|
217
|
+
备用部署方式(拷贝 + 手写挂载行),适用于无法使用 pnpm 的环境。
|
|
218
|
+
|
|
219
|
+
维护者笔记(本机环境、踩过的坑、发布流程)见 [`NOTES.md`](./NOTES.md)。
|
|
220
|
+
|
|
221
|
+
## 许可证
|
|
222
|
+
|
|
223
|
+
[MIT](./LICENSE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lixiangzhong/dsh-shell-secrets",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "DSH bundle: re-inject KEY/PASSWORD/SECRET/TOKEN variables from the launching environment into dsh bash subprocesses under their original names",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "lixiangzhong",
|