前言¶
鸿蒙端的一次发版,通常串着一串不能出错的动作:签名检查、版本号校验、release 打包、Bugly 符号表上传、AppGallery Connect(AGC)上传、最后提交审核。把这套流程交给 DSH Agent 直接跑,风险点很明显——它要读证书和密钥,还要往 AGC 的线上写入(上传包、提审)动手,一旦参数被模型编错,代价不低。
已有的做法是把这些步骤写成脚本,或者做成 Codex skill(harmony-agc-publish),凭据放在项目里的 .agc_env / .bugly_env。模型拿到的是无差别的执行权限。这个插件做的是在这两者之间加一层:沿用 skill 的流水线,但把凭据收进 DSH 凭据库,把写线上的动作全部收回人工审批,并把每一步的变化落成审计日志。
下面介绍 angchow/xrxs-dsh-harmony-publish,由 AngChow 维护,社区目录归类为 admin-security,目录页显示星标 0,当前版本 0.2.1,许可证 MIT,只支持 macOS。
这是什么¶
一个 DeepSeek Harness(DSH)插件:把 harmony-agc-publish Codex skill 的鸿蒙发布流水线(签名检查 → 版本校验 → devecocli 打包 → Bugly 符号表 → 上传 AGC → 提审)以安全、可审计的方式暴露给 DSH Agent。
它不新建一套流程,而是把 skill 里已经跑通的步骤映射成插件内的工具和脚本,再在外面套上凭据解析、环境隔离、脱敏和审批。插件附带一个客户端半身,在桌面端 / Web 端把 5 个工具渲染成发布卡片,页面上直接看到产品、发布模式、七步进度和警告。
前置条件:目标 DSH 版本 >=0.2.0-rc.1 <0.3.0-0(来自 engines.dsh);平台 macOS(AGC 上传与提审仅限 darwin);构建依赖 devecocli。它与 xrxs-dsh-android-publish 共用同一套安全模型与工具形状,便于两端并行维护。
发布模式与写入面¶
三个 mode,写入面逐级扩大:
| mode | 行为 | 写入面 |
|---|---|---|
buildOnly |
签名检查 + 构建 + Bugly 符号表 | 仅本地 + Bugly |
upload |
上述 + 版本校验 + 上传 AGC 软件包 | 加 AGC 草稿态 |
submit |
上述 + app-submit 提审 |
加 AGC 线上审核流程 |
默认 allowedModes 只有 buildOnly 和 upload,submit 需要显式打开。这意味着即使模型拿到了启动工具,没有配置授权也不会走到提审。
五个工具与客户端界面¶
插件注册给模型的工具如下:
| 工具 | 用途 |
|---|---|
harmony_publish_doctor |
体检:Python/requests、Java、devecocli、工程结构、发布证书与 Profile、Bugly jar、凭据配置状态(只报状态,永不报值) |
harmony_publish_plan |
生成确定性发布计划(校验模式/工程/路径/凭据,不执行) |
harmony_publish_preflight |
跑 pre_check.py(签名状态 + 在架版本对比),不构建不上传 |
harmony_publish_start |
启动构建/上传/提审后台任务;upload 与 submit 都走审批卡片 |
harmony_publish_status |
非消费式读取任务状态与脱敏输出 |
status 工具读的是子进程返回的 steps,可以把「预检 → 签名 → 版本号 → 构建 → Bugly 符号表 → 上传 AGC → 提交审核」七步的完成、失败、跳过状态还原出来。卡片数据走 output.presentationMeta 的结构化通道,客户端读 block.meta,不解析模型可见文本;旧会话里没有 meta 时回退展示原文本。审批卡片仍由宿主 userQuestions 渲染(plan-review),插件只负责标题与正文。
安装¶
桌面版 DSH 推荐走插件管理器:把仓库目录,或 Releases 里的 xrxs-dsh-harmony-publish-<version>.tgz,交给 DSH 的插件安装入口即可。profile 的 package.json / cordis.patch.yml 由安装动作维护,不要手写。
需要自行构建时:
pnpm install
pnpm run build # 产物在 lib/,不入库
pnpm pack # 生成 xrxs-dsh-harmony-publish-<version>.tgz
命令行方式直接按本地绝对路径添加插件:
dsh plugin --profile <name> add /absolute/path/to/xrxs-dsh-harmony-publish
dsh --profile <name> --dump-config # 检查组合
有一点必须注意:@deepseek-ai/dsh-* 绝不能出现在本插件的 dependencies 里,它们由宿主提供。一旦被复制进 profile 的 node_modules,进程内会出现两份工具调度器 Symbol,该实例下所有工具调用都会失败。
配置¶
plugin 的配置文件写在 profile 覆盖层,按 id 整行覆盖(整对象替换,不是深合并)。下面是 README 里的示例,其中的 projectRoot、bundleName、keystore 与 JAVA_HOME 路径是作者本机的样子,按自己工程替换:
- id: xrxs-harmony-publish
name: xrxs-dsh-harmony-publish
config:
pythonExecutable: /opt/homebrew/opt/python@3.11/libexec/bin/python3
profiles:
xrxs-harmony:
displayName: 薪人薪事 鸿蒙
projectRoot: /Users/ang/workspace_codex/mobile_harmony
productName: default
bundleName: com.client.xrxs.app
allowedModes: [buildOnly, upload, submit]
allowSubmit: false
symbolPolicy: optional
requireManagedCredentialSource: true
appArtifactGlob: "**/build/outputs/**/*-signed.app"
credentialRefs:
AGC_CLIENT_ID: HARMONY_PUBLISH_XRXS_AGC_CLIENT_ID
AGC_CLIENT_SECRET: HARMONY_PUBLISH_XRXS_AGC_CLIENT_SECRET
BUGLY_APP_ID: HARMONY_PUBLISH_XRXS_BUGLY_APP_ID
BUGLY_APP_KEY: HARMONY_PUBLISH_XRXS_BUGLY_APP_KEY
plainEnv:
AGC_APP_ID: "109600000000000000"
DEVECO_CLI: /opt/homebrew/bin/devecocli
HARMONY_KEYSTORE_DIR: /Users/ang/develop/keystore/harmony
HARMONY_RELEASE_PROFILE: /Users/ang/develop/keystore/harmony/发布Profile/Release_Profile.p7b
HARMONY_RELEASE_CERT: /Users/ang/develop/keystore/harmony/发布证书/薪人薪事发布证书.cer
JAVA_HOME: /Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home
几个配置项的含义:
allowSubmit:提审总开关,默认false,需要提审时才改成true,改后工具会强制弹审批卡。symbolPolicy:required= 符号表上传失败/缺失即中断;optional= 失败只警告;disabled= 完全跳过。默认optional。allowedModes:允许的发布模式。requireManagedCredentialSource:默认true,即要求凭据来源为托管库file。
允许写进 plainEnv 的键只有这 8 个:AGC_APP_ID、DEVECO_CLI、DEVECO_HOME、HARMONY_KEYSTORE_DIR、HARMONY_RELEASE_PROFILE、HARMONY_RELEASE_CERT、BUGLY_JAR_PATH、JAVA_HOME。密钥形变量不允许出现在这里,只能通过 credentialRefs 指向 DSH 凭据库:
version: 1
refs:
HARMONY_PUBLISH_XRXS_AGC_CLIENT_ID: "..."
HARMONY_PUBLISH_XRXS_AGC_CLIENT_SECRET: "..."
HARMONY_PUBLISH_XRXS_BUGLY_APP_ID: "..."
HARMONY_PUBLISH_XRXS_BUGLY_APP_KEY: "..."
默认托管库路径是 ~/.dsh/.credentials.yaml。也支持 ~/.dsh/.env 作为只读兜底层,但 requireManagedCredentialSource: true 时提审要求来源为托管文件(file)。配完调用 harmony_publish_doctor,可以看到每个 ref 是否 configured,不会显示值。
典型用法¶
README 给的调用顺序是体检 → 预检 → 启动 → 轮询:
1、harmony_publish_doctor { profileId } —— 确认 Python/Java/devecocli/证书/凭据都到位。
2、harmony_publish_preflight { profileId } —— 确认签名状态与「本地版本 > 在架版本」,这一步不构建也不上传。
3、harmony_publish_start { profileId, mode, remark } —— 审批后启动后台任务。
4、harmony_publish_status { jobId } —— 轮询进度与脱敏日志。
mode: submit 时用户必须在审批卡片上点「确认提审」;拒绝的话不会有任何 AGC 写操作。
老脚本(resources/scripts/ 下的 Python 脚本)也可以脱离插件当独立 CLI 使用,此时 load_agc_env() / load_bugly_env() 仍会读项目里的 .agc_env / .bugly_env;插件驱动时插件侧始终设置 HARMONY_PUBLISH_DISABLE_PROJECT_ENV=1,脚本遇该变量直接返回,明文凭据不可达。
脚本退出码是固定的,可以直接用于判断卡在哪一步:
| 脚本 | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
pre_check.py |
通过 | 存在阻塞问题 | AGC 查询失败 | — |
check_version.py |
本地 > 在架 | 版本未升级 | AGC 查询失败 | — |
check_signing.py |
已是发布 / 已切换 | 无法安全切换 | — | dry-run 且需要切换 |
build_and_submit.py |
全流程成功 | 某步失败 | submit 安全锁未满足 | — |
submit_review.py |
提交成功 | 提交失败 | 安全锁未满足 | — |
安全模型¶
几个关键设计,写插件配置前值得逐条看一遍。
1、凭据零暴露。AGC_CLIENT_ID / AGC_CLIENT_SECRET / BUGLY_APP_ID / BUGLY_APP_KEY 只在每次操作时经 DSH 凭据库解析(credentialRefs → ref 名),只注入子进程环境,模型可见输出、任务缓冲、审计日志全部经过精确子串脱敏。凭据值永不出现在 argv 中。
2、模型不能传任意旗标或凭据。环境键走白名单,secret 形只能走 credentialRefs,其余走 plainEnv;--skip-*、--i-know-this-submits-to-production、HARMONY_CONFIRM_SUBMIT=YES 全部由 profile 策略与审批结果推导,不由模型直接指定。
3、三道闸门。提审需要 allowSubmit: true + 预检查通过 + 用户在审批卡片点选「确认提审」,任一缺失则什么都不启动。提审安全锁为 --i-know-this-submits-to-production 加 HARMONY_CONFIRM_SUBMIT=YES,与 skill 同构,变量名前缀改为 HARMONY。
4、签名切换 fail-closed。只在能精确定位目标 product 的 signingConfig 时改写 build-profile.json5,无法安全定位就报错交人工,storeFile(.p12)永不修改。
5、审计。<runtimeDir>/audit.ndjson 记录 preflight / start / approval_denied / complete / failed / cancelled。
与 Codex skill 的差异¶
梳理一下,避免照搬 skill 的习惯:
- 凭据从 DSH 凭据库注入,插件模式下不读
.agc_env/.bugly_env。 - 签名检查拆成「只读判定」(
pre_check.py)与「可写切换」(check_signing.py)两步,pre_check.py绝不改文件。 - 双签名配置只改目标 product 的
signingConfig,多个 product 共用调试配置名时也安全。 - Bugly jar 查找顺序:
BUGLY_JAR_PATH→resources/tools/→~/.dsh/harmony-publish/tools缓存 →BUGLY_JAR_SEARCH_DIRS(冒号分隔,可指向 Codex skill 的tools/)→ 下载(BUGLY_JAR_URL可覆盖)。官方下载链接会失效,建议本机放一份 jar 到缓存目录。 symbolPolicy: required时,「没有任何符号表可上传」也算失败(fail-closed)。
目录结构上,src/ 是宿主插件实现(工具注册、凭据解析、脱敏、任务),resources/python/plugin_runner.py 是子进程脱敏包装器,resources/scripts/ 是可独立 CLI 运行的发布脚本,locale/{en,zh}.json 是插件管理器的显示元数据,测试在 tests/ 下用 vitest。
适用场景与注意¶
适合已经在用 DSH、想把鸿蒙发版交给 Agent 但不想让它直接拿着明文凭据写线上的人。也适合 Android 侧在用 xrxs-dsh-android-publish、希望两套平台保持同一安全模型和工具形状的团队。
需要注意的地方:
- 插件以当前 dsh 进程的权限运行,安装前先读源码并确认许可证(MIT),别盲装。
- 环境只支持 macOS,构建依赖
devecocli,Java、Python/requests、keystore 路径都要事先就位,用harmony_publish_doctor自检。 - 提审是本插件唯一动线上数据的操作,把
allowSubmit保持false是常态,只有在确认要走提审时才打开。 - 升级宿主 DSH 版本后需要重新
pnpm build生成lib/client.js,否则客户端卡片可能与新宿主不匹配。 - 目录页显示星标 0,属于新仓库,采用前建议自己跑一遍
vitest和本地buildOnly流程。
结尾¶
这个插件的价值不在新增功能,而在给已有发布脚本加了一层护栏:凭据进库不进 argv,写线上动作必须过审批,每一步都有审计;同时保留了 skill 原有的流程和退出码语义。配置是一次性的,之后就可以用工具串起体检、预检、启动、轮询四步。
目录页:https://www.skillhub.cn/plugins/AngChow/xrxs-dsh-harmony-publish
GitHub:https://github.com/AngChow/xrxs-dsh-harmony-publish