From 888d503d1d5cbf154d705d5e828c3e89170ffaac Mon Sep 17 00:00:00 2001 From: Jeffery Date: Wed, 15 Jul 2026 10:43:21 +0800 Subject: [PATCH] =?UTF-8?q?chore(ai-review=20=E7=8B=80=E6=85=8B):=20?= =?UTF-8?q?=E6=B8=85=E7=A9=BA=20findings=20=E4=B8=A6=E7=99=BB=E8=A8=98?= =?UTF-8?q?=E5=9B=9E=E6=87=89=E6=91=98=E8=A6=81=E5=91=8A=E8=AD=A6=E7=82=BA?= =?UTF-8?q?=E8=AA=A4=E5=A0=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .gitea/ai-review/exclusions.json | 8 +++++ .gitea/ai-review/findings.json | 51 +------------------------------- 2 files changed, 9 insertions(+), 50 deletions(-) diff --git a/.gitea/ai-review/exclusions.json b/.gitea/ai-review/exclusions.json index b884c6a..d93f429 100644 --- a/.gitea/ai-review/exclusions.json +++ b/.gitea/ai-review/exclusions.json @@ -142,5 +142,13 @@ "reason": "release 數量預期不大,全量排序成本可忽略;後續同時需要「保留的前 K 筆」與「其餘待刪清單」,一次排序是最直接清楚的實作,引入 top-K 堆反而增加複雜度(與既有「分頁結果先完整收集到陣列」的排除理由一致)。", "source": "develop...ai-review-resolve/develop-20260711-131608", "date": "2026-07-15" + }, + { + "location": "src/index.js:317", + "role": "Assassin", + "original_finding": "例外訊息只保留 HTTP 狀態碼與請求目標,不要預設帶回應 body;若真的需要除錯資訊,改成在受控的 debug 模式下才輸出,而且要先過濾敏感欄位並更短截斷。", + "reason": "已有等價防護:回應摘要先經 sanitizeLogText 去除控制字元(無法注入換行/ANSI 偽造 log),再截斷至 200 字;請求對象是參數檢查階段驗證過的 HTTPS Gitea 端點,非任意外部來源。保留截斷後的錯誤摘要對排查 API 失敗(如 403 權限訊息)必要,移除反而增加維運成本。", + "source": "develop...master", + "date": "2026-07-15" } ] diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 4eb067d..fe51488 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1,50 +1 @@ -[ - { - "level": "warning", - "role": "Mage", - "problem": "`KEEP_COUNT` 只驗證是數字字串,沒有保證落在安全整數範圍內。像 `9007199254740993` 這種值會在 `Number()` 轉換時失真,導致 `releaseCount <= keepCount` 與 `slice(keepCount)` 的保留/刪除判斷偏掉,最終清理結果可能和設定不一致。", - "suggestion": "除了字串格式外,還要驗證 `Number.isSafeInteger(Number(KEEP_COUNT))`,並加上合理上限;超出範圍時直接報錯,避免用不精確的數值做刪除決策。", - "location": "src/index.js:336", - "is_new": false - }, - { - "level": "warning", - "role": "Assassin", - "location": "src/index.js:317", - "problem": "非 2xx 回應時,這裡會把遠端回應 body 的摘要直接拼進例外訊息。攻擊者只要能控制對端回應,就能把內部錯誤、設定細節或其他敏感字串塞進 CI logs,讓有 log 權限的人直接讀到。", - "suggestion": "例外訊息只保留 HTTP 狀態碼與請求目標,不要預設帶回應 body;若真的需要除錯資訊,改成在受控的 debug 模式下才輸出,而且要先過濾敏感欄位並更短截斷。", - "is_new": true - }, - { - "level": "warning", - "role": "Mage", - "location": "src/index.js:308", - "problem": "這裡把分頁數硬性上限鎖死為 1000 頁。只要 releases 或 tags 的總量超過這個門檻,`fetchAllPages` 就會直接拋錯中止,即使 API 其實還有資料可取。以每頁 30 筆來算,超過約 3 萬筆就會永久卡死清理流程。", - "suggestion": "改用 API 回傳的分頁資訊或 `Link` header 判斷是否還有下一頁;如果仍要保留上限,請改成可設定且預設足夠大的值,而不是固定寫死。", - "is_new": true - }, - { - "level": "warning", - "role": "Mage", - "location": "src/index.js:460", - "problem": "當 `releaseItem.id` 缺失或不是安全整數時,這裡只警告然後回傳 `true`,等於把資料異常當成處理成功。最壞情況是 API 回傳壞資料或 schema 改版,舊 release 被靜默跳過,最後 job 仍可能顯示成功。", - "suggestion": "遇到無效 `id` 時應直接視為失敗,改成 `throw` 或回傳 `false`,讓工作非正常結束並停止後續 tag 清理。", - "is_new": true - }, - { - "level": "warning", - "role": "Mage", - "location": "src/index.js:504", - "problem": "tag 沒有 `name` 時也只是警告後回傳 `true`,這會讓壞資料被靜默略過。若 tag 清單中出現異常項目,cleanup 會看起來成功,但實際上有 tag 沒被處理。", - "suggestion": "把空白或缺失的 `name` 視為失敗,至少讓整體結果反映出資料異常;不要把無法辨識的 tag 當成成功案例。", - "is_new": true - }, - { - "level": "info", - "role": "Assassin", - "location": "src/index.js:536", - "problem": "這裡直接輸出 `error.stack`,會把檔案路徑、函式名稱與執行細節一起灑到標準錯誤。對能看 CI logs 的人來說,這等於免費拿到更多內部結構資訊,方便後續針對性利用。", - "suggestion": "預設只輸出 `error.message` 或自訂錯誤代碼;堆疊資訊只在明確開啟除錯模式時才顯示,避免把內部實作細節帶到正式 log。", - "is_new": true - } -] +[]