將儲存庫開源
為公開釋出準備儲存庫,使沒有先前背景的外部人員能夠建構、使用並貢獻其中,同時確保沒有任何敏感內容隨之釋出。請按順序逐步執行;秘密審計是第一步,因為其結果(保留或重建儲存庫)會影響後續所有步驟。
使用時機
- 將私人儲存庫設為公開
- 審計現有公開儲存庫的釋出品質(「使其正式化」)
- 為專案選擇授權條款
- 在公開釋出前設定打包、版本控制或發佈自動化
不使用時機
- 對已釋出專案的例行開發(無釋出事件)
- 審計第三方程式碼的安全性(請使用安全審查技能)
- 從將保持私有的儲存庫發佈套件 — 僅適用發佈管理步驟;跳過其餘部分
工作流程
步驟 1:偵測組織設定檔
bash {baseDir}/scripts/detect_org.sh
此腳本會檢查 git 遠端和最近的提交者電子郵件,並輸出設定檔名稱。如果輸出 trailofbits,請立即閱讀 references/trailofbits.md,並在後續步驟中套用其授權政策、發佈帳戶和流程注意事項。如果輸出 generic,則僅按照通用指引進行。如果使用者表示偵測結果錯誤,請信任使用者。
步驟 2:審計秘密 — 優先於其他所有步驟
一個曾經包含秘密(API 金鑰、憑證、客戶資料)的儲存庫不應該被設為公開。重寫歷史容易出錯,且無法涵蓋分支、快取或 CI 工件。可靠的解決方案是建立一個全新的儲存庫:複製當前目錄樹、提交,並將舊儲存庫私下歸檔。
- 詢問專案是否曾處理過秘密或客戶機密資料。對於安全顧問公司的工具,也請詢問測試用數據或範例資料是否來自客戶專案。
- 使用專用工具掃描完整歷史記錄(若可用)— 例如
gitleaks git .或trufflehog git file://.,而不是僅靠肉眼檢查。 - 檢查 Git 樹以外的部分:GitHub Actions 日誌和工件、舊版本、問題和 PR 歷史,以及儲存庫 Wiki,這些都會隨著儲存庫公開而公開。
- 公開後,在儲存庫設定中啟用 GitHub 秘密掃描與推送保護。
拒絕以下合理化理由 — 這是唯一一個在發佈後無法修正的步驟:
- 「金鑰已撤銷,所以歷史記錄沒問題。」 已撤銷的憑證仍會洩漏基礎設施名稱、內部 URL 以及攻擊者用於鎖定目標的模式。
- 「我們會用 git-filter-repo 重寫歷史。」 重寫會遺漏分支、克隆、快取和 CI 工件;而全新儲存庫的做法則不會。
- 「這只是測試資料。」 從客戶專案或生產系統衍生的測試固定資料,無論如何標示,都是機密的。
步驟 3:執行就緒檢查
bash {baseDir}/scripts/check_readiness.sh
此腳本會輸出存在性檢查清單(README、LICENSE、CONTRIBUTING、SECURITY.md、CI、測試、semver 標籤等),並警告追蹤到的檔案中常見的機密內容。將未勾選的項目視為討論提示,而非強制失敗 — 研究原型不需要旗艦級庫所需的一切。與使用者逐一檢視差距,並修正對該專案重要的項目。
步驟 4:文件
README 是專案的門面。請確認它說明了:
- 專案是什麼以及它解決了什麼問題(第一段)
- 如何安裝 — 套件管理器、容器映像或從原始碼建構;全新克隆的建構必須僅使用儲存庫內的內容就能成功
- 如何使用 — 至少一個具體、可複製貼上的範例
- 如何貢獻 — 內嵌或透過
CONTRIBUTING.md - 授權條款 — 簡短說明其名稱
另外加入:
SECURITY.md附上漏洞回報說明(聯絡信箱或 GitHub 私有漏洞回報)。對於安全工具來說,這是基本要求。- API 文件,建構並託管(通常透過 CI 使用 GitHub Pages),並從 README 和儲存庫網站欄位連結。請參閱下方語言參考以了解各生態系的文件工具。
- 若專案預期有外部貢獻者,則需要一份行為準則。
步驟 5:授權
沒有授權條款就代表不是開源,無論其可見性如何。請閱讀 references/licensing.md 以了解選擇標準和實作細節。簡短版本:
- 若步驟 1 中偵測到組織政策,則套用該政策。
- 否則:預設使用 Apache 2.0 作為寬容授權,當競爭者私下修改確實是考量時使用 AGPLv3,非程式碼工件則使用 Creative Commons。
- 加入
LICENSE檔案,在套件中繼資料中設定 SPDX 識別碼,在 README 中說明授權條款,並確認三者一致。
步驟 6:測試與 CI
- 確認測試套件存在且通過;公開儲存庫若預設分支失敗,代表專案已被遺棄。
- 確保 CI 在每個 PR 上、在支援的語言版本和平臺矩陣中運行測試。
- 在 CI 中強制執行格式化和靜態分析(下方參考資料有各語言工具),讓樣式討論不會進入審查。
- 尊重現有工具。 不要在開源過程中更換現有的格式化工具、靜態分析工具或型別檢查器。若其落後於當代(語言參考會列出當前工具),請警告維護者並讓他們決定;僅在完全缺少某一類別時(沒有型別檢查器、沒有格式化工具)才加入當前預設工具。
- 考慮設定覆蓋率門檻,使 CI 在覆蓋率下降時失敗。
- 在工作流程本身成為公開攻擊面之前,先強化它們:
- 將第三方 Action 固定到完整的提交 SHA;啟用
github-actions的 Dependabot 以保持固定版本更新。 - 設定最小權限的
permissions:區塊(從permissions: {}開始)。 - 使用
zizmor .github/workflows/進行審計,並使用actionlint進行語法檢查。
- 將第三方 Action 固定到完整的提交 SHA;啟用
步驟 7:儲存庫設定
- 分支保護 在預設分支上:禁止強制推送、需要 PR。新儲存庫優先使用規則集;經典分支保護仍受支援。
- 合併保護:需要狀態檢查,讓 PR 不能在測試失敗時合併。
- Dependabot 或 Renovate 用於依賴項和 Actions 更新。合併更新以減少 PR 噪音,並設定冷卻窗口(例如 7 天),使剛發布且偶爾被劫持的版本在採用前經過一段時間。
.editorconfig讓貢獻者的編輯器在空白字元基礎上達成一致。- 標籤:當需要超過一個 issue 或 PR 時就建立標籤;使用前綴的構面(facet)可良好擴展(
C:元件,P:平台)。請參閱 blight 的標籤 作為實例。
步驟 8:版本與發佈
- 每個版本以
vX.Y.Z標記,遵循 semver;使用-rc.N/-pre.N後綴表示候選版本和預發佈版本。 - 讓發佈由 CI 驅動:推送標籤(或發佈 GitHub Release)會觸發建構、打包和上傳,無需手動步驟。發佈應為
git tag vX.Y.Z && git push origin vX.Y.Z。 - 使用組織擁有的帳戶發佈套件,而非個人帳戶,並在套件索引支援的地方使用信任發佈(OIDC)而非長期令牌。
步驟 9:語言特定實作
根據專案的標記檔案識別其語言,並閱讀對應的參考文件以了解打包、發佈和品質工具:
| 標記檔案 | 參考文件 |
|---|---|
pyproject.toml, setup.py | references/python.md — 將工具部分委託給現代 Python 技能 |
CMakeLists.txt, Makefile (C/C++) | references/c-cpp.md |
Cargo.toml | references/rust.md |
go.mod | references/go.md |
package.json | references/javascript.md |
Gemfile, *.gemspec | references/ruby.md |
對於其他生態系,請套用跨領域原則:從全新克隆中可重現建構、CI 驅動的發佈、信任發佈或組織擁有的帳戶,以及套件清單中的授權中繼資料。
最終審查
在切換可見性之前,請從外部人員的角度驗證:
- 克隆到一個乾淨的目錄,並逐字遵循 README 的建構說明 — 在沒有隱性知識的情況下是否能成功?
- 重新執行
{baseDir}/scripts/check_readiness.sh,並確認剩餘的差距是有意選擇的,並已告知使用者。 - 確認秘密審計(步驟 2)確實已執行;這是唯一一個在發佈後無法修正的步驟。
將儲存庫設為公開後,只需變更儲存庫設定。若組織有公告流程,請將發佈與公告一同進行。
其他資源
參考文件
- references/licensing.md — 授權選擇標準、SPDX 中繼資料、分支與重新授權
- references/trailofbits.md — Trail of Bits 政策覆蓋層(僅在步驟 1 偵測到時載入)
- references/python.md、references/c-cpp.md、references/rust.md、references/go.md、references/javascript.md、references/ruby.md — 各語言的打包、發佈與品質工具
腳本
scripts/detect_org.sh— 從 git 遠端和提交者電子郵件輸出組織設定檔(trailofbits或generic)scripts/check_readiness.sh— 輸出釋出就緒檔案的存存在性指示,並標記常包含機密內容的追蹤檔案