Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b60f50f2b4 | ||
|
|
43ad2b56d2 | ||
|
|
8e18bbacc2 | ||
|
|
1f012c6cfb |
@@ -1989,5 +1989,115 @@
|
|||||||
"endLine": 188,
|
"endLine": 188,
|
||||||
"problem": "`resolveMergeBase` 新增了多階段 fetch 補歷史流程:先 fetch base、首次 merge-base、再 deepen base、deepen PR HEAD、必要時 unshallow,且每個策略成功後要立即重試並短路返回。現有測試只驗證不安全 `baseRef` 會在 fetch 前被拒絕,沒有測到淺層 checkout、首次失敗後補抓成功、策略失敗繼續下一個、全部失敗時診斷訊息等邊界。這正是容易 off-by-one 或順序錯的流程,現在還沒有測試保護。",
|
"problem": "`resolveMergeBase` 新增了多階段 fetch 補歷史流程:先 fetch base、首次 merge-base、再 deepen base、deepen PR HEAD、必要時 unshallow,且每個策略成功後要立即重試並短路返回。現有測試只驗證不安全 `baseRef` 會在 fetch 前被拒絕,沒有測到淺層 checkout、首次失敗後補抓成功、策略失敗繼續下一個、全部失敗時診斷訊息等邊界。這正是容易 off-by-one 或順序錯的流程,現在還沒有測試保護。",
|
||||||
"reason": "Paladin:可排除(重複)。resolveMergeBase 多階段 fetch、淺層與非淺層路徑、策略停止條件、全部失敗診斷與 cause 缺少測試,已由歷史 findings 涵蓋。"
|
"reason": "Paladin:可排除(重複)。resolveMergeBase 多階段 fetch、淺層與非淺層路徑、策略停止條件、全部失敗診斷與 cause 缺少測試,已由歷史 findings 涵蓋。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:26:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Assassin",
|
||||||
|
"severity": "嚴重",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 105,
|
||||||
|
"endLine": 116,
|
||||||
|
"problem": "這裡把審查結果 commit/push 失敗吞掉並回傳 `false`,而本次變更又把主流程改成「本輪審查不因嚴重問題直接 exit 1,靠下一輪讀到 `[failure]` commit 才失敗」。攻擊者只要讓結果 commit 推不上去,例如在 PR head 競態推送、讓 token 沒有 push 權限、或讓來源分支拒絕 bot push,就能讓嚴重安全 finding 已產生但沒有 failure commit、也沒有下一輪失敗檢查,等同把必要檢查繞過。",
|
||||||
|
"reason": "人工裁示排除:主流程已在 result === failure 且 commitFindings 回傳 false 時直接回傳 1;本 finding 針對舊位置的描述已由現有收尾防線涵蓋。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:30:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Bard",
|
||||||
|
"severity": "建議",
|
||||||
|
"file": "readme.md",
|
||||||
|
"startLine": 48,
|
||||||
|
"endLine": 48,
|
||||||
|
"problem": "Mermaid 節點代號從 `N8` 跳回 `N2`,雖然流程語意是「步驟 2 延後」,但原始碼讀起來像旋律突然倒帶;維護者在對照圖與步驟時容易被代號順序絆住。",
|
||||||
|
"reason": "Paladin:可排除(重複)。歷史 findings 已指出流程步驟編號與實際順序、README 流程圖及文件對照會產生認知落差;本條 Mermaid 節點代號問題屬同一類指控。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:30:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Bard",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 167,
|
||||||
|
"endLine": 235,
|
||||||
|
"problem": "`main()` 內新增了建 issue 模式狀態、暫存佇列與三個帶長篇 JSDoc 的閉包,讓主流程的旋律被大量伴奏蓋過。這段同時管理 `issueModeActive`、`trackingIssue`、`pendingIssueCommentBodies` 與 PR 留言 id,可讀性負擔明顯升高。",
|
||||||
|
"reason": "Paladin:可排除(重複)。已知排除事項與歷史 findings 已涵蓋 main() 內留言路由、issue 狀態、暫存佇列與發布職責耦合造成可讀性與維護負擔。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:30:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Bard",
|
||||||
|
"severity": "建議",
|
||||||
|
"file": "src/lib/gitrepo.js",
|
||||||
|
"startLine": 121,
|
||||||
|
"endLine": 128,
|
||||||
|
"problem": "`strategies` 以陣列位置承載語意,`[label, ...args]` 雖簡短,卻讓每個元素的第二欄之後全靠讀者猜是 git argv;這裡的可讀性像沒有小節線的樂譜。",
|
||||||
|
"reason": "Paladin:可排除(重複)。歷史 finding 已針對 resolveMergeBase 內 strategies 與補救策略編排使閱讀節奏偏密提出問題;本條 tuple 可讀性屬同一段策略結構的細項。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:30:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Leo",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 163,
|
||||||
|
"endLine": 231,
|
||||||
|
"problem": "`main()` 這次把一般模式/建問題模式/降級模式的留言去向都塞進閉包狀態:`issueModeActive`、`trackingIssue`、`pendingIssueCommentBodies`、`currentRunCommentIds` 彼此耦合。半年後要新增一種落地方式或調整「何時清舊留言」時,維護者必須同時追多個可變狀態與後續多個 `if (issueModeActive)` 分支,很容易漏掉 flush、清空、登錄留言 id 或 fallback 後的收尾行為。",
|
||||||
|
"reason": "Paladin:可排除(重複)。與 F003 及既有排除事項相同,均指向 main() 以可變閉包狀態承擔留言目的地、issue 生命週期與 fallback 狀態機。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:30:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Leo",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 232,
|
||||||
|
"endLine": 241,
|
||||||
|
"problem": "流程註解把「將舊留言標記為解決」稱為「步驟 2(延後執行)」,但實際執行點在審查結果產生後、接近原本步驟 9 前。這種「編號是 2、時間點是 8 後」的設計已經擴散到多個檔案的 JSDoc 與 log 描述,未來查 CI log 或維護流程圖時會產生認知落差:看到 `步驟2` 不代表它真的發生在第二步。",
|
||||||
|
"reason": "Paladin:可排除(重複)。歷史 findings 已明確記錄步驟編號散落於 log、JSDoc、README 且實際順序變成 1、3 到 8、2、9 到 10 的維護風險。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:30:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Leo",
|
||||||
|
"severity": "建議",
|
||||||
|
"file": "src/lib/gitrepo.js",
|
||||||
|
"startLine": 103,
|
||||||
|
"endLine": 160,
|
||||||
|
"problem": "`resolveMergeBase()` 內同時負責驗證 base ref、fetch base、重試 merge-base、補抓淺層歷史、累積診斷與組錯誤訊息。這些都和「取得 merge-base」有關,但現在全部攤在同一個函式裡,策略陣列、診斷格式與 git 操作細節混在一起;未來要新增 fetch 策略或改診斷文字時,容易不小心改壞主流程判斷。",
|
||||||
|
"reason": "Paladin:可排除(重複)。歷史 finding 已指出 resolveMergeBase 同時負責驗證、fetch 策略編排、診斷與錯誤包裝,難以分辨主流程與補救策略。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:30:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Maya",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 164,
|
||||||
|
"endLine": 232,
|
||||||
|
"problem": "建問題模式新增了「先暫存情境留言、確定有保留 finding 才建 issue、建 issue 失敗時降級回 PR 留言」這一整段流程,但目前測試只覆蓋了部分 helper,沒有驗證主流程在 create-issue=true 下的分流行為。這代表像「無保留問題時不應建 issue/不應留言」、「建立 issue 失敗時應把 pending 留言補回 PR」、「trackingIssue 建立後後續留言應改送 issue」這些行為都還沒通過試煉。",
|
||||||
|
"reason": "Paladin:可排除(重複)。歷史 findings 已涵蓋建問題模式核心流程、暫存留言、issue 建立條件、發布分流、外部 API 狀態切換與降級路徑缺少測試。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:30:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Maya",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/lib/gitrepo.js",
|
||||||
|
"startLine": 104,
|
||||||
|
"endLine": 150,
|
||||||
|
"problem": "resolveMergeBase 新增了多階段 fetch/deepen/unshallow fallback 與診斷錯誤,但測試只驗證不安全 baseRef 會被拒絕,沒有驗證任何成功或失敗 fallback 路徑。這段是 diff 基準的核心邏輯,若 shallow checkout 下 deepen PR HEAD 用錯 ref、策略順序跑錯,或全部失敗時診斷不正確,現有測試都抓不到。",
|
||||||
|
"reason": "Paladin:可排除(重複)。歷史 findings 已針對 resolveMergeBase 多階段 fetch、淺層與非淺層分支、策略停止條件、降級與最終診斷缺少測試提出相同問題。"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"addedAt": "2026/07/21 16:30:12",
|
||||||
|
"prNumber": 6,
|
||||||
|
"reviewer": "Maya",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/lib/gitrepo.js",
|
||||||
|
"startLine": 272,
|
||||||
|
"endLine": 322,
|
||||||
|
"problem": "commitAndPushFindings 改成一律透過 pushWithCredential 用 PAT extraheader 推送,且新增 headRef 安全檢查與固定錯誤遮蔽;但目前 gitrepo 測試沒有覆蓋 commitAndPushFindings/pushWithCredential 的推送行為。這讓「token 不進 argv」、「清掉 checkout 既有 extraheader」、「遠端 URL 不符時拒絕」、「push 失敗不洩漏 URL/token」這些失敗與安全邊界都沒有被驗證。",
|
||||||
|
"reason": "Paladin:可排除(重複)。歷史 findings 已涵蓋 commitAndPushFindings 與 pushWithCredential 的推送策略、認證遮蔽、失敗路徑與 token 不外洩等測試缺口。"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -7,84 +7,7 @@
|
|||||||
"version": "codex-cli 0.144.6",
|
"version": "codex-cli 0.144.6",
|
||||||
"model": "gpt-5.5"
|
"model": "gpt-5.5"
|
||||||
},
|
},
|
||||||
"findings": [
|
"findings": [],
|
||||||
{
|
|
||||||
"reviewer": "Assassin",
|
|
||||||
"focus": "security",
|
|
||||||
"badge": "🗡️",
|
|
||||||
"severity": "嚴重",
|
|
||||||
"file": "src/index.js",
|
|
||||||
"startLine": 105,
|
|
||||||
"endLine": 116,
|
|
||||||
"problem": "這裡把審查結果 commit/push 失敗吞掉並回傳 `false`,而本次變更又把主流程改成「本輪審查不因嚴重問題直接 exit 1,靠下一輪讀到 `[failure]` commit 才失敗」。攻擊者只要讓結果 commit 推不上去,例如在 PR head 競態推送、讓 token 沒有 push 權限、或讓來源分支拒絕 bot push,就能讓嚴重安全 finding 已產生但沒有 failure commit、也沒有下一輪失敗檢查,等同把必要檢查繞過。",
|
|
||||||
"suggestion": "嚴重問題存在時,結果 commit/push 失敗必須直接讓本輪 workflow 失敗;只有 success 結果或無變更時才可降級不阻擋。呼叫端應檢查 `commitFindings` 回傳值,或讓 `commitFindings` 在 `result === 'failure'` 時重拋錯誤。",
|
|
||||||
"suggestedCode": "const committed = commitFindings({ cwd, ctx, files: filesToCommit, result });\nif (result === 'failure' && !committed) {\n log('收尾', 'ERR', '存在嚴重問題,但無法推送 failure 結果 commit;本輪直接失敗以避免繞過檢查。');\n return 1;\n}\nreturn 0;",
|
|
||||||
"id": "F001",
|
|
||||||
"verdicts": {
|
|
||||||
"Paladin": {
|
|
||||||
"exclude": false,
|
|
||||||
"reason": "保留(成立)。已知排除事項與歷史 findings 未涵蓋「嚴重 finding 依賴 failure commit,但 failure commit 推送失敗時本輪仍可能通過」這個繞過風險;證據不足以排除。"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"reviewer": "Bard",
|
|
||||||
"focus": "style",
|
|
||||||
"badge": "🎼",
|
|
||||||
"severity": "建議",
|
|
||||||
"file": "action.yml",
|
|
||||||
"startLine": 18,
|
|
||||||
"endLine": 19,
|
|
||||||
"problem": "中文敘述裡混入 `PR/issue`、`findings/exclusions` 這種半形斜線寫法,但同一份變更其他地方大量使用 `PR/issue`、`警告+建議` 這類全形符號。標點像節拍器,這裡忽然換拍,讓 manifest 的文字風格不夠一致。",
|
|
||||||
"suggestion": "統一中文文件與註解中的分隔符號,建議在中文語境使用全形斜線:`PR/issue`、`findings/exclusions`;若是程式路徑或指令片段才保留半形 `/`。",
|
|
||||||
"suggestedCode": "",
|
|
||||||
"id": "F004",
|
|
||||||
"verdicts": {
|
|
||||||
"Paladin": {
|
|
||||||
"exclude": false,
|
|
||||||
"reason": "保留(成立)。未命中已知排除事項,也未見歷史 finding 涵蓋 action.yml 中文標點半形/全形風格不一致;依現有資料不能判為重複或誤報。"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"reviewer": "Bard",
|
|
||||||
"focus": "style",
|
|
||||||
"badge": "🎼",
|
|
||||||
"severity": "建議",
|
|
||||||
"file": "src/lib/gitrepo.js",
|
|
||||||
"startLine": 299,
|
|
||||||
"endLine": 344,
|
|
||||||
"problem": "`pushWithCredential` 的 JSDoc 幾乎把安全設計、CI 觸發語意、checkout extraheader 行為全部寫成一篇短文。資訊本身有價值,但集中在函式註解裡會壓過函式簽名,讀者想找參數與責任邊界時,得先穿過一大段敘事。",
|
|
||||||
"suggestion": "保留函式層級的摘要與關鍵安全不變式,其餘背景可移到較短的段落或專門文件。JSDoc 建議聚焦在「做什麼、為何不能改、參數怎麼用」,避免把完整決策紀錄塞進 API 註解。",
|
|
||||||
"suggestedCode": "",
|
|
||||||
"id": "F005",
|
|
||||||
"verdicts": {
|
|
||||||
"Paladin": {
|
|
||||||
"exclude": false,
|
|
||||||
"reason": "保留(成立)。歷史 finding 雖有 resolveMergeBase 閱讀密度問題,但未涵蓋 pushWithCredential JSDoc 過長且混入決策紀錄;目前不能排除。"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"reviewer": "Leo",
|
|
||||||
"focus": "maintainability",
|
|
||||||
"badge": "🧰",
|
|
||||||
"severity": "建議",
|
|
||||||
"file": "src/lib/gitrepo.js",
|
|
||||||
"startLine": 367,
|
|
||||||
"endLine": 369,
|
|
||||||
"problem": "為了測試把內部函式掛在 `module.exports.__test`,會讓 production module 的公開形狀混入測試專用 API。未來其他程式碼可能誤用 `__test.assertSafeBranchRef`,而維護者也得在重構時顧慮這個非正式出口,模組邊界會慢慢變模糊。",
|
|
||||||
"suggestion": "把分支名稱驗證抽到獨立小模組並正常匯出,例如 `src/lib/gitref.js`,讓 production code 與測試都依賴同一個正式 API;或若它只屬於 gitrepo 內部,就改由測試 `resolveMergeBase`/`commitAndPushFindings` 的外部行為覆蓋,不暴露 `__test`。",
|
|
||||||
"suggestedCode": "",
|
|
||||||
"id": "F009",
|
|
||||||
"verdicts": {
|
|
||||||
"Paladin": {
|
|
||||||
"exclude": false,
|
|
||||||
"reason": "保留(成立)。目前提供的排除事項與歷史 findings 未涵蓋 module.exports.__test 暴露測試專用 API 的模組邊界問題;證據不足以排除。"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"excluded": [
|
"excluded": [
|
||||||
{
|
{
|
||||||
"reviewer": "Bard",
|
"reviewer": "Bard",
|
||||||
|
|||||||
@@ -0,0 +1,280 @@
|
|||||||
|
{
|
||||||
|
"generatedAt": "2026/07/21 16:30:12",
|
||||||
|
"commitSha": "43ad2b56d27429aa3c812522dc1d4fedce4a9b76",
|
||||||
|
"prNumber": 6,
|
||||||
|
"tool": {
|
||||||
|
"name": "codex",
|
||||||
|
"version": "codex-cli 0.144.6",
|
||||||
|
"model": "gpt-5.5"
|
||||||
|
},
|
||||||
|
"findings": [
|
||||||
|
{
|
||||||
|
"reviewer": "Mage",
|
||||||
|
"focus": "logic",
|
||||||
|
"badge": "🔮",
|
||||||
|
"severity": "嚴重",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 134,
|
||||||
|
"endLine": 139,
|
||||||
|
"problem": "這裡把「本輪審查」改成即使找到嚴重 finding 也回傳 0,並依賴後續 `[ai-review-bot][failure]` 結果 commit 觸發下一輪才讓檢查失敗。最小重現情境:PR 內有 1 條嚴重問題,但 `commitFindings()` 因分支保護、token 無 push 權限、遠端競態或 PAT 無法觸發 CI 而回傳 false;本輪仍成功結束,且沒有下一輪 failure commit 可被步驟 1 讀到,嚴重問題就被靜默放行。未驗證「結果 commit 一定成功且一定觸發下一輪」這個假設時,它就是流程成敗判定的單點失效。",
|
||||||
|
"suggestion": "嚴重 finding 已確認後,若 failure 結果 commit/push 沒有成功產生,就應在本輪直接回傳 1;只有在確認 failure commit 已成功推送時,才可把失敗狀態交給下一輪快速回報。也就是:`severe.length > 0 && !resultCommitPushed` 必須阻擋。",
|
||||||
|
"suggestedCode": "const result = severe.length === 0 ? 'success' : 'failure';\nlet pushed = false;\nif (filesToCommit.length > 0) {\n pushed = commitFindings({ cwd, ctx, files: filesToCommit, result });\n}\n\nif (severe.length > 0 && !pushed) {\n log('收尾', 'ERR', '已有嚴重問題,但 failure 結果 commit 未成功產生;本輪直接以失敗收場。');\n return 1;\n}\n\nreturn 0;",
|
||||||
|
"id": "F009",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": false,
|
||||||
|
"reason": "保留。此條指控嚴重 finding 依賴結果 commit 觸發下一輪才失敗,且 commit/push 失敗時本輪可能靜默通過;既有排除事項未涵蓋此成敗判定風險。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Mage",
|
||||||
|
"focus": "logic",
|
||||||
|
"badge": "🔮",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 201,
|
||||||
|
"endLine": 209,
|
||||||
|
"problem": "`createIssueAndFlushBufferedComments()` 先建立 `trackingIssue`,再逐則寫入暫存留言;但只要其中一則留言失敗,外層 catch 會呼叫 `fallbackToPrComments()`,把整批 `pendingIssueCommentBodies` 全部改貼回 PR。最小重現情境:追蹤 issue 建立成功,第一則工具留言也成功寫入 issue,第二則 diff 留言 API 回 500;流程降級後 PR 會收到全部暫存留言,而已建立的 issue 仍殘留第一則留言、沒有後續 finding、也可能沒有 PR 連結或相依關係。這會留下部分成功、部分降級的不一致狀態。",
|
||||||
|
"suggestion": "flush 時應在每則留言成功後立刻從 pending 佇列移除,並明確處理「issue 已建立但 flush 失敗」的狀態:要嘛繼續沿用已建立 issue 並讓後續失敗冒泡,要嘛在降級前補一則 PR 診斷/連結並避免重貼已成功寫入 issue 的留言。",
|
||||||
|
"suggestedCode": "while (pendingIssueCommentBodies.length > 0) {\n const body = pendingIssueCommentBodies[0];\n await gitea.createCommentOnIssue(ctx, trackingIssue.number, body);\n pendingIssueCommentBodies.shift();\n}",
|
||||||
|
"id": "F010",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": false,
|
||||||
|
"reason": "保留。既有排除事項涵蓋 issue 建立後留言失敗導致重跑重複 issue,但本條另指出 flush 部分成功後 fallback 會把整批 pending 留言改貼 PR,造成 issue 與 PR 狀態不一致;不是單純重複。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Bard",
|
||||||
|
"focus": "style",
|
||||||
|
"badge": "🎼",
|
||||||
|
"severity": "建議",
|
||||||
|
"file": "action.yml",
|
||||||
|
"startLine": 3,
|
||||||
|
"endLine": 3,
|
||||||
|
"problem": "手動維護的「更新時間」已與本次檔案標示的最後更新時間不同步;樂譜開頭的拍號一錯,讀者後面每段註解都會多一分懷疑。同樣的不協調也出現在 `readme.md` 與 `src/index.js` 的 banner/文件時間。",
|
||||||
|
"suggestion": "移除這類容易走調的手動時間戳,或改由發布流程自動產生。若一定要保留,請讓所有檔案的時間標示與本次變更一致。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F001",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": false,
|
||||||
|
"reason": "保留。已知排除事項與歷史 findings 未涵蓋手動更新時間不同步;目前也無足夠原始碼證據可判定為誤報。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Bard",
|
||||||
|
"focus": "style",
|
||||||
|
"badge": "🎼",
|
||||||
|
"severity": "建議",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 199,
|
||||||
|
"endLine": 199,
|
||||||
|
"problem": "`createIssueAndFlushBufferedComments` 這個名稱把「建立 issue」與「flush 暫存留言」兩個實作細節硬串在一起,像一句過長的歌詞;呼叫點讀起來偏機械,沒有清楚表達業務意圖。",
|
||||||
|
"suggestion": "改成較語意化的命名,例如 `openTrackingIssue` 或 `createTrackingIssueWithContext`,讓讀者先理解目的,再從函式內容看見 flush 的細節。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F004",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": false,
|
||||||
|
"reason": "保留。此條針對 createIssueAndFlushBufferedComments 的命名語意與可讀性,未明確命中既有排除事項;與先前 ensureIssueCreated 暗示冪等的問題不完全相同。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Maya",
|
||||||
|
"focus": "testing",
|
||||||
|
"badge": "🧪",
|
||||||
|
"severity": "建議",
|
||||||
|
"file": "src/lib/gitref.js",
|
||||||
|
"startLine": 12,
|
||||||
|
"endLine": 24,
|
||||||
|
"problem": "assertSafeBranchRef 目前只測了一個正常分支與一個 ../../ 路徑穿越案例;但這個函式承擔 refspec 安全邊界,新增的空值、前後斜線、反斜線、以及 git check-ref-format 拒絕的格式都沒有案例。邊界沒被驗證時,未來調整條件很容易放過不合法 ref。",
|
||||||
|
"suggestion": "補上表格測試,至少涵蓋空字串、純空白、/feature、feature/、feature\\\\x、feature..x、feature.lock、feature@{x},並斷言錯誤訊息能區分「不安全」與「不合法 git 分支名稱」。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F014",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": false,
|
||||||
|
"reason": "保留。此條針對 assertSafeBranchRef 的 refspec 安全邊界測試不足,未見已知排除事項或歷史 findings 明確涵蓋;證據不足以排除。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"excluded": [
|
||||||
|
{
|
||||||
|
"reviewer": "Bard",
|
||||||
|
"focus": "style",
|
||||||
|
"badge": "🎼",
|
||||||
|
"severity": "建議",
|
||||||
|
"file": "readme.md",
|
||||||
|
"startLine": 48,
|
||||||
|
"endLine": 48,
|
||||||
|
"problem": "Mermaid 節點代號從 `N8` 跳回 `N2`,雖然流程語意是「步驟 2 延後」,但原始碼讀起來像旋律突然倒帶;維護者在對照圖與步驟時容易被代號順序絆住。",
|
||||||
|
"suggestion": "節點 id 建議改用語意名稱,而把顯示文字保留步驟編號。例如 `ResolveOldComments[2 延後將舊留言標記解決...]`,讓圖的原始碼與顯示內容各自清楚。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F002",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": true,
|
||||||
|
"reason": "可排除(重複)。歷史 findings 已指出流程步驟編號與實際順序、README 流程圖及文件對照會產生認知落差;本條 Mermaid 節點代號問題屬同一類指控。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Bard",
|
||||||
|
"focus": "style",
|
||||||
|
"badge": "🎼",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 167,
|
||||||
|
"endLine": 235,
|
||||||
|
"problem": "`main()` 內新增了建 issue 模式狀態、暫存佇列與三個帶長篇 JSDoc 的閉包,讓主流程的旋律被大量伴奏蓋過。這段同時管理 `issueModeActive`、`trackingIssue`、`pendingIssueCommentBodies` 與 PR 留言 id,可讀性負擔明顯升高。",
|
||||||
|
"suggestion": "把留言路由與建 issue 暫存邏輯抽成小型 helper(例如 `createCommentRouter`),`main()` 只保留流程編排;JSDoc 也移到 helper 旁,讓主流程步驟重新一眼可讀。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F003",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": true,
|
||||||
|
"reason": "可排除(重複)。已知排除事項與歷史 findings 已涵蓋 main() 內留言路由、issue 狀態、暫存佇列與發布職責耦合造成可讀性與維護負擔。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Bard",
|
||||||
|
"focus": "style",
|
||||||
|
"badge": "🎼",
|
||||||
|
"severity": "建議",
|
||||||
|
"file": "src/lib/gitrepo.js",
|
||||||
|
"startLine": 121,
|
||||||
|
"endLine": 128,
|
||||||
|
"problem": "`strategies` 以陣列位置承載語意,`[label, ...args]` 雖簡短,卻讓每個元素的第二欄之後全靠讀者猜是 git argv;這裡的可讀性像沒有小節線的樂譜。",
|
||||||
|
"suggestion": "改成物件陣列,明確標出 `label` 與 `args`,可降低後續新增 fetch 策略時的閱讀成本。",
|
||||||
|
"suggestedCode": "const strategies = [\n { label: 'deepen base', args: ['fetch', '--no-tags', '--deepen=1000', 'origin', `+refs/heads/${baseRef}:refs/remotes/${remoteBase}`] },\n { label: 'deepen PR HEAD', args: ['fetch', '--no-tags', '--deepen=1000', 'origin', headSha] },\n];",
|
||||||
|
"id": "F005",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": true,
|
||||||
|
"reason": "可排除(重複)。歷史 finding 已針對 resolveMergeBase 內 strategies 與補救策略編排使閱讀節奏偏密提出問題;本條 tuple 可讀性屬同一段策略結構的細項。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Leo",
|
||||||
|
"focus": "maintainability",
|
||||||
|
"badge": "🧰",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 163,
|
||||||
|
"endLine": 231,
|
||||||
|
"problem": "`main()` 這次把一般模式/建問題模式/降級模式的留言去向都塞進閉包狀態:`issueModeActive`、`trackingIssue`、`pendingIssueCommentBodies`、`currentRunCommentIds` 彼此耦合。半年後要新增一種落地方式或調整「何時清舊留言」時,維護者必須同時追多個可變狀態與後續多個 `if (issueModeActive)` 分支,很容易漏掉 flush、清空、登錄留言 id 或 fallback 後的收尾行為。",
|
||||||
|
"suggestion": "把留言目的地抽成小型物件,讓主流程只呼叫 `commentSink.postContext()`、`commentSink.finalizeAfterFindings()`、`commentSink.postFinding()` 這類語意方法。一般 PR、issue buffering、fallback 的狀態轉換集中在同一個模組或工廠函式內,`main()` 保持審查流程編排,不承擔留言狀態機。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F006",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": true,
|
||||||
|
"reason": "可排除(重複)。與 F003 及既有排除事項相同,均指向 main() 以可變閉包狀態承擔留言目的地、issue 生命週期與 fallback 狀態機。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Leo",
|
||||||
|
"focus": "maintainability",
|
||||||
|
"badge": "🧰",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 232,
|
||||||
|
"endLine": 241,
|
||||||
|
"problem": "流程註解把「將舊留言標記為解決」稱為「步驟 2(延後執行)」,但實際執行點在審查結果產生後、接近原本步驟 9 前。這種「編號是 2、時間點是 8 後」的設計已經擴散到多個檔案的 JSDoc 與 log 描述,未來查 CI log 或維護流程圖時會產生認知落差:看到 `步驟2` 不代表它真的發生在第二步。",
|
||||||
|
"suggestion": "不要用固定序號承載流程語意。建議改成穩定階段名稱,例如 `清理舊留言`、`工具偵測`、`diff整理`,或重新編號為實際執行順序並在文件說明「清理舊留言延後到結果產生後」。這樣 log、JSDoc、README 流程圖才不會互相背離。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F007",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": true,
|
||||||
|
"reason": "可排除(重複)。歷史 findings 已明確記錄步驟編號散落於 log、JSDoc、README 且實際順序變成 1、3 到 8、2、9 到 10 的維護風險。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Leo",
|
||||||
|
"focus": "maintainability",
|
||||||
|
"badge": "🧰",
|
||||||
|
"severity": "建議",
|
||||||
|
"file": "src/lib/gitrepo.js",
|
||||||
|
"startLine": 103,
|
||||||
|
"endLine": 160,
|
||||||
|
"problem": "`resolveMergeBase()` 內同時負責驗證 base ref、fetch base、重試 merge-base、補抓淺層歷史、累積診斷與組錯誤訊息。這些都和「取得 merge-base」有關,但現在全部攤在同一個函式裡,策略陣列、診斷格式與 git 操作細節混在一起;未來要新增 fetch 策略或改診斷文字時,容易不小心改壞主流程判斷。",
|
||||||
|
"suggestion": "把補抓策略與重試邏輯拆成私有 helper,例如 `fetchBaseRef()`、`mergeBaseOrNull()`、`shallowFetchStrategies()`。主函式保留高階流程:驗證 ref → 更新 base → 嘗試 merge-base → 逐一套用策略 → 丟出診斷錯誤。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F008",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": true,
|
||||||
|
"reason": "可排除(重複)。歷史 finding 已指出 resolveMergeBase 同時負責驗證、fetch 策略編排、診斷與錯誤包裝,難以分辨主流程與補救策略。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Maya",
|
||||||
|
"focus": "testing",
|
||||||
|
"badge": "🧪",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/index.js",
|
||||||
|
"startLine": 164,
|
||||||
|
"endLine": 232,
|
||||||
|
"problem": "建問題模式新增了「先暫存情境留言、確定有保留 finding 才建 issue、建 issue 失敗時降級回 PR 留言」這一整段流程,但目前測試只覆蓋了部分 helper,沒有驗證主流程在 create-issue=true 下的分流行為。這代表像「無保留問題時不應建 issue/不應留言」、「建立 issue 失敗時應把 pending 留言補回 PR」、「trackingIssue 建立後後續留言應改送 issue」這些行為都還沒通過試煉。",
|
||||||
|
"suggestion": "建議把 main 流程拆出可注入 gitea/review/agents/gitrepo 的 orchestrator,或至少匯出可測的流程函式,補上 create-issue=true 的案例:1. kept=[] 時不呼叫 createIssue/createIssueComment;2. kept>0 時先 flush pending issue comments 再發 finding;3. createIssue 拋錯時 fallbackToPrComments 會發回 PR 並記錄 currentRunCommentIds;4. issueModeActive 降級後會走一般 PR 留言與 resolveOldComments。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F011",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": true,
|
||||||
|
"reason": "可排除(重複)。歷史 findings 已涵蓋建問題模式核心流程、暫存留言、issue 建立條件、發布分流、外部 API 狀態切換與降級路徑缺少測試。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Maya",
|
||||||
|
"focus": "testing",
|
||||||
|
"badge": "🧪",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/lib/gitrepo.js",
|
||||||
|
"startLine": 104,
|
||||||
|
"endLine": 150,
|
||||||
|
"problem": "resolveMergeBase 新增了多階段 fetch/deepen/unshallow fallback 與診斷錯誤,但測試只驗證不安全 baseRef 會被拒絕,沒有驗證任何成功或失敗 fallback 路徑。這段是 diff 基準的核心邏輯,若 shallow checkout 下 deepen PR HEAD 用錯 ref、策略順序跑錯,或全部失敗時診斷不正確,現有測試都抓不到。",
|
||||||
|
"suggestion": "建議用假的 git 執行層或臨時 git repo 補測:首次 merge-base 成功時不跑後續策略;首次失敗但 deepen base 後成功;deepen base 失敗會繼續 deepen PR HEAD;shallow repo 才嘗試 --unshallow;全部失敗時錯誤訊息包含各策略診斷且保留 cause。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F012",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": true,
|
||||||
|
"reason": "可排除(重複)。歷史 findings 已針對 resolveMergeBase 多階段 fetch、淺層與非淺層分支、策略停止條件、降級與最終診斷缺少測試提出相同問題。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reviewer": "Maya",
|
||||||
|
"focus": "testing",
|
||||||
|
"badge": "🧪",
|
||||||
|
"severity": "警告",
|
||||||
|
"file": "src/lib/gitrepo.js",
|
||||||
|
"startLine": 272,
|
||||||
|
"endLine": 322,
|
||||||
|
"problem": "commitAndPushFindings 改成一律透過 pushWithCredential 用 PAT extraheader 推送,且新增 headRef 安全檢查與固定錯誤遮蔽;但目前 gitrepo 測試沒有覆蓋 commitAndPushFindings/pushWithCredential 的推送行為。這讓「token 不進 argv」、「清掉 checkout 既有 extraheader」、「遠端 URL 不符時拒絕」、「push 失敗不洩漏 URL/token」這些失敗與安全邊界都沒有被驗證。",
|
||||||
|
"suggestion": "建議以 stub child_process.execFileSync 或可注入 git runner 的方式補測:commit 後呼叫 git push 的 argv 不含 token;env 內含 GIT_CONFIG_COUNT 與 Authorization extraheader;headRef 不安全時在 git add/commit/push 前拋錯;remote origin 不符與 push 失敗時錯誤訊息不包含 token、repo URL 或 Basic header。",
|
||||||
|
"suggestedCode": "",
|
||||||
|
"id": "F013",
|
||||||
|
"verdicts": {
|
||||||
|
"Paladin": {
|
||||||
|
"exclude": true,
|
||||||
|
"reason": "可排除(重複)。歷史 findings 已涵蓋 commitAndPushFindings 與 pushWithCredential 的推送策略、認證遮蔽、失敗路徑與 token 不外洩等測試缺口。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+2
-2
@@ -16,11 +16,11 @@ author: 'Jeffery'
|
|||||||
# 輸入參數區塊:呼叫端 workflow 以 `with:` 傳入,
|
# 輸入參數區塊:呼叫端 workflow 以 `with:` 傳入,
|
||||||
# runner 會自動注入為 INPUT_* 環境變數(例如 INPUT_TOKEN、INPUT_MODEL、INPUT_CREATE-ISSUE)供主程式讀取。
|
# runner 會自動注入為 INPUT_* 環境變數(例如 INPUT_TOKEN、INPUT_MODEL、INPUT_CREATE-ISSUE)供主程式讀取。
|
||||||
inputs:
|
inputs:
|
||||||
# Gitea API token:用於對 PR/issue 留言審查結果,以及 push 審查結果檔(findings/exclusions)回 repo。
|
# Gitea API token:用於對 PR/issue 留言審查結果,以及 push 審查結果檔(findings/exclusions)回 repo。
|
||||||
token:
|
token:
|
||||||
# 參數用途說明:secrets/vars context 在 action 內不可用,故由呼叫端 workflow 以 secrets 傳入。
|
# 參數用途說明:secrets/vars context 在 action 內不可用,故由呼叫端 workflow 以 secrets 傳入。
|
||||||
# 建議傳入能觸發 CI 的 PAT;自動 token 推送結果 commit 時可能不會再觸發 workflow。
|
# 建議傳入能觸發 CI 的 PAT;自動 token 推送結果 commit 時可能不會再觸發 workflow。
|
||||||
description: 'Gitea API token(PR/issue 留言與 push findings 用;建議以能觸發 CI 的 PAT 由 secrets 傳入)'
|
description: 'Gitea API token(PR/issue 留言與 push findings 用;建議以能觸發 CI 的 PAT 由 secrets 傳入)'
|
||||||
# 必填:缺少 token 無法呼叫 Gitea API,action 無法運作。
|
# 必填:缺少 token 無法呼叫 Gitea API,action 無法運作。
|
||||||
required: true
|
required: true
|
||||||
# 指定 AI 工具使用的模型名稱。
|
# 指定 AI 工具使用的模型名稱。
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { execFileSync } = require('child_process');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驗證遠端分支名稱可安全用於 refspec 與 refs/remotes/origin/*。
|
||||||
|
*
|
||||||
|
* @param {string} refName - 使用者或事件 payload 提供的分支名稱。
|
||||||
|
* @param {string} fieldName - 錯誤訊息中的欄位名稱。
|
||||||
|
* @returns {string} 原樣回傳通過驗證的分支名稱。
|
||||||
|
* @throws {Error} 分支名稱空白、含路徑穿越,或不符合 git 分支 ref 規則時拋出。
|
||||||
|
*/
|
||||||
|
function assertSafeBranchRef(refName, fieldName) {
|
||||||
|
const value = String(refName || '').trim();
|
||||||
|
if (!value) throw new Error(`${fieldName} 不可為空。`);
|
||||||
|
if (value.includes('..') || value.startsWith('/') || value.endsWith('/') || value.includes('\\')) {
|
||||||
|
throw new Error(`${fieldName} 不是安全的分支名稱:${value}`);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
execFileSync('git', ['check-ref-format', '--branch', value], {
|
||||||
|
encoding: 'utf8',
|
||||||
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
throw new Error(`${fieldName} 不是合法的 git 分支名稱:${value}`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
assertSafeBranchRef,
|
||||||
|
};
|
||||||
+4
-43
@@ -1,37 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { execFileSync } = require('child_process');
|
const { execFileSync } = require('child_process');
|
||||||
|
const { assertSafeBranchRef } = require('./gitref');
|
||||||
|
|
||||||
// git 操作工具:一律以 execFileSync 呼叫 git(不經 shell,避免注入),輸出以 UTF-8 回傳。
|
// git 操作工具:一律以 execFileSync 呼叫 git(不經 shell,避免注入),輸出以 UTF-8 回傳。
|
||||||
|
|
||||||
/**
|
|
||||||
* 驗證遠端分支名稱可安全用於 refspec 與 refs/remotes/origin/*。
|
|
||||||
*
|
|
||||||
* @param {string} refName - 使用者或事件 payload 提供的分支名稱。
|
|
||||||
* @param {string} fieldName - 錯誤訊息中的欄位名稱。
|
|
||||||
* @returns {string} 原樣回傳通過驗證的分支名稱。
|
|
||||||
* @throws {Error} 分支名稱空白、含路徑穿越,或不符合 git 分支 ref 規則時拋出。
|
|
||||||
* @remarks
|
|
||||||
* 使用情境:`resolveMergeBase` 的 `baseRef` 與 `commitAndPushFindings` 的
|
|
||||||
* `headRef` 會被組進 refspec;先驗證可避免惡意 payload 影響本地 refs 路徑。
|
|
||||||
*/
|
|
||||||
function assertSafeBranchRef(refName, fieldName) {
|
|
||||||
const value = String(refName || '').trim();
|
|
||||||
if (!value) throw new Error(`${fieldName} 不可為空。`);
|
|
||||||
if (value.includes('..') || value.startsWith('/') || value.endsWith('/') || value.includes('\\')) {
|
|
||||||
throw new Error(`${fieldName} 不是安全的分支名稱:${value}`);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
execFileSync('git', ['check-ref-format', '--branch', value], {
|
|
||||||
encoding: 'utf8',
|
|
||||||
stdio: ['ignore', 'pipe', 'pipe'],
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
throw new Error(`${fieldName} 不是合法的 git 分支名稱:${value}`);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步執行 git 指令並回傳原始 stdout 輸出。
|
* 同步執行 git 指令並回傳原始 stdout 輸出。
|
||||||
*
|
*
|
||||||
@@ -308,18 +281,9 @@ function commitAndPushFindings(cwd, { headRef, headSha, message, files, token, s
|
|||||||
/**
|
/**
|
||||||
* 以帶認證的方式推送到指定遠端,認證資訊只經環境變數傳入、不進命令列 argv。
|
* 以帶認證的方式推送到指定遠端,認證資訊只經環境變數傳入、不進命令列 argv。
|
||||||
*
|
*
|
||||||
* 認證方式:等同 `https://ai-review-bot:<secret>@host/...` 的 HTTP Basic(git 會把
|
* 以 `GIT_CONFIG_*` 注入本次 HTTP Basic extraheader,避免憑證出現在 argv;
|
||||||
* URL 帳密轉成相同的 `Authorization: Basic` 標頭送出),但改以 git 的
|
* 同時先清空 checkout 持久化的自動 token extraheader,確保本次 push 使用呼叫端 token。
|
||||||
* `GIT_CONFIG_*` 環境變數注入 `http.<serverUrl>/.extraheader`,使 base64 憑證**不出現在 argv**
|
* 推送失敗時改拋固定訊息,避免原始例外帶出遠端 URL 或認證資訊。
|
||||||
* (避免程序清單/例外回顯洩漏);推送目標 URL 亦不含帳密。
|
|
||||||
*
|
|
||||||
* 觸發 CI 關鍵:`actions/checkout` 會把「自動 Actions token」持久化在同一個
|
|
||||||
* `http.<serverUrl>/.extraheader` scope;若沿用它推送,Gitea 會視為「自動 token 觸發」而
|
|
||||||
* **不再觸發 workflow**(防遞迴)。故本函式對這次 push 於該 scope**先以空值重置**(清掉自動
|
|
||||||
* token——git 對 extraHeader 給空值即清空既有清單),**再注入 PAT 的 Authorization**,讓推送以
|
|
||||||
* PAT 身分進行、觸發 PR 的 synchronize;作用範圍僅限本次 push 的環境變數,不影響 action 其他
|
|
||||||
* 仰賴 checkout 持久化憑證的 fetch(如 {@link resolveMergeBase})。
|
|
||||||
* 推送失敗時**不重拋原始例外**(其 message 會含命令列與遠端 URL),改拋固定訊息。
|
|
||||||
*
|
*
|
||||||
* @param {string} cwd - git 工作目錄(repo 的 checkout 路徑)。
|
* @param {string} cwd - git 工作目錄(repo 的 checkout 路徑)。
|
||||||
* @param {string} remoteUrl - 不含帳密的遠端 URL(形如 `https://host/owner/repo.git`)。
|
* @param {string} remoteUrl - 不含帳密的遠端 URL(形如 `https://host/owner/repo.git`)。
|
||||||
@@ -367,7 +331,4 @@ module.exports = {
|
|||||||
fileDiff,
|
fileDiff,
|
||||||
fileLastUpdatedIso,
|
fileLastUpdatedIso,
|
||||||
commitAndPushFindings,
|
commitAndPushFindings,
|
||||||
__test: {
|
|
||||||
assertSafeBranchRef,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ const assert = require('node:assert/strict');
|
|||||||
const test = require('node:test');
|
const test = require('node:test');
|
||||||
|
|
||||||
const gitrepo = require('../src/lib/gitrepo');
|
const gitrepo = require('../src/lib/gitrepo');
|
||||||
|
const gitref = require('../src/lib/gitref');
|
||||||
|
|
||||||
test('assertSafeBranchRef 接受一般分支名稱', () => {
|
test('assertSafeBranchRef 接受一般分支名稱', () => {
|
||||||
assert.equal(gitrepo.__test.assertSafeBranchRef('feature/review-123', 'baseRef'), 'feature/review-123');
|
assert.equal(gitref.assertSafeBranchRef('feature/review-123', 'baseRef'), 'feature/review-123');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('assertSafeBranchRef 拒絕路徑穿越分支名稱', () => {
|
test('assertSafeBranchRef 拒絕路徑穿越分支名稱', () => {
|
||||||
assert.throws(
|
assert.throws(
|
||||||
() => gitrepo.__test.assertSafeBranchRef('../../hooks/pre-push', 'baseRef'),
|
() => gitref.assertSafeBranchRef('../../hooks/pre-push', 'baseRef'),
|
||||||
/不是安全的分支名稱/,
|
/不是安全的分支名稱/,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user