Graphify Release 聚合¶
本檔角色:定義
open-4wd、open-4wd-pinning、open-4wd-signaling、open-4wd-turn如何各自發布 Graphify 衍生成品,以及open-4wd-specs如何在不取得私有 repo 權限的前提下聚合知識圖。Graphify 是導覽與檢索層,原始碼與 canon 文檔仍是權威。
1. 發布與聚合契約¶
四個產品 repo 在各自的 upstream CI 成功後,才由 graphify-release.yml 對該次 exact source SHA
執行 Graphify 0.9.25。Release tag 固定為 graphify-<source SHA 前 12 碼>,不設為 Latest,且只含:
graphify-site.zip:deterministic store-only ZIP,exactly 包含graph.json與可搜尋的index.html。graphify-manifest.json:記錄 repo、完整 source SHA、exact tag、Graphify 版本、canonical 產生時間、 node/edge 數,以及 ZIP size 與 SHA-256。
發布前會拒絕不在固定四 repo allowlist 的名稱、非相對 source path、.git/.env/
graphify-out 路徑、常見本機 home path、私鑰或 GitHub token 形狀的內容。Release repository 必須已
開啟 immutable releases;同一 exact tag 已存在時不覆寫。正式啟用前仍須人工檢查圖中的檔名、
節點文字與查詢結果,靜態掃描不是內容審查的替代品。
specs 的 refresh-graphify-releases.mjs 永遠重新查詢固定 allowlist,不信任 dispatch payload 提供的
repo、tag 或 URL。每個 repo 獨立挑選最新且完整通過 manifest、asset exact-set、size、digest 與 ZIP
member 驗證的 graphify-* Release;不要求四個 repo 彼此或與 specs 對齊版本。有效者照常顯示,
其他 repo 明示為 missing、private、fetch-failed 或 invalid,不阻斷 canon docs 建置。
Release 解開至未追蹤的 .graphify-releases/run-*/<repo>/;每次 refresh 使用新目錄,不覆寫舊
cache。沒有遠端成品時,本機建站仍可讀 sibling graphify-out;只有 graph.json 而沒有 Graphify
HTML 的 repo 也會產生本機搜尋頁,不再靜默消失。
Graphify 產生的互動圖頁引用 CDN 上的繪圖函式庫,站台不接受任何外部資源(資安規範.md §5)。 建站時該引用一律改寫為站內自架副本;本地副本缺席時,該 repo 的圖降級為內建檢視器並在狀態列標明, 而非帶著外連上站。未知來源的外部引用直接讓建置失敗,不靜默放行。
2. GitHub App 最小權限設定¶
GitHub App 只用來在來源 Release 成功後喚醒 specs;它不讀來源 repo,也不攜帶圖譜資料。
- 在維護者帳號的 Developer settings 建立 GitHub App。名稱須全 GitHub 唯一;Homepage URL 可填 專案公開首頁。Webhook 關閉,不設定 callback URL,不啟用 OAuth。
- Repository permissions 只給 Contents: Read and write,其餘保持 No access。這個 write 權限只
是 GitHub
repository_dispatchAPI 的要求,不代表 App 可修改工作樹。 - 安裝 App 時選 Only select repositories,只勾
open-4wd-specs。不得安裝到四個來源 repo, 也不得用 All repositories;因此 App token 無法替 specs 取得任何私有來源內容。 - 產生 private key。四個來源 repo 各設定 Actions variable
OPEN4WD_GRAPH_APP_ID,並把 PEM 全文存為 Actions secretOPEN4WD_GRAPH_APP_PRIVATE_KEY。若使用帳號/組織層 secret,repository access 必須只限固定 四個來源 repo。specs 不保存 App ID 或 private key。 - 在來源 repo 手動跑一次 Graphify Release 後,確認
notify-specsmint 的 token 只列出 specs installation,且 specs 收到graphify-release-publisheddispatch。dispatch payload 只是喚醒提示; refresh 仍從 allowlist 重新取得 Release。
App 未設定或 token mint/dispatch 失敗時,Release 本身仍成功,通知 job 只留下明確訊息。specs 可
由 workflow_dispatch 立即補跑,也會在每週一 04:17 UTC 低頻刷新;同一時間只保留一個 refresh。
3. 公開與 Pages 啟用順序¶
來源 repo 還是 private 時,不給 specs 或 App read 權限,也不發布 Graphify Release。每個 repo 獨立
完成以下檢查後,才設定 repository variable GRAPHIFY_RELEASE_ENABLED=true:
- repo 已公開,upstream CI 全綠,且 GitHub immutable releases 已開啟。
- 本機
check-graphify.ps1顯示 fresh,query/path/explain 能回答預期的內部關係。 - 以相同 prepare script 對
graphify-out/graph.json預演,人工檢查 manifest、source paths、搜尋頁 與關鍵字,確認沒有個資、內部基礎設施、憑證、尷尬註記或其他不應公開內容。 - 手動執行 Graphify Release workflow,下載兩個 assets 回讀 digest、exact SHA 與頁面內容,再確認
specs refresh 對該 repo 顯示
available。
四個 repo 不必同時啟用;尚未公開的項目保持狀態列,不拖延已公開 repo。specs 的
DOCS_PAGES_ENABLED=true 只在 Pages origin 與環境設定完成後才打開;未開啟時 refresh 仍會建置
並驗證站點,但不部署 Pages。
4. 金鑰輪替、撤銷與故障復原¶
- 定期輪替:先在 App 產生新 private key,更新固定四 repo 可見的 Actions secret,逐 repo 手動驗證 notification,再撤銷舊 key。App ID 不變。
- 疑似外洩:立即撤銷涉事 key,停用或刪除來源 secret,檢查 App installation 與 audit log;必要時 suspend/uninstall App。Release refresh 可繼續靠 specs 手動/排程執行。
- App 權限或安裝範圍誤設:先收回多餘 repo access,再輪替 key。不得用擴大來源 read 權限來解決
private狀態;該狀態會在 repo 公開並有有效 Release 後自然消失。 - Release 不合法:因 immutable asset 不可覆寫,修正來源或工具後以新 source commit 產生新 tag; specs 會跳過 invalid Release,繼續嘗試較舊的有效版本並保留錯誤摘要。
- refresh 失敗:先看
.graphify-releases/status.json區分 API、缺 Release、manifest 或 digest 問題; 修正後手動 dispatch。不可直接編輯 cache 冒充有效來源。