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';