新增 OpenCode 自簽憑證略過設定 #20

Merged
admin merged 4 commits from ai-review-resolve/20260620131600 into develop 2026-06-20 13:18:17 +00:00
4 changed files with 28 additions and 5 deletions
Showing only changes of commit f7e4f09d4e - Show all commits
+5
View File
@@ -95,6 +95,10 @@ inputs:
OPENCODE_SERVER_PASSWORD: OPENCODE_SERVER_PASSWORD:
description: 'OpenCode server Basic Auth password' description: 'OpenCode server Basic Auth password'
required: false required: false
OPENCODE_SKIP_TLS_VERIFY:
description: '跳過 OpenCode server SSL/TLS 憑證驗證(自簽憑證時使用)'
required: false
default: 'false'
runs: runs:
using: 'docker' using: 'docker'
@@ -129,3 +133,4 @@ runs:
OPENCODE_PROVIDER: ${{ inputs.OPENCODE_PROVIDER }} OPENCODE_PROVIDER: ${{ inputs.OPENCODE_PROVIDER }}
OPENCODE_SERVER_USERNAME: ${{ inputs.OPENCODE_SERVER_USERNAME }} OPENCODE_SERVER_USERNAME: ${{ inputs.OPENCODE_SERVER_USERNAME }}
OPENCODE_SERVER_PASSWORD: ${{ inputs.OPENCODE_SERVER_PASSWORD }} OPENCODE_SERVER_PASSWORD: ${{ inputs.OPENCODE_SERVER_PASSWORD }}
OPENCODE_SKIP_TLS_VERIFY: ${{ inputs.OPENCODE_SKIP_TLS_VERIFY }}
+4
View File
@@ -11,6 +11,10 @@ export const PR_BASE_BRANCH = process.env.PR_BASE_BRANCH || '';
export const FINDINGS_PATH = '.gitea/ai-review/findings.json'; export const FINDINGS_PATH = '.gitea/ai-review/findings.json';
export const EXCLUSIONS_PATH = '.gitea/ai-review/exclusions.json'; export const EXCLUSIONS_PATH = '.gitea/ai-review/exclusions.json';
export function shouldSkipOpenCodeTLSVerify() {
return process.env.OPENCODE_SKIP_TLS_VERIFY === 'true';
}
/** 將逗號分隔的 API key 字串拆成陣列 */ /** 將逗號分隔的 API key 字串拆成陣列 */
function splitKeys(value) { function splitKeys(value) {
if (!value) return []; if (!value) return [];
+11 -3
View File
@@ -1,5 +1,6 @@
import axios from 'axios'; import axios from 'axios';
import { getLLMConfig } from './config.js'; import https from 'https';
import { getLLMConfig, shouldSkipOpenCodeTLSVerify } from './config.js';
import { line, error } from './log.js'; import { line, error } from './log.js';
function isOpenAIGpt55(provider, model) { function isOpenAIGpt55(provider, model) {
@@ -46,6 +47,13 @@ function applyOpenCodeAuth(headers) {
headers['Authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`; headers['Authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
} }
function opencodeAxiosOptions(headers) {
return {
headers,
httpsAgent: shouldSkipOpenCodeTLSVerify() ? new https.Agent({ rejectUnauthorized: false }) : undefined,
};
}
function extractOpenCodeContent(data) { function extractOpenCodeContent(data) {
const parts = data.parts || data.data?.parts || data.info?.content || data.data?.info?.content || []; const parts = data.parts || data.data?.parts || data.info?.content || data.data?.info?.content || [];
return parts return parts
@@ -60,7 +68,7 @@ async function chatOpenCode(baseURL, model, systemPrompt, userContent, headers)
const session = await axios.post( const session = await axios.post(
`${base}/session`, `${base}/session`,
{ title: 'AI Code Review', model: { providerID, id: modelID } }, { title: 'AI Code Review', model: { providerID, id: modelID } },
{ headers } opencodeAxiosOptions(headers)
); );
const sessionID = session.data.id || session.data.data?.id; const sessionID = session.data.id || session.data.data?.id;
if (!sessionID) throw new Error('OpenCode session 建立失敗:回應中沒有 session id'); if (!sessionID) throw new Error('OpenCode session 建立失敗:回應中沒有 session id');
@@ -72,7 +80,7 @@ async function chatOpenCode(baseURL, model, systemPrompt, userContent, headers)
system: systemPrompt, system: systemPrompt,
parts: [{ type: 'text', text: userContent }], parts: [{ type: 'text', text: userContent }],
}, },
{ headers } opencodeAxiosOptions(headers)
); );
return extractOpenCodeContent(resp.data); return extractOpenCodeContent(resp.data);
} }
+8 -2
View File
@@ -8,6 +8,7 @@ import {
GITEA_SKIP_TLS_VERIFY, GITEA_SKIP_TLS_VERIFY,
PR_NUMBER, PR_NUMBER,
getLLMConfig, getLLMConfig,
shouldSkipOpenCodeTLSVerify,
} from './config.js'; } from './config.js';
import { verifyRemoteAccess } from './git.js'; import { verifyRemoteAccess } from './git.js';
import { step, line, ok, error } from './log.js'; import { step, line, ok, error } from './log.js';
@@ -26,6 +27,11 @@ const applyOpenCodeAuth = (headers) => {
const username = process.env.OPENCODE_SERVER_USERNAME || 'opencode'; const username = process.env.OPENCODE_SERVER_USERNAME || 'opencode';
headers['Authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`; headers['Authorization'] = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
}; };
const opencodeAxiosOptions = (headers) => ({
headers,
timeout: 30000,
httpsAgent: shouldSkipOpenCodeTLSVerify() ? new https.Agent({ rejectUnauthorized: false }) : undefined,
});
function giteaErr(e) { function giteaErr(e) {
const status = e.response?.status; const status = e.response?.status;
@@ -89,8 +95,8 @@ export async function verifyLLM() {
const { providerID, modelID } = opencodeModelConfig(model); const { providerID, modelID } = opencodeModelConfig(model);
applyOpenCodeAuth(headers); applyOpenCodeAuth(headers);
try { try {
await axios.get(`${base}/global/health`, { headers, timeout: 30000 }); await axios.get(`${base}/global/health`, opencodeAxiosOptions(headers));
const providers = await axios.get(`${base}/config/providers`, { headers, timeout: 30000 }); const providers = await axios.get(`${base}/config/providers`, opencodeAxiosOptions(headers));
const configuredProvider = providers.data.providers?.find(p => p.id === providerID); const configuredProvider = providers.data.providers?.find(p => p.id === providerID);
if (!configuredProvider) return { ok: false, provider, error: `OpenCode server 未設定 provider=${providerID}` }; if (!configuredProvider) return { ok: false, provider, error: `OpenCode server 未設定 provider=${providerID}` };
if (!configuredProvider.models?.[modelID]) return { ok: false, provider, error: `OpenCode server provider=${providerID} 未列出 model=${modelID}` }; if (!configuredProvider.models?.[modelID]) return { ok: false, provider, error: `OpenCode server provider=${providerID} 未列出 model=${modelID}` };