fix(anthropic): forward selected profiles to Claude CLI (#112458)

* fix(anthropic): forward Claude CLI auth profiles

* fix(system-agent): inject CLI auth route stores

* fix(claude-cli): pass profile credentials by descriptor

* fix(anthropic): repair selected profile CI coverage

* fix(anthropic): preserve profile owner validation

* test(system-agent): preserve selected profile fixtures

* test(system-agent): narrow selected profile fixture

* test(system-agent): resolve profile store merge

* fix(anthropic): forward profiles to node Claude runs

* fix(system-agent): reconcile profile route projection

* test(system-agent): thread profile store through projection

* fix(anthropic): make selected profile authoritative

* fix(system-agent): type auth setup failures

* fix(system-agent): type setup auth failures

* style: format Claude profile maintenance

* fix(anthropic): keep gateway credentials off nodes

* fix(anthropic): clear ambient auth for selected profiles

* fix(anthropic): secure paired-node Claude auth

* fix(node-host): type Claude fd spawn streams

* style(node-host): satisfy Claude spawn lint

* fix(process): capture exit before secret delivery

* fix(anthropic): preserve node-native Claude auth
This commit is contained in:
Jason (Json)
2026-07-21 23:27:37 -06:00
committed by GitHub
parent 13716ad4f4
commit 1a42e005fb
30 changed files with 1252 additions and 75 deletions
+45
View File
@@ -517,14 +517,22 @@ describe("runCliAgent spawn path", () => {
],
forkArg: "--fork-session",
liveSession: "claude-stdio",
env: { ANTHROPIC_API_KEY: "configured-backend-key" },
clearEnv: ["ANTHROPIC_API_KEY", "CLAUDE_CODE_OAUTH_TOKEN"],
systemPromptWhen: "always",
},
preparedEnv: { CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR: "3" },
resolveExecutionArgs: (execution) => {
toolAvailability = execution.toolAvailability;
return [...execution.baseArgs];
},
cliToolAvailability: { native: [], mcp: ["mcp__openclaw__message"] },
});
context.preparedBackend.secretInput = {
fd: 3,
fingerprint: "selected-node-token-fingerprint",
createData: () => Buffer.from("selected-node-token"),
};
context.openClawHistoryPrompt = "gateway transcript reseed";
context.claudeSkillsPluginArgs = ["--plugin-dir", "/tmp/gateway-skills"];
context.params.forkCliSessionOnResume = true;
@@ -546,8 +554,14 @@ describe("runCliAgent spawn path", () => {
stdin: "current turn",
argv: expect.arrayContaining(["--resume", "source-node-session", "--fork-session"]),
systemPrompt: "You are a helpful assistant.",
env: { CLAUDE_CODE_OAUTH_TOKEN: "selected-node-token" },
clearEnv: ["ANTHROPIC_API_KEY", "CLAUDE_CODE_OAUTH_TOKEN"],
}),
);
expect(invokeNode.mock.calls[0]?.[0].env).not.toHaveProperty("ANTHROPIC_API_KEY");
expect(invokeNode.mock.calls[0]?.[0].env).not.toHaveProperty(
"CLAUDE_CODE_SUBPROCESS_ENV_SCRUB",
);
const argv = invokeNode.mock.calls[0]?.[0].argv ?? [];
expect(argv).not.toContain("--mcp-config");
expect(argv).not.toContain("--permission-mode");
@@ -591,6 +605,7 @@ describe("runCliAgent spawn path", () => {
resumeArgs: ["-p", "--output-format", "stream-json", "--resume", "{sessionId}"],
forkArg: "--fork-session",
liveSession: "claude-stdio",
env: { ANTHROPIC_API_KEY: "gateway-backend-key" },
systemPromptWhen: "always",
},
});
@@ -598,6 +613,8 @@ describe("runCliAgent spawn path", () => {
await expect(executePreparedCliRun(context, undefined)).rejects.toThrow(
/truncated the Claude CLI stream before the terminal result/,
);
expect(invokeNode.mock.calls[0]?.[0].env).toBeUndefined();
expect(invokeNode.mock.calls[0]?.[0].clearEnv).toBeUndefined();
});
it("cancels a node-placed Claude process when the run aborts", async () => {
@@ -5851,6 +5868,34 @@ ${JSON.stringify({
expect(input.env?.SAFE_OVERRIDE).toBe("from-override");
});
it("keeps selected Claude auth authoritative over ambient and configured credentials", async () => {
vi.stubEnv("OPENCLAW_LIVE_CLI_BACKEND_PRESERVE_ENV", '["ANTHROPIC_API_KEY"]');
vi.stubEnv("ANTHROPIC_API_KEY", "ambient-api-key");
mockSuccessfulClaudeJsonlRun();
await executePreparedCliRun(
buildPreparedCliRunContext({
provider: "claude-cli",
model: "claude-sonnet-4-6",
runId: "run-claude-selected-auth-authority",
preparedEnv: {
CLAUDE_CODE_OAUTH_TOKEN: "selected-oauth-token",
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB: "1",
},
backend: {
env: { ANTHROPIC_API_KEY: "configured-api-key" },
clearEnv: ["ANTHROPIC_API_KEY", "CLAUDE_CODE_OAUTH_TOKEN"],
},
}),
);
const input = mockCallArg(supervisorSpawnMock) as {
env?: Record<string, string | undefined>;
};
expect(input.env?.ANTHROPIC_API_KEY).toBeUndefined();
expect(input.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("selected-oauth-token");
});
it("clears claude-cli provider-routing, auth, telemetry, compaction, and host-managed env", async () => {
vi.stubEnv("ANTHROPIC_BASE_URL", "https://proxy.example.com/v1");
vi.stubEnv("ANTHROPIC_API_TOKEN", "env-api-token");