From f5b32f2c0bd0fb7296745a4da3bb21d37d2c13c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Andr=C3=A9?= Date: Sun, 26 Apr 2026 16:49:42 +0200 Subject: [PATCH] fix(server): respect configured OpenCode auth (#366) Fixes #315 ## Summary - stop overwriting configured `OPENCODE_SERVER_USERNAME` and `OPENCODE_SERVER_PASSWORD` when CodeNomad launches managed OpenCode servers - reuse user-provided OpenCode auth from workspace environment or process env before falling back to generated credentials - add focused tests for configured, inherited, and generated auth paths ## Testing - `npx tsx --test "packages/server/src/workspaces/opencode-auth.test.ts"` - `npx tsc --noEmit --target ES2020 --module ESNext --moduleResolution Node --strict --esModuleInterop --types node "packages/server/src/workspaces/opencode-auth.ts" "packages/server/src/workspaces/opencode-auth.test.ts"` - `git diff --check` ## Notes - full server workspace typecheck still has unrelated baseline failures in this branch (`commander` typings and missing `fuzzysort` types) --- packages/server/src/workspaces/manager.ts | 9 ++-- .../src/workspaces/opencode-auth.test.ts | 41 +++++++++++++++++++ .../server/src/workspaces/opencode-auth.ts | 26 ++++++++++++ 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 packages/server/src/workspaces/opencode-auth.test.ts diff --git a/packages/server/src/workspaces/manager.ts b/packages/server/src/workspaces/manager.ts index dc939758..40bf2861 100644 --- a/packages/server/src/workspaces/manager.ts +++ b/packages/server/src/workspaces/manager.ts @@ -13,10 +13,9 @@ import { Logger } from "../logger" import { getOpencodeConfigDir } from "../opencode-config.js" import { buildOpencodeBasicAuthHeader, - DEFAULT_OPENCODE_USERNAME, - generateOpencodeServerPassword, OPENCODE_SERVER_PASSWORD_ENV, OPENCODE_SERVER_USERNAME_ENV, + resolveOpencodeServerAuth, } from "./opencode-auth" const STARTUP_STABILITY_DELAY_MS = 1500 @@ -124,8 +123,10 @@ export class WorkspaceManager { const envVars = (serverConfig as any)?.environmentVariables const userEnvironment = envVars && typeof envVars === "object" && !Array.isArray(envVars) ? (envVars as any) : {} - const opencodeUsername = DEFAULT_OPENCODE_USERNAME - const opencodePassword = generateOpencodeServerPassword() + const { username: opencodeUsername, password: opencodePassword } = resolveOpencodeServerAuth({ + userEnvironment, + processEnv: process.env, + }) const authorization = buildOpencodeBasicAuthHeader({ username: opencodeUsername, password: opencodePassword }) if (!authorization) { throw new Error("Failed to build OpenCode auth header") diff --git a/packages/server/src/workspaces/opencode-auth.test.ts b/packages/server/src/workspaces/opencode-auth.test.ts new file mode 100644 index 00000000..e4a13a4d --- /dev/null +++ b/packages/server/src/workspaces/opencode-auth.test.ts @@ -0,0 +1,41 @@ +import assert from "node:assert/strict" +import { describe, it } from "node:test" + +import { resolveOpencodeServerAuth } from "./opencode-auth" + +describe("resolveOpencodeServerAuth", () => { + it("uses configured OpenCode auth from workspace environment", () => { + const auth = resolveOpencodeServerAuth({ + userEnvironment: { + OPENCODE_SERVER_USERNAME: "alice", + OPENCODE_SERVER_PASSWORD: "secret", + }, + processEnv: {}, + generatePassword: () => "generated", + }) + + assert.deepEqual(auth, { username: "alice", password: "secret" }) + }) + + it("uses process environment when workspace environment does not provide credentials", () => { + const auth = resolveOpencodeServerAuth({ + userEnvironment: {}, + processEnv: { + OPENCODE_SERVER_PASSWORD: "process-secret", + }, + generatePassword: () => "generated", + }) + + assert.deepEqual(auth, { username: "codenomad", password: "process-secret" }) + }) + + it("falls back to generated credentials", () => { + const auth = resolveOpencodeServerAuth({ + userEnvironment: {}, + processEnv: {}, + generatePassword: () => "generated", + }) + + assert.deepEqual(auth, { username: "codenomad", password: "generated" }) + }) +}) diff --git a/packages/server/src/workspaces/opencode-auth.ts b/packages/server/src/workspaces/opencode-auth.ts index 8713272f..d6b9059b 100644 --- a/packages/server/src/workspaces/opencode-auth.ts +++ b/packages/server/src/workspaces/opencode-auth.ts @@ -9,6 +9,32 @@ export function generateOpencodeServerPassword(): string { return crypto.randomBytes(32).toString("base64url") } +function readConfiguredValue(key: string, ...sources: Array | undefined>): string | undefined { + for (const source of sources) { + const value = source?.[key] + if (typeof value === "string" && value.trim().length > 0) { + return value + } + } + return undefined +} + +export function resolveOpencodeServerAuth(options: { + userEnvironment?: Record + processEnv?: NodeJS.ProcessEnv + generatePassword?: () => string +} = {}): { username: string; password: string } { + const generatePassword = options.generatePassword ?? generateOpencodeServerPassword + const username = + readConfiguredValue(OPENCODE_SERVER_USERNAME_ENV, options.userEnvironment, options.processEnv) ?? + DEFAULT_OPENCODE_USERNAME + const password = + readConfiguredValue(OPENCODE_SERVER_PASSWORD_ENV, options.userEnvironment, options.processEnv) ?? + generatePassword() + + return { username, password } +} + export function buildOpencodeBasicAuthHeader(params: { username?: string; password?: string }): string | undefined { const username = params.username const password = params.password