From 817c431df213e20cd9e98149b848fa8dd2e4919d Mon Sep 17 00:00:00 2001 From: Dotta Date: Tue, 22 Sep 2026 16:44:21 -0500 Subject: [PATCH] fix(grok): keep company credential discovery controller-owned --- .../services/native-runtime/grok-runner-credentials.test.ts | 3 ++- .../src/services/native-runtime/grok-runner-credentials.ts | 4 +++- tests/runner-e2e/harness-env.ts | 2 +- tests/runner-e2e/support.test.ts | 6 ++++++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/server/src/services/native-runtime/grok-runner-credentials.test.ts b/server/src/services/native-runtime/grok-runner-credentials.test.ts index f9b39d3b518..07cc32e46b5 100644 --- a/server/src/services/native-runtime/grok-runner-credentials.test.ts +++ b/server/src/services/native-runtime/grok-runner-credentials.test.ts @@ -19,7 +19,8 @@ describe("Grok runner company credentials", () => { companyHome.mockReturnValue(join(root, "company-without-login")); const host = join(root, "host"); await mkdir(host, { mode: 0o700 }); await writeFile(join(host, "auth.json"), "host-secret", { mode: 0o600 }); - await expect(prepareGrokRunnerCredentials({ companyId: "test-company", remote: true, environment: { GROK_HOME: host } })).rejects.toThrow("subscription login is unavailable"); + await expect(prepareGrokRunnerCredentials({ companyId: "test-company", remote: true, environment: { GROK_HOME: host, PAPERCLIP_HOME: host, PAPERCLIP_INSTANCE_ID: "other" } })).rejects.toThrow("subscription login is unavailable"); + expect(companyHome).toHaveBeenCalledWith(process.env, "test-company"); }); it("uses only an explicitly selected API key and strips subscription payloads and homes", async () => { expect(await prepareGrokRunnerCredentials({ companyId: "test-company", remote: true, environment: { XAI_API_KEY: "selected", GROK_HOME: "/host", PAPERCLIP_ACPX_GROK_AUTH_JSON_SECRET: "stale" } })).toEqual({ environment: { XAI_API_KEY: "selected" }, home: null }); diff --git a/server/src/services/native-runtime/grok-runner-credentials.ts b/server/src/services/native-runtime/grok-runner-credentials.ts index 2ba08481022..1d7a297818c 100644 --- a/server/src/services/native-runtime/grok-runner-credentials.ts +++ b/server/src/services/native-runtime/grok-runner-credentials.ts @@ -18,7 +18,9 @@ export async function prepareGrokRunnerCredentials(input: { delete environment.GROK_HOME; if (environment.XAI_API_KEY?.trim()) return { environment, home: null }; delete environment.XAI_API_KEY; - const companyHome = resolveManagedGrokHomeDir(input.environment, input.companyId); + // Credential discovery belongs to the controller instance. Agent-supplied + // PAPERCLIP_HOME/INSTANCE_ID values must not redirect company login reads. + const companyHome = resolveManagedGrokHomeDir(process.env, input.companyId); const home = configuredHome ?? (await grokHomeHasUsableAuth(companyHome) ? companyHome : input.remote ? companyHome : join(homedir(), ".grok")); try { diff --git a/tests/runner-e2e/harness-env.ts b/tests/runner-e2e/harness-env.ts index 6539f905b81..afab17b6ead 100644 --- a/tests/runner-e2e/harness-env.ts +++ b/tests/runner-e2e/harness-env.ts @@ -25,7 +25,7 @@ const AMBIENT_EXTERNAL_STATE_KEYS = [ "PAPERCLIP_STORAGE_S3_PREFIX", "PAPERCLIP_STORAGE_S3_FORCE_PATH_STYLE", ] as const; -const PROVIDER_SECRET_KEY = /^(?:OPENAI|ANTHROPIC|OPENROUTER|DAYTONA)(?:_|$)/; +const PROVIDER_SECRET_KEY = /^(?:OPENAI|ANTHROPIC|OPENROUTER|DAYTONA|XAI|GROK)(?:_|$)/; export function runnerE2EServerControlPaths(temporaryRoot: string) { const controlDirectory = path.join(temporaryRoot, "control"); diff --git a/tests/runner-e2e/support.test.ts b/tests/runner-e2e/support.test.ts index e7c4cb95fff..855efccaf35 100644 --- a/tests/runner-e2e/support.test.ts +++ b/tests/runner-e2e/support.test.ts @@ -824,6 +824,9 @@ describe("runner E2E server isolation", () => { ANTHROPIC_API_KEY: "anthropic", OPENROUTER_API_KEY: "openrouter", DAYTONA_API_KEY: "daytona", + XAI_API_KEY: "xai", + XAI_ORG_ID: "xai-sensitive", + GROK_HOME: "/outside/grok", OPENAI_ORG_ID: "also-provider-sensitive", PAPERCLIP_API_KEY: "ambient-board-key", PAPERCLIP_AGENT_API_KEY: "ambient-agent-key", @@ -847,6 +850,9 @@ describe("runner E2E server isolation", () => { expect(env.DATABASE_URL).toBeUndefined(); expect(env.OPENAI_API_KEY).toBeUndefined(); expect(env.OPENAI_ORG_ID).toBeUndefined(); + expect(env.XAI_API_KEY).toBeUndefined(); + expect(env.XAI_ORG_ID).toBeUndefined(); + expect(env.GROK_HOME).toBeUndefined(); expect(env.PAPERCLIP_API_KEY).toBeUndefined(); expect(env.PAPERCLIP_AGENT_API_KEY).toBeUndefined(); expect(env.XDG_CACHE_HOME).toBe("/tmp/cell/xdg-cache");