feat(ai-code-review): 建問題模式導向 issue,並整併流程調整、文件與 CI #10
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#10
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.6cfbbbe5f6c3beb591848162100bdbc6073759731📋 變更摘要(送審 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⚔️ 攻擊方登場
🛡️ 防守方登場
🔴 嚴重|🔮 Mage
位置:
src/lib/gitrepo.js第 145–145 行問題描述
名為
deepen HEAD的補抓策略實際執行git fetch ... origin HEAD;這裡的HEAD由遠端解析,通常代表遠端預設分支,不是目前 checkout 的 PR head。最小重現為:PR 分支使用 shallow checkout、--unshallow不可用,且共同祖先位於目前 PR head 的淺層邊界之外;此策略只加深預設分支,PR head 歷史仍不完整,最後錯誤回報找不到 merge-base。修改建議
以明確的 PR head ref 或 SHA 補抓目前 head 的歷史;若介面沒有 head ref,可取得目前 HEAD SHA 後用伺服器支援的 refspec fetch,或使用會加深目前設定 refspec 的 fetch 方式,避免把遠端符號
HEAD當成本地目前 HEAD。建議寫法
🔴 嚴重|🗡️ Assassin
位置:
src/lib/gitrepo.js第 274–278 行問題描述
攻擊者若能讀取 runner 的程序命令列、診斷資訊或失敗例外,就可能取得完整 PAT。此處把
pushToken直接嵌入遠端 URL,再作為git push的命令列參數;推送失敗時,Node/Git 產生的錯誤也可能包含帶憑證的完整指令,並沿呼叫鏈進入頂層錯誤日誌。新增的 PAT 通常權限與效期都高於自動 token,外洩後可被用來竄改存取庫或存取其他資源。修改建議
不要把 PAT 放進 argv 或遠端 URL。改用僅存在於子程序環境的
GIT_ASKPASS/credential helper,並確保暫時 credential 設定於推送後清除;Git 執行封裝也應攔截錯誤並重新拋出不含命令列、URL、stdout 與 stderr 的安全錯誤。建議寫法
🔴 嚴重|🔮 Mage
位置:
src/lib/gitrepo.js第 276–276 行問題描述
提供
pushToken時仍把 Git HTTP 使用者名稱固定為ai-review-bot。若 PAT 屬於其他帳號,最小重現為:傳入開發者帳號的有效 PAT 後執行結果推送;伺服器會以錯誤的帳號/PAT 組合驗證,導致 push 失敗,新增的專用 PAT 功能無法運作。修改建議
新增與
push-token配對的使用者名稱輸入,或先以該 PAT 查詢實際帳號,再用取得的 login 組成認證 URL;不可假設所有 PAT 都屬於ai-review-bot。建議寫法
🟠 警告|🧰 Leo
位置:
src/index.js第 257–307 行問題描述
流程步驟編號同時硬編碼在 log 字串、區段註解、JSDoc、README 與多個函式庫中。本次只是插入一個步驟,就必須跨大量檔案把「步驟 3~8」全面改號;這種散落的同步責任很容易讓半年後新增或調整流程時產生文件與實際紀錄不一致。
修改建議
程式內改用穩定的語意階段名稱,例如
diff、attack、defend、publish,由單一流程定義集中決定顯示順序;JSDoc 以函式或階段名稱互相引用,不再引用易變動的數字。README 的流程圖則由同一份階段資料產生,或只在文件層維護展示編號。建議寫法
🟠 警告|⚡ Rogue
位置:
src/lib/gitrepo.js第 132–136 行問題描述
淺層 checkout 一旦首次
merge-base失敗,就優先執行git fetch --unshallow origin,可能把大型儲存庫的完整歷史一次下載到 runner;原本只需數百或數千筆 commit 的 merge-base,卻可能膨脹成 O(全庫歷史) 的網路傳輸、磁碟占用與處理時間。修改建議
先採用有限深度的 base/HEAD 補抓並重試 merge-base,只有多輪漸進加深仍失敗時,才把
--unshallow當最後手段,避免為一次 diff 浪費整份歷史的 I/O。建議寫法
🟠 警告|🧪 Maya
位置:
src/lib/gitrepo.js第 252–289 行問題描述
commitAndPushFindings新增pushToken推送分支,但沒有測試證明:有 PAT 時略過origin、PAT 推送失敗不會誤用一般 token、空 PAT 時仍維持 origin 失敗後以token重試,以及無檔案變更時完全不推送。這直接影響結果 commit 是否能觸發下一輪 CI,是本次變更的核心行為。修改建議
mock Git 命令並分別測試非空、空字串與未提供
pushToken;精確斷言 push 的呼叫次數、目標 ref 與分支選擇。另保留無 staged diff 的案例,確認回傳false且不執行 commit/push。🟠 警告|🗡️ Assassin
位置:
src/lib/review.js第 64–70 行問題描述
開啟
ACTIONS_STEP_DEBUG=true後,攻擊者可讓 AI CLI 回顯 PR diff、提示內容或任意敏感文字,再由此處把 stdout/stderr 寫入 CI log。redactSecrets只比對少數憑證外觀,無法可靠辨識 PII、短密碼、私鑰片段或不符合既定格式的機密;截斷至 500 字也不是資料防洩措施。只要提交惡意內容誘導 CLI 在失敗前回顯,即可能把存取庫秘密永久留在多人可讀的日誌。修改建議
CI 日誌即使在 debug 模式也不要輸出 AI CLI 的原始 stdout、stderr 或錯誤訊息;只記錄退出碼、訊號、逾時狀態與隨機診斷 ID。若確實需要內容級診斷,應寫入具存取控制與短保存期限的獨立 artifact,並採 allowlist 結構化欄位,而非依賴正規表示式遮罩。
建議寫法
🔵 建議|🎼 Bard
位置:
src/index.js第 195–205 行問題描述
postComment這個名字承諾「立即發布留言」,但建問題模式下實際上可能只把內容塞進issueBuffer,甚至回傳null。名稱與行為沒有押上同一個韻,呼叫端無法從字面判斷留言究竟已發布或仍在佇列中。修改建議
改用能涵蓋「發布或暫存」語意的名稱,例如
queueOrPostComment,並讓註解與回傳型別沿用相同詞彙。建議寫法
🔵 建議|🎼 Bard
位置:
src/index.js第 219–230 行問題描述
ensureIssueCreated不只「確保 issue 已建立」,還會依序發布所有暫存留言並清空 buffer;名稱淡化了這段具副作用且可能耗時的工作。此外函式本身沒有檢查既有issue,ensure一詞也暗示了並不存在的冪等性。修改建議
將名稱改成明確描述完整行為的
createIssueAndFlushBufferedComments;若確實要保留ensure,則應先檢查issue並把 flush 拆成獨立函式。建議寫法
🔵 建議|🧪 Maya
位置:
src/lib/gitea.js第 171–215 行問題描述
新增的
addLabelsToIssue與addIssueDependency沒有契約測試驗證 endpoint、HTTP method 與 request body;尤其相依關係的方向由 URL 與 body 決定,一旦參數次序寫反,mock 較粗略的主流程測試也不容易察覺。修改建議
補 Gitea client 單元測試:空或缺少 labels 時不呼叫 API並回傳
null;有 labels 時送出正確陣列;相依 API 應以 PR 編號置於 URL、追蹤 issue 編號置於index,並帶入正確 owner/repo。🔵 建議|🎼 Bard
位置:
src/lib/review.js第 75–78 行問題描述
診斷輸出的
500字元上限在相鄰兩行重複出現,讀者只能靠猜測理解這是共同政策還是巧合;日後調整時也容易讓 stderr 與 stdout 的節奏走成兩拍。修改建議
為診斷片段長度建立具名常數,讓限制的用途與一致性一目了然。
建議寫法
請把這個問題列為誤報
🤖 AI Code Review Resolve|處理結果
已依嚴重度(🔴 嚴重 → 🟠 警告 → 🔵 建議)逐條處理本 issue 的 11 條問題,結果如下:
src/lib/gitrepo.js145deepen HEAD改以目前 HEAD 的 commit SHA 補抓(原用遠端符號HEAD,只會加深遠端預設分支、補不到 PR head 歷史)src/lib/gitrepo.js274–278pushWithCredential以GIT_CONFIG_*環境變數注入認證、不進 argv,推送目標 URL 不含帳密,且失敗改拋固定訊息src/lib/gitrepo.js276exclusions.jsonsrc/index.js257–307src/lib/gitrepo.js132–136--unshallow已降為最後手段src/lib/gitrepo.js252–289src/lib/review.js64–70src/index.js195–205postComment→queueOrPostCommentsrc/index.js219–230ensureIssueCreated→createIssueAndFlushBufferedCommentssrc/lib/gitea.js171–215src/lib/review.js75–78AGENT_DIAGNOSTIC_OUTPUT_LIMIT(= 500)統計
exclusions.json:1 條(F3)待人工處理項追蹤
4 條待人工處理問題已寫回 findings 追蹤檔
.gitea/ai-review/findings/2026-07-20-18:00:02.json,確保關閉本 issue 後不會遺失待辦:src/index.js257–307src/lib/gitrepo.js252–289src/lib/review.js64–70src/lib/gitea.js171–215修復內容已於分支
ai-review-resolve/develop-20260717-185330提交,隨後對develop發 PR。本 issue 問題已全數分流完成(已修復/已解決/誤報/待人工追蹤),隨後關閉本 issue。