Files
ai-code-review/src/config.js
T

105 lines
5.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import https from 'https';
import fs from 'fs';
// 本 action 會連接自架 Gitea / OpenCode,部署環境可能使用內部 CA 或自簽憑證。
// 對外部服務請優先使用預設 TLS 驗證;需要內部服務相容時才使用 getInsecureHttpsAgent()。
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
/**
* 讀取 runner 寫入的事件 payload JSON(`GITHUB_EVENT_PATH` / `GITEA_EVENT_PATH`)。
* 讀不到或解析失敗時回傳空物件,讓後續取值一律走 fallback,不讓 import 期噴錯。
*
* @returns {Record<string, any>} 事件 payload 物件,失敗時為 `{}`。
*/
function readEventPayload() {
const eventPath = process.env.GITHUB_EVENT_PATH || process.env.GITEA_EVENT_PATH;
if (!eventPath) return {};
try {
return JSON.parse(fs.readFileSync(eventPath, 'utf8'));
} catch {
return {};
}
}
const EVENT = readEventPayload();
const PR = EVENT.pull_request || {};
// 取值優先序:有對應 `with:` 輸入的欄位一律 INPUT_* 優先(使用端明確傳入的值最權威,
// 蓋過環境中剛好存在的 ambient env)→ 專用 env(相容舊 Docker 版與測試)→ 內建預設。
// 無對應輸入的欄位(server url / repository / PR_*)則走專用 env → runner 內建 / 事件 payload。
// 使用端 workflow 只需傳 `with: token`。
export const GITEA_TOKEN = process.env.INPUT_TOKEN || process.env.GITEA_TOKEN || '';
export const GITEA_COMMENT_TOKEN = process.env.INPUT_COMMENT_TOKEN || process.env.GITEA_COMMENT_TOKEN || process.env.INPUT_TOKEN || process.env.GITEA_TOKEN || '';
export const GITEA_SERVER_URL = process.env.GITEA_SERVER_URL || process.env.GITHUB_SERVER_URL || 'https://gitea.com';
export const GITEA_REPOSITORY = process.env.GITEA_REPOSITORY || process.env.GITHUB_REPOSITORY || '';
export const PR_NUMBER = process.env.PR_NUMBER || (PR.number != null ? String(PR.number) : '');
export const PR_HEAD_SHA = process.env.PR_HEAD_SHA || PR.head?.sha || process.env.GITHUB_SHA || '';
export const PR_HEAD_BRANCH = process.env.PR_HEAD_BRANCH || PR.head?.ref || process.env.GITHUB_HEAD_REF || '';
export const PR_BASE_BRANCH = process.env.PR_BASE_BRANCH || PR.base?.ref || process.env.GITHUB_BASE_REF || '';
export const CLI_PROXY_API = process.env.INPUT_CLI_PROXY_API || process.env.CLI_PROXY_API || '';
export const CLI_PROXY_API_KEY = process.env.INPUT_CLI_PROXY_API_KEY || process.env.CLI_PROXY_API_KEY || '';
export const LLM_PROVIDER = 'cliproxyapi';
export const FINDINGS_PATH = '.gitea/ai-review/findings.json';
export const EXCLUSIONS_PATH = '.gitea/ai-review/exclusions.json';
const MODEL_NAME_RE = /^[A-Za-z0-9._-]+$/;
function normalizeModelName(raw) {
const model = String(raw || '').trim();
if (!model) return { model: null, modelError: null };
if (!MODEL_NAME_RE.test(model)) {
return { model: null, modelError: '無效的 model 參數,僅允許英數字、點、底線與連字號' };
}
return { model, modelError: null };
}
let _insecureHttpsAgent = null;
/**
* 取得一個關閉 TLS 憑證驗證的 HTTPS Agent 單例,供連接使用自簽或無效憑證的內部服務時使用
* (例如自架 Gitea、CLIProxyAPI)。
*
* @remarks 首次呼叫時建立,之後快取為模組層級單例(singleton)重複使用,
* 避免每次都新建 Agent 與連線池、浪費 TCP 三次握手。
* 停用憑證驗證有中間人攻擊風險,僅限受信任的內部環境使用;
* 若需要完整 TLS 安全性,應改用預設 `https.Agent`,不要調用這個函式。
* @returns {import('https').Agent} 已關閉憑證驗證的 HTTPS Agent 單例。
*/
export function getInsecureHttpsAgent() {
return (_insecureHttpsAgent ??= new https.Agent({ rejectUnauthorized: false }));
}
// 過渡別名:既有呼叫端仍可用 OpenCode 語意名稱;新程式碼請直接使用 getInsecureHttpsAgent。
export const getOpenCodeHttpsAgent = getInsecureHttpsAgent;
/**
* 依環境變數解析並回傳 CLIProxyAPI 設定。
*
* 優先讀取 `INPUT_CLI_PROXY_API` / `CLI_PROXY_API` 作為 base URL(會 trim 並移除結尾斜線),
* `INPUT_MODEL` / `CLI_PROXY_API_MODEL` / `MODEL` / `OPENCODE_MODEL`(依序 fallback,
* 相容 action input、舊 OpenCode 設定與環境變數)作為可選模型名稱;若未提供,
* 則交由 CLIProxyAPI 自動選擇模型。若提供的名稱含非法字元,會被視為無效並於
* `modelError` 回報,`INPUT_CLI_PROXY_API_KEY` / `CLI_PROXY_API_KEY` 作為存取金鑰(會 trim)。
*
* 若 base URL 無法解析出任何值,視為沒有可用的 proxy 設定:`provider`/`baseURL` 回傳 `null`、
* `apiKeys` 回傳空陣列,但 `model`(若有解析到)仍會回傳,不會被清空。
*
* @returns {{ provider: ('cliproxyapi'|null), apiKeys: string[], baseURL: (string|null), model: (string|null), modelError: (string|null), command: null }}
* 設定物件;`provider` 為 `null` 表示沒有可用的 proxy 設定。
*/
export function getLLMConfig() {
const baseURL = String(process.env.INPUT_CLI_PROXY_API || process.env.CLI_PROXY_API || '').trim().replace(/\/$/, '');
const rawModel = process.env.INPUT_MODEL || process.env.CLI_PROXY_API_MODEL || process.env.MODEL || process.env.OPENCODE_MODEL || '';
const { model, modelError } = normalizeModelName(rawModel);
const apiKey = String(process.env.INPUT_CLI_PROXY_API_KEY || process.env.CLI_PROXY_API_KEY || '').trim();
if (!baseURL) return { provider: null, apiKeys: [], baseURL: null, model, modelError, command: null };
return {
provider: LLM_PROVIDER,
apiKeys: apiKey ? [apiKey] : [],
baseURL,
model,
modelError,
command: null,
};
}