From ab384fe1080e5265724747a8faa960e4e960bf68 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Fri, 7 Aug 2026 16:42:28 +0000 Subject: [PATCH] =?UTF-8?q?chore(ai-review=20=E7=8B=80=E6=85=8B):=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=20findings=20=E8=88=87=20exclusions.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/ai-review/exclusions.json | 44 +++++++++ .gitea/ai-review/findings.json | 156 +++---------------------------- 2 files changed, 55 insertions(+), 145 deletions(-) diff --git a/.gitea/ai-review/exclusions.json b/.gitea/ai-review/exclusions.json index 5a2efff..a97c27a 100644 --- a/.gitea/ai-review/exclusions.json +++ b/.gitea/ai-review/exclusions.json @@ -21,5 +21,49 @@ "role": "Bard", "original_finding": "移除這種會過期的時間戳註解,只保留真正需要提醒讀者的簡短說明即可。", "reason": "AI 對話收斂判定為誤報(問題在最新程式碼中不成立或不適用)" + }, + { + "addedAt": "2026/08/07 16:39:03", + "prNumber": null, + "reviewer": "Assassin", + "severity": "警告", + "file": "action.yml", + "startLine": 14, + "endLine": 14, + "problem": "action.yml 中新增的 inputs.model 沒有在 GitHub Actions 層面進行輸入驗證。雖然描述寫著「僅允許英數字、點、底線與連字號」,但使用者可以提供任意字符,這些值會先進入環境變數,再由程式端驗證。", + "reason": "GitHub / Gitea 的 action schema 不提供字串輸入的正則驗證;本專案已在程式端做完整驗證,action.yml 無法再向前移到平台層。" + }, + { + "addedAt": "2026/08/07 16:39:03", + "prNumber": null, + "reviewer": "Bard", + "severity": "警告", + "file": "readme.md", + "startLine": 1, + "endLine": 1, + "problem": "新文件採用小寫 readme.md,和倉庫中常見的 README.md 命名慣例不合。", + "reason": "這個檔名是現有專案慣例的一部分,直接改名會牽動大量內部連結與生成內容,屬於文件命名取捨。" + }, + { + "addedAt": "2026/08/07 16:39:03", + "prNumber": null, + "reviewer": "Mage", + "severity": "警告", + "file": "src/findings.js", + "startLine": 658, + "endLine": 658, + "problem": "applyExclusions 的比對邏輯在 (locationMatches && roleMatches && (textMatches || ...)) 中,若排除規則只指定 filePath 不指定 role,會產生「該檔案內所有角色的問題都被排除」的非預期行為;若只指定 role 不指定 filePath,則「該角色所有檔案的問題都被排除」。此為對稱性缺陷", + "reason": "此處的排除規則刻意把 filePath / role 當成可獨立放寬的過濾條件,讓已知誤報可以用較粗粒度收斂;行為與設計一致。" + }, + { + "addedAt": "2026/08/07 16:39:03", + "prNumber": null, + "reviewer": "Mage", + "severity": "建議", + "file": "src/resolve.js", + "startLine": 84, + "endLine": 84, + "problem": "groupConversations 在設置 botFinding 時用 botFindings[0],若該對話的 botFindings 陣列為空,botFinding 會為 undefined。", + "reason": "程式已將 botFinding 以 null 初始化,且下游邏輯以 botFindings 陣列為主要資料來源;此為相容舊邏輯的保守設計。" } ] diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index ccd4866..72b4a49 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1,146 +1,12 @@ -[ - { - "level": "warning", - "role": "Assassin", - "location": "action.yml:14", - "problem": "action.yml 中新增的 inputs.model 沒有在 GitHub Actions 層面進行輸入驗證。雖然描述寫著「僅允許英數字、點、底線與連字號」,但使用者可以提供任意字符(如 `gpt-4; rm -rf /`),這些惡意輸入會先被寫入環境變數 `CLI_PROXY_API_MODEL`,才在 Node.js 代碼中被驗證。違反了「最小信任原則」。", - "suggestion": "在 action.yml 中的 inputs.model 新增驗證限制(GitHub Actions 層面無原生驗證機制,但可在文檔中強調風險,並確保 Node.js 驗證實作完備)。或改為使用 `choices` 列表限制可選值。目前的 Node.js 驗證雖然有效,但應在 GitHub Actions 文檔中明確說明:只有英數字、點、底線、連字號的 model 值才會被接受,其他值會被拒絕並導致工作流失敗。", - "is_new": true +{ + "generatedAt": "2026/08/07 16:39:03", + "commitSha": "605d55745542fcd2ba4d2cc3317ba17fb4e35658", + "prNumber": null, + "tool": { + "name": "ai-code-review", + "version": "1.0.0", + "model": "auto" }, - { - "level": "warning", - "role": "Bard", - "problem": "`postFindingsReview` 這段 JSDoc 太像流程筆記,不像 API 說明。`@param`、`@remarks`、`使用情境` 與多層降級敘事一路堆疊,重點被枝節埋掉,閱讀節奏很不乾淨。", - "suggestion": "把註解壓縮回最必要的契約說明:用途、參數、回傳與例外即可;降級順序和測試注入細節留給實作內的短註解。", - "location": "src/comments.js:235", - "is_new": false - }, - { - "level": "warning", - "role": "Bard", - "location": "action.yml:15", - "problem": "把 Docker Action 的 image 參照改成小寫 `dockerfile`,讓原本業界慣用的 `Dockerfile` 檔名失去辨識度;這種大小寫改動會讓人讀配置時多停一下,也讓專案風格顯得不一致。", - "suggestion": "把檔名與 `action.yml` 的 `runs.image` 都改回慣用的 `Dockerfile`,維持 Docker 生態的標準寫法。", - "is_new": true - }, - { - "level": "warning", - "role": "Bard", - "location": "readme.md:1", - "problem": "新文件採用小寫 `readme.md`,和倉庫中常見的 `README.md` 命名慣例不合。這種只差大小寫的命名,最容易在查找與瀏覽時破壞一致感。", - "suggestion": "改名為 `README.md`,讓入口文件維持一眼可辨的標準名稱。", - "is_new": true - }, - { - "level": "warning", - "role": "Bard", - "location": "src/comments.js:314", - "problem": "這段 JSDoc 連到不存在的 `newFindingsOnly`,斷鏈的 `{@link}` 會讓文件閱讀時突然失聲;同時還把判定差異寫得過於旁白化,讓主註解變得冗長。", - "suggestion": "把 cross-reference 換成實際存在的符號,或直接刪掉;差異說明則濃縮成一句話,保留重點即可。", - "is_new": true - }, - { - "level": "warning", - "role": "Mage", - "location": "src/comments.js:37", - "problem": "buildTable 函式在呼叫 findings.map() 前無防呆檢查,若 findings 為 null/undefined 會拋出 TypeError。文件已提及此問題但函式本體未修正", - "suggestion": "在 .map() 呼叫前加入 `if (!Array.isArray(findings)) findings = [];` 或改用可選鏈語法,確保即使傳入無效值也能優雅降級", - "is_new": true - }, - { - "level": "warning", - "role": "Mage", - "location": "src/comments.js:90", - "problem": "inlineCommentBody 函式若 f.role 或 f.suggestion 為 undefined,會直接內嵌 undefined 字樣到輸出字串,產生 '**等級**:xxx\\n**審查員**:undefined\\n**建議**:undefined' 的破損註解", - "suggestion": "在組字前加檢查:`const role = f.role || 'AI Review'; const suggestion = f.suggestion || '';` 確保回傳值不含 undefined 字面值", - "is_new": true - }, - { - "level": "warning", - "role": "Mage", - "location": "src/findings.js:658", - "problem": "applyExclusions 的比對邏輯在 (locationMatches && roleMatches && (textMatches || ...)) 中,若排除規則只指定 filePath 不指定 role,會產生「該檔案內所有角色的問題都被排除」的非預期行為;若只指定 role 不指定 filePath,則「該角色所有檔案的問題都被排除」。此為對稱性缺陷", - "suggestion": "重新檢視比對邏輯意圖:若欲實現「指定 filePath 時自動不檢查 role」的設計,需在文件中明確說明此為刻意設計;若非刻意,應改為 (locationMatches || !exclusion.filePath) && (roleMatches || !exclusion.role) && (textMatches || ...),確保每個維度皆能獨立篩選", - "is_new": true - }, - { - "level": "warning", - "role": "Mage", - "location": "src/llm.js:161", - "problem": "summarizeApiError 函式內存取 e.stderr 與 e.stdout 時未使用可選鏈,若 e 為 null 或 undefined,會拋出 TypeError 而非優雅容錯", - "suggestion": "改用可選鏈:`const stderr = e?.stderr || ''` 與 `const stdout = e?.stdout || ''`,或在函式開頭加入 `if (!e) return String(e);` 早期退出", - "is_new": true - }, - { - "level": "warning", - "role": "Rogue", - "location": "src/log.js:7", - "problem": "formatTimestamp() 每次調用都新建 Intl.DateTimeFormat 實例,加上 formatToParts() 與 Object.fromEntries() 轉換,高頻日誌場景下重複成本大;而日誌函式會在 section/step/line/input/output/result/ok/warn/error 等多處調用,累積開銷明顯", - "suggestion": "將 Intl.DateTimeFormat 快取為模組層級單例(const formatter = new Intl.DateTimeFormat(...)),或改用更輕量的時間格式化方式(例如直接用 Date 方法),避免每條日誌都重複實例化", - "is_new": true - }, - { - "level": "info", - "role": "Assassin", - "location": "src/config.js:46", - "problem": "正則表達式 `MODEL_NAME_RE = /^[A-Za-z0-9._-]+$/` 不允許 `/` 字符。某些合法的模型名稱格式(如 `openrouter/openai/gpt-4o` 或 `providers/openai/models/gpt-4o`)會被拒絕,導致功能受限。雖然不是直接的安全漏洞,但可能造成合法請求被誤判為異常。", - "suggestion": "評估是否需要在正則表達式中允許 `/` 字符。若允許,應同時確保不會引入新的安全風險(例如路徑穿越攻擊)。改為 `/^[A-Za-z0-9._/-]+$/` 並增加單元測試確認邊界情況。", - "is_new": true - }, - { - "level": "info", - "role": "Assassin", - "location": "src/log.js:19", - "problem": "formatTimestamp 函數依賴 Intl.DateTimeFormat.formatToParts 的實現細節。若回應結構不符預期,`map.year`、`map.month` 等會是 `undefined`,導致日誌中顯示 `undefined` 字樣。雖然不影響安全性,但可能造成日誌混亂及除錯困難。", - "suggestion": "加強容錯處理。在存取 `map.year` 等屬性前先驗證其存在性;或改用更穩定的日期格式化方式(如 `new Date().toISOString()`)。同時增加單元測試,確保在異常情況下(例如不同的語言環境或舊版本瀏覽器)仍能產生正確的日誌格式。", - "is_new": true - }, - { - "level": "info", - "role": "Bard", - "location": "src/llm.js:31", - "problem": "`mapWithConcurrency` 內部工作者 `run()` 的註解太像設計文件,對 `cursor`、`Promise.all` 行為、背景工作都展開長篇解釋,視覺重量遠超過程式本身。", - "suggestion": "把這段縮成一兩句重點註解,保留「限制併發、保序寫入」即可,其餘執行細節交回外層函式說明。", - "is_new": true - }, - { - "level": "info", - "role": "Mage", - "location": "src/findings.js:349", - "problem": "mergeFindings 用 suggestion 前 50 字作為 key 的一部分進行去重。若兩個 findings 的 role 與 location 相同但 suggestion 在第 50 字之後才出現差異,會被誤判為重複而遭移除", - "suggestion": "考慮是否改用完整 suggestion 或增加其他識別字段(如 problem)來組成 key,確保去重不會誤刪本質不同的問題", - "is_new": true - }, - { - "level": "info", - "role": "Mage", - "location": "src/findings.js:363", - "problem": "sortByLevel 使用 LEVELS.indexOf() 排序,級別不在 ['critical','warning','info'] 中的項目因 indexOf 回傳 -1 而被排到 critical 之前(最前面),此邊界行為是否為預期設計不明確", - "suggestion": "在文件或代碼中明確說明未知級別項目的預期排序位置,或改用顯式的條件判斷以提升代碼可讀性", - "is_new": true - }, - { - "level": "info", - "role": "Mage", - "location": "src/resolve.js:98", - "problem": "groupConversations 在設置 botFinding 時用 `botFindings[0]`,若該對話的 botFindings 陣列為空,botFinding 會為 undefined。此設計雖有文件說明是為相容舊邏輯,但下游代碼仍需確保可安全處理 undefined 值", - "suggestion": "在文件中明確註記 botFinding 可為 undefined,並在此函式或其呼叫端加入明確的 null 檢查,或改用 `botFinding: botFindings.length > 0 ? botFindings[0] : null` 以更清晰地表達意圖", - "is_new": true - }, - { - "level": "info", - "role": "Rogue", - "location": "src/llm.js:154", - "problem": "runProxyAPI() 中 body 物件先建立後再條件性添加 model 屬性;若此函式在併發量大的場景反覆呼叫,每次都會新建完整物件結構", - "suggestion": "改用 Object.assign() 或 const body = { messages: [...], temperature: 0, stream: false, ...(model && { model }) },減少不必要的中間物件建立步驟", - "is_new": true - }, - { - "level": "info", - "role": "Rogue", - "location": "src/log.js:18", - "problem": "formatToParts() 後用 Object.fromEntries(parts.map(...)) 進行雙次陣列與物件轉換,再拼字串;格式化操作偏複雜,對日誌輸出這種高頻操作成本偏高", - "suggestion": "改用 reduce() 直接在一次遍歷內組出 map 物件,或改寫為單一模板字符串拼接,避免中間陣列轉換", - "is_new": true - } -] + "findings": [], + "excluded": [] +}