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
@@ -59,6 +59,45 @@ type ClaudeCliNodeInvokeDeps = Pick<
) => Promise<void>;
};
const CLAUDE_NODE_AUTH_INPUTS = [
{
requestEnv: "CLAUDE_CODE_OAUTH_TOKEN",
descriptorEnv: "CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR",
},
{
requestEnv: "ANTHROPIC_API_KEY",
descriptorEnv: "CLAUDE_CODE_API_KEY_FILE_DESCRIPTOR",
},
] as const;
function prepareClaudeNodeSecretInput(params: {
requestEnv: Record<string, string> | undefined;
childEnv: Record<string, string>;
}): { secretInput?: { fd: 3; createData: () => Buffer }; cleanup: () => void } {
const selected = CLAUDE_NODE_AUTH_INPUTS.find(({ requestEnv }) =>
Object.hasOwn(params.requestEnv ?? {}, requestEnv),
);
if (!selected) {
return { cleanup: () => {} };
}
for (const key of [
"ANTHROPIC_API_KEY",
"CLAUDE_CODE_OAUTH_TOKEN",
"CLAUDE_CODE_SUBPROCESS_ENV_SCRUB",
]) {
delete params.childEnv[key];
}
const source = Buffer.from(params.requestEnv?.[selected.requestEnv] ?? "", "utf8");
params.childEnv[selected.descriptorEnv] = "3";
return {
secretInput: {
fd: 3,
createData: () => Buffer.from(source),
},
cleanup: () => source.fill(0),
};
}
export async function handleClaudeCliNodeInvoke(params: {
frame: NodeInvokeRequestPayload;
client: NodeHostClient;
@@ -137,16 +176,31 @@ export async function handleClaudeCliNodeInvoke(params: {
isCmdExeInvocation: params.deps.isCmdExeInvocation,
sanitizeEnv: params.deps.sanitizeEnv,
runCommand: async (approvalArgv, cwd, env, timeoutMs) => {
runResult = await runClaudeCliNodeCommand({
client: params.client,
frame: params.frame,
request,
argv: approvalArgv,
cwd,
env,
timeoutMs,
signal: params.runtime.signal,
const childEnv = { ...env };
for (const key of request.clearEnv ?? []) {
if (!Object.hasOwn(request.env ?? {}, key)) {
delete childEnv[key];
}
}
const preparedSecret = prepareClaudeNodeSecretInput({
requestEnv: request.env,
childEnv,
});
try {
runResult = await runClaudeCliNodeCommand({
client: params.client,
frame: params.frame,
request,
argv: approvalArgv,
cwd,
env: childEnv,
secretInput: preparedSecret.secretInput,
timeoutMs,
signal: params.runtime.signal,
});
} finally {
preparedSecret.cleanup();
}
return runResult;
},
runViaMacAppExecHost: params.deps.runViaMacAppExecHost,