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:
DottaandPaperclip committed 2026-09-12 18:29:56 -05:00
1 parent 84da6c8034
commit 7d8552f22b
2 files changed
+38 -2

No files matched your search

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