{"record":{"id":"98309bbb12536573","repo":"paperclipai/paperclip","slug":"managed-opencode-authentication-requires-an-isolated-remote","errorCode":null,"errorMessage":"Managed OpenCode authentication requires an isolated remote runtime directory.","messagePattern":"Managed OpenCode authentication requires an isolated remote runtime directory\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/adapters/opencode-local/src/server/runtime-config.ts","lineNumber":253,"sourceCode":"      XDG_CONFIG_HOME: runtimeConfigHome,\n    },\n    notes,\n    cleanup: async () => {\n      await fs.rm(runtimeConfigHome, { recursive: true, force: true });\n    },\n  };\n}\n\n/** Managed credentials must never leave host-only homes in a remote process. */\nexport function prepareManagedOpenCodeRemoteHomes(input: {\n  env: Record<string, string>;\n  config: Record<string, unknown>;\n  runtimeRootDir: string | null | undefined;\n  runId: string;\n  configDir?: string;\n}): void {\n  if (!input.config.managedAiConnection) return;\n  if (!input.runtimeRootDir) throw new Error(\"Managed OpenCode authentication requires an isolated remote runtime directory.\");\n  const home = path.posix.join(input.runtimeRootDir, \"managed-auth\", input.runId);\n  Object.assign(input.env, {\n    HOME: home,\n    XDG_CONFIG_HOME: input.configDir ?? path.posix.join(home, \"config\"),\n    XDG_DATA_HOME: path.posix.join(home, \"data\"),\n    XDG_CACHE_HOME: path.posix.join(home, \"cache\"),\n    XDG_STATE_HOME: path.posix.join(home, \"state\"),\n  });\n}\n","sourceCodeStart":235,"sourceCodeEnd":263,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/adapters/opencode-local/src/server/runtime-config.ts#L235-L263","documentation":"When a managed AI connection is configured for OpenCode, the runtime must isolate HOME/XDG directories per run under a remote runtime root so credentials never collide or leak between runs. If the runtime root directory is not provided (null/undefined), the setup function refuses to build a managed-auth home and throws. This protects the managed authentication model: without isolation, OpenCode would use the ambient HOME.","triggerScenarios":"prepareManagedOpenCodeRemoteHomes (via execute or testEnvironment) receives input.config.managedAiConnection set but input.runtimeRootDir null or undefined.","commonSituations":"Calling the adapter's execute/testEnvironment without provisioning the sandbox runtime root; a refactor stopped passing runtimeRootDir; running managed-auth mode on a runtime type that does not supply a remote root (local vs remote mismatch).","solutions":["Provision and pass runtimeRootDir when constructing the adapter execution environment.","Only enable config.managedAiConnection on runtimes that supply an isolated remote runtime directory.","Check the caller (execute/testEnvironment) wiring so runtimeRootDir is derived before managed-auth setup runs."],"exampleFix":"// before\nawait adapter.testEnvironment({ config: { managedAiConnection } });\n// after\nawait adapter.testEnvironment({ config: { managedAiConnection }, runtimeRootDir });","handlingStrategy":"validation","validationCode":"if (config.managedAiConnection && !runtimeRootDir) throw new Error(\"managed OpenCode auth needs runtimeRootDir\");","typeGuard":"const canPrepareManagedAuth = (i: { config: { managedAiConnection?: unknown }; runtimeRootDir?: string | null }): i is typeof i & { runtimeRootDir: string } =>\n  !i.config.managedAiConnection || (typeof i.runtimeRootDir === \"string\" && i.runtimeRootDir.length > 0);","tryCatchPattern":"try { await prepareManagedOpenCodeRemoteHomes(input); } catch (e) {\n  if (e.message.includes(\"isolated remote runtime directory\")) { console.error(\"provide runtimeRootDir or disable managedAiConnection\"); }\n  throw e;\n}","preventionTips":["Always provision runtimeRootDir before adapter execute/testEnvironment","Only enable managedAiConnection on runtimes with remote isolation support","Add an assertion at call sites that pass managedAiConnection","Keep managed-auth wiring tests covering the missing-runtimeRootDir case"],"tags":["opencode","managed-auth","config","isolation"],"backgroundTag":"missing-required-config-field","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}