前言¶
鴻蒙端的一次發版,通常串着一串不能出錯的動作:簽名檢查、版本號校驗、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