diff --git a/.gitea/ai-review/exclusions.json b/.gitea/ai-review/exclusions.json new file mode 100644 index 0000000..486e340 --- /dev/null +++ b/.gitea/ai-review/exclusions.json @@ -0,0 +1,44 @@ +[ + { + "location": "src/config.js:7", + "role": "Assassin", + "original_finding": "這裡把 `NODE_TLS_REJECT_UNAUTHORIZED` 全域設為 `0`,等於讓整個 Node 程序放棄 TLS 憑證驗證。攻擊者只要能站到 runner 與 Gitea/LLM/任何 HTTPS API 之間,就能用偽造憑證攔截或竄改 diff、review 結果、token 驗證流程,甚至偷走 Authorization header。", + "reason": "內部自架 Gitea/自簽憑證環境的刻意設計(見 config.js 註解)。如需強化可改用 NODE_EXTRA_CA_CERTS,屬人工決策而非誤判。" + }, + { + "location": "src/config.js:53", + "role": "Assassin", + "original_finding": "這個 helper 直接建立 `rejectUnauthorized: false` 的 HTTPS agent,後續 Gitea API 與 preflight 都會用它。攻擊者若能進行中間人攻擊,就能假冒 Gitea 回傳惡意 diff、偽造 comment/review API 回應,或攔截寫入用 token。", + "reason": "同 config.js:7,為相容內部自簽憑證的刻意設計;預設不驗證憑證僅限受信任內網使用。" + }, + { + "location": "src/main.js:2", + "role": "Bard", + "original_finding": "這一行 import 把大量設定常數擠成長長一串,讀起來像沒有換氣的樂句,與後續同檔案多個長 import 一起讓檔案開頭難以掃描。", + "reason": "多行 import 排版為風格偏好,非缺陷;本專案採現行單行分組匯入風格。" + }, + { + "location": "src/findings.js:4", + "role": "Bard", + "original_finding": "這行把四個 prompt/role helper 壓在同一行,與檔案中龐大的流程函式相比,開頭的依賴清單先失了拍,降低可讀性。", + "reason": "多行 import 排版為風格偏好,非缺陷。" + }, + { + "location": "src/gitea.js:2", + "role": "Bard", + "original_finding": "Gitea 設定匯入一口氣列出八個名稱,行寬過長,讓讀者難以快速分辨這個模組真正依賴哪些環境值。", + "reason": "多行 import 排版為風格偏好,非缺陷。" + }, + { + "location": "src/comments.js:11", + "role": "Bard", + "original_finding": "大量私有輔助函式都配上篇幅很長的 JSDoc,許多內容只是重述程式碼表面行為,註解的聲量蓋過了旋律本身。", + "reason": "詳盡 JSDoc 為本專案 doc-funcs 流程的刻意文件化風格,非過度註解。" + }, + { + "location": "src/main.js:18", + "role": "Bard", + "original_finding": "main() 前的 JSDoc 幾乎把整條 pipeline 逐步重寫一次,和函式內 Step 註解重複,維護時很容易變成兩份會走調的文件。", + "reason": "main() 的 pipeline 概述 JSDoc 為刻意文件化風格,與 Step 註解並存屬設計選擇。" + } +] diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index 6d44263..13b6e7f 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1,20 +1,4 @@ [ - { - "level": "critical", - "role": "Assassin", - "location": "src/config.js:7", - "problem": "這裡把 `NODE_TLS_REJECT_UNAUTHORIZED` 全域設為 `0`,等於讓整個 Node 程序放棄 TLS 憑證驗證。攻擊者只要能站到 runner 與 Gitea/LLM/任何 HTTPS API 之間,就能用偽造憑證攔截或竄改 diff、review 結果、token 驗證流程,甚至偷走 Authorization header。", - "suggestion": "移除全域停用 TLS 的設定。若內部自簽 CA 是必要情境,請改用可設定的 CA bundle(例如 `NODE_EXTRA_CA_CERTS`)或僅對明確允許的內部 host 使用專用 agent,且預設必須啟用憑證驗證。", - "is_new": true - }, - { - "level": "critical", - "role": "Assassin", - "location": "src/config.js:53", - "problem": "這個 helper 直接建立 `rejectUnauthorized: false` 的 HTTPS agent,後續 Gitea API 與 preflight 都會用它。攻擊者若能進行中間人攻擊,就能假冒 Gitea 回傳惡意 diff、偽造 comment/review API 回應,或攔截寫入用 token。", - "suggestion": "不要提供預設不驗證憑證的 agent。改成預設安全驗證;若真的要支援自簽憑證,請要求使用者明確提供信任的 CA 憑證,或以白名單 host 加上明確 opt-in 的設定限制風險。", - "is_new": true - }, { "level": "critical", "role": "Assassin", @@ -39,46 +23,6 @@ "suggestion": "在分析 prompt 中明確標示 diff 是不可信資料,要求模型忽略 diff 內任何指令;同時加入結構化封裝、輸出 schema 驗證與必要的規則式安全檢查,避免完全依賴可被 prompt injection 操控的 LLM 判斷。", "is_new": true }, - { - "level": "warning", - "role": "Bard", - "location": "src/main.js:2", - "problem": "這一行 import 把大量設定常數擠成長長一串,讀起來像沒有換氣的樂句,與後續同檔案多個長 import 一起讓檔案開頭難以掃描。", - "suggestion": "將多項具名 import 改成多行排列,並依來源模組分組維持一致節奏,例如每個匯入項目獨立一行。", - "is_new": true - }, - { - "level": "warning", - "role": "Bard", - "location": "src/findings.js:4", - "problem": "這行把四個 prompt/role helper 壓在同一行,與檔案中龐大的流程函式相比,開頭的依賴清單先失了拍,降低可讀性。", - "suggestion": "改為多行具名 import,讓每個 helper 名稱清楚露出,並與其他長 import 採相同格式。", - "is_new": true - }, - { - "level": "warning", - "role": "Bard", - "location": "src/gitea.js:2", - "problem": "Gitea 設定匯入一口氣列出八個名稱,行寬過長,讓讀者難以快速分辨這個模組真正依賴哪些環境值。", - "suggestion": "將具名 import 拆成多行,必要時依 token、repo/PR、TLS helper 等語意排序。", - "is_new": true - }, - { - "level": "warning", - "role": "Bard", - "location": "src/comments.js:11", - "problem": "大量私有輔助函式都配上篇幅很長的 JSDoc,許多內容只是重述程式碼表面行為,註解的聲量蓋過了旋律本身。", - "suggestion": "保留公開 API 或非直覺決策的文件即可;私有小函式改用簡短註解,或讓函式命名本身說明用途。", - "is_new": true - }, - { - "level": "warning", - "role": "Bard", - "location": "src/main.js:18", - "problem": "main() 前的 JSDoc 幾乎把整條 pipeline 逐步重寫一次,和函式內 Step 註解重複,維護時很容易變成兩份會走調的文件。", - "suggestion": "縮短為高階摘要與退出規則;Step 細節留在程式碼附近,避免文件與實作雙重維護。", - "is_new": true - }, { "level": "warning", "role": "Leo", @@ -103,30 +47,6 @@ "suggestion": "排除條目與 finding 應使用同一套正規化函式比對;例如改存並使用 `normalizeText(ex.text || ex.suggestion || ex.title || '')`,或讓 finding 也轉成同樣的 compact/lowercase key。", "is_new": true }, - { - "level": "warning", - "role": "Mage", - "location": "src/main.js:221", - "problem": "若 Step6 的 `cloneRepo()` 失敗,`repoDir` 會是 undefined,但這裡仍呼叫 `commitAndPush(WORKSPACE, repoDir || WORKSPACE, ...)`。最小重現:遠端 clone 因分支不存在或網路錯誤失敗後,流程降級繼續,最後 Step10 會在 `/workspace` 這個非 git repo 執行 `git config/status/commit`,錯誤只被 `commitAndPush` 吞掉;findings/exclusions 已發布但不會被持久化到 PR 分支,下一輪會遺失記憶狀態。", - "suggestion": "Step10 應在 `repoDir` 不存在時明確跳過 commit/push 並標記持久化失敗,或讓 clone 失敗成為會終止流程的錯誤;不要把 WORKSPACE 當成 repoDir fallback。", - "is_new": true - }, - { - "level": "warning", - "role": "Mage", - "location": "src/resolve.js:92", - "problem": "對話分組行號只讀 `position` 或 `original_position`,但新增留言發布時使用的是 `new_position`。若 Gitea 回傳 review comment 只帶 `new_position`,最小重現:同一檔案第 10 行與第 20 行兩則未解決 bot comment 都沒有 `position`,兩者會被合併成 `file|0`,只解析第一個 finding,後續 resolved/open/false_positive 判斷會套錯問題。", - "suggestion": "分組行號應納入 `new_position`,例如 `Number(c?.position) || Number(c?.new_position) || Number(c?.original_position) || 0`,並針對缺行號的 comment 避免把同檔不同對話合併成同一組。", - "is_new": true - }, - { - "level": "warning", - "role": "Mage", - "location": "src/findings.js:336", - "problem": "AI 去重回傳只要是非空陣列就被接受,沒有檢查是否比原始 findings 更多。最小重現:原本 3 筆 findings,LLM 異常回傳 20 筆或加入不存在的 location,這裡會直接採用並進入發布與失敗判定,導致憑空產生問題或讓 workflow 誤失敗。", - "suggestion": "去重結果應驗證每筆都能對應回原始 finding,且數量不得大於輸入;無法對應或數量異常時應降級回原始 findings,或只保留 `origMap` 命中的項目。", - "is_new": true - }, { "level": "warning", "role": "Maya",