feat(ai-code-review): 建問題模式導向 issue,並整併流程調整、文件與 CI #9
Notifications
Due Date
No due date set.
Blocks
#6 feat(ai-code-review): 建問題模式導向 issue,並整併流程調整、文件與 CI
node-actions/ai-code-review
Reference: node-actions/ai-code-review#9
Reference in New Issue
Block a user
變更摘要
本 PR 將 ai-code-review action 分支的完整成果併入
develop,主要含四塊:create-issue: 'true'時,審查留言(工具/diff/角色/嚴重問題/警告+建議)全部改發到追蹤 issue、不再張貼到 PR;不執行「舊留言標過時/resolve」;issue 延後到「確定有保留問題」才建立;無保留問題或無可審查變更則不建 issue、PR 也完全不留言(靜默通過);有問題時最後在 PR 回貼一則 issue 連結並補掛標籤,形成雙向關聯。action.yml/src各模組文件、重建readme.md,新增.gitea/workflows/ci.yaml(多工具 code review 驗證)並啟用建問題模式。影響範圍
src/index.jsmain()依模式分流:留言去向、跳過 resolveOldComments、issue 延後建立、severe/others 導向 issue、有問題才在 PR 回貼連結src/lib/gitea.js新增addLabelsToIssuesrc/lib/templates.js新增issueLinkCommentsrc/lib/review.js新增postSevereToIssue,移除createIssueWithFindings、sortFindingsForIssuesrc/lib/gitrepo.js補抓淺層 checkout 的 base 歷史readme.md、action.yml、.gitea/workflows/ci.yaml、.gitea/workflows/readme.md風險與注意事項
readme.md尚未反映「建問題模式導向 issue」的最新行為與新/移除的函式,建議後續以 doc-funcs 重建文件。2026/07/17 18:49:58,未刷新。🤖 AI Code Review|審查工具
codexcodex-cli 0.144.6b2129e0bc6c533cc5cfabd198698950377495966📋 變更摘要(送審 git diff)
action.ymlreadme.mdsrc/index.jssrc/lib/agents.jssrc/lib/context.jssrc/lib/gitea.jssrc/lib/gitrepo.jssrc/lib/review.jssrc/lib/roles.jssrc/lib/templates.js⚔️ 攻擊方登場
🛡️ 防守方登場
🔴 嚴重|🗡️ Assassin
位置:
src/lib/gitrepo.js第 273–278 行問題描述
攻擊者只要讓 PAT 推送失敗,
git執行錯誤就可能把含pushToken的完整遠端 URL收進錯誤訊息;例外再往上傳到主流程日誌後,具寫入權限的 PAT 便會暴露於 CI 紀錄。註解宣稱不輸出 URL 並不能阻止底層程序錯誤回顯命令列。修改建議
不要把憑證放進 Git 命令列或遠端 URL。改用暫時的
GIT_ASKPASS/credential helper,並在所有錯誤跨越日誌邊界前強制移除 PAT;暫存憑證檔須設為僅擁有者可讀並於finally清除。建議寫法
🟠 警告|🧰 Leo
位置:
src/index.js第 121–145 行問題描述
流程步驟編號被硬編碼在主流程註解、日誌字串、README 與多個函式 JSDoc 中;本次僅插入一個步驟,就必須同步修改大量檔案。這已顯示文件與實作存在高耦合,未來再次調整流程時很容易漏改,造成日誌、文件與實際執行順序互相矛盾。
修改建議
共用函式的 JSDoc 改以語意階段名稱描述,不引用易變動的數字;日誌則集中定義階段名稱或由單一流程描述產生編號。README 的流程圖也應以語意名稱為主,避免把編號當成跨模組契約。
建議寫法
🟠 警告|🔮 Mage
位置:
src/index.js第 343–343 行問題描述
舊審查留言仍在新問題留言發布前就被標記為過時。最小重現:裁決成功後執行此行,舊 finding 已被解決/加上過時標記;接著
postSevereComments或步驟 10 的 PR 留言 API 失敗,流程以錯誤結束,PR 上便只剩工具、diff、角色等情境留言,既有問題已失效而新的問題尚未發布。這仍違反本次改動宣稱的「避免舊結果先被清掉卻沒有新結果」。修改建議
先完整發布本回合所有問題留言,確認成功後再呼叫
resolveOldComments。為避免新留言被一併清理,讓嚴重問題留言函式回傳建立的留言/review ID,加入本回合排除集合;或讓清理函式只處理本回合開始前取得的舊留言快照。🟠 警告|🧪 Maya
位置:
src/lib/gitea.js第 172–215 行問題描述
新增加標籤與建立 issue 相依關係的 API 封裝沒有對應測試。尚未驗證空標籤不送請求、issue 編號與 repository 資訊正確放入 URL/body,以及非 2xx 錯誤是否原樣往上傳遞;端點或 payload 任一欄位錯誤都只會在實際 PR 執行時被發現。
修改建議
mock 底層 API,驗證
addLabelsToIssue([], null)不發請求並回傳 null;有標籤時使用正確 endpoint 與{labels}。另驗證addIssueDependency的 URL issue 編號及{index, owner, repo}payload,並加入 4xx/5xx 拋錯案例,搭配主流程測試確認相依失敗會被降級而不阻斷審查。🟠 警告|🧰 Leo
位置:
src/lib/gitrepo.js第 47–65 行問題描述
tryGit將所有 Git 失敗壓成布林值,呼叫端只能知道策略失敗,無法區分認證失敗、refspec 錯誤、網路問題或 Git 版本不支援。新增的resolveMergeBase雖彙整策略成敗,卻刻意捨棄真正原因;未來 CI 出錯時,維護者只能重跑或自行重現,診斷成本會很高。修改建議
讓嘗試結果保留結構化且已清理的錯誤分類,例如 exit code、Git 子命令與安全化後的短訊息;仍可避免記錄遠端 URL 或憑證。如此既能依序降級,也能在最終錯誤中提供足以採取行動的原因,並可對各失敗類型做單元測試。
建議寫法
🟠 警告|⚡ Rogue
位置:
src/lib/gitrepo.js第 138–140 行問題描述
淺層 checkout 找不到 merge-base 時,第一個補救策略直接執行
--unshallow,會先下載整個儲存庫歷史;大型或長壽 repo 可能多傳輸數百 MB、耗費數十秒到數分鐘,即使只加深少量歷史便足以找到共同祖先。修改建議
先以固定深度分批加深 base 與 HEAD,並在每次 fetch 後重試 merge-base;只有達到合理上限仍失敗時才把
--unshallow當最後手段。建議寫法
🟠 警告|🧪 Maya
位置:
src/lib/gitrepo.js第 270–291 行問題描述
新增
pushToken後,push 行為分成「PAT 直接推送」與「origin 失敗後使用一般 token 重試」,但本次 diff 沒有測試這兩條認證路徑。尚未驗證空字串邊界、PAT 路徑不碰 origin、origin 成功時不建立認證 URL,以及失敗重試使用正確 token;若分支選錯,可能讓 CI 不再觸發或直接無法推送。修改建議
補單元測試攔截 git 參數:有
pushToken時只推送一次且使用 PAT URL;沒有或空白 token 時先推 origin;origin 成功不得重試;origin 失敗才以token重試。斷言測試輸出與錯誤訊息中不含任何 token 原文。🟠 警告|🗡️ Assassin
位置:
src/lib/review.js第 62–70 行問題描述
攻擊者可在送審 diff 或 AI 回覆中安插會被 CLI 回顯的敏感內容;開啟
ACTIONS_STEP_DEBUG後,程式便把 stderr/stdout 寫入 CI 日誌。黑名單遮罩無法涵蓋任意格式的 token、JWT、私鑰、PII 或原始碼機密,且截取前 500 字不會降低外洩風險。修改建議
CI 日誌一律不要輸出 AI CLI 的原始 stderr/stdout,即使在 debug 模式亦然;只記錄退出碼、訊號與預先定義的錯誤分類。若確實需要除錯內容,應寫入權限受控、短期保存的 artifact,並先套用結構化允許清單與平台 secret masking。
建議寫法
🔵 建議|🎼 Bard
位置:
action.yml第 3–3 行問題描述
檔頭的「更新時間」仍寫成
2026/07/17 18:49:58,與本次變更所示的檔案更新時間2026/07/20 15:00:23不一致。手動維護且散落各檔的時間戳已經走調,讀者無法判斷哪個資訊可信。修改建議
移除容易過期的手動更新時間,改以版本控制紀錄作為唯一依據;若專案規範要求保留,則應由腳本統一產生並同步更新所有位置。
建議寫法
🔵 建議|🎼 Bard
位置:
readme.md第 3–3 行問題描述
README 的手動「更新時間」與本次檔案實際更新時間不符,也和
action.yml、src/index.js重複保存同一類易過期資訊。這種散落的版本註記會逐漸形成彼此不押韻的多個真相來源。修改建議
刪除此手動時間戳,讓 Git 歷史承擔更新追蹤;若讀者確實需要顯示更新日期,請由發布流程自動注入,避免人工同步。
建議寫法
🔵 建議|🎼 Bard
位置:
src/index.js第 7–7 行問題描述
啟動橫幅硬編碼的「更新時間」與本次程式實際更新時間不一致,而且每次修改程式都得額外人工校準,既製造視覺噪音,也讓執行日誌呈現失真的版本資訊。
修改建議
移除手動時間戳;若日誌需要辨識執行版本,改顯示由建置或 CI 注入的 commit SHA/版本號,語義會比模糊的更新時間更穩定。
建議寫法
🔵 建議|🎼 Bard
位置:
src/index.js第 179–231 行問題描述
main()內新增兩個帶完整 JSDoc 的閉包函式,再接上一大段「步驟 2:延後執行」說明,使主流程在真正進入步驟 3 前被近六十行細節打斷。審查編排應像總譜般一眼看出段落走向,目前留言路由、issue 建立與流程辯解混在同一層,閱讀節奏顯得沉重。修改建議
將留言路由與 issue 建立封裝成具語義名稱的輔助物件或模組,例如
createCommentPublisher,讓main()只保留流程級呼叫;延後清理的理由則縮成一則貼近實際呼叫點的簡短註解。建議寫法
🔵 建議|🎼 Bard
位置:
src/lib/gitea.js第 171–194 行問題描述
新增的
addLabelsToIssue在同一份變更中已被主流程明確註明「不再於事後補掛」,卻仍以大篇幅註解保留為未見使用情境的通用能力。這段程式與本次實際流程沒有呼應,讓 API 表面多出一個無聲部可接的樂句,也增加讀者辨識真正入口的負擔。修改建議
若目前沒有呼叫端,先移除此函式與匯出;待出現實際需求時再連同使用情境加入。若確有外部使用者,則應在文件中明確列出呼叫契約,而非只以「通用能力」籠統交代。
🔧 AI Code Review 問題處理進度
已依嚴重度逐條處理議題 #9(審查 commit
b2129e0)的 13 條問題。由於 #9 審的是較早的 commit,多條所指程式碼已在後續 commit 修復,逐一對照目前程式碼確認。統計:✅ 已解決 3 條、🚫 不採納 2 條、⏭️ 待人工處理 8 條。
exclusions.json本輪無新增(兩條不採納皆已有等價排除項)。src/lib/gitrepo.jsGIT_CONFIG_*/extraheader 以 env 傳入、不進 argv,URL 不含帳密、push 失敗遮蔽錯誤(先前 commit8349fe8等)src/lib/gitea.jsaddLabelsToIssue已移除(先前 commit0a51aff)src/lib/gitrepo.jsresolveMergeBase改為先 deepen base/HEAD、--unshallow降為最後手段,避免大型 repo 只為找共同祖先就拉全史(本輪修復)src/index.jsresolveOldComments時序——維護者(議題 #8 留言 #4838)已明確裁示舊留言須刻意在本回合結果前標記過時、不可延後;exclusions.json已有等價排除src/lib/review.jsredactSecrets遮罩的片段」以便診斷(如 claude OAuth 過期即靠此查出),方向相反;exclusions.json已有等價排除src/index.jssrc/lib/gitea.jssrc/lib/gitrepo.jstryGit改結構化錯誤(保留 sanitize 後原因)——診斷重構+需測試src/lib/gitrepo.jsaction.ymlreadme.mdsrc/index.jssrc/index.js⏭️ 待人工處理已寫回 findings 追蹤
8 條待人工處理已寫成 findings wrapper 檔
.gitea/ai-review/findings/2026-07-20-17:37:54.json(F001–F008)供後續追蹤,不會因關閉議題而遺失。待人工處理共同原因
多為「無測試框架/devDependencies」(Maya 測試)、「跨檔/主流程重構+設計取捨」(Leo 步驟語意化、tryGit 結構化、Bard publisher 抽離)或「jsc spec-time-log 時間戳慣例(交 doc-funcs 統一)」。皆屬架構/慣例決策,依規範不逕自硬改。