fix: address review findings for ANTHROPIC_API_KEY removal

- Add deprecation warning when ANTHROPIC_API_KEY is set but neither
  CLAUDE_CODE_OAUTH_TOKEN nor CLAUDE_API_KEY is present, so users
  migrating from direct Anthropic SDK usage get a clear hint
- Clarify JSDoc: replace "(backwards compatibility)" with more precise
  "Auto-detect — use explicit tokens if present, otherwise fall back
  to global auth" to avoid implying a legacy alias still exists
- Add regression test: ANTHROPIC_API_KEY alone falls through to global
  auth path (hasExplicitTokens=false), preventing silent re-introduction
  of the startup warning bug
- Update .claude/agents/sdk-verifier.md: replace stale ANTHROPIC_API_KEY
  checklist reference with CLAUDE_CODE_OAUTH_TOKEN/CLAUDE_API_KEY
This commit is contained in:
Rasmus Widing 2026-04-06 16:34:45 +03:00
parent e788dc7e5d
commit 94a12f6d85
3 changed files with 49 additions and 2 deletions

View file

@ -49,7 +49,7 @@ Your verification should prioritize SDK functionality and best practices over ge
6. **Environment and Security**:
- Check that `.env.example` exists with `ANTHROPIC_API_KEY`
- Check that `.env.example` exists with Claude auth options (`CLAUDE_CODE_OAUTH_TOKEN` or `CLAUDE_API_KEY`)
- Verify `.env` is in `.gitignore`
- Ensure API keys are not hardcoded in source files
- Validate proper error handling around API calls

View file

@ -360,6 +360,41 @@ describe('ClaudeClient', () => {
}
});
test('ANTHROPIC_API_KEY alone does not set hasExplicitTokens (falls through to global auth)', async () => {
const originalOauth = process.env.CLAUDE_CODE_OAUTH_TOKEN;
const originalApiKey = process.env.CLAUDE_API_KEY;
const originalAnthropicKey = process.env.ANTHROPIC_API_KEY;
delete process.env.CLAUDE_CODE_OAUTH_TOKEN;
delete process.env.CLAUDE_API_KEY;
process.env.ANTHROPIC_API_KEY = 'sk-ant-test-key';
mockQuery.mockImplementation(async function* () {
// Empty generator
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for await (const _ of client.sendQuery('test', '/workspace')) {
// consume
}
// ANTHROPIC_API_KEY should pass through (not filtered) since useGlobalAuth=true path
// strips only CLAUDE_CODE_OAUTH_TOKEN and CLAUDE_API_KEY
const callArgs = mockQuery.mock.calls[0][0] as { options: { env: NodeJS.ProcessEnv } };
expect(callArgs.options.env.ANTHROPIC_API_KEY).toBe('sk-ant-test-key');
// Explicit SDK vars are absent (useGlobalAuth=true path)
expect(callArgs.options.env.CLAUDE_API_KEY).toBeUndefined();
expect(callArgs.options.env.CLAUDE_CODE_OAUTH_TOKEN).toBeUndefined();
// Cleanup
if (originalOauth !== undefined) process.env.CLAUDE_CODE_OAUTH_TOKEN = originalOauth;
else delete process.env.CLAUDE_CODE_OAUTH_TOKEN;
if (originalApiKey !== undefined) process.env.CLAUDE_API_KEY = originalApiKey;
else delete process.env.CLAUDE_API_KEY;
if (originalAnthropicKey !== undefined) process.env.ANTHROPIC_API_KEY = originalAnthropicKey;
else delete process.env.ANTHROPIC_API_KEY;
});
test('strips VSCODE_INSPECTOR_OPTIONS from subprocess env', async () => {
const original = process.env.VSCODE_INSPECTOR_OPTIONS;
process.env.VSCODE_INSPECTOR_OPTIONS = 'some-value';

View file

@ -69,7 +69,7 @@ function normalizeClaudeUsage(usage?: {
* Auth behavior:
* - CLAUDE_USE_GLOBAL_AUTH=true: Filter tokens, use global auth from `claude /login`
* - CLAUDE_USE_GLOBAL_AUTH=false: Pass tokens through explicitly
* - Not set: Auto-detect - if tokens exist in env, use them (backwards compatibility)
* - Not set: Auto-detect use explicit tokens if present, otherwise fall back to global auth
*/
function buildSubprocessEnv(): NodeJS.ProcessEnv {
const globalAuthSetting = process.env.CLAUDE_USE_GLOBAL_AUTH?.toLowerCase();
@ -81,6 +81,18 @@ function buildSubprocessEnv(): NodeJS.ProcessEnv {
getLog().warn({ emptyTokens }, 'empty_token_values');
}
// Warn if user has the legacy variable but not the new ones
if (
process.env.ANTHROPIC_API_KEY &&
!process.env.CLAUDE_CODE_OAUTH_TOKEN &&
!process.env.CLAUDE_API_KEY
) {
getLog().warn(
{ hint: 'Use CLAUDE_API_KEY or CLAUDE_CODE_OAUTH_TOKEN instead' },
'deprecated_anthropic_api_key_ignored'
);
}
const hasExplicitTokens = Boolean(
process.env.CLAUDE_CODE_OAUTH_TOKEN ?? process.env.CLAUDE_API_KEY
);