Files
ai-code-review/.gitea/ai-review/findings/2026-07-21-14:27:42.json
T
Jeffery d424447d15
node-actions/template: CI / BUILD (pull_request) Successful in 4s
CI / TEST (Antigravity) (pull_request) Successful in 52s
CI / TEST (Codex) (pull_request) Successful in 2m47s
CI / TEST (Claude) (pull_request) Successful in 26s
chore(ai-review 狀態): 回寫本輪已處理 findings
2026-07-21 14:39:42 +08:00

185 lines
12 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"generatedAt": "2026/07/21 14:27:42",
"commitSha": "9e7f8a2a0a807c26e12e9bf0381e7decfb9e5568",
"prNumber": 6,
"tool": {
"name": "codex",
"version": "codex-cli 0.144.6",
"model": "gpt-5.5"
},
"findings": [],
"excluded": [
{
"reviewer": "Assassin",
"focus": "security",
"badge": "🗡️",
"severity": "嚴重",
"file": "src/lib/diagnostics.js",
"startLine": 23,
"endLine": 23,
"problem": "攻擊者只要讓 AI CLI 在 debug 模式下把 `Authorization: token <secret>` 或 `Authorization: Basic <base64>` 印到 stderr/stdout,這條遮罩規則只會遮掉 `token``Basic` 這個 scheme,後面的真正憑證仍會進 CI log。這正好打穿本檔宣稱的「安全診斷」防線,PAT 或 API token 會被長期保存並暴露給可讀 log 的人。",
"suggestion": "把整個 Authorization header value 視為機密,不要只特判 Bearer。應遮掉 scheme 與 credential 全段;若要保留 scheme,也只能保留固定白名單字樣,不能留下後面的 token。",
"suggestedCode": ".replace(/(authorization\\s*[:=]\\s*)(?:\\S+\\s+)?\\S+/gi, '$1***')",
"id": "F001",
"verdicts": {
"Paladin": {
"exclude": true,
"reason": "可排除(重複)。歷史 finding 已指出除錯診斷輸出中 Authorization 遮罩規則可能只遮到 scheme、留下後方憑證,並造成 CI log 洩漏,與本條同一問題。"
}
}
},
{
"reviewer": "Leo",
"focus": "maintainability",
"badge": "🧰",
"severity": "警告",
"file": "src/index.js",
"startLine": 181,
"endLine": 239,
"problem": "`main()` 這次把「PR 留言」、「issue 暫存」、「issue 建立後 flush」三種狀態直接塞進閉包變數 `currentRunCommentIds`、`issueBuffer`、`issue` 與 `queueOrPostComment()`。未來只要再新增一種落地方式或調整留言順序,維護者必須同時理解整個主流程的時序,否則很容易出現留言漏發、舊留言誤標、或 issue 尚未建立卻被使用的狀態錯誤。這段已經不是單純編排,而是隱含一個留言發布狀態機。",
"suggestion": "把留言目的地抽成小型模組,例如 `CommentSink` / `ReviewPublisher`,讓 `main()` 只負責流程編排:`publisher.postContext()`、`publisher.flushIssue()`、`publisher.resolveOldPrComments()`。建問題模式的暫存與 flush 可獨立測試,半年後改流程時不用在 `main()` 裡追閉包狀態。",
"suggestedCode": "",
"id": "F007",
"verdicts": {
"Paladin": {
"exclude": true,
"reason": "可排除(命中已知排除事項且重複)。既有紀錄已涵蓋 main() 內留言路由、issue 狀態、緩衝佇列與發布狀態機耦合的同一問題。"
}
}
},
{
"reviewer": "Leo",
"focus": "maintainability",
"badge": "🧰",
"severity": "警告",
"file": "readme.md",
"startLine": 56,
"endLine": 132,
"problem": "README 這次把大量連結從 `branch/master` 改成 `branch/develop`,同時保留許多硬編碼行號。這種文件會隨分支名稱、預設分支、或任一檔案插入幾行就整批失準;未來維護者每次調整程式都得同步修幾十個 URL,否則文件看起來精準、實際上卻導到錯誤位置。",
"suggestion": "改用 repo 相對連結並盡量避免行號,例如 `src/lib/log.js` 或 `src/lib/log.js#L20` 只保留少數真正需要精準定位的 API。若這段是產生文件,請把分支名稱與連結格式集中在產生器設定,不要把同一個 branch 字串散落在 README 表格裡。",
"suggestedCode": "",
"id": "F008",
"verdicts": {
"Paladin": {
"exclude": true,
"reason": "可排除(重複)。歷史 findings 已多次指出 README 大量硬編 branch 與行號深連結,造成文件與原始碼高同步成本;本條為同一問題。"
}
}
},
{
"reviewer": "Mage",
"focus": "logic",
"badge": "🔮",
"severity": "警告",
"file": "src/index.js",
"startLine": 217,
"endLine": 225,
"problem": "建問題模式先建立 issue,再逐則 flush `issueBuffer`,但中途任一留言 API 失敗會直接拋出,沒有回滾或冪等處理。最小重現:`gitea.createIssue` 成功建立 #10,第一則 buffered comment 成功,第二則因 500/timeout 失敗 → 主流程 exit 1,PR 沒有 issue 連結、也沒有結果 commit;重跑時又建立 #11,留下半成品 issue #10。這會在暫時性 API 錯誤下造成重複追蹤 issue 與狀態不一致。",
"suggestion": "建立 issue 後立即寫入可重試識別資訊,重跑前先搜尋/復用既有本 PR 的 AI review issue;或在 flush 失敗時捕捉錯誤,將已建立 issue 補上失敗狀態與 PR 回連,再讓流程以可診斷方式收束。",
"suggestedCode": "",
"id": "F010",
"verdicts": {
"Paladin": {
"exclude": true,
"reason": "可排除(命中已知排除事項且重複)。issue 建立後 flush 暫存留言失敗、重跑又建立重複 issue,正是已知排除事項與多筆歷史 findings 已記錄的問題。"
}
}
},
{
"reviewer": "Maya",
"focus": "testing",
"badge": "🧪",
"severity": "警告",
"file": "src/index.js",
"startLine": 180,
"endLine": 241,
"problem": "建問題模式新增了「先暫存留言、確定有保留問題才建立 issue、再 flush 暫存留言」的流程,但目前新增測試只驗到低階 helper,沒有驗證主流程在 create-issue=true 時的留言去向與靜默通過行為。這裡若順序錯了,可能會把原本應該留在 issue 的工具/diff/角色留言發到 PR,或在無保留問題時留下不該出現的 PR 留言。",
"suggestion": "請補主流程層級測試,stub `gitea`、`review.runAttackers`、`review.runDefenders`、`agents.detectTool`,至少驗證:\n\n| 情境 | 應斷言 |\n| --- | --- |\n| `createIssue=true` 且 `kept.length > 0` | 建 issue 前的情境留言先暫存,issue 建立後依序寫入該 issue |\n| `createIssue=true` 且 `kept.length === 0` | 不建立 issue、不對 PR 留言、不呼叫 `resolveOldComments` |\n| 一般模式 | 情境留言仍發到 PR,且 id 被加入 `currentRunCommentIds` |",
"suggestedCode": "",
"id": "F012",
"verdicts": {
"Paladin": {
"exclude": true,
"reason": "可排除(重複)。歷史 findings 已涵蓋 create-issue 模式中留言先暫存、issue 建立後依序寫入、無 finding 靜默通過與一般模式留言目的地缺少主流程測試。"
}
}
},
{
"reviewer": "Maya",
"focus": "testing",
"badge": "🧪",
"severity": "警告",
"file": "src/index.js",
"startLine": 354,
"endLine": 395,
"problem": "新增的建問題模式會依嚴重度分流:嚴重問題改發到 issue、PR 回貼 issue 連結,且只有嚴重問題才呼叫 `addIssueDependency`。目前測試沒有覆蓋這個決策矩陣,等於沒有驗證「警告/建議不阻擋合併」與「嚴重問題要建立相依」這兩個關鍵行為。",
"suggestion": "請補 create-issue 模式的結果分流測試,至少涵蓋:\n\n| findings | 應斷言 |\n| --- | --- |\n| 只有警告/建議 | 建 issue、逐條留言、PR 回貼連結,但不呼叫 `addIssueDependency` |\n| 有嚴重問題 | 呼叫 `postSevereToIssue`、PR 回貼連結,並呼叫 `addIssueDependency(ctx, ctx.prNumber, issue.number)` |\n| `addIssueDependency` 拋錯 | 流程降級完成,不中斷收尾 commit |",
"suggestedCode": "",
"id": "F013",
"verdicts": {
"Paladin": {
"exclude": true,
"reason": "可排除(重複)。歷史 findings 已涵蓋建問題模式的嚴重/非嚴重分流、PR 回貼、相依 API 降級與核心分支缺少測試;本條屬同一測試缺口。"
}
}
},
{
"reviewer": "Maya",
"focus": "testing",
"badge": "🧪",
"severity": "警告",
"file": "src/lib/gitrepo.js",
"startLine": 130,
"endLine": 188,
"problem": "`resolveMergeBase` 新增了多段 fetch 補歷史策略、每次補抓後重試 merge-base、以及淺層 repo 才執行 `--unshallow` 的行為,但測試只驗證不安全 baseRef 會被拒絕,沒有驗證這些成功/失敗路徑。這段是 diff 基準的核心,一旦 fallback 順序或條件壞掉,review 可能拿錯範圍或在 shallow checkout 直接失敗。",
"suggestion": "請把 git 執行層抽成可注入或以臨時 repo 測試,補齊:首次 merge-base 成功不跑 fallback、deepen base 後成功即停止、deepen PR HEAD 用目前 HEAD SHA、只有 shallow repo 才嘗試 `--unshallow`、全部策略失敗時錯誤訊息含診斷且保留 cause。",
"suggestedCode": "",
"id": "F014",
"verdicts": {
"Paladin": {
"exclude": true,
"reason": "可排除(重複)。歷史 findings 已針對 resolveMergeBase 多階段 fetch、shallow 與非 shallow 分支、停止條件、降級與最終失敗診斷缺少測試提出相同問題。"
}
}
},
{
"reviewer": "Maya",
"focus": "testing",
"badge": "🧪",
"severity": "警告",
"file": "src/lib/gitrepo.js",
"startLine": 331,
"endLine": 366,
"problem": "`pushWithCredential` 是這次結果 commit 能否用 PAT 觸發下一輪 CI 的關鍵,但目前沒有測試驗證它真的清掉 checkout 的自動 token、再注入 PAT Authorization,也沒有測失敗時不外洩 remote URL/token。這條失敗路徑沒被試煉過,可能讓 `[failure]` 結果 commit 無法觸發快速回報,或在錯誤訊息裡洩漏認證資訊。",
"suggestion": "請補 `commitAndPushFindings``pushWithCredential` 的測試,stub `execFileSync` 驗證:`git push` 使用不含帳密的 remote URL、`GIT_CONFIG_COUNT=2`、第 0 筆 extraheader 為空值、第 1 筆為 Basic Authorization、remote origin 不符時拒絕、push 失敗時拋出的錯誤不包含 token 或 remote URL。",
"suggestedCode": "",
"id": "F015",
"verdicts": {
"Paladin": {
"exclude": true,
"reason": "可排除(重複)。歷史 findings 已涵蓋 pushWithCredentialcommitAndPushFindings 的認證推送策略、token 注入、推送目標與失敗時不外洩 token 或 URL 的測試缺口。"
}
}
},
{
"reviewer": "Maya",
"focus": "testing",
"badge": "🧪",
"severity": "建議",
"file": "src/lib/diagnostics.js",
"startLine": 21,
"endLine": 32,
"problem": "`redactSecrets` 新增多個遮罩規則與控制字元單行化,但測試只透過 `agentFailureDetail` 間接覆蓋 Authorization 與 token 兩種格式。URL 內嵌帳密、長 token、GitHub token 樣式、控制字元注入與 null/undefined 邊界都還沒被直接驗證。",
"suggestion": "請補 `redactSecrets` 的直接單元測試,包含:`https://user:pass@host`、`ghp_...`、40 字以上 token、含換行/tab 的假日誌注入、`null``undefined`。斷言重點是輸出為單行、敏感片段被 `***` 取代,且一般錯誤文字仍保留可診斷性。",
"suggestedCode": "",
"id": "F016",
"verdicts": {
"Paladin": {
"exclude": true,
"reason": "可排除(重複)。歷史 findings 已記錄失敗診斷與 redactSecrets 對 Authorization、URL 帳密、token 格式、控制字元、截斷與空值邊界缺少測試;本條為同一測試缺口。"
}
}
}
]
}