尧图精选

Qwen Code Desktop 发布加固实战:原子运行时替换、官方校验和验证与发布物白名单

🕒 发布时间:2026/9/13 2:53:52 📁 来源:尧图网络
Qwen Code Desktop 发布加固实战原子运行时替换、官方校验和验证与发布物白名单【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读Qwen Code Desktop 是围绕 Web Shell 构建的 Tauri 2 桌面外壳其发布流程最脆弱的地方在于捆绑 Node.js 运行时、打安装包、签名、上架更新源、镜像到 OSS 的每一步都可能因为中断、篡改或误传而产出不可用、不安全甚至版本回退的制品。本文基于仓库中的设计文档 desktop-release-hardening.md逐条讲解其发布加固契约——从「旧运行时保留到新运行时完全组装完成」的原子替换到「以官方校验和复核 Node.js 归档」「仅发布安装器/更新器产物」「预发布必须带 SemVer 后缀」「OSS 镜像与 GitHub 稳定源联动校验」等落地实现并结合 prepare-runtime.js、test-release.js 与 desktop-release.yml 给出源码级依据。读完你将掌握一套可直接复用的桌面应用发布加固模式。一、加固目标五个必须守住的发布契约设计文档将 Desktop 发布的加固要求归纳为五条核心契约保留最后的完整捆绑运行时直到替代品完全组装完成交换被中断时下一次运行要能恢复旧运行时Node.js 归档必须用官方新鲜校验和fresh official checksum复核后复用只发布安装器 / 更新器产物发布的预发布版本必须带 SemVer 预发布后缀保证后续稳定版在更新器视角下严格更新。后两条之外稳定版发布还需先将版本化资产镜像到阿里云 OSS再推进 OSS latest 清单正常发布运行时若 GitHub 稳定源与刚发布的版本不一致则直接失败手动回填旧版本不得改动 latest 源。下面逐一展开这五条契约在仓库中的具体实现。二、运行时原子替换与中断恢复Desktop 的运行时会整体组装到packages/desktop-shell/runtime/qwen-code/包含当前平台的 Node.js 运行时、捆绑的qwenCLI以及构建好的 Web Shelllib/web-shell/。由于该目录会被 Tauri 应用直接消费替换过程必须保证任意时刻都存在一个完整可用的运行时。2.1 先组装、后替换的两阶段提交prepare-runtime.js 的流程本质上是「两阶段提交」在runtime/下用fs.mkdtempSync创建临时目录.prepare-*在其中完成全部组装拷贝dist产物到lib/、安装 Node 运行时、写启动脚本、写入 [LICENSE / NOTICE / manifest.json]、最后调用writeChecksums()生成 checksums.json组装与校验全部通过后才调用replaceRuntime()做目录切换若runtime/qwen-code已存在先rename为.prepare-*/previous再把新组装好的packageRootrename为runtime/qwen-code一旦切换失败回滚把previous再rename回来然后重新抛出错误。关键顺序被测试显式钉死testDesktopReleaseHardening断言replaceRuntime();必须出现在writeChecksums();之后见 test-release.js即「先完成组装与校验再替换」。2.2 中断恢复recoverInterruptedRuntime如果替换发生在两次rename之间例如进程被杀旧运行时可能滞留在.prepare-*/previous中。prepare-runtime.js在每次运行开头调用recoverInterruptedRuntime()扫描runtime/下所有.prepare-*目录若runtime/qwen-code不存在且该目录内存在previous则把previous还原为runtime/qwen-code无论是否还原都清理掉残留的.prepare-*目录。对应测试场景在testRuntimePreparation中构造「complete-marker 文件 .prepare-stranded/previous」的滞留现场并让下一次准备失败断言 marker 内容仍被保留、残留的.prepare-*目录被清空test-release.js。这保证了任何一次失败的准备都不会把用户机器上的 Desktop 运行时弄丢。三、Node.js 归档官方校验和验证 可复用缓存捆绑 Node.js 的下载、校验与缓存逻辑位于installNodeRuntime()prepare-runtime.js。3.1 版本一致性门禁脚本读取仓库根目录的.nvmrc要求当前 Node 版本的主版本号与之匹配否则直接报错Node ${nodeVersion} does not match .nvmrc major version。CI 中对应NODE_VERSION: 22.20.0desktop-release.yml。这避免在不同 Node 主版本下产出运行时导致行为漂移。3.2 每次都对官方 SHASUMS256.txt 做校验与「信任本地缓存」不同加固后的逻辑是每次下载https://nodejs.org/dist/v${version}/SHASUMS256.txt120 秒超时先删除缓存目录里的旧SHASUMS256.txtfs.rmSync(path.join(cacheDir, SHASUMS256.txt), { force: true })保证永远用官方新鲜校验和比对若本地缓存归档存在先复制出来用本次校验和验证通过则直接复用copyValidCachedArchive验证失败则删除缓存并重新下载重新下载的归档必须通过verifyChecksum()SHA-256 比对见 prepare-runtime.js通过后才写入缓存目录先写.tmp再rename避免半截文件污染缓存。缓存目录可通过环境变量QWEN_DESKTOP_NODE_CACHE_DIR指定默认在系统临时目录的qwen-desktop-node-cache/。CI 中使用actions/cache以键desktop-node-v2-${rust_target}-${NODE_VERSION}-${dry_run}持久化该目录并保证 restore 与 save 共用同一路径desktop-release.yml、test-release.js。testRuntimePreparation用 mock fetch 完整验证了三态首次下载并落缓存、二次运行命中缓存、缓存被篡改后自动回退重新下载断言 fetch 日志中归档下载次数为 2、SHASUMS256.txt 为 3 次且篡改后缓存目录里不再残留 SHASUMS256.txt见 test-release.js。3.3 平台目标与归档命名目标平台由QWEN_DESKTOP_TARGET或process.platform-arch推导支持darwin-arm64、darwin-x64、linux-arm64、linux-x64、win32-x64五种含 rust target 别名映射。归档名对应为node-v${version}-${target}.tar.gz|tar.xz|zipprepare-runtime.js。四、发布物白名单只发布安装器与更新器产物「只发布安装器/更新器产物」的约束落在两处版本门禁与资产收集过滤。4.1 资产收集阶段的严格过滤build作业收集 bundle 产物时desktop-release.yml按平台执行白名单casemacOS只收集.dmg、Qwen-Code-Desktop-*.zip、.app.tar.gz含对应.sig并做重命名Qwen-Code-Desktop-$LEGACY_ARCH.dmgWindows只收集*-setup.exe与*-setup.exe.sig其余一律continueLinux只收集*.AppImage、*.AppImage.sig、*.deb、*.deb.sig。测试显式断言Windows 收集分支不得包含通用*.exe防止把嵌入的可执行文件误传且必须保留*-setup.exe.sig签名文件test-release.js。收集结束后若无任何产物则::error::No desktop artifacts were produced.直接失败。4.2 更新清单生成与签名强制发布阶段用 create-desktop-update-manifest.mjs 生成desktop-latest.json含各平台 URL 与签名并用sha256sum -- * SHA256SUMS.txt汇总校验。testUpdateManifest验证清单覆盖darwin-aarch64 / darwin-x86_64 / linux-x86_64 / windows-x86_64四个平台且任一平台缺少.sig时脚本必须以Missing updater signature失败test-release.js。Tauri 更新器端点配置为 OSS 优先、GitHub 兜底tauri.conf.jsonRust 侧更新检查超时固定为 3 秒UPDATE_CHECK_TIMEOUT见 main.rs 与 test-release.js。五、版本门禁预发布必须带 SemVer 后缀版本解析在prepare作业的Resolve version步骤desktop-release.yml版本必须匹配^[0-9]\.[0-9]\.[0-9]([-][0-9A-Za-z.-])?$若prereleasetrue版本必须带-开头的预发布后缀如0.2.1-rc.1否则报错退出——这是防止「预发布复用了稳定版版本号、导致后续稳定版在更新器眼里不更新」的关键非 dry-run、非 draft、非 prerelease 的已发布稳定版则必须恰好是X.Y.Z纯三段式。对应断言见 test-release.js。桌面版本的三处来源——packages/desktop-shell/package.json、src-tauri/tauri.conf.json、src-tauri/Cargo.toml——由 version.js 同步修改testVersionSynchronization验证三者一致。另外electron_bridge场景Electron 0.0.5 迁移到 Tauri 的一次性桥要求版本严格大于0.0.5防止桥接版本回退。六、稳定发布与 OSS 镜像的联动校验设计文档的后半部分聚焦稳定版发布与镜像的一致性。6.1 GitHub 稳定源只进不退Update stable updater feed步骤desktop-release.yml逻辑为下载desktop-latestrelease 上的desktop-latest.json校验其中版本必须是合法稳定版用sort -V比较「刚发布的版本」与「当前源版本」若当前源已更新正常流程输出 notice 并跳过不降级electron_bridge流程则直接报错退出只有刚发布版本是较新或相同时才--clobber上传新清单。6.2 先传 OSS 版本化目录再推 OSS latestOSS 镜像由独立工作流 sync-desktop-to-oss.yml 负责且只接受X.Y.Z稳定版与已发布的非 draft、非 prerelease 版本上传版本化资产scripts/upload-aliyun-oss-assets.js以desktop/v${VERSION}为前缀上传到 bucket默认qwen-code-assets验证版本化资产下载远端文件逐项sha256sum -c比对再推 latest比对刚上传的desktop-latest.json与 GitHub 稳定源版本——两者一致才推进 OSS latestGitHub 源已更新则 notice 跳过若源反而落后于刚发布版本且 source 为 artifact 场景则::error::GitHub stable feed is ...失败。这一「先版本化、后 latest」的顺序保证客户端在任何时刻指向的desktop-latest.json都指向已完整上传并验证过的资产杜绝「清单先到、文件未齐」的窗口。七、验证矩阵工作流契约、helper 与双重冒烟设计文档最后一条要求验证覆盖四类对象仓库均有对应实现验证对象位置覆盖内容发布工作流契约test-release.jstestDesktopReleaseHardening、testElectronBridgeWorkflow、testDesktopReleaseSigningWorkflow等预发布版本门禁、资产白名单、Node 缓存键、签名顺序、电子桥清单生成与歧义检测Desktop 发布 helpertestRuntimePreparation、testUpdateManifest、testElectronBridgeManifest、testVersionSynchronization、testResolveLogRoot/testSliceNewLog运行时两阶段提交与中断恢复、更新清单、版本同步、日志增量读取运行时冒烟smoke-runtime.js对runtime/qwen-code做完整性校验manifest 字段 checksums.json 全量 SHA-256随后以随机 token 启动qwen serve轮询/health与深健康/health?deeptrue再断言 Web Shell HTML 含div idroot/div打包产物冒烟smoke-packaged.js启动真实安装包可执行文件解析desktop-runtime.log等待就绪验证未认证导航边界Web Shell HTML 无需 token 可访问、API 路由保持 bearer 门禁且不得签发 cookiemacOS 上还校验打包运行时manifest.json的qwenCodeCommit与源码 HEAD 一致此外dry_run输入可让任何 fork 在不发布的前提下完整走一遍「构建运行时 → 打无签名安装包」的打包路径是文档中「dry-run installer build」的落地形式desktop-release.yml。八、小结可迁移的发布加固清单从这份设计文档与对应实现中可以提炼出对任何「捆绑运行时 更新器」类桌面应用的通用加固清单两阶段提交替换运行时临时目录组装 → 生成校验和 → 原子 renameprevious兜底回滚启动时清理滞留目录外部二进制一律以官方新鲜校验和复核缓存可复用但永不跳过校验缓存文件用「tmp rename」写入发布物按平台白名单收集安装器与签名文件.sig必须成对出现更新清单缺签名即失败预发布强制 SemVer 后缀稳定发布只进不退sort -V守卫镜像先版本化后 latest并用sha256sum回读远端文件做最终一致性验证契约级测试 双重冒烟 dry-run把工作流行为、helper 逻辑、运行时与打包产物分别纳入自动化验证。仓库中可直接对照阅读的入口设计文档 desktop-release-hardening.md、运行时准备 prepare-runtime.js、发布测试 test-release.js、CI 工作流 desktop-release.yml 与 sync-desktop-to-oss.yml。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →