diff --git a/packages/adapters/opencode-local/src/server/runtime-config.test.ts b/packages/adapters/opencode-local/src/server/runtime-config.test.ts index 14791829a8..94a980ffe5 100644 --- a/packages/adapters/opencode-local/src/server/runtime-config.test.ts +++ b/packages/adapters/opencode-local/src/server/runtime-config.test.ts @@ -2,10 +2,43 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { prepareOpenCodeRuntimeConfig } from "./runtime-config.js"; +import { prepareManagedOpenCodeRemoteHomes, prepareOpenCodeRuntimeConfig } from "./runtime-config.js"; const cleanupPaths = new Set(); +describe("prepareManagedOpenCodeRemoteHomes", () => { + it("keeps the sandbox home while isolating managed credentials outside scoped folders", () => { + const env = { HOME: "/host/private", XDG_DATA_HOME: "/host/data" }; + prepareManagedOpenCodeRemoteHomes({ + env, + config: { managedAiConnection: true }, + runtimeRootDir: "/home/daytona/.paperclip-runtime/opencode", + runId: "run-1", + configDir: "/home/daytona/.paperclip-runtime/opencode/config", + workFolderHome: "/home/daytona", + }); + expect(env).toEqual({ + HOME: "/home/daytona", + XDG_CONFIG_HOME: "/home/daytona/.paperclip-runtime/opencode/config", + XDG_DATA_HOME: "/home/daytona/.paperclip-runtime/opencode/managed-auth/run-1/data", + XDG_CACHE_HOME: "/home/daytona/.paperclip-runtime/opencode/managed-auth/run-1/cache", + XDG_STATE_HOME: "/home/daytona/.paperclip-runtime/opencode/managed-auth/run-1/state", + }); + }); + + it("preserves the isolated remote home for execution without work folders", () => { + const env: Record = { HOME: "/host/private" }; + prepareManagedOpenCodeRemoteHomes({ + env, + config: { managedAiConnection: true }, + runtimeRootDir: "/remote/runtime", + runId: "run-1", + }); + expect(env.HOME).toBe("/remote/runtime/managed-auth/run-1"); + expect(env.XDG_DATA_HOME).toBe("/remote/runtime/managed-auth/run-1/data"); + }); +}); + afterEach(async () => { await Promise.all( [...cleanupPaths].map(async (filepath) => { diff --git a/packages/adapters/opencode-local/src/server/runtime-config.ts b/packages/adapters/opencode-local/src/server/runtime-config.ts index b77aa7c8e9..51367efe82 100644 --- a/packages/adapters/opencode-local/src/server/runtime-config.ts +++ b/packages/adapters/opencode-local/src/server/runtime-config.ts @@ -248,12 +248,15 @@ export function prepareManagedOpenCodeRemoteHomes(input: { runtimeRootDir: string | null | undefined; runId: string; configDir?: string; + workFolderHome?: string; }): void { if (!input.config.managedAiConnection) return; if (!input.runtimeRootDir) throw new Error("Managed OpenCode authentication requires an isolated remote runtime directory."); const home = path.posix.join(input.runtimeRootDir, "managed-auth", input.runId); Object.assign(input.env, { - HOME: home, + // Scoped work folders live beneath the sandbox's real home. OpenCode's + // credential/configuration stores still use the isolated XDG directories. + HOME: input.workFolderHome ?? home, XDG_CONFIG_HOME: input.configDir ?? path.posix.join(home, "config"), XDG_DATA_HOME: path.posix.join(home, "data"), XDG_CACHE_HOME: path.posix.join(home, "cache"),