feat(runtime): detect Claude Platform on AWS safely

This commit is contained in:
777genius 2026-05-12 21:26:38 +03:00
parent 3f2b807bbc
commit 7138887a3b
5 changed files with 93 additions and 1 deletions

View file

@ -35,9 +35,57 @@ describe('applyProviderRuntimeEnv', () => {
expect(env.GOOGLE_CLOUD_PROJECT).toBe('project-1');
});
it('preserves Claude Platform on AWS as an Anthropic runtime backend', () => {
const env: NodeJS.ProcessEnv = {
ANTHROPIC_AWS_WORKSPACE_ID: 'wrkspc_123',
AWS_PROFILE: 'cc',
AWS_REGION: 'us-west-2',
};
applyProviderRuntimeEnv(env, 'anthropic');
expect(env.CLAUDE_CODE_ENTRY_PROVIDER).toBe('claude-platform-aws');
expect(env.ANTHROPIC_AWS_WORKSPACE_ID).toBe('wrkspc_123');
expect(env.CLAUDE_CODE_USE_BEDROCK).toBeUndefined();
expect(env.CLAUDE_CODE_USE_VERTEX).toBeUndefined();
expect(env.CLAUDE_CODE_USE_FOUNDRY).toBeUndefined();
expect(env.AWS_PROFILE).toBe('cc');
expect(env.AWS_REGION).toBe('us-west-2');
});
it('does not infer Claude Platform on AWS from AWS profile and region alone', () => {
const env: NodeJS.ProcessEnv = {
AWS_PROFILE: 'cc',
AWS_REGION: 'us-west-2',
};
applyProviderRuntimeEnv(env, 'anthropic');
expect(env.CLAUDE_CODE_ENTRY_PROVIDER).toBe('anthropic');
expect(env.CLAUDE_CODE_USE_BEDROCK).toBeUndefined();
expect(env.AWS_PROFILE).toBe('cc');
expect(env.AWS_REGION).toBe('us-west-2');
});
it('keeps Bedrock ahead of Claude Platform on AWS when both are configured', () => {
const env: NodeJS.ProcessEnv = {
CLAUDE_CODE_USE_BEDROCK: '1',
ANTHROPIC_AWS_WORKSPACE_ID: 'wrkspc_123',
AWS_PROFILE: 'cc',
AWS_REGION: 'us-east-1',
};
applyProviderRuntimeEnv(env, 'anthropic');
expect(env.CLAUDE_CODE_ENTRY_PROVIDER).toBe('bedrock');
expect(env.CLAUDE_CODE_USE_BEDROCK).toBe('1');
expect(env.ANTHROPIC_AWS_WORKSPACE_ID).toBe('wrkspc_123');
});
it('still strips Anthropic backend routing when Codex is selected', () => {
const env: NodeJS.ProcessEnv = {
CLAUDE_CODE_USE_BEDROCK: '1',
ANTHROPIC_AWS_WORKSPACE_ID: 'wrkspc_123',
AWS_PROFILE: 'cc',
};
@ -45,6 +93,7 @@ describe('applyProviderRuntimeEnv', () => {
expect(env.CLAUDE_CODE_ENTRY_PROVIDER).toBe('codex');
expect(env.CLAUDE_CODE_USE_BEDROCK).toBeUndefined();
expect(env.ANTHROPIC_AWS_WORKSPACE_ID).toBe('wrkspc_123');
expect(env.AWS_PROFILE).toBe('cc');
});
});

View file

@ -4,7 +4,12 @@ import type { CliProviderId, TeamProviderId } from '@shared/types';
type RuntimeEnvProviderId = CliProviderId | TeamProviderId;
type AnthropicRuntimeBackendProviderId = 'anthropic' | 'bedrock' | 'vertex' | 'foundry';
type AnthropicRuntimeBackendProviderId =
| 'anthropic'
| 'bedrock'
| 'vertex'
| 'foundry'
| 'claude-platform-aws';
const PROVIDER_ROUTING_ENV_KEYS = [
'CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST',
@ -51,6 +56,9 @@ function resolveAnthropicRuntimeBackendFromEnv(
if (isTruthyEnvValue(env.CLAUDE_CODE_USE_FOUNDRY)) {
return 'foundry';
}
if (env.ANTHROPIC_AWS_WORKSPACE_ID?.trim()) {
return 'claude-platform-aws';
}
return 'anthropic';
}

View file

@ -841,6 +841,8 @@ const DIRECT_TMUX_RESTART_ENV_KEYS = [
CLAUDE_TEAM_ANTHROPIC_AUTH_MODE_ENV,
CLAUDE_TEAM_ANTHROPIC_API_KEY_HELPER_SETTINGS_PATH_ENV,
'ANTHROPIC_BASE_URL',
'ANTHROPIC_AWS_WORKSPACE_ID',
'ANTHROPIC_AWS_API_KEY',
'ANTHROPIC_API_KEY',
'ANTHROPIC_AUTH_TOKEN',
'GEMINI_BASE_URL',

View file

@ -35,6 +35,25 @@ describe('providerRuntimeEnv', () => {
expect(result.CLAUDE_CODE_USE_OPENAI).toBeUndefined();
});
it('pins Claude Platform on AWS only when the workspace id is explicit', () => {
const awsOnlyEnv: NodeJS.ProcessEnv = {
AWS_PROFILE: 'cc',
AWS_REGION: 'us-west-2',
};
expect(applyProviderRuntimeEnv(awsOnlyEnv, 'anthropic').CLAUDE_CODE_ENTRY_PROVIDER).toBe(
'anthropic'
);
const platformEnv: NodeJS.ProcessEnv = {
ANTHROPIC_AWS_WORKSPACE_ID: 'wrkspc_123',
AWS_PROFILE: 'cc',
AWS_REGION: 'us-west-2',
};
expect(applyProviderRuntimeEnv(platformEnv, 'anthropic').CLAUDE_CODE_ENTRY_PROVIDER).toBe(
'claude-platform-aws'
);
});
it('preserves gemini as a valid team provider id', () => {
expect(resolveTeamProviderId('gemini')).toBe('gemini');
expect(resolveTeamProviderId('codex')).toBe('codex');

View file

@ -392,6 +392,20 @@ describe('TeamProvisioningService prepare/auth behavior', () => {
expect(assignments).toContain("CODEX_HOME='/tmp/codex-connected-home'");
});
it('preserves Claude Platform on AWS settings for direct tmux restart', () => {
const assignments = buildDirectTmuxRestartEnvAssignments(
{
ANTHROPIC_AWS_WORKSPACE_ID: 'wrkspc_123',
ANTHROPIC_AWS_API_KEY: 'aws-platform-key',
},
'anthropic'
);
expect(assignments).toContain("ANTHROPIC_AWS_WORKSPACE_ID='wrkspc_123'");
expect(assignments).toContain("ANTHROPIC_AWS_API_KEY='aws-platform-key'");
expect(assignments).toContain("CLAUDE_CODE_ENTRY_PROVIDER='anthropic'");
});
it('does not flatten Anthropic helper settings into non-Anthropic lead cross-provider args', async () => {
const svc = new TeamProvisioningService();
const helperSettingsPath = path.join(tempRoot, 'team-runtime-auth', 'helper-settings.json');