Preserve sandbox home in managed OpenCode runtime configuration

Move the optional HOME helper and focused coverage ahead of its caller so the runtime hardening layer remains under the review file limit.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Dotta 2026-09-12 18:29:56 -05:00
parent 84da6c8034
commit 7d8552f22b
2 changed files with 38 additions and 2 deletions

View File

@ -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<string>();
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<string, string> = { 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) => {

View File

@ -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"),