Skip to content
 
 

Repository files navigation

dsh-encrypt

DSH 凭证加密 Fabric 插件:不替换 dsh-credentials-local,只通过 Fabric hook 增加密文 sidecar、解锁和输出脱敏能力。

Fabric 重写架构

Fabric 版本不再禁用或复制官方 credentials-local row。官方 provider 继续负责 .credentials.yaml 的 YAML 解析、环境变量优先级、watcher、文件锁、明文写入和 credentials/updated 生命周期;本插件只挂载 EncryptController 并注册目标函数的 hook。

加密态使用旁路文件,保证 Fabric 关闭时普通 dsh 仍能启动:

.credentials.yaml                 # 官方 provider 看到的 comment-only marker
.credentials.encrypt.yaml         # AES-GCM / Argon2id 密文 sidecar
.dsh-encrypt.json                 # remember 和解锁锁定状态

代码边界:

  • lib/vault.jslib/lockout.jslib/leak-guard.js:不依赖 Fabric 的安全核心。
  • lib/plain.jslib/fabric-controller.js:sidecar、状态、迁移和密码操作,不注册宿主 hook。
  • lib/fabric-handlers.jslib/fabric-entry.js:唯一的 Fabric 适配层;只 hook resolvedescribesetunset 以及 Web route 注册。
  • lib/web.jslib/client.js:独立 Web/API 和浏览器面,headless 组合不会注册 HTTP 路由。

普通 dsh 跳过 dsh-encrypt-fabric row;fabric-dsh 才启用该 Fabric-required row。旧版“密文直接写在 .credentials.yaml”的文件不能在 provider 已启动后自动迁移,必须先执行迁移工具或手动移动到 sidecar,插件会 fail-closed 而不是把它当成空凭证库。

项目
形态 bundledsh.bundle.patchcordis.patch.yml,随 profile 启动,dsh plugin add 原生安装)
版本 0.1.0-rc.10
依赖线 npm rc.6(@deepseek-ai/cordis@^4.0.1 等 scoped 包 + @node-rs/argon2 原生绑定 + Fabric peer)
环境 Node.js ≥ 18(官方教程建议 22+);DSH @deepseek-ai/dsh@0.0.1-rc.1+
License MIT

解决的问题

DSH 默认的凭证存储把密钥以明文 YAML 写在 $DSH_HOME/.credentials.yaml。dsh-encrypt Fabric 版本保持这条官方 provider 不变;设置密码后,官方文件只保留 marker,凭证按需写入并从 .credentials.encrypt.yaml 解密,Fabric 关闭时不会读取 sidecar。

特性

  • 旁路双文件:明文模式由官方 .credentials.yaml 负责;加密模式使用 marker + .credentials.encrypt.yaml,Fabric 关闭时不会把密文误解析为普通凭证
  • WebUI 全生命周期:设置密码 / 解锁 / 修改密码,全部在「设置 → 加密安全」完成(永远密文策略下没有「移除密码」)
  • AES-256-GCM:每条凭证独立随机 nonce,凭证引用名绑定为 GCM AAD(换位即认证失败)
  • SHA3-256 双重完整性:条目级指纹 + 覆盖文档头部的文档级指纹,损坏文件在启动时即被拒绝(绝不当作“空库”)
  • Argon2id 密码派生@node-rs/argon2,m=64 MiB, t=3, p=1,OWASP 对齐):密码不落盘,仅存盐与 AEAD 验证器;旧版 scrypt(v2)密文仍可解锁并在解锁时自动升级到 Argon2id
  • 摘要校验(前后端分离):WebUI 用纯 JS Keccak-f[1600] 计算密码的 SHA3-256,只 POST { digest } 到后端;后端用 Argon2id 拉伸摘要并与 AEAD 验证器匹配,原始密码不离开浏览器
  • 解锁爆破锁定:连续密码解锁失败计数持久化到状态文件(重启不清零),达到阈值(默认 5 次)后指数退避锁定(30 s 起,2 倍递增,上限 15 min),WebUI 显示剩余锁定时间,HTTP 返回 429 + Retry-After
  • 凭证泄露检测与输出脱敏(Leak Guard):模型实际解析过的凭证值会被登记为掩码模式——WebUI 的 HTTP 响应体与 WebSocket 事件帧在离开主机前扫描并替换为 [REDACTED:dsh-encrypt],提示词注入诱导模型回显密钥时也会被脱敏
  • 发行代码完整性自校验:打包时生成 lib/integrity-manifest.json(所有发行文件的 SHA3-256),启动时逐文件校验、不一致即拒绝加载(fail-closed),覆盖 Fabric 入口、sidecar 控制器、Web 和浏览器面板包;哈希对行尾/BOM 归一化,git 克隆(CRLF↔LF)与 tarball 安装校验一致,真实代码篡改仍会被拦截
  • 免密登录滑块:设置「多少天免密」(0 = 每次都输密码 / 1–30 天 / 永远,刻度仅保留头尾),解锁成功后签发 256 位票据(HttpOnly Cookie + 响应体回传,浏览器同时存 localStorage 并随 x-dsh-encrypt-remember 请求头回传,不再依赖 Cookie 存取可靠性);打开 WebUI 即自动尝试免密解锁(localhost 专属),磁盘只存被 AEAD 包裹的密钥副本;到期或票据不匹配即失效
  • 仅 localhost 免密与改密:非本机访问强制每次都输密码,且不能设置/修改密码(后端强制,返回 LOCAL_ONLY
  • 永远密文(ciphertext-only):一旦设置密码,官方文件只保留 marker;外部把 marker 替换成明文时,控制器拒绝采用并保留最后可信 sidecar 快照,直到恢复 marker。
  • 阅后即焚:密文只在被使用的那一刻解密;解密中间 Buffer 立即清零,新增 withUnlockedBuffer 擦除式接口(回调结束后在 finally 中焚毁明文副本),改密时的明文集合用后即清空,密钥在锁定/卸载时清零
  • 按请求解密:明文只存活于单次操作,不缓存、不进日志;密钥在锁定/卸载时清零
  • 热重载:外部编辑明文即时生效;外部加密即时转锁定;损坏的中间状态保留最后一个好快照
  • 原子写 + 文件锁:写入经 dsh-atomic-write,POSIX 上强制 0600 权限(启动即校验)
  • 自动化解锁DSH_CREDENTIAL_PASSWORD 环境变量在启动时解锁(适合 headless)

形态与架构

本插件是 Fabric bundle。它不禁用官方 credentials row,也不提供第二个 CredentialProviderdsh-encrypt-fabric 只在 fabric-dsh 中启用,并在当前 plugin fiber 注册六个可信 handler。

文件 职责
安全核心 lib/vault.jslib/lockout.jslib/leak-guard.js 加解密、KDF、完整性、锁定和输出扫描;无 Fabric 注册
sidecar 控制器 lib/plain.jslib/fabric-controller.js marker、密文文件、状态文件、密码生命周期和 watcher
Fabric hook lib/fabric-entry.jslib/fabric-handlers.js 只 hook 官方 resolve / describe / set / unset 与 Web route 注册
Web/client lib/web.jslib/client.js 密码 API、响应脱敏和「加密安全」设置面板

四个 credential hook 是 required: true;两个 Web route hook 是可选的,headless profile 没有 WebServer 时不会因为脱敏 hook 绑定为空而失败。Hook 没有 handler 时官方函数照常运行,普通 dsh 则直接跳过整个 Fabric-required row。

官方 provider 继续拥有 .credentials.yaml 的解析、环境优先级、热更新、文件锁、明文写入和 credentials/updated 生命周期。加密态只新增旁路 .credentials.encrypt.yaml,官方文件变成 comment-only marker;因此 Fabric 关闭时不会把密文 JSON 当作普通凭证文档。

安装

1. Profile Bundle(推荐)

先打包,再装进 profile(dsh plugin add 会把声明了 dsh.bundle.patch 的依赖自动 reconcile 进 bundles 列表):

# 打包(files 字段只含显式列出的 Fabric/core/Web 文件与 cordis.patch.yml,test/ 不入包;
# prepack 会自动重新生成 lib/integrity-manifest.json)
npm pack
# → dsh-encrypt-0.1.0-rc.10.tgz

# web profile(设置页「加密安全」)
dsh plugin --profile web add ./dsh-encrypt-0.1.0-rc.10.tgz

# headless profile(一次性任务 / 自动化解锁;web 与 headless 是不同 profile,需分别安装)
dsh plugin --profile headless add ./dsh-encrypt-0.1.0-rc.10.tgz

@node-rs/argon2 是带预编译二进制(napi-rs)的原生依赖,dsh plugin add 安装依赖时会拉取对应平台的 optionalDependencies;Node.js ≥ 18(建议 22+)。若安装后出现原生模块缺失(极少数平台组合),重新执行一次 npm rebuild @node-rs/argon2 即可。

本地源码目录同样可以直接安装(路径用 Windows 正斜杠形式):

dsh plugin --profile web add "D:/path/to/DSH-Encrypt"

2. Web 路由

Fabric 入口通过可选的 webServer/httpServer 注入自动注册密码路由;headless 组合不会挂载 Web API,不需要再插入 dsh-encrypt-web row。dsh-encrypt/client 仍由 package.jsondsh.client 声明挂载设置面板。

3. 验证安装

dsh --profile web --dump-config | grep dsh-encrypt
# 期望:出现 disabled 的 dsh-encrypt-fabric;通过 fabric-dsh 启动时由 launcher 自动启用

4. 运行验证

必须通过 Fabric launcher 启动:

fabric-dsh web

普通 dsh web 会跳过 Fabric-required row,不读取加密 sidecar。headless 使用环境变量自动解锁:

DSH_CREDENTIAL_PASSWORD='<密码>' fabric-dsh headless

旧版直接把密文写入 .credentials.yaml 的文件不能在 provider 已启动后自动迁移。启动 Fabric 前执行:

dsh-encrypt-migrate --path "$DSH_HOME/.credentials.yaml"

该命令只移动并验证密文,不需要密码;目标 sidecar 已存在时拒绝覆盖。

使用

全部操作在「设置 → 加密安全」完成(面板 id encryption):

操作 前置状态 效果
设置加密密码(输入两次,至少 8 个字符) 明文 .credentials.yaml 写入 marker,明文凭证加密到 .credentials.encrypt.yaml,进程保持解锁
解锁 加密+锁定(重启后) 校验密码摘要并派生密钥,立即恢复模型调用
修改密码 加密+解锁 全部条目在新密钥下重加密
免密登录时长(滑块) 任意 0 = 每次都输密码;1–30 = N 天内免密;31 = 永远免密(均仅本机)

滑块即改即存(松开即提交到 /api/credentials.config,只接受 localhost;刻度只显示「每次」与「永远」两头)。解锁成功后按当前滑块时长签发免密票据;改动滑块会作废旧票据,若当前已解锁则立即按新时长重新签发。打开 WebUI 时自动尝试免密解锁(localhost 专属),免密期间无需输密码;到期后回到密码解锁。非 localhost 访问始终需要输入密码,且不显示改密入口(后端同样强制)。

永远密文:设置密码后 .credentials.yaml 只保留 marker。若凭证文件被人替换成明文,控制器拒绝启动/刷新并保留 sidecar;恢复 marker 后即可继续使用。

解锁锁定:连续输错密码达到阈值(默认 5 次)后,解锁接口进入指数退避锁定——第 1 次锁定 30 秒,之后每次失败翻倍,上限 15 分钟;计数与截止时间持久化在状态文件里,重启进程不能清零。锁定期间面板显示剩余秒数并禁用解锁按钮,接口返回 429 + Retry-After;成功解锁即清零。

状态机:

             set-password                    (restart)            unlock
  plain ──────────────────► encrypted+unlocked ──────► encrypted+locked ──► unlocked
    ▲                            │  ▲                                        │
    └────── marker-restore ──────┘  └──────────── change-password ───────────┘
  • 锁定期间:web 服务照常运行;继承环境中的凭证仍可解析,文件内凭证解析抛 VAULT_LOCKEDdescribe 报告 source: "locked"——设置页即是解锁入口
  • 免密窗口:票据在签发时写入 issuedAtdaysdays: -1 永不失效。滑块改动会立即作废旧票据
  • 忘记密码:设计上不可恢复(密码不落盘);恢复手段 = 备份并删除 marker、sidecar 和状态文件后重新配置

凭证解析顺序

优先级 来源 说明
1 继承环境(launching environment) 只读、高于受管文件;对被其遮蔽的引用写入会被拒绝
2 受管文件 / 加密 sidecar 明文模式读取 .credentials.yaml;加密模式由 Fabric 从 .credentials.encrypt.yaml 按需解密
3 .env 回退(project-env / user-env) 低于受管文件,仅在文件无此引用时兜底

allowEnvFallback: false 可关闭第 1、3 层(严格仅文件策略)。

磁盘格式

明文形态(未设密码,与 dsh-credentials-local 完全一致):

OPENCODE_GO_API_KEY: sk-…

加密形态由两个文件组成:

.credentials.yaml
# dsh-encrypt: encrypted sidecar
# Credential values are stored in .credentials.encrypt.yaml.

.credentials.encrypt.yaml 的内容是 JSON 密文文档:

{
  "format": "dsh-encrypt-credentials",
  "version": 3,
  "algorithm": "aes-256-gcm+sha3-256",
  "kdf": "argon2id",
  "kdfInput": "sha3-256-password",
  "m": 65536, "t": 3, "p": 1,
  "salt": "<base64url>",
  "verifier": { "data": "<base64url>", "sha3": "<hex>" },
  "entries": {
    "OPENCODE_GO_API_KEY": { "data": "<base64url>", "sha3": "<hex>" }
  },
  "sha3": "<document fingerprint>"
}
  • kdf: "argon2id":主密钥 = Argon2id(密码的 SHA3-256 摘要, salt, m/t/p),原始密码不进后端。
  • v2 scrypt 文档仍可解析与解锁,密码解锁后升级为 v3;旧版单文件位置必须先迁移到 sidecar。
  • verifier、条目级指纹、文档级指纹和 GCM AAD 继续由 lib/vault.js 校验。
  • 密码与票据从不落盘;.credentials.yaml marker 本身不含秘密。

HTTP 路由(可选 WebServer 注入)

POST application/json(与官方 /api 相同的跨站写护栏);响应 { ok: true, value }{ ok: false, code, message },错误消息不含密码或任何密钥材料:

路径 请求体 作用
/api/credentials.status {} 返回 { format, unlocked, plaintextForbidden, local, remember, ticketRejected, lockout, leakGuard };localhost 且携带免密票据(x-dsh-encrypt-remember 请求头或 Cookie)时先尝试票据解锁
/api/credentials.unlock { digest } 密码摘要解锁(64 位小写 hex SHA3-256);localhost 成功后再按滑块签发免密票据(票据随响应体 ticket 字段回传);失败次数过多时返回 429 + Retry-AfterTOO_MANY_ATTEMPTS
/api/credentials.set-password { digest } 明文 → marker + 密文 sidecar(仅 localhost
/api/credentials.change-password { digest } 重加密(需已解锁,仅 localhost,作废旧票据并签发新票据)
/api/credentials.config { action: "get" } / { action: "set", rememberDays } 读取状态或设置免密天数(-1 = 永远,0 = 每次,1–30;set 仅 localhost,签发新票据时随响应回传)

所有路由只接受 POST application/json。密码本身永不出现在任何请求体里——浏览器只提交 digest(可用 node -p "require('crypto').createHash('sha3-256').update('密码').digest('hex')" 计算)。

headless 组合不挂载 web 行,因此没有 HTTP 面。

配置项

config:
  path: ''            # 凭证文件绝对路径;未设置时取 $DSH_HOME/.credentials.yaml
  encryptedPath: ''    # 加密 sidecar;默认与 credentials 文件同目录
  statePath: ''        # 状态文件;默认 $DSH_HOME/.dsh-encrypt.json
  allowEnvFallback: true          # 允许继承环境与 .env 回退层
  passwordEnv: DSH_CREDENTIAL_PASSWORD  # 启动自动解锁的环境变量名
  watch: true         # 监听文件变化热重载
  debounceMs: 100     # 热重载防抖(毫秒)
  leakGuard: true     # 凭证泄露检测与输出脱敏
  leakMinMaskLength: 8     # 短于该长度的值不脱敏(避免误伤普通文本)
  leakMaxMaskLength: 256   # 长于该长度的值不脱敏(流式回看窗口)
  maxUnlockAttempts: 5     # 连续解锁失败触发锁定的阈值
  lockoutBaseMs: 30000     # 首次锁定窗口(毫秒,之后指数翻倍)
  lockoutMaxMs: 900000     # 锁定窗口上限(毫秒)
   trustedHosts: []     # 非回环部署允许的 Host authority(host 或 host:port)
字段 类型 默认值 说明
path string $DSH_HOME/.credentials.yaml 凭证文件绝对路径(运行时注入 dshHome 计算默认值)
dshHome string 运行时注入 Harness home
encryptedPath string .credentials.encrypt.yaml 加密 sidecar 路径
statePath string $DSH_HOME/.dsh-encrypt.json remember/lockout 状态文件
allowEnvFallback boolean true 是否启用继承环境与 .env 回退层
passwordEnv string DSH_CREDENTIAL_PASSWORD 启动自动解锁密码的环境变量名
watch boolean true 是否监听文件热重载
debounceMs number 100 热重载防抖毫秒数(≥ 0)
rememberDays number 0 免密登录天数:0 = 每次都输密码,1..30 天,-1 = 永远(补丁配置的初始值;滑块运行时值写入 $DSH_HOME/.dsh-encrypt.json 并优先生效)
leakGuard boolean true 泄露检测与输出脱敏总开关(关闭后 HTTP/WS 输出不再扫描)
leakMinMaskLength number 8 参与脱敏的最小值长度(4–64;更短的值视为普通文本)
leakMaxMaskLength number 256 参与脱敏的最大值长度(16–1024;同时是流式脱敏的跨块回看窗口)
maxUnlockAttempts number 5 连续解锁失败多少次后进入锁定(≥ 1)
lockoutBaseMs number 30000 首次锁定窗口毫秒数(≥ 1000;之后每次失败 ×2)
lockoutMaxMs number 900000 锁定窗口上限毫秒数(≥ 1000)
trustedHosts string[] [] 非回环部署允许的 Host authority(host 或 host:port);密码修改仍要求 socket 回环

安全模型

保证

  • 静态存储只含密文;内存快照在密文形态下只保存密文记录
  • 每条目随机 12 字节 nonce;引用名作为 GCM AAD,记录换位会认证失败
  • 双层 SHA3-256 指纹 + GCM 认证标签:篡改且重算指纹的攻击仍会以 VAULT_KEY_MISMATCH 失败(与错误主密钥不可区分——这是 AEAD 的诚实答案)
  • 密码经 Argon2id(m=65536 KiB, t=3, p=1,@node-rs/argon2)派生,只存盐与 AEAD 验证器;文档中成本参数有上限(m ≤ 256 MiB、t ≤ 64、p ≤ 32),恶意构造的参数无法耗尽内存/CPU
  • 阅后即焚:密文只在被使用的一刻解密;解密中间 Buffer 立即清零;withUnlockedBuffer 在回调结束后焚毁明文副本;改密的明文集合用后即清空;密钥(KEK)在锁定/卸载时清零(zeroizeBuffer
  • 永远密文:设密后文件不可能回退明文;外部明文替换在解锁态被立即重加密,锁定/启动态被拒绝(plaintextForbidden
  • POSIX 上凭证文件必须是 owner-only(0600),否则启动直接拒绝(chmod 600 修复);Windows 无 mode 可查,保护由创建 API 与 OS ACL 表达
  • 防爆破:连续解锁失败计数 + 指数退避锁定,计数持久化(重启不清零);接口返回 429 + Retry-After,面板显示剩余时间
  • 防注入回显(Leak Guard):模型解析过的凭证值成为掩码模式;WebUI 的 HTTP 响应体与 WebSocket 文本帧在离开主机前被替换为 [REDACTED:dsh-encrypt](分块边界安全的流式脱敏,绝不先漏出前缀)
  • Web API 先校验 Host 信任围栏(回环或 trustedHosts),密码变更和 remember 设置还要求 socket 来自回环;请求体限制为 64 KiB,内部错误不会回传路径或堆栈
  • 运行时兼容护栏会检测 dsh 版本;跨越不支持的主次版本时以 UNSUPPORTED_DSH fail-closed,同一版本线的 rc 漂移给出警告

诚实边界

  • JavaScript 字符串不可变:解密出的明文无法在内存中清零。给出的保证是不持久化、不缓存、不进日志,以及操作结束即丢弃引用
  • 解锁期间主密钥必须驻留内存(否则无法解密任何条目),请以操作系统账户与 0600 文件保护
  • 忘记密码无法找回(设计如此);唯一恢复手段是清除凭证文件后重新配置
  • 完整性清单不是信任根:能改写插件目录的攻击者也能重新生成清单;该校验拦住的是未重算清单的篡改(运行时打补丁、截断、供应链替换)。真正的信任根是用户密码
  • 锁定计数存在状态文件:同一 OS 用户可编辑 .dsh-encrypt.json 重置计数——锁定防的是「在线猜密码」,不是同账户内的自我解锁
  • 脱敏只覆盖本插件已知的值:仅模型实际解析过的凭证会被掩码;模型把密钥通过工具调用(bash/web_search/网络请求)外传不属于输出脱敏的覆盖范围,那属于 permission/tools 层职责;二进制 WS 帧与静态资源不做扫描;把密钥拆分/转码后再输出可绕过子串匹配
  • 脱敏掩码集在解锁期间驻留内存(仅已解析值,锁定/改密/卸载即清空)——这是"掩码输出"与"不缓存明文"之间的有意识取舍
  • 锁定态下未注册任何掩码(无明文可知),但也没有任何凭证会被解析出去,泄露面为零

错误码

VaultError 携带稳定的机器可读 code,消息永不含明文/密文/密钥材料:

code 含义
PASSWORD_WRONG 摘要与验证器不匹配(错误密码在触碰任何条目之前即被拒绝)
PASSWORD_INVALID 摘要不是 64 位小写 hex 的 SHA3-256
LOCAL_ONLY 该操作(改密/移除密码/免密设置)仅允许 localhost
REMEMBER_EXPIRED 免密票据已超过其窗口,需重新输入密码
REMEMBER_INVALID 免密票据与本凭证库不匹配(或库中无票据)
VAULT_LOCKED 凭证库已锁定;在「设置 → 加密安全」解锁(或导出 DSH_CREDENTIAL_PASSWORD
VAULT_NOT_ENCRYPTED 尚未设置密码,无锁可解/无密可改/可除
VAULT_ALREADY_ENCRYPTED 已设密码;修改密码请用 change-password
VAULT_CORRUPTED SHA3-256 完整性校验失败,错误中指名出问题的引用
VAULT_MIGRATION_REQUIRED 检测到旧版单文件密文;先运行 sidecar 迁移再启动 Fabric
VAULT_KEY_MISMATCH GCM 认证失败:主密钥不匹配,或密文被替换
PASSWORD_INVALID / MASTER_KEY_INVALID 参数或密钥材料非法
TOO_MANY_ATTEMPTS 解锁失败次数过多,已进入锁定窗口(HTTP 429 + Retry-After,错误携带 retryAfterMs
INTEGRITY_FAILED 发行代码完整性校验失败(插件拒绝加载;合法重建后运行 npm run integrity
FORBIDDEN_HOST Web 请求 Host 未通过信任围栏
UNSUPPORTED_DSH 当前 dsh 主次版本不在已验证兼容线

兼容性与升级

  • rc.6 → rc.10 Fabric 重写:官方 credentials-local row 不再被禁用;加密文档从旧版 .credentials.yaml 迁移到 .credentials.encrypt.yaml sidecar,启动时遇到旧位置会返回 VAULT_MIGRATION_REQUIRED,避免静默丢失凭证。
  • KDF 兼容:旧 v2 scrypt sidecar 仍可解锁,成功后升级为 v3 Argon2id;新增解锁爆破锁定、凭证泄露检测与输出脱敏、发行代码完整性自校验。
  • 运行时兼容lib/compat.js 对运行中的 dsh 做兼容线检查;同一 0.1.x 线的 rc 漂移警告,跨主次版本抛 UNSUPPORTED_DSH
  • 官方 provider 的 resolve / describe / set / unset 接缝保持不变;Fabric 关闭时普通 dsh 完全按官方明文 provider 工作。
  • 对外导出:dsh-encrypt(Fabric 入口)、dsh-encrypt/migrate(旧单文件迁移)、dsh-encrypt/vault(密码学核心)、dsh-encrypt/web(可选路由)、dsh-encrypt/client(浏览器包)

卸载与回滚

卸载前若希望普通 dsh 继续读取凭证,先把 sidecar 解密导出为官方明文 .credentials.yaml;若没有密码,无法恢复明文。删除插件前至少备份并移除 marker、sidecar 和状态文件:

  1. 备份/迁移 $DSH_HOME/.credentials.yaml.credentials.encrypt.yaml.dsh-encrypt.json
  2. 从 profile bundle 列表移除 dsh-encrypt;不需要删除额外的 dsh-encrypt-web row,因为 Web 路由由 Fabric 入口的可选注入负责
  3. 移除 bundle:
dsh plugin --profile web remove dsh-encrypt
dsh plugin --profile headless remove dsh-encrypt

基础 credentials 行随 bundle 移除自动恢复启用,之后在 DSH 设置中重新录入凭证。

开发与测试

pnpm install        # 从 GitHub Releases 拉取 cordis-fabric runtime;Fabric bundle 复用同一 release 源

pnpm test           # Fabric hook、marker、sidecar/controller 回归测试;pretest 自动重建完整性清单
pnpm run check:patch # 校验 cordis.patch.yml 与运行时 patch descriptors 无漂移
pnpm pack           # prepack 自动重建清单后打包

安全测试覆盖:锁定期望(阈值/指数退避/上限/不复位)、泄露检测(正则元字符转义、长度窗口、去重)、流式脱敏的分块边界不泄漏性质、WebSocket 帧过滤(拆分帧/长度类重建/控制帧直通/二进制直通)、完整性清单(篡改/缺失 fail-closed)、429 响应与路由包装(注册前后均被包裹)、101 握手缓冲后过滤帧。

额外验证脚本:

node test/client-smoke.mjs     # 浏览器包 ModuleLoader/SSR 冒烟
# 两阶段真实重启 e2e(目标实例与 home 均显式传入,不硬编码回环地址):
node test/e2e-webui.mjs --base http://localhost:3199 --home <dsh-home> --phase 1
node test/e2e-webui.mjs --base http://localhost:3199 --home <dsh-home> --phase 2

测试套件仅本地回归用,不随 npm 包分发(files 只含显式列出的 Fabric/core/Web 文件与 cordis.patch.yml)。

许可证

MIT · © 2026 Yauntyours

About

DeepSeek Harness 凭证加密插件,通过设置密码使用AES-256-GCM+SHA3-256实现的全流程加密+校验,运行时临时解密,内存安全。

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages