安全升级与回滚 devopsfortunato/dsh-plugin-safe-upgrade
DeepSeek Harness非官方社区插件。 它并非由 DeepSeek 或 DeepSeek Harnessdsh团队制作、认可或支持。它仅使用…
28.2/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/16 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add devopsfortunato/dsh-plugin-safe-upgrade该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
装得上吗[实装验证]—
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →数据截至 2026/09/30·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 备份配置历史
- 升级失败自动回滚
README
由 DeepSeek 最新模型翻译生成dsh-plugin-safe-upgrade
[!IMPORTANT]
非官方社区插件。 它并非由 DeepSeek 或 DeepSeek Harness(dsh)团队制作、认可或支持。它仅使用 dsh 的公开插件接口。请在本仓库的 issues 中报告问题,切勿向 dsh 项目报告。“DeepSeek”和“DeepSeek Harness”归其所有者所有,此处仅用于说明该插件可与什么配合使用。
为 DeepSeek Harness(dsh)提供安全的配置历史、受保护的升级和自动回滚。
dsh 经常发布候选版本,而 cordis.patch.yml 中一个错误的行就可能导致它无法启动。此插件让这两件事都变得轻松无忧:
- 配置历史。 对决定 dsh 能否启动的文件(settings.yaml、profile 补丁和清单、agent 预设、AGENTS.md)的每次编辑,都会在发生几秒后提交到 $DSH_HOME 中的 git 仓库,包括之后创建的 profile 和预设文件夹。会话、凭据、缓存和 node_modules 永远不会被跟踪,并且 secret guard 会在任何包含字面密钥的文件被写入 git 之前拒绝它。
- 已知良好的启动。 每次启动后,插件都会检查插件加载器是否有失败的插件、永远无法完成加载的插件以及损坏的预设。
展开完整文档(README 剩余 1 节)
dsh-plugin-safe-upgrade
[!IMPORTANT]
非官方社区插件。 它并非由 DeepSeek 或 DeepSeek Harness(dsh)团队制作、认可或支持。它仅使用 dsh 的公开插件接口。请在本仓库的 issues 中报告问题,切勿向 dsh 项目报告。“DeepSeek”和“DeepSeek Harness”归其所有者所有,此处仅用于说明该插件可与什么配合使用。
为 DeepSeek Harness(dsh)提供安全的配置历史、受保护的升级和自动回滚。
dsh 经常发布候选版本,而 cordis.patch.yml 中一个错误的行就可能导致它无法启动。此插件让这两件事都变得轻松无忧:
- 配置历史。 对决定 dsh 能否启动的文件(settings.yaml、profile 补丁和清单、agent 预设、AGENTS.md)的每次编辑,都会在发生几秒后提交到 $DSH_HOME 中的 git 仓库,包括之后创建的 profile 和预设文件夹。会话、凭据、缓存和 node_modules 永远不会被跟踪,并且 secret guard 会在任何包含字面密钥的文件被写入 git 之前拒绝它。
- 已知良好的启动。 每次启动后,插件都会检查插件加载器是否有失败的插件、永远无法完成加载的插件以及损坏的预设。一次干净的启动会将其配置标记为 good-,并附带其运行所用的 dsh 版本,每个配置和版本一次。
- /upgrade。 升级 dsh 时不会触碰正在运行的服务,直到最后一刻。新版本会安装到一个旁路副本中,每个 profile 都会在 $DSH_HOME 的一次性副本中用 dsh --dump-config 进行验证,再次检查空闲状态,只有到那时才会停止 dsh、交换目录并启动。如果新版本无法恢复健康状态,则会自动恢复之前的安装和配置。停机时间就是交换加上一次启动(几秒钟)。
- 你的会话继续可用。 在任何停机之前,插件会用正在运行的 dsh 和新版 dsh 分别打开每个已存储会话的副本。如果今天能打开的会话在升级后无法打开,升级就会停止。如果会话是在新版本不再定义的 agent 预设下记录的(例如 ~/.dsh/.agent-presets 文件夹,0.1.7 已停止读取它),插件会以旧名称添加默认预设的旧版副本,因此这些对话仍然可以继续。当在较新版本上继续的会话会从较旧 dsh 中消失时,回滚会发出警告。
- Web UI 检查。 新版本启动后,真实的 Web 应用会在无头 Chromium 中加载。如果 dsh 显示其“Failed to load plugins”屏幕,升级就会回滚。这可以捕获服务器永远看不到的浏览器端插件故障,例如某个客户端一半在等待新版本已移除的服务。
- 警告,而不是意外。 升级、试运行和回滚会报告在新版本中不再匹配任何内容的补丁,以及插件记录的错误不会失败。开启 failOnWarnings 可将这些视为失败:试运行会失败,升级会在 dsh 被触及之前停止(配置警告)或回滚(启动警告),手动回滚会被撤销。自动恢复永远不会因警告而被撤销。
- /rollback。 回退到任何已知良好的启动或配置快照。在 dsh 停止之前,会先验证目标配置。当标签记录在另一个 dsh 版本上,且该版本的安装副本仍然存在时,该安装也会被换回。
- 启动守卫(可选)。 一个 systemd drop-in 会在每次启动前验证配置。如果 dsh 连续三次启动失败,则恢复机器可回退到的最新已知良好配置,并再次启动 dsh。这也能捕获损坏的手工编辑,而不仅仅是升级导致的问题。它每 15 分钟最多运行一次,因此不会陷入循环,并且以与 dsh 相同的账户运行。
- 可选的 Telegram 警报,用于每次升级、回滚和恢复。
升级如何运行
/upgrade ─▶ 主机部分(在 dsh 内):空闲?没有作业在运行? ─▶ systemd-run 一个 supervisor 单元 │ (在 dsh 重启后仍然存活) supervisor ─▶ 获取作业锁,快照 + 打标签 pre-upgrade-* │ ─▶ cp -a install → install.next-,将 @deepseek-ai/* 固定到 ,npm install ─▶ 在一个一次性的 $DSH_HOME 中执行 dsh --profile --dump-config (不触及任何在线内容) ─▶ 用旧版和新版 dsh 分别打开每个会话的副本:任何一个都不能停止打开;新版 dsh 缺少的预设会获得旧版副本,并优先与新版本组合 ─▶ 仍然空闲?(最多等待 idleWaitMs 以等待正在运行的回合) ─▶ 停止 dsh,确认其已停止 ─▶ install → install.prev-,install.next- → install ─▶ 将旧版预设(如果有)写入 profile 补丁 ─▶ 启动 ─▶ 等待 HTTP + 新的启动标记:版本正确,没有失败或卡住的插件 ─▶ 在无头 Chromium 中加载 Web UI:composer,还是 "Failed to load plugins"?
─▶ 从日志中收集警告失败 ─▶ 停止 ─▶ 恢复 install.prev + 升级前配置 ─▶ 启动 ─▶ 验证
dsh --dump-config 并非只读:dsh 0.1.7 在组合时会重写每个 profile 的
cordis.yml,规范化随附的 profile 清单,并删除 0.1.5 的链接投影。因此,验证会针对配置文件的副本运行,每个 profile 的 node_modules 以只读方式链接进来(减去 dsh 会删除的投影),并且在线 $DSH_HOME 永远不会被试运行或被拒绝的升级写入。
要求
- dsh 0.1.5 或更高版本,使用 npm 安装(其 node_modules 中包含 @deepseek-ai/dsh 的文件夹),作为 systemd 服务运行(系统级或用户级)。
- 带有 git、npm、cp 和 systemd-run 的 Linux。Node 22 或更高版本。
- 可选:用于 Web UI 检查的 Chromium 或 Chrome。如果没有,则跳过该检查并报告为警告。
- 会话检查会在检查期间复制 $DSH_HOME/sessions,因此它需要在 $DSH_HOME 旁边有同样多的可用磁盘空间。
- 该插件本身不需要任何依赖。
配置历史和启动健康检查在没有 systemd 的情况下也能工作。升级和回滚则需要它。
安装
git clone https://github.com/MovieMaker93/dsh-plugin-safe-upgrade ~/.dsh/plugins/safe-upgrade
dsh plugin --profile web add link:$HOME/.dsh/plugins/safe-upgrade
sudo systemctl restart dsh # 或者你的单元叫什么名字
dsh plugin add 将该包注册为 profile bundle,这会插入
safe-upgrade 行。在首次启动时,插件会启动配置历史并将该次启动标记为良好。
可选的启动守卫(以拥有该单元的用户身份运行一次):
node ~/.dsh/plugins/safe-upgrade/bin/dsh-safe-upgrade.mjs install-guard --unit dsh
使用
在 Web UI 中,输入命令并按 Enter:
| 命令 | 作用 |
| /upgrade | 列出更新的 latest/next 版本、一次试运行、“立即检查”以及上一个任务。当有回合正在运行时会拒绝执行。 |
| /rollback | 列出已知良好的启动和最近的配置快照。 |
当任务完成时你会收到通知:如果允许通知,则显示浏览器通知,否则显示页内 toast。从 shell 中:
dsh-safe-upgrade status
dsh-safe-upgrade upgrade latest --dry-run
dsh-safe-upgrade upgrade 0.1.7-rc.2
dsh-safe-upgrade rollback good-20260928-190522
dsh-safe-upgrade check-ui # Web UI 现在真的能加载吗?
dsh-safe-upgrade sessions # 哪些会话无法打开,哪些无法继续 dsh-safe-upgrade sessions --fix-presets # 为预设已消失的会话添加旧版预设 dsh-safe-upgrade install-guard --unit dsh [--remove]
sessions 在 $DSH_HOME/sessions 的副本上工作,绝不会更改会话。--fix-presets 会在将旧版预设追加到 profile 的 cordis.patch.yml 之前,用正在运行的 dsh 组合它们;带有 patchReload: live 的 profile 无需重启即可加载它们。
CLI 会在各自的 systemd 单元中运行任务并跟踪其日志,因此你可以安全地断开连接。如果没有全局安装,请以
node ~/.dsh/plugins/safe-upgrade/bin/dsh-safe-upgrade.mjs 运行它。
--force 会跳过两项空闲检查(在请求任务时以及即将停止 dsh 之前)。
配置
一切都是自动检测的:单元来自进程 cgroup,安装目录来自正在运行的 dsh 二进制文件,健康检查 URL 来自 --host/--port, profiles 来自 $DSH_HOME/profiles。要覆盖,请向你的 profile 的 cordis.patch.yml 添加一行。补丁会替换整个配置,因此列出你想要保留的每一个键。
- id: safe-upgrade
config:
channel: latest # /upgrade 首先提供的 dist-tag failOnWarnings: false telegram: # 可选;凭据在发送时读取 envFile: /etc/dsh/alerts.envyaml tokenVar: TELEGRAM_BOT_TOKEN chatVar: TELEGRAM_CHAT_ID
| 键 | 默认值 | 含义 |
| unit / scope | 自动检测 | systemd 单元以及 system/user 作用域 |
| installDir | 自动检测 | 其 node_modules 中包含 @deepseek-ai/dsh 的文件夹 |
| profiles | 全部 | 通过 --dump-config 验证的配置文件 |
| healthUrl | 来自 --port | 除 5xx 外的任何 HTTP 响应都算作已启动(401 是正常的) |
| healthTimeoutMs | 150000 | 一次新启动最多可以花费多长时间 |
| bootTimeoutMs | 120000 | 插件在启动被判定为不健康之前可以保持加载状态多长时间 |
| idleWaitMs | 300000 | 升级或回滚在放弃且不停止 dsh 之前,等待正在运行的轮次多长时间 |
| channel | latest | 优先提供的 dist-tag;其后的标签会被隐藏 |
| checkIntervalHours | 6 | npm dist-tag 检查间隔 |
| keepPrev | 2 | 为回滚保留的先前安装副本数量 |
| keepGoodTags | 10 | 保留的 good- 标签数量 |
| snapshots | true | 自动提交配置编辑 |
| failOnWarnings | false | 将警告视为失败(试运行、升级、手动回滚) |
| uiCheck | auto | auto:在 dsh 的失败屏幕上回滚,如果检查无法运行则发出警告;true:在无法运行时也回滚;false:跳过 |
| chromium | 自动检测 | 用于 UI 检查的 Chromium/Chrome 二进制文件路径 |
| uiTimeoutMs | 45000 | UI 显示 composer 最多可以花费多长时间 |
| sessionCheck | true | 在升级前用旧版和新版 dsh 打开每个已存储的会话;false 则跳过 |
| legacyPresets | true | 为那些新 dsh 缺少其预设的会话添加默认预设的旧版副本;false 则改为停止升级 |
| telegram | 关闭 | {envFile?, tokenVar?, chatVar?} |
跟踪的内容
无论 .gitignore 如何设置,该插件仅记录并恢复以下文件:
.gitignore settings.yaml AGENTS.md cordis.patch.yml .agent-presets/*
profiles//{package.json,pnpm-lock.yaml,pnpm-workspace.yaml,cordis.yml,cordis.patch.yml}
(node_modules、.bak 和 .tmp- 始终被排除。)当该插件创建仓库时,它会写入一个匹配的白名单 .gitignore,以便 git status 保持可读;现有的仓库和 .gitignore 会原样采用,并且所有者在列表之外提交的任何内容都不会被回滚。
快照从不运行 git add。每个文件只读取一次、扫描一次,并且提交的正是这些字节,因此看起来包含字面密钥的文件,或超过 2 MiB 的文件,会保留其最后记录的版本,并且永远不会进入 git 的对象存储。当回滚替换一个当前内容不在历史记录中的文件时(例如因密钥而被跳过的文件),会先将副本放入 $DSH_HOME/safe-upgrade/restore-backups/。
安全说明
- 升级以运行 dsh 的用户身份运行(通常是 root)。HTTP 路由使用 dsh 自身的身份验证(connection.requestRejection)。当任何轮次正在运行或另一个作业持有锁时,升级和回滚会返回 409。
锁是以原子方式获取的,因此两个任务永远不会同时运行。
- 在 dsh 停止之前会再次检查空闲状态,因为暂存可能需要数分钟。dsh 没有稳定的方式让插件阻止新的轮次,因此在 systemctl stop 调用本身期间开始的轮次仍会被中断。
- 如果无法停止 dsh,任务会在任何安装或配置更改之前中止。
- dsh 作为非特权系统单元运行(设置了 User=):监督程序和启动守卫的恢复以同一账户运行,绝不以 root 身份运行(root 不得执行服务账户可写入的插件代码)。该账户随后需要有权管理自己的单元并启动临时的 dsh-safe-upgrade- 单元,例如使用下面这样的 polkit 规则(一个起点;此处未测试,此处 dsh 以 root 身份运行)。每当你更改单元的 User= 时,请重新运行 install-guard。
js
// /etc/polkit-1/rules.d/50-dsh-safe-upgrade.rules
polkit.addRule(function (action, subject) {
if (action.id === "org.freedesktop.systemd1.manage-units" && subject.user === "dsh") {
var unit = action.lookup("unit") || ""
if (unit === "dsh.service" || unit.indexOf("dsh-safe-upgrade-") === 0) return polkit.Result.YES
}
})
- 每个先前的安装副本的大小等于你的 dsh 安装大小(约 300 MB)。
默认保留两个。
- 回滚仅恢复被跟踪的配置。它绝不触及会话、凭据、附件或 $DSH_HOME 和安装目录之外的任何内容。
- testing: true 通过 API 启用故障注入(simulateFailure)。
在生产环境中请保持关闭。
在将真实安装从 0.1.5-rc.1 升级到 0.1.7-rc.2 时发现
这些正是检查的用途:
- 服务器看起来健康,但 Web UI 停止加载。 Smart-DSH 的 dsh-esc-stop 浏览器部分等待 settingsScope 服务,而 0.1.7 移除了该服务,因此页面停在“Failed to load plugins — dsh-esc-stop:
pending (waiting for service: settingsScope)”。每个宿主插件都
处于活动状态,因此只有 Web UI 检查能捕获此问题。它是在这次确切事件之后添加的,并已针对真实的 0.1.7 实例进行验证。
- patch: entry "agent-presets" not found:0.1.7 用 agent-preset-registry 和 preset- 行替换了基于目录的 agent 预设($DSH_HOME/.agent-presets/)。针对 agent-presets 的补丁会被静默忽略,并且自定义预设文件夹不再被读取。
- 旧对话无法继续。 会话仅在其记录时所用的预设下恢复,因此用 .agent-presets/standard-tools 文件夹创建的 94 个会话失败,并显示 Unknown agent preset: standard-tools,而 dsh 拒绝将已启动的会话切换到另一个预设。会话检查和旧版预设正是为此而存在(已在上游 discussion #8320 中报告)。
- 某些子代理记录完全无法打开。 写入于格式 v0 由 dsh 0.0.1-rc.1 到 0.1.1-rc.2 携带一条子代理记录, 0.1.5 及更高版本会拒绝(uses unsupported descriptor version 2)。会话检查会报告它们,但不会将其计入升级,因为正在运行的版本已经无法打开它们。
- [esc-stop] settings registration failed TypeError: settingsCtx.settings.register is not a function:
宿主设置 API 也发生了变化。为 0.1.5 构建的插件会记录此错误,而不是失败。
- 在首次启动时,0.1.7 将 settings.yaml 移动到已启动配置文件的 cordis.patch.yml 中(保留 settings.yaml.imported)。配置历史将其记录为一次“boot: config at startup”提交,回滚会恢复 settings.yaml。其他配置文件(例如 headless)不会获得导入的模型提供程序。
开发 bash
npm test # 单元测试套件:engine、repo、host、client、systemd、UI check
scripts/install-dsh.sh latest /tmp/dsh # 来自 npm 的真实 dsh,用于回归测试套件
DSH_E2E_INSTALL=/tmp/dsh DSH_E2E_UPGRADE_TO=next npm run test:e2e
这些测试将桩程序 systemctl、npm、systemd-run、journalctl 和 dsh 二进制文件放到 PATH 上。桩程序 dsh --dump-config 会像 0.1.7 那样写入 $DSH_HOME,因此测试证明验证过程绝不会触碰实际的主目录。
它们覆盖真实的升级、回滚和恢复代码路径,包括每个阶段的失败(半完成的交换、停止失败、并发任务、升级中途开始的一轮),而不会触碰正在运行的服务。
回归测试套件(tests/e2e/)不使用桩程序。它从 npm 启动一个真实的 dsh,并将此插件链接到一个一次性配置文件中,然后检查启动标记、已知良好标签、经过身份验证的路由、无头 Chrome 中的 Web UI 以及实时配置快照。
它证明 --dump-config 验证会让实时 $DSH_HOME 逐字节保持不变,并对到下一个 dsh 版本的真实升级(包括所有 npm 版本固定)进行试运行。
CI/CD
| 工作流 | 何时 | 做什么 |
| ci.yml | 每次推送和 PR | 约定式提交 lint、语法和包内容、在 Node 22 和 24 上的单元测试套件、针对 dsh latest 的回归测试套件 |
| e2e.yml | 每晚以及按需 | 针对 dsh latest(外加到 next 的试运行升级)和 next 的回归测试套件,以便在您升级之前捕获会破坏插件的 dsh 版本 |
| pr-title.yml | PR | PR 标题(压缩合并提交)是约定式提交 |
| release.yml | 推送到 main | release-please 维护一个包含下一个版本和变更日志的发布 PR;合并它会打上 vX.Y.Z 标签、发布 GitHub release 并附加 npm pack tarball |
Dependabot 保持工作流 action 为最新。
提交和发布
提交遵循 Conventional Commits: feat: 表示新功能(次要版本),fix: 表示错误修复(补丁), feat!: 或 BREAKING CHANGE: 页脚表示破坏性变更。docs:、test:、 ci:、refactor: 和 chore: 本身不会发布新版本。请使用压缩合并 PR,这样 PR 标题就会成为 main 上的提交。
没有人手动编辑版本号或 CHANGELOG.md:release-please 会在其发布 PR 中完成这两项操作。
当安装了无头 Chromium 时,UI 检查测试会驱动一个真实的无头 Chromium。
许可证
MIT。这是一个非官方社区项目,按原样提供,不附带任何担保(见 LICENSE)。与 DeepSeek 无关联。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
devopsfortunato/dsh-plugin-safe-upgrade
非官方社区插件。 它并非由 DeepSeek 或 DeepSeek Harnessdsh团队制作、认可或支持。它仅使用…
相关插件 · 其他
模型破甲清洗HunYiSage/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,993已汉化DeepSeek 客户端
73
女娲蒸馏alchaincyf/nuwa-skill
输入名人名字,提炼其思维模型与决策方式供你调用
★ 37,308已汉化DSH
72
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 888已汉化DSH
71.6
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,269已汉化DSH
70.8
这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。