feat(ai-review 對話收斂): 讀 PR review 留言判斷解決狀態並收斂 findings #42

Merged
jiantw83 merged 68 commits from ai-review-resolve/20260623-110950 into develop 2026-06-23 08:29:38 +00:00
Showing only changes of commit 983efeb13f - Show all commits
+17 -4
View File
2
@@ -23,7 +23,7 @@ export function extractUsage(data) {
if (u && typeof u === 'object') {
const prompt = num(u.prompt_tokens ?? u.input_tokens);
const completion = num(u.completion_tokens ?? u.output_tokens);
const total = num(u.total_tokens) || prompt + completion;
const total = u.total_tokens != null ? num(u.total_tokens) : prompt + completion;
if (prompt || completion || total) return { promptTokens: prompt, completionTokens: completion, totalTokens: total };
}
@@ -32,7 +32,7 @@ export function extractUsage(data) {
if (g && typeof g === 'object') {
const prompt = num(g.promptTokenCount);
const completion = num(g.candidatesTokenCount);
const total = num(g.totalTokenCount) || prompt + completion;
const total = g.totalTokenCount != null ? num(g.totalTokenCount) : prompt + completion;
if (prompt || completion || total) return { promptTokens: prompt, completionTokens: completion, totalTokens: total };
}
@@ -48,7 +48,7 @@ export function extractUsage(data) {
if (t && typeof t === 'object') {
const prompt = num(t.input ?? t.prompt);
const completion = num(t.output ?? t.completion);
const total = num(t.total) || prompt + completion;
const total = t.total != null ? num(t.total) : prompt + completion;
if (prompt || completion || total) return { promptTokens: prompt, completionTokens: completion, totalTokens: total };
}
3
@@ -124,6 +124,19 @@ export function resetRateLimit() {
const stripSlash = (s) => String(s || '').replace(/\/$/, '');
/**
* 以實際 hostname 精確比對是否為 OpenRouter,避免被偽造的 baseURL
* (如 `openrouter.ai.evil.com` 或 `evil.com/openrouter.ai`)矇騙而把 API key 送往惡意主機。
*/
function isOpenRouterBaseURL(baseURL) {
try {
admin marked this conversation as resolved Outdated
Outdated
Review

嚴重等級🔴 嚴重
審查員:Assassin
問題:在 QUOTA_STRATEGIES 中,如果 config.apiKeys 是一個陣列,代碼只取 [0] 作為 API Key,但如果這個 key 是洩漏的或是環境配置錯誤,可能會導致敏感資訊在未經嚴格驗證的情況下被發送到 baseURL 指定的端點。
建議:請務必確保所有的 API 請求都經過完整的信任邊界審核,不要僅憑環境變數就自動信任該 Key 具備查詢帳號額度的權限,並在傳輸前對 baseURL 進行嚴格的白名單檢查。

**嚴重等級**:🔴 嚴重 **審查員**:Assassin **問題**:在 `QUOTA_STRATEGIES` 中,如果 `config.apiKeys` 是一個陣列,代碼只取 `[0]` 作為 API Key,但如果這個 key 是洩漏的或是環境配置錯誤,可能會導致敏感資訊在未經嚴格驗證的情況下被發送到 `baseURL` 指定的端點。 **建議**:請務必確保所有的 API 請求都經過完整的信任邊界審核,不要僅憑環境變數就自動信任該 Key 具備查詢帳號額度的權限,並在傳輸前對 baseURL 進行嚴格的白名單檢查。
const host = new URL(baseURL).hostname.toLowerCase();
return host === 'openrouter.ai' || host.endsWith('.openrouter.ai');
} catch {
return false;
}
}
/**
* OpenRouter:以 API key 呼叫 GET /auth/key 取得額度(可靠)。
* 回傳金額單位為 USD credits。
1
@@ -147,7 +160,7 @@ async function fetchOpenRouterQuota({ apiKey, baseURL }, get) {
*/
const QUOTA_STRATEGIES = {
openai: async (cfg, get) => {
if (/openrouter\.ai/i.test(cfg.baseURL || '')) return fetchOpenRouterQuota(cfg, get);
if (isOpenRouterBaseURL(cfg.baseURL)) return fetchOpenRouterQuota(cfg, get);
return { available: false, reason: 'OpenAI 帳號額度需 dashboard session 權限,API key 無法取得' };
},
claude: async () => ({ available: false, reason: 'Anthropic 額度需 Admin API 權限,一般 API key 無法取得' }),
admin marked this conversation as resolved
Review

嚴重等級🟡 警告
審查員:Assassin
問題:在 fetchAccountQuota 中,使用 axios.get 直接請求傳入的 baseURL。如果 baseURL 是由設定檔動態讀取,攻擊者可能會透過修改設定檔將其導向惡意伺服器(SSRF),進而竊取 API Key 或發送偽造請求。
建議:應對 baseURL 進行嚴格的白名單校驗,確保其僅能連線至合法的 API 提供商域名。不要信任外部設定檔中的 URL。

**嚴重等級**:🟡 警告 **審查員**:Assassin **問題**:在 `fetchAccountQuota` 中,使用 `axios.get` 直接請求傳入的 `baseURL`。如果 `baseURL` 是由設定檔動態讀取,攻擊者可能會透過修改設定檔將其導向惡意伺服器(SSRF),進而竊取 API Key 或發送偽造請求。 **建議**:應對 `baseURL` 進行嚴格的白名單校驗,確保其僅能連線至合法的 API 提供商域名。不要信任外部設定檔中的 URL。
Review

嚴重等級🟡 警告
審查員:Assassin
問題:在 fetchAccountQuota 中,使用 axios.get 直接請求傳入的 baseURL。如果 baseURL 是由設定檔動態讀取,攻擊者可能會透過修改設定檔將其導向惡意伺服器(SSRF),進而竊取 API Key 或發送偽造請求。
建議:應對 baseURL 進行嚴格的白名單校驗,確保其僅能連線至合法的 API 提供商域名。不要信任外部設定檔中的 URL。

**嚴重等級**:🟡 警告 **審查員**:Assassin **問題**:在 `fetchAccountQuota` 中,使用 `axios.get` 直接請求傳入的 `baseURL`。如果 `baseURL` 是由設定檔動態讀取,攻擊者可能會透過修改設定檔將其導向惡意伺服器(SSRF),進而竊取 API Key 或發送偽造請求。 **建議**:應對 `baseURL` 進行嚴格的白名單校驗,確保其僅能連線至合法的 API 提供商域名。不要信任外部設定檔中的 URL。
4