| name | npm-oidc-publish |
| description | 協助 subembed 專案進行基於 OIDC 信任發佈(Trusted Publishing)與 Rust 多平台二進位檔整合的自動化 npm 發佈技能。 |
NPM OIDC 信任發佈與 Rust CLI 包裝整合技能 (NPM OIDC Publish & Rust Wrapper Skill)
本技能 (Skill) 專為 subembed 專案(一個包裝 Rust CLI 的輕量級 npm 套件)設計,用於指導與執行基於 GitHub Actions、OIDC 信任發佈 (Trusted Publishing) 的全自動二進位檔編譯與 npm 套件無密碼安全發佈。
🎯 適用場景與觸發時機
當需要進行以下操作時,AI Agent 應立刻調用此技能:
- 升級版本並準備發佈新版本(例如從
0.1.1 升級到 0.1.2)。
- 排查與修復 npm 發佈工作流 (CI/CD)。
- 優化 GitHub Actions 執行效率或編譯速度。
- 解決 OIDC(OpenID Connect)驗證或 TLS 握手失敗。
🏗️ 核心架構與生命週期 (Architecture & Lifecycle)
subembed 的核心特色是輕量化的包裝套件,其 npm 套件本身不含厚重的編譯代碼,而是透過 postinstall 腳本向 GitHub Release 下載對應作業系統的預編譯 Rust 二進位檔案。
因此,發佈時存在強烈的雙向依賴關係:
- 發佈 npm時,必須確保 GitHub Release 上的 4 平台執行檔已被編譯並成功上傳,否則
prepublishOnly 的安全檢查腳本(prepublish-check.cjs)會失敗,拒絕發佈,防止發佈一個損壞的 npm 套件。
- 安裝 npm 時,不需再透過 Rust toolchain 本地編譯,大幅提升使用者的安裝速度與相容性。
1. 全自動發佈拓撲圖 (Automation Topology)
graph TD
A[本地推送版本標籤 vX.Y.Z] --> B[1. 觸發 release.yml 工作流]
B --> C[建立 GitHub Release]
C --> D[編譯 4 平台 Rust 執行檔]
D --> E[計算 .sha256 並上傳 8 個資產至 GitHub Release]
E --> F[2. 執行 publish-npm 任務]
F --> G[執行 npm install -g npm@latest 與 Node 24 環境]
G --> H[執行 prepublish-check.cjs]
H -->|透過 36 次 HEAD 請求,輪詢 Release Assets 存在性| I[安全校驗通過]
I --> J[OIDC 握手取得 npm 10 分鐘一次性 Token]
J --> K[成功無密碼發佈至 npmjs.com]
⚡ 實戰踩坑紀錄與終極優化 (Lessons Learned & Optimizations)
在建置此專案的 CI/CD 過程中,我們踩過了兩大深坑,並成功實施了頂級的工程優化。未來遇到類似錯誤時,必須以此最優方案為基準進行診斷:
🚨 痛點一:NPM OIDC 握手失敗與誤導性的 404 錯誤
🚨 痛點二:macos-13 實體伺服器停用導致佇列卡住
🚨 痛點三:Cargo.lock 版本未同步導致編譯失敗
🚨 痛點四:釋出二進位檔與 npm 發佈必須合併於單一工作流 (Single Workflow Integration)
- 異常狀況 / 痛點:
若將「編譯釋出(
release.yml)」與「發佈至 npm(npm-publish.yml)」拆分為兩個工作流(或使用 Reusable Workflows 呼叫):
- OIDC 信任關係配置複雜化:在 npm 官網設定 Trusted Publishing 時,若使用 Reusable Workflows,權限宣告與 Token 交換的來源工作流名稱(OIDC 聲明中的
job_workflow_ref)不易對齊,容易導致 OIDC 握手失敗或 403 拒絕發佈。
- 資產依賴與時序競態條件 (Race Condition):npm 的
prepublish-check.cjs 需要確認 4 平台二進位檔已上傳至 GitHub Release。若兩者分屬不同工作流,通常需依賴事件觸發(如 release: published),這容易遇到 GitHub API 更新延遲或資產尚未完整上傳的競態問題,導致發佈失敗。
- 最佳實踐與解決方案:
強烈建議將兩者合併為單一工作流(
release.yml),並利用作業依賴關係(needs: build-and-upload)進行順序調度:
- 優勢 1:npm Trusted Publishing 的 Workflow 欄位只需簡單配置為單一的
release.yml,避免複雜的多檔案權限授權錯誤。
- 優勢 2:透過
needs 依賴關係,確保 100% 編譯成功且資產完整上傳後才啟動發佈,徹底解決時序 race condition。
- 優勢 3:發佈若失敗,可透過 GitHub 介面一鍵
Re-run failed jobs 單獨重試發佈作業,維護性極佳。
🛠️ 首次發佈「冷啟動」指南 (First-Time Cold Start Guide)
[!IMPORTANT]
「雞生蛋、蛋生雞」難題:
在尚未將套件首次手動發佈至 npmjs.com 之前,您無法在 npm 後台為此套件設定 OIDC Trusted Publishing。
同時,若您直接用 CI 自動發佈,因為此時還沒有 OIDC 權限,發佈必然會被 npm 拒絕。
因此,首次發佈必須遵循以下三階段「冷啟動」流程:
第一階段:全自動跳過 OIDC 的 Release 建立
當您本地推送第一個 Tag v0.1.0 時,.github/workflows/release.yml 中配置了智慧控制參數 (Trigger Parameters)。
在 Publish package 步驟中:
if: ${{ !startsWith(github.ref_name, 'v0.1.0') }}
- 運作機制:偵測到 Tag 名稱為
v0.1.0 開頭時,自動發佈流程會全自動安全跳過,只建立 GitHub Release 並上傳二進位檔案,而不嘗試向 npm 發佈。
第二階段:本地首次手動發佈
當第一階段自動上傳 4 平台二進位檔至 GitHub Release 成功後,您可以在本地進行首次手動發佈:
- 登入您的個人 npm 帳號:
npm login
- 手動執行發佈:
npm publish
註:此時本地的 prepublishOnly 會執行 prepublish-check.cjs。由於第一階段的資產已存在於 GitHub Release,檢查會順利通過!
第三階段:設定 Trusted Publishing 與驗證後續發佈
- 進入 npmjs.com/package/subembed。
- 進入 Settings > Publishing > Trusted Publishing。
- 新增 GitHub Publisher:
- GitHub Owner:
doggy8088 (或您的組織帳號)
- Repository:
subembed
- Workflow Name:
release.yml
- Environment: (留空)
- 驗證全自動發佈:
📋 後續版本發佈標準流程 (Standard Release Runbook)
當專案已經完成「冷啟動」,後續發佈新版本(如 0.1.2)時,只需執行以下零配置步驟:
- 更新專案版本與日誌:
- 在
package.json 與 Cargo.toml 中,將 "version" 修改為 "0.1.2"。
- 在
CHANGELOG.md 中紀錄變更。
- 重要:在本地執行
cargo build 以確保 Cargo.lock 被自動同步更新為新版本。
- 提交並推送到主分支:
git add package.json Cargo.toml Cargo.lock CHANGELOG.md
git commit -m "chore: bump version to 0.1.2"
git push origin main
- 推送版本 Tag 觸發全自動 CI:
git tag v0.1.2
git push origin v0.1.2
- 監控 GitHub Actions:
Release 工作流會自動開始編譯。
- 待編譯與上傳完成後,
publish-npm 任務將被觸發,透過 OIDC 全自動、無痛地將新版本釋出到 npmjs.com。
🔍 常見排查與手動干預 (Troubleshooting)
1. GitHub Actions 已成功釋出 Release,但 npm 發佈失敗或超時
- 原因:可能 GitHub Release 的資產上傳較慢,超過了
prepublish-check.cjs 的等待極限,或者 OIDC 握手臨時失敗。
- 解決方案:
進入 GitHub Actions 的
Release 工作流執行頁面,點選右上角的 Re-run failed jobs 重新執行 publish-npm 任務。
2. CI 遇到 cannot update the lock file because --locked was passed 錯誤
- 原因:更新了
Cargo.toml 中的版本號,但在提交/推送前沒有在本地執行 cargo build 更新 Cargo.lock。
- 解決方案:在本地執行
cargo build,將變更後的 Cargo.lock 提交並 push 到主分支,然後重新 tag 發佈。
[!NOTE]
本 Skill 定義了 subembed 專案高安全、極速編譯的發佈基石。未來不論是更換 CI 伺服器或調整部署,皆應嚴格遵循 OIDC 無密碼安全性規範。