From 9d759464c21376ead9576cd3acf511d9067962ab Mon Sep 17 00:00:00 2001 From: Jeffery Date: Sat, 20 Jun 2026 13:56:00 +0000 Subject: [PATCH 1/4] =?UTF-8?q?feat(OpenCode=20TLS):=20=E9=A0=90=E8=A8=AD?= =?UTF-8?q?=E8=B7=B3=E9=81=8E=20TLS=20=E9=A9=97=E8=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- action.yaml | 4 ++-- app/config.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/action.yaml b/action.yaml index 30b6eb4..46bfbc0 100644 --- a/action.yaml +++ b/action.yaml @@ -96,9 +96,9 @@ inputs: description: 'OpenCode server Basic Auth password' required: false OPENCODE_SKIP_TLS_VERIFY: - description: '跳過 OpenCode server SSL/TLS 憑證驗證(自簽憑證時使用)' + description: '跳過 OpenCode server SSL/TLS 憑證驗證' required: false - default: 'false' + default: 'true' runs: using: 'docker' diff --git a/app/config.js b/app/config.js index 0fcf655..da8e864 100644 --- a/app/config.js +++ b/app/config.js @@ -14,7 +14,7 @@ export const FINDINGS_PATH = '.gitea/ai-review/findings.json'; export const EXCLUSIONS_PATH = '.gitea/ai-review/exclusions.json'; export function shouldSkipOpenCodeTLSVerify() { - return process.env.OPENCODE_SKIP_TLS_VERIFY === 'true'; + return process.env.OPENCODE_SKIP_TLS_VERIFY !== 'false'; } export function getOpenCodeHttpsAgent() { -- 2.53.0 From 648334d15339f5d2cdd8ff1d8d34f91d79a84a0b Mon Sep 17 00:00:00 2001 From: Jeffery Date: Sat, 20 Jun 2026 13:56:00 +0000 Subject: [PATCH 2/4] =?UTF-8?q?test(OpenCode=20TLS):=20=E8=A6=86=E8=93=8B?= =?UTF-8?q?=E9=A0=90=E8=A8=AD=E8=B7=B3=E9=81=8E=E9=A9=97=E8=AD=89=E8=A1=8C?= =?UTF-8?q?=E7=82=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/config.test.js | 12 +++++++++++- app/llm.test.js | 16 ++++++++++++++-- app/preflight.test.js | 18 ++++++++++++++++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/app/config.test.js b/app/config.test.js index 869e811..dec24c9 100644 --- a/app/config.test.js +++ b/app/config.test.js @@ -1,6 +1,6 @@ import { describe, it, beforeEach, afterEach } from 'node:test'; import assert from 'node:assert/strict'; -import { getLLMConfig } from './config.js'; +import { getLLMConfig, shouldSkipOpenCodeTLSVerify } from './config.js'; const ENV_KEYS = [ 'OPENAI_API_KEY', 'OPENAI_BASE_URL', 'OPENAI_MODEL', @@ -10,6 +10,7 @@ const ENV_KEYS = [ 'AMAZONQ_API_KEY', 'AMAZONQ_BASE_URL', 'AMAZONQ_MODEL', 'OPENCODE_BASE_URL', 'OPENCODE_MODEL', 'OPENCODE_PROVIDER', 'OPENCODE_SERVER_USERNAME', 'OPENCODE_SERVER_PASSWORD', + 'OPENCODE_SKIP_TLS_VERIFY', ]; let saved = {}; @@ -104,6 +105,15 @@ describe('getLLMConfig', () => { assert.equal(cfg.model, 'google/gemini-2.5-pro'); }); + it('skips OpenCode TLS verification by default', () => { + assert.equal(shouldSkipOpenCodeTLSVerify(), true); + }); + + it('allows explicitly enabling OpenCode TLS verification', () => { + process.env.OPENCODE_SKIP_TLS_VERIFY = 'false'; + assert.equal(shouldSkipOpenCodeTLSVerify(), false); + }); + it('openai takes priority over gemini when both set', () => { process.env.OPENAI_API_KEY = 'sk-test'; process.env.GEMINI_API_KEY = 'gemini-key'; diff --git a/app/llm.test.js b/app/llm.test.js index 541fdbb..6f2196c 100644 --- a/app/llm.test.js +++ b/app/llm.test.js @@ -164,9 +164,8 @@ describe('chat - key rotation', async () => { assert.equal(headers[0]['Authorization'], `Basic ${Buffer.from('opencode:secret').toString('base64')}`); }); - it('passes an insecure https agent to OpenCode when TLS verification is disabled', async () => { + it('passes an insecure https agent to OpenCode by default', async () => { process.env.OPENCODE_BASE_URL = 'https://opencode.local:4096'; - process.env.OPENCODE_SKIP_TLS_VERIFY = 'true'; const agents = []; mock.method(axios, 'post', async (url, _payload, opts) => { agents.push(opts.httpsAgent); @@ -179,6 +178,19 @@ describe('chat - key rotation', async () => { assert.equal(agents[1].options.rejectUnauthorized, false); }); + it('does not pass an insecure https agent to OpenCode when TLS verification is enabled', async () => { + process.env.OPENCODE_BASE_URL = 'https://opencode.local:4096'; + process.env.OPENCODE_SKIP_TLS_VERIFY = 'false'; + const agents = []; + mock.method(axios, 'post', async (url, _payload, opts) => { + agents.push(opts.httpsAgent); + if (url.endsWith('/session')) return { data: { id: 'ses_test' } }; + return { data: { parts: [{ type: 'text', text: 'ok' }] } }; + }); + await chat('sys', 'user'); + assert.deepEqual(agents, [undefined, undefined]); + }); + it('uses Responses API for openai GPT-5.5', async () => { process.env.OPENAI_API_KEY = 'sk-test'; process.env.OPENAI_MODEL = 'GPT-5.5'; diff --git a/app/preflight.test.js b/app/preflight.test.js index 91eced4..0270c33 100644 --- a/app/preflight.test.js +++ b/app/preflight.test.js @@ -183,10 +183,9 @@ describe('verifyLLM', () => { assert.deepEqual(urls, ['http://opencode.local:4096/global/health', 'http://opencode.local:4096/config/providers']); }); - it('passes an insecure https agent for opencode when TLS verification is disabled', async () => { + it('passes an insecure https agent for opencode by default', async () => { clearLLMEnv(); process.env.OPENCODE_BASE_URL = 'https://opencode.local:4096'; - process.env.OPENCODE_SKIP_TLS_VERIFY = 'true'; const agents = []; mock.method(axios, 'get', async (url, opts) => { agents.push(opts.httpsAgent); @@ -200,6 +199,21 @@ describe('verifyLLM', () => { assert.equal(agents[1].options.rejectUnauthorized, false); }); + it('does not pass an insecure https agent for opencode when TLS verification is enabled', async () => { + clearLLMEnv(); + process.env.OPENCODE_BASE_URL = 'https://opencode.local:4096'; + process.env.OPENCODE_SKIP_TLS_VERIFY = 'false'; + const agents = []; + mock.method(axios, 'get', async (url, opts) => { + agents.push(opts.httpsAgent); + if (url.endsWith('/global/health')) return { data: { healthy: true } }; + return { data: { providers: [{ id: 'google', models: { 'gemini-2.5-flash': { id: 'gemini-2.5-flash' } } }] } }; + }); + const result = await verifyLLM(); + assert.equal(result.ok, true); + assert.deepEqual(agents, [undefined, undefined]); + }); + it('checks openai GPT-5.5 with Responses API', async () => { clearLLMEnv(); process.env.OPENAI_API_KEY = 'sk-test'; -- 2.53.0 From 6036ce45c43c083b89d0dad2774790c6cea3c8c4 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Sat, 20 Jun 2026 13:56:00 +0000 Subject: [PATCH 3/4] =?UTF-8?q?docs(README):=20=E8=AA=AA=E6=98=8E=20OpenCo?= =?UTF-8?q?de=20TLS=20=E9=A9=97=E8=AD=89=E9=A0=90=E8=A8=AD=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a6205d1..3fd5a0f 100644 --- a/README.md +++ b/README.md @@ -224,8 +224,8 @@ jobs: OPENCODE_BASE_URL: http://192.168.3.124:4096 OPENCODE_PROVIDER: google OPENCODE_MODEL: gemini-2.5-flash - # 若 OpenCode server 使用自簽憑證,才需要提供: - # OPENCODE_SKIP_TLS_VERIFY: true + # 預設會跳過 OpenCode TLS 驗證;若要強制驗證憑證才需要設定: + # OPENCODE_SKIP_TLS_VERIFY: false # 若 OpenCode server 有設定 OPENCODE_SERVER_PASSWORD,才需要提供: # OPENCODE_SERVER_USERNAME: opencode # OPENCODE_SERVER_PASSWORD: ${{ secrets.OPENCODE_SERVER_PASSWORD }} -- 2.53.0 From a02d7f374cd3178310aaa10af2d5a0494eaed80f Mon Sep 17 00:00:00 2001 From: AI Review Bot Date: Sat, 20 Jun 2026 14:08:55 +0000 Subject: [PATCH 4/4] chore: update ai-review findings [ai-review-bot][success] --- .gitea/ai-review/findings.json | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.gitea/ai-review/findings.json b/.gitea/ai-review/findings.json index fe51488..ff3c0a8 100644 --- a/.gitea/ai-review/findings.json +++ b/.gitea/ai-review/findings.json @@ -1 +1,16 @@ -[] +[ + { + "level": "warning", + "role": "Mage", + "location": "app/config.test.js", + "suggestion": "`shouldSkipOpenCodeTLSVerify` 函式的新增測試案例未能涵蓋所有可能的輸入情境。在 `process.env.OPENCODE_SKIP_TLS_VERIFY !== 'false'` 的新邏輯下,應增加測試案例來驗證當環境變數設定為空字串 `''`、字串 `'0'` 或其他任意非 `'false'` 字串時,函式是否如預期般返回 `true`(跳過 TLS 驗證)。這有助於確保此關鍵安全邏輯的行為符合預期,並揭示潛在的誤配置風險。", + "is_new": true + }, + { + "level": "warning", + "role": "Maya", + "location": "app/preflight.test.js", + "suggestion": "在 `preflight.test.js` 中,關於 `httpsAgent` 的測試案例也已涵蓋了預設行為(跳過 TLS)和明確設定為 `false`(不跳過 TLS)的情況。請新增一個測試,驗證當環境變數 `process.env.OPENCODE_SKIP_TLS_VERIFY` 明確設定為 `'true'` 時,`verifyLLM` 函式是否會傳遞一個不安全的 `httpsAgent` 給 OpenCode 服務進行預檢。", + "is_new": true + } +] -- 2.53.0