Fix: OPENCODE Auth not passing through properly (#347)
This commit is contained in:
@@ -2086,6 +2086,24 @@ const ENV_SKIP_OPENCODE_START = process.env.OPENCODE_SKIP_START === 'true' ||
|
|||||||
process.env.OPENCHAMBER_SKIP_OPENCODE_START === 'true';
|
process.env.OPENCHAMBER_SKIP_OPENCODE_START === 'true';
|
||||||
const ENV_DESKTOP_NOTIFY = process.env.OPENCHAMBER_DESKTOP_NOTIFY === 'true';
|
const ENV_DESKTOP_NOTIFY = process.env.OPENCHAMBER_DESKTOP_NOTIFY === 'true';
|
||||||
|
|
||||||
|
// OpenCode server authentication (Basic Auth with username "opencode")
|
||||||
|
const ENV_OPENCODE_SERVER_PASSWORD = (() => {
|
||||||
|
const pwd = process.env.OPENCODE_SERVER_PASSWORD;
|
||||||
|
return typeof pwd === 'string' && pwd.length > 0 ? pwd : null;
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns auth headers for OpenCode server requests if OPENCODE_SERVER_PASSWORD is set.
|
||||||
|
* Uses Basic Auth with username "opencode" and the password from the env variable.
|
||||||
|
*/
|
||||||
|
function getOpenCodeAuthHeaders() {
|
||||||
|
if (!ENV_OPENCODE_SERVER_PASSWORD) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const credentials = Buffer.from(`opencode:${ENV_OPENCODE_SERVER_PASSWORD}`).toString('base64');
|
||||||
|
return { Authorization: `Basic ${credentials}` };
|
||||||
|
}
|
||||||
|
|
||||||
const ENV_CONFIGURED_API_PREFIX = normalizeApiPrefix(
|
const ENV_CONFIGURED_API_PREFIX = normalizeApiPrefix(
|
||||||
process.env.OPENCODE_API_PREFIX || process.env.OPENCHAMBER_API_PREFIX || ''
|
process.env.OPENCODE_API_PREFIX || process.env.OPENCHAMBER_API_PREFIX || ''
|
||||||
);
|
);
|
||||||
@@ -2591,6 +2609,7 @@ const startGlobalEventWatcher = async () => {
|
|||||||
Accept: 'text/event-stream',
|
Accept: 'text/event-stream',
|
||||||
'Cache-Control': 'no-cache',
|
'Cache-Control': 'no-cache',
|
||||||
Connection: 'keep-alive',
|
Connection: 'keep-alive',
|
||||||
|
...getOpenCodeAuthHeaders(),
|
||||||
},
|
},
|
||||||
signal,
|
signal,
|
||||||
});
|
});
|
||||||
@@ -2789,7 +2808,10 @@ async function waitForReady(url, timeoutMs = 10000) {
|
|||||||
const timeout = setTimeout(() => controller.abort(), 3000);
|
const timeout = setTimeout(() => controller.abort(), 3000);
|
||||||
const res = await fetch(`${url.replace(/\/+$/, '')}/global/health`, {
|
const res = await fetch(`${url.replace(/\/+$/, '')}/global/health`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { Accept: 'application/json' },
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
...getOpenCodeAuthHeaders(),
|
||||||
|
},
|
||||||
signal: controller.signal
|
signal: controller.signal
|
||||||
});
|
});
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
@@ -3042,7 +3064,10 @@ const fetchSessionParentId = async (sessionId) => {
|
|||||||
try {
|
try {
|
||||||
const response = await fetch(buildOpenCodeUrl('/session', ''), {
|
const response = await fetch(buildOpenCodeUrl('/session', ''), {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { Accept: 'application/json' },
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
...getOpenCodeAuthHeaders(),
|
||||||
|
},
|
||||||
signal: AbortSignal.timeout(2000),
|
signal: AbortSignal.timeout(2000),
|
||||||
});
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -3564,11 +3589,11 @@ async function waitForOpenCodeReady(timeoutMs = 20000, intervalMs = 400) {
|
|||||||
const [configResult, agentResult] = await Promise.all([
|
const [configResult, agentResult] = await Promise.all([
|
||||||
fetch(buildOpenCodeUrl('/config', ''), {
|
fetch(buildOpenCodeUrl('/config', ''), {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { Accept: 'application/json' }
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() }
|
||||||
}).catch((error) => error),
|
}).catch((error) => error),
|
||||||
fetch(buildOpenCodeUrl('/agent', ''), {
|
fetch(buildOpenCodeUrl('/agent', ''), {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { Accept: 'application/json' }
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() }
|
||||||
}).catch((error) => error)
|
}).catch((error) => error)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -3631,7 +3656,7 @@ async function waitForAgentPresence(agentName, timeoutMs = 15000, intervalMs = 3
|
|||||||
try {
|
try {
|
||||||
const response = await fetch(buildOpenCodeUrl('/agent'), {
|
const response = await fetch(buildOpenCodeUrl('/agent'), {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { Accept: 'application/json' }
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@@ -3657,7 +3682,7 @@ async function fetchAgentsSnapshot() {
|
|||||||
|
|
||||||
const response = await fetch(buildOpenCodeUrl('/agent'), {
|
const response = await fetch(buildOpenCodeUrl('/agent'), {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { Accept: 'application/json' }
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -3678,7 +3703,7 @@ async function fetchProvidersSnapshot() {
|
|||||||
|
|
||||||
const response = await fetch(buildOpenCodeUrl('/provider'), {
|
const response = await fetch(buildOpenCodeUrl('/provider'), {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { Accept: 'application/json' }
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -3699,7 +3724,7 @@ async function fetchModelsSnapshot() {
|
|||||||
|
|
||||||
const response = await fetch(buildOpenCodeUrl('/model'), {
|
const response = await fetch(buildOpenCodeUrl('/model'), {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: { Accept: 'application/json' }
|
headers: { Accept: 'application/json', ...getOpenCodeAuthHeaders() }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -3834,6 +3859,11 @@ function setupProxy(app) {
|
|||||||
onProxyReq: (proxyReq, req, res) => {
|
onProxyReq: (proxyReq, req, res) => {
|
||||||
console.log(`Proxying ${req.method} ${req.path} to OpenCode`);
|
console.log(`Proxying ${req.method} ${req.path} to OpenCode`);
|
||||||
|
|
||||||
|
const authHeaders = getOpenCodeAuthHeaders();
|
||||||
|
if (authHeaders.Authorization) {
|
||||||
|
proxyReq.setHeader('Authorization', authHeaders.Authorization);
|
||||||
|
}
|
||||||
|
|
||||||
if (req.headers.accept && req.headers.accept.includes('text/event-stream')) {
|
if (req.headers.accept && req.headers.accept.includes('text/event-stream')) {
|
||||||
console.log(`[SSE] Setting up SSE proxy for ${req.method} ${req.path}`);
|
console.log(`[SSE] Setting up SSE proxy for ${req.method} ${req.path}`);
|
||||||
proxyReq.setHeader('Accept', 'text/event-stream');
|
proxyReq.setHeader('Accept', 'text/event-stream');
|
||||||
@@ -3849,7 +3879,6 @@ function setupProxy(app) {
|
|||||||
proxyRes.headers['Content-Type'] = 'text/event-stream';
|
proxyRes.headers['Content-Type'] = 'text/event-stream';
|
||||||
proxyRes.headers['Cache-Control'] = 'no-cache';
|
proxyRes.headers['Cache-Control'] = 'no-cache';
|
||||||
proxyRes.headers['Connection'] = 'keep-alive';
|
proxyRes.headers['Connection'] = 'keep-alive';
|
||||||
|
|
||||||
proxyRes.headers['X-Accel-Buffering'] = 'no';
|
proxyRes.headers['X-Accel-Buffering'] = 'no';
|
||||||
proxyRes.headers['X-Content-Type-Options'] = 'nosniff';
|
proxyRes.headers['X-Content-Type-Options'] = 'nosniff';
|
||||||
}
|
}
|
||||||
@@ -4426,7 +4455,8 @@ async function main(options = {}) {
|
|||||||
const headers = {
|
const headers = {
|
||||||
Accept: 'text/event-stream',
|
Accept: 'text/event-stream',
|
||||||
'Cache-Control': 'no-cache',
|
'Cache-Control': 'no-cache',
|
||||||
Connection: 'keep-alive'
|
Connection: 'keep-alive',
|
||||||
|
...getOpenCodeAuthHeaders(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const lastEventId = req.header('Last-Event-ID');
|
const lastEventId = req.header('Last-Event-ID');
|
||||||
@@ -4558,7 +4588,8 @@ async function main(options = {}) {
|
|||||||
const headers = {
|
const headers = {
|
||||||
Accept: 'text/event-stream',
|
Accept: 'text/event-stream',
|
||||||
'Cache-Control': 'no-cache',
|
'Cache-Control': 'no-cache',
|
||||||
Connection: 'keep-alive'
|
Connection: 'keep-alive',
|
||||||
|
...getOpenCodeAuthHeaders(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const lastEventId = req.header('Last-Event-ID');
|
const lastEventId = req.header('Last-Event-ID');
|
||||||
|
|||||||
Reference in New Issue
Block a user