185 lines
12 KiB
JSON
185 lines
12 KiB
JSON
{
|
||
"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 已涵蓋 pushWithCredential/commitAndPushFindings 的認證推送策略、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 格式、控制字元、截斷與空值邊界缺少測試;本條為同一測試缺口。"
|
||
}
|
||
}
|
||
}
|
||
]
|
||
}
|