掩码录入密钥,代理只能调用不能读取
30.7/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/zerodegress/dsh-tui-secret.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 16 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 2 处,展示前 2 条)
- 读取密钥环境变量lib/types/index.js:70
return process.env.DSH_TUI_SECRET_DEBUG === '1'; - 发起网络请求lib/types/index.js:264
const outcome = await deps.channel.request({ ref, purpose, sessionId }, { signal: exec?.signal });
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
dsh-tui 插件,帮你把密钥藏好,不让智能体看到。
README
由 DeepSeek 最新模型翻译生成dsh-tui-secret
给 dsh-TUI 用的密钥录入插件:/secrets 打开一个全屏场景,掩码录入 → 引用列表 → 删除确认。值只经 DSH 自己的凭据接缝写入,插件本体不回显、不记日志、不进会话。
agent 也可以主动来要:request_credential 把一张掩码卡片推到你面前,值直接进 DSH 凭据存储,工具只拿到一个状态;use_credential 再用它跑一条命令,值只在那一个子进程
的环境里,返回的输出里凡是出现值的地方都换成 [credential]。
功能亮点
- 场景内掩码录入 — /secrets 打开一个全屏场景:按 a 新建引用,逐字掩码输入,Enter 写入。
- 逐字符回显 — 默认一个字符一个 •,传统密码框的样子;配 echo: none 则完全不回显,连长度都看不出来。
- agent 来要,你决定 — request_credential(ref, purpose) 弹卡片:名字、用途,以及四个选项:不允许 / 仅本次 / 仅本会话 / 到某个时刻。
- 只存好,不交出去 — 值只到 ctx.credentials;工具结果里只有状态,值不进会话。
展开完整文档(README 剩余 1 节)
dsh-tui-secret
给 dsh-TUI 用的密钥录入插件:/secrets 打开一个全屏场景,掩码录入 → 引用列表 → 删除确认。值只经 DSH 自己的凭据接缝写入,插件本体不回显、不记日志、不进会话。
agent 也可以主动来要:request_credential 把一张掩码卡片推到你面前,值直接进 DSH 凭据存储,工具只拿到一个状态;use_credential 再用它跑一条命令,值只在那一个子进程
的环境里,返回的输出里凡是出现值的地方都换成 [credential]。
功能亮点
- 场景内掩码录入 — /secrets 打开一个全屏场景:按 a 新建引用,逐字掩码输入,Enter 写入。
- 逐字符回显 — 默认一个字符一个 •,传统密码框的样子;配 echo: none 则完全不回显,连长度都看不出来。
- agent 来要,你决定 — request_credential(ref, purpose) 弹卡片:名字、用途,以及四个选项:不允许 / 仅本次 / 仅本会话 / 到某个时刻。
- 只存好,不交出去 — 值只到 ctx.credentials;工具结果里只有状态,值不进会话。
- 能用它,但拿不走它 — use_credential(ref, argv) 跑一条命令,值只在那一个子进程里,返回输出里出现的值一律换成 [credential]。
- 列表、删除与撤销,值永不上屏 — 列表出「是否已配置」+ agent 授权;d 删除(要 y)、 v 撤销单条授权、R 一键全撤。
- 声明有闸门 — npm test 会把 dsh-plugin.json 送进宿主自己的解析器与 TUI profile 校验器,manifest 一漂本地就红。
快速开始
支持目标:@deepseek-harness-tui/dsh-tui 0.16.x —— 其他 TUI 实现不在目标内。
在 shell 里:
dsh plugin --profile dsh-tui add github:zerodegress/dsh-tui-secret
已经在 TUI 里,就直接输入:
/plugin install https://github.com/zerodegress/dsh-tui-secret
或在 profile 的 cordis.patch.yml 里插一行(本包的 cordis.patch.yml 就是这一行,装包时由 bundle 机制自动应用):
- insert:
- id: dsh-tui-secret
name: dsh-tui-secret
config:
entryCommand: secrets # 可以改成别的命令名 echo: dots # 一个字符一个 •;none 则连长度都不显示
装完重启 TUI,输入 /secrets。
两个 agent 工具
两个工具在运行期注册(宿主没有工具类的 manifest 契约):
| 工具 | 参数 | 返回 |
| request_credential | ref、purpose | stored / cancelled / refused |
| use_credential | ref、argv[]、timeoutMs? | exitCode、stdout、stderr、redacted、timedOut、aborted、injectedAs |
use_credential 只跑一条命令。值进的是那个子进程的环境,变量名就是返回给你的 injectedAs;它不会进你或 agent 所在的 shell,执行器该有的沙箱策略照样生效。argv 是数组,每个元素由插件引号包裹 —— 模型喂不进裸 shell 文本;要用管道或变量,它得自己写 ["sh","-c","…"],由那层内层 shell 展开。
值由你在卡片上输入。两个工具都不接受模型给的值,也都不返回值。
快捷键
界面文案为英文(与上游默认一致),下方键位与说明为中文。
| 键 | 作用 |
| a | 新建引用:先输名字,再输值 |
| d | 删除光标所在的引用(再按 y 确认) |
| v | 撤销光标所在引用的 agent 授权 |
| R | 撤销全部 agent 授权(再按 y 确认;值保留) |
| ↑ ↓ | 移动选择 |
| Enter | 下一步 / 写入 |
| Esc | 返回上一层;卡片上取消;列表里关屏 |
agent 发起的卡片只有一屏:输入值(掩码)→ ↑/↓ 选授权范围 → Enter 落库并直接回到聊天, Esc 取消。数字算值的一部分,所以范围只能用方向键选。
名字规则与 DSH 一致:大写字母开头,只含 A-Z 0-9 _,≤64 字符;DEEPSEEK_ / DSH_ 开头归宿主所有,插件当场拒绝并说明理由(dsh-TUI 的 credentialRefGuard 在这些前缀上本来也会剔掉插件自己的 ref,这里提前给出可读的理由,而不是等宿主静默丢弃)。
工作原理
- 值只走 ctx.credentials.set(ref, value):不另开文件、不写 .credentials.yaml 本体、不复制值到别处。空值被拒(DSH 语义里空值等于未配置)。
- 值不进 React state:存 useRef,提交前先在本地丢弃,失败也不留在 state 里。
- 默认回显会暴露长度:一个字符一个 * 是常规观感,但屏幕上和回滚缓冲里都能数出长度。
在意长度就配 echo: none,那时字符和长度都不显示。
- 不注册 shellEnv 贡献者:$NAME 不进模型可执行的环境;唯一持有它的环境是 use_credential 为那一次调用拉起的子进程。
- 模型侧只有两个出口:request_credential(只回状态)与 use_credential(只回 exit code 与脱敏输出);除此之外不挂任何 model-facing 面。
- 四个 scope 全在 use_credential 入口判定:none 直接拒;once 用完即撤;session 比 session id(恢复会话后仍有效,不自动清);until 到期即撤。
- 日志与报错只记名字与错误 code:原始错误文本可能夹带值,一律不上屏、不落盘。
- 列表只出「是否已配置 / 来源 / 可写性」:来自 credentials.describe(),它按设计就不返回值。
这些断言不是靠读源码得出的:npm test 会把场景真正跑起来逐帧检查,详见「开发」。
- 接缝 —— ctx.tuiScenes(全屏场景)、ctx.commands(命令)、ctx.credentials (DSH 核心凭据服务)。场景面缺失时静默降级为「什么都没发生」,绝不拖垮 TUI 启动。
存储
| 内容 | 位置 | 权限 |
| 值(由 DSH 管) | <DSH_HOME>/.credentials.yaml | provider 保证 0600 |
| 引用记录(本插件) | $DSH_TUI_HOME/dsh-tui-secret/refs.json(默认 ~/.dsh-tui/…) | 文件 0600、目录 0700,原子写 |
| 审计(本插件) | 同目录 audit.jsonl(每行一条:名字、用途、时间、会话、exit code) | 文件 0600,追加写 |
名字清单为什么要自己存:ctx.credentials 的接口只有 resolve / describe / set / unset——没有 list(),所以「登记过哪些名字」无法反推。
这份 refs.json 记的是名字 + agent 授权(none/once/session/until、用途、时间、用了几次), 只有名字没有值,不是密钥库;文件损坏时读作空表,绝不覆盖原字节。v1 的旧格式
({version:1,names:[…]})会被自动读成 v2。
生态里插件私有数据的正规位置是 ctx.get('tuiPluginStorage', false) 的 storage.local (落 ~/.dsh-tui/plugin-storage/<namespace>.json),但它的 storage.local.read/write 默认拒绝、要写 ~/.dsh-tui/extension-grants.json 才通。v1 选择零授权,因此先落在上面那个插件私有目录。
已知限制
- 凭据库是明文:DSH 把值存成 <DSH_HOME>/.credentials.yaml(不加密)、权限 0600 ——只挡同机其他用户;沙箱只限写、不限读。所以有 bash 的 agent 直接 cat 就能拿到。
要挡住这条得靠 OS 级读限制、或把值挪出该用户可达范围(宿主/运维的活),不是本插件能给的。
- 脱敏只覆盖那一次执行的返回片段:值不会出现在我们产生的工具结果里,但命令可以把它写进文件/网络/日志再取回;被截断或变换过的副本也认不出。redacted: false 的含义是「返回的这段里没检测到」,不是「输出里从来没有过」。
- 闸门是我们自己的,不是存储的:别的插件按同名 credentials.resolve(ref) 直接就能拿到值——我们不假装拦得住;我们能保证的那句更窄也真实:凡走 agent 这条路的,都从这两个工具过。
- 短凭据会让输出难读:脱敏替换所有出现(安全侧的选择——只替换一次会漏值),而场景允许 2 字符的凭据,所以一条短值会把命令输出里所有同串都换掉。实现是单遍替换,所以值恰为 credential 时占位符不会被再替换一次。
- session 授权不会自己过期:恢复会话会新建 agent、session id 不变,所以没有任何信号能判断「这个会话不会回来了」。要收就自己按 v / R 撤,或删掉那个引用;会自失效的只有 once 与 until。
- 不做系统 keyring(keyring / DPAPI):按 DSH 的存储语义走。
- 不向上游提交补丁:dsh-TUI 的设置区块已经声明了 secret: { ref } 字段,等它的设置屏自己把掩码渲染补上,这个场景可以退化成纯列表管理。
开发
pnpm install # 首次:装构建依赖(typescript / @types/node / @deepseek-ai/cordis,仅构建用)
npm test # = npm run compile && node scripts/verify.mjs
源码是 src/ 里的 TypeScript;tsc 把它编译进 lib/types/,产物随仓库提交,宿主加载的就是它。改完 src/ 跑 npm run compile,把 lib/types/ 和源码放进同一个提交。
脚本覆盖三层加一道闸门:①–⑫ 场景(哨兵验证,含真 ink 渲染)、⑬–⑮ 引号与 shell 边界(跑真 /bin/sh)、㉑–㊶ 两个工具与权限表(注册、拒绝、四个 scope、审计、脱敏的两条诚实边界、撤销、降级、卡片来回、拒绝 note 的原因码、两个工具的返回值用宿主自己的校验器过一遍声明的 schema)、 ⑳ 插件声明 —— 用宿主自己的 @dsh-std/manifest 解析器与 TUI profile 校验器离线跑一遍, manifest 一漂当场就红。
排障:场景是第一次使用时才注册的(启动时不注册)—— dsh-TUI 只接受来自「已被 fiber 插桩记录」的激活的 tuiScenes 调用,而 apply 与 inject 回调都跑在别的 ambient 激活下。
/secrets 报「the secrets scene is not registered」时,括号里带短原因码 —— registration failed: (注册那一步抛了,日志里也有同一句,只记 code/name 不记原始文本)或 open failed: 。卡片总是 refused 时,用 DSH_TUI_SECRET_DEBUG=1 起 TUI —— request_credential 的 note 会附上具体原因(the host did not open the scene、the card was answered with refuse、the tool call was aborted…),里面永远没有值。默认不区分「人拒绝」与「卡片弹不出来」,以免失败原因变成可探测的侧信道。
- 场景那半实现一份最小 React hook runtime 与 ui kit 替身,把场景真正跑起来,按真人按键顺序驱动(a → 名字 → Enter → 值 → Enter),把每一帧渲染字符串、每一条日志、每一次对外调用记入记录,再用哨兵值 grep。其中 ⑫ 换成宿主自己的 React 19 与 ink,把场景渲进非 TTY 流逐帧 grep——元素符号、hook dispatcher、渲染路径都是真的。
- 两个工具用一个假宿主驱动(和场景用假 React 一个路子),引号那组则把拼出来的命令真的交给 /bin/sh 跑:恶意参数必须原样当数据,只有模型自己写的脚本才允许展开。
工具链:Node ^22.19 || >=24,ESM,无运行时依赖;@deepseek-ai/cordis 是可选 peer。三个
devDependencies 只服务构建与类型 —— 新克隆的仓库要先 pnpm install(联网)再 npm test。
未决的契约项集中记在 docs/plugin-design.md。
文档
- 设计 —— plugin-design.md · 文档索引
· dsh-TUI 插件指南
License
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
zerodegress/dsh-tui-secret
掩码录入密钥,代理只能调用不能读取
相关插件 · UI / 主题
破甲增强版JeffKeeping/dsh-purge-plus
dsh-purge 的非官方分支fork:适配 DeepSeek Harness 0.2.1-rc.2、破甲内核…
★ 387已汉化DeepSeek 客户端
71.9
无代码业务系统平台nocobase/nocobase
NocoBase 是什么
★ 24,804已汉化DSH
71.8
1Panel 服务器面板1Panel-dev/1Panel
全球 250 万+ 自托管用户共同喜爱。
★ 37,350已汉化DSH
71.5
工作状态行动态ccch1mneyyy/working-activity
作者:chimney@ccch1mneyyy。社区项目,非 DeepSeek 官方项目。
★ 664已汉化DSH
71.2
多模型配置管家farion1231/cc-switch
跨平台桌面一体化助手,支持 Claude Code、Codex、OpenCode、DeepSeek Harness 等工具,唯一官网 ccswitch.io
★ 151,506已汉化DSH
71.1
AI 矢量设计工具ZSeven-W/openpencil
全球首个 AI 原生开源矢量设计工具。
★ 7,027已汉化DSH
71.1
这是你的仓库?认领条目