dsh-ssh-vault
把 SSH 主机存进 AES-256-GCM 加密保险库,智能体按别名执行命令,口令经 SSH_ASKPASS 交给 ssh 而不进入命令行。仅支持 Windows。
安装
dsh plugin --profile web add dsh-ssh-vault
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
<div align="center">
dsh-ssh-vault
简体中文 | [English](README.md)





</div>
给 DeepSeek Harness 的智能体提供 SSH 能力:主机地址、端口、账号、口令与私钥都存进加密保险库,对话里只用别名。模型永远看不到口令,口令也不会出现在命令行或远端进程列表里。
简介
仅支持 Windows。 保险库数据密钥由 Windows DPAPI 保护,SSH_ASKPASS 辅助程序是 Windows 的 .cmd 包装器;插件声明了 os: ["win32"],在其它平台上直接拒绝启动,而不是把密钥退化成明文。
三个能力合在一个插件里:
- 模型面向的工具 ——
ssh_hosts、ssh_run、ssh_transfer、ssh_probe,让智能体按别名操作远端主机。 - 设置界面 —— 在「设置 → SSH 连接」里增删改主机、测试连通性。口令经 HTTP body 提交,不进入会话日志。
/hosts命令 —— 人类直接在对话里探测主机、执行命令,不必经过模型。
底层调用本机 OpenSSH 客户端(ssh / scp),不自带 SSH 协议实现。
安装
从 npm 安装。插件已发布为 dsh-ssh-vault;下面这种只写包名的形式会自动解析到 npm registry:
dsh plugin --profile desktop install dsh-ssh-vault
需要固定版本或离线安装时,先用 npm 拉取 tarball,再把文件交给同一条命令:
npm pack dsh-ssh-vault # 在当前目录生成 dsh-ssh-vault-<version>.tgz dsh plugin --profile desktop install ./dsh-ssh-vault-<version>.tgz
从本地目录安装。参数是路径,已经在插件目录里时直接用 .:
# 在插件目录内执行 dsh plugin --profile desktop install . # 或从别处指向该目录 dsh plugin --profile desktop install ../dsh-ssh-vault # 或从打包好的 tarball 安装 dsh plugin --profile desktop install ./dsh-ssh-vault-<version>.tgz
需要 --profile。 DSH 按 profile 隔离插件集,同一台机器可以有多个 profile(如 desktop 与 cli)。不指定时取决于当前默认 profile,容易出现「装到了别处」。装完用下面的命令确认落点:
dsh plugin --profile desktop list
安装完成后重启 DSH。Host 侧的工具与路由在重启后才会加载。
本插件仅支持 Windows。 package.json 声明了 os: ["win32"],因此在 Linux / macOS 上 dsh plugin ... install 会直接拒绝安装;从源码加载也会因为同样的原因拒绝启动(见[已知限制](#平台与认证))。
环境要求
项 · 要求
Node · ≥ 20
本机 · Windows 10 / 11,且启用 OpenSSH 客户端(ssh -V 能输出版本)
平台 · 仅 Windows(win32)——Linux / macOS 上安装与加载都会被拒绝
快速开始
1. 安装并重启 DSH。
2. 打开 设置 → SSH 连接,点「添加连接」,填别名、地址、端口、账号,选择口令或私钥认证。
卡片上的圆点会自动体检:灰=未检测、黄=检测中、绿=连通、红=不通。
3. 在对话里说一句话,例如:
用 kali 跑一下 uptime
模型会调用 ssh_run,结果以终端卡片出现在对话中。
口令不要写在对话里。设置界面录入的口令直接进加密保险库,不经过模型上下文。
使用方式
模型调用工具
工具 · 用途 · 典型说法
ssh_hosts · 管理保险库(list / show / add / update / remove) · 「有哪些主机」「改一下 kali 的备注」
ssh_run · 在主机上执行命令,返回 stdout 与 stderr · 「在 kali 上看看磁盘占用」
ssh_transfer · 上传或下载文件(scp),可选 sudo 读写 · 「把这个文件传到 kali 的 /tmp」
ssh_probe · 连接自检,回读系统与能力信息并写入主机元数据 · 「kali 还连得上吗」
ssh_tunnel · 维护本地端口转发(ssh -L) · 「把 kali 的 8787 映射到本地 18787」
ssh_run 的几条约定:
- 显式 shell 包装。 POSIX 目标默认用
bash --norc -c '<command>':命令固定由 bash 解析一次,不会落到远端登录 shell(fish/zsh)上被改写成另一个意思。login_shell: true改用bash -lc(需要 profile 里定义的 PATH 时)。返回里的remoteShell会说明这次实际用了什么。
--norc 不是可有可无的:RHEL/CentOS 的 bash 打了 SSH_SOURCE_BASHRC 补丁,SSH 会话里非交互 bash 也会 source ~/.bashrc,用户 .bashrc 里一条失败的 source 就会让每条命令的 stderr 多一行噪声,进而干扰失败诊断。
- 命令数组。
command_array: ["find", ".", "-name", "*.log"]会逐元素引号化,远端 shell 不做分词、通配或变量展开,彻底避开双层 shell 的引号陷阱。 - sudo 三态。
sudo: true自动选形态;sudo: "wrap"把整条命令包成sudo -n bash -c '...';sudo: "script"写临时脚本再以 root 执行——heredoc、管道、后台任务、多行流程都不会在提权边界上变形,脚本执行完即删,口令经 base64 管道喂给sudo -S,两端命令行与远端ps都看不到;sudo: "prime"只预热缓存,命令里照旧自己写 sudo。口令始终来自保险库。用了任一形态后不要在命令里再写 sudo。 - 错误分类。 失败时附一行类别标签(连接 / 认证 / sudo / 远端命令 / 输出截断);sudo 失败还会细分「需要密码 / 不在 sudoers / 没有 sudo」并给出修复命令。
- 大输出落盘。 超过上限时响应只保留摘要,完整内容写进保险库目录下的
outputs/,并把绝对路径附在结果里。
ssh_transfer 在 scp 之上补了三件事:sudo: true 读写 root-only 文件(远端临时文件中转 + 自动清理);normalize_eol: true 上传前把 CRLF 规范成 LF(Windows 上写的脚本在远端不会报 $'\r': 未找到命令,二进制文件自动跳过);mode / owner / preserve_mode 设置远端权限与属主。
ssh_tunnel 在开隧道之前先读远端 sshd -T 的转发策略:AllowTcpForwarding no 时直接给出「用 sshd_config 的 Match User <user> 放行 LocalForwarding、不要全局改」的可粘贴片段与 PermitOpen 说明,而不是等撞上 administratively prohibited。它维护隧道生命周期(本地端口占用预检、断线事件、指数退避重连、插件卸载时清理),并返回本地可用地址。
在哪里看到效果: ssh_run / ssh_probe / ssh_transfer / ssh_tunnel 的调用会渲染成终端卡片——标题栏是「主机 · 命令」加一个状态点,下方是可滚动的等宽输出区。状态点:蓝=运行中、灰=成功、红=失败(含非零退出码)。
设置界面
「设置 → SSH 连接」提供:
- 主机列表,含连通状态圆点,悬停看详情
- 添加 / 编辑 / 删除连接(编辑时别名可改,凭据随之搬迁)
- 每张卡的「测试连接」,结果同时反映到圆点
- 「用资源管理器打开」保险库目录
- 口令认证与私钥认证;私钥可整份上传,由宿主写入保险库并收紧权限
界面语言
插件显示的所有文字都跟随 设置 → 常规 → 语言,这里没有另一套开关。
- 设置页与对话内的 SSH 卡片从宿主的 locale 服务取词,语言一换立刻跟着变。
/hosts输出、连接诊断、设置接口错误、保险库错误与后台任务状态都由 Host 生成;它们读取同一个持久偏好(locale.preference)并跟随之后的切换,只有在从未选择过语言时才退回请求的Accept-Language。- 面向模型的定义保持英文:工具名、描述与参数 schema 属于模型接口,而不是界面。
/hosts 命令
在输入框里以 / 开头,命令不经模型直接执行。
/hosts 列出全部主机,按在线 / 离线分组 /hosts kali 探测一台 /hosts kali,win10 探测多台(中英文逗号都行) /hosts kali; apt update 在 kali 上执行命令 /hosts kali,win10; uptime 在每台可达主机上执行
- 分隔符支持中英文:
,与,、;与; - 分号后如果写的是自然语言(例如「帮我看看磁盘」),命令不会执行,会提示你直接把它发给对话——命令的产出不回流给模型,这类请求不能走命令
- 输出渲染为两张卡片:连接状态、命令执行,各自独立亮灯
- 在
/菜单里选中/hosts只是「认领」这个命令:输入框里出现命令 token 与提示。再按一次回车=无参执行(列出主机);或者接着输入别名; shell 命令作为它的参数。想回到普通提示词,删掉这个命令 token 即可——在那之前输入的内容都会被当作命令参数 - 首条消息之前,结果显示在输入框上方。 DSH 把「整段记录只有命令行」的会话视为非活跃视图,所以全新会话里单独跑
/hosts以前看起来像「什么都没发生」,要等发出第一条消息才看到卡片。插件现在会在会话仍空白时把这些/hosts卡片(含运行中状态)镜像到输入框上方的 dock;首条消息发出后由对话区接管,不会重复显示 - 无参执行只在体检缓存为空时现测,且并行、总预算 4 秒;即使多台主机不可达也能在几秒内给出结果
架构
双端形态
这是 Host + Client 双端插件,两半由不同机制加载:
半边 · 入口 · 加载方式
Host · index.js · Cordis 插件,经 cordis.patch.yml 插入 Loader
Client · client.js · 浏览器模块,经 package.json 的 dsh.client 声明后由宿主注入页面
Host 承担全部敏感操作:保险库加解密、调用本机 ssh、Web 路由、命令与工具注册。
Client 只做呈现与表单,不直接执行任何命令。
数据流
flowchart TB
subgraph entry [入口]
chat[对话 / 模型工具调
…(truncated)以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:3,最后更新 2026-11-01