Skip to content

Commit 886168a

Browse files
Claudelpcox
andauthored
fix: set CLAUDE_CODE_API_KEY_HELPER env var for credential isolation (#851)
* Initial plan * fix: set CLAUDE_CODE_API_KEY_HELPER env var for credential isolation When api-proxy is enabled with an Anthropic key, set the CLAUDE_CODE_API_KEY_HELPER environment variable to point to the get-claude-key.sh script. This ensures Claude Code CLI properly uses the API key helper for credential isolation. Previously, only ANTHROPIC_BASE_URL was set, but Claude Code requires either a config file with apiKeyHelper or the environment variable to actually use the helper script. Without this, Claude Code would not read the config and authentication would fail. This fix: - Sets CLAUDE_CODE_API_KEY_HELPER=/usr/local/bin/get-claude-key.sh when api-proxy is enabled with Anthropic key - Adds comprehensive tests for the new environment variable - Updates type documentation to reflect the new env var Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --------- Co-authored-by: anthropic-code-agent[bot] <242468646+Claude@users.noreply.github.com> Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
1 parent eefeff9 commit 886168a

3 files changed

Lines changed: 25 additions & 0 deletions

File tree

src/docker-manager.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ describe('docker-manager', () => {
15681568
const agent = result.services.agent;
15691569
const env = agent.environment as Record<string, string>;
15701570
expect(env.ANTHROPIC_BASE_URL).toBe('http://172.30.0.30:10001');
1571+
expect(env.CLAUDE_CODE_API_KEY_HELPER).toBe('/usr/local/bin/get-claude-key.sh');
15711572
});
15721573

15731574
it('should set both BASE_URL variables when both keys are provided', () => {
@@ -1577,6 +1578,7 @@ describe('docker-manager', () => {
15771578
const env = agent.environment as Record<string, string>;
15781579
expect(env.OPENAI_BASE_URL).toBe('http://172.30.0.30:10000');
15791580
expect(env.ANTHROPIC_BASE_URL).toBe('http://172.30.0.30:10001');
1581+
expect(env.CLAUDE_CODE_API_KEY_HELPER).toBe('/usr/local/bin/get-claude-key.sh');
15801582
});
15811583

15821584
it('should not set OPENAI_BASE_URL in agent when only Anthropic key is provided', () => {
@@ -1586,6 +1588,7 @@ describe('docker-manager', () => {
15861588
const env = agent.environment as Record<string, string>;
15871589
expect(env.OPENAI_BASE_URL).toBeUndefined();
15881590
expect(env.ANTHROPIC_BASE_URL).toBe('http://172.30.0.30:10001');
1591+
expect(env.CLAUDE_CODE_API_KEY_HELPER).toBe('/usr/local/bin/get-claude-key.sh');
15891592
});
15901593

15911594
it('should not set ANTHROPIC_BASE_URL in agent when only OpenAI key is provided', () => {
@@ -1614,6 +1617,22 @@ describe('docker-manager', () => {
16141617
expect(env.no_proxy).toContain('172.30.0.30');
16151618
});
16161619

1620+
it('should set CLAUDE_CODE_API_KEY_HELPER when Anthropic key is provided', () => {
1621+
const configWithProxy = { ...mockConfig, enableApiProxy: true, anthropicApiKey: 'sk-ant-test-key' };
1622+
const result = generateDockerCompose(configWithProxy, mockNetworkConfigWithProxy);
1623+
const agent = result.services.agent;
1624+
const env = agent.environment as Record<string, string>;
1625+
expect(env.CLAUDE_CODE_API_KEY_HELPER).toBe('/usr/local/bin/get-claude-key.sh');
1626+
});
1627+
1628+
it('should not set CLAUDE_CODE_API_KEY_HELPER when only OpenAI key is provided', () => {
1629+
const configWithProxy = { ...mockConfig, enableApiProxy: true, openaiApiKey: 'sk-test-key' };
1630+
const result = generateDockerCompose(configWithProxy, mockNetworkConfigWithProxy);
1631+
const agent = result.services.agent;
1632+
const env = agent.environment as Record<string, string>;
1633+
expect(env.CLAUDE_CODE_API_KEY_HELPER).toBeUndefined();
1634+
});
1635+
16171636
it('should not leak ANTHROPIC_API_KEY to agent when api-proxy is enabled', () => {
16181637
// Simulate the key being in process.env (as it would be in real usage)
16191638
const origKey = process.env.ANTHROPIC_API_KEY;

src/docker-manager.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,11 @@ export function generateDockerCompose(
997997
if (config.anthropicApiKey) {
998998
environment.ANTHROPIC_BASE_URL = `http://${networkConfig.proxyIp}:10001`;
999999
logger.debug(`Anthropic API will be proxied through sidecar at http://${networkConfig.proxyIp}:10001`);
1000+
1001+
// Set API key helper for Claude Code CLI to use credential isolation
1002+
// The helper script returns a placeholder key; real authentication happens via ANTHROPIC_BASE_URL
1003+
environment.CLAUDE_CODE_API_KEY_HELPER = '/usr/local/bin/get-claude-key.sh';
1004+
logger.debug('Claude Code API key helper configured: /usr/local/bin/get-claude-key.sh');
10001005
}
10011006

10021007
logger.info('API proxy sidecar enabled - API keys will be held securely in sidecar container');

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ export interface WrapperConfig {
398398
* variables are set in the agent container:
399399
* - OPENAI_BASE_URL=http://api-proxy:10000 (set when OPENAI_API_KEY is provided)
400400
* - ANTHROPIC_BASE_URL=http://api-proxy:10001 (set when ANTHROPIC_API_KEY is provided)
401+
* - CLAUDE_CODE_API_KEY_HELPER=/usr/local/bin/get-claude-key.sh (set when ANTHROPIC_API_KEY is provided)
401402
*
402403
* API keys are passed via environment variables:
403404
* - OPENAI_API_KEY - Optional OpenAI API key for Codex

0 commit comments

Comments
 (0)