feat(runtime): detect Claude Platform on AWS safely
This commit is contained in:
parent
3f2b807bbc
commit
7138887a3b
5 changed files with 93 additions and 1 deletions
|
|
@ -35,9 +35,57 @@ describe('applyProviderRuntimeEnv', () => {
|
||||||
expect(env.GOOGLE_CLOUD_PROJECT).toBe('project-1');
|
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', () => {
|
it('still strips Anthropic backend routing when Codex is selected', () => {
|
||||||
const env: NodeJS.ProcessEnv = {
|
const env: NodeJS.ProcessEnv = {
|
||||||
CLAUDE_CODE_USE_BEDROCK: '1',
|
CLAUDE_CODE_USE_BEDROCK: '1',
|
||||||
|
ANTHROPIC_AWS_WORKSPACE_ID: 'wrkspc_123',
|
||||||
AWS_PROFILE: 'cc',
|
AWS_PROFILE: 'cc',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -45,6 +93,7 @@ describe('applyProviderRuntimeEnv', () => {
|
||||||
|
|
||||||
expect(env.CLAUDE_CODE_ENTRY_PROVIDER).toBe('codex');
|
expect(env.CLAUDE_CODE_ENTRY_PROVIDER).toBe('codex');
|
||||||
expect(env.CLAUDE_CODE_USE_BEDROCK).toBeUndefined();
|
expect(env.CLAUDE_CODE_USE_BEDROCK).toBeUndefined();
|
||||||
|
expect(env.ANTHROPIC_AWS_WORKSPACE_ID).toBe('wrkspc_123');
|
||||||
expect(env.AWS_PROFILE).toBe('cc');
|
expect(env.AWS_PROFILE).toBe('cc');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,12 @@ import type { CliProviderId, TeamProviderId } from '@shared/types';
|
||||||
|
|
||||||
type RuntimeEnvProviderId = CliProviderId | TeamProviderId;
|
type RuntimeEnvProviderId = CliProviderId | TeamProviderId;
|
||||||
|
|
||||||
type AnthropicRuntimeBackendProviderId = 'anthropic' | 'bedrock' | 'vertex' | 'foundry';
|
type AnthropicRuntimeBackendProviderId =
|
||||||
|
| 'anthropic'
|
||||||
|
| 'bedrock'
|
||||||
|
| 'vertex'
|
||||||
|
| 'foundry'
|
||||||
|
| 'claude-platform-aws';
|
||||||
|
|
||||||
const PROVIDER_ROUTING_ENV_KEYS = [
|
const PROVIDER_ROUTING_ENV_KEYS = [
|
||||||
'CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST',
|
'CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST',
|
||||||
|
|
@ -51,6 +56,9 @@ function resolveAnthropicRuntimeBackendFromEnv(
|
||||||
if (isTruthyEnvValue(env.CLAUDE_CODE_USE_FOUNDRY)) {
|
if (isTruthyEnvValue(env.CLAUDE_CODE_USE_FOUNDRY)) {
|
||||||
return 'foundry';
|
return 'foundry';
|
||||||
}
|
}
|
||||||
|
if (env.ANTHROPIC_AWS_WORKSPACE_ID?.trim()) {
|
||||||
|
return 'claude-platform-aws';
|
||||||
|
}
|
||||||
return 'anthropic';
|
return 'anthropic';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -841,6 +841,8 @@ const DIRECT_TMUX_RESTART_ENV_KEYS = [
|
||||||
CLAUDE_TEAM_ANTHROPIC_AUTH_MODE_ENV,
|
CLAUDE_TEAM_ANTHROPIC_AUTH_MODE_ENV,
|
||||||
CLAUDE_TEAM_ANTHROPIC_API_KEY_HELPER_SETTINGS_PATH_ENV,
|
CLAUDE_TEAM_ANTHROPIC_API_KEY_HELPER_SETTINGS_PATH_ENV,
|
||||||
'ANTHROPIC_BASE_URL',
|
'ANTHROPIC_BASE_URL',
|
||||||
|
'ANTHROPIC_AWS_WORKSPACE_ID',
|
||||||
|
'ANTHROPIC_AWS_API_KEY',
|
||||||
'ANTHROPIC_API_KEY',
|
'ANTHROPIC_API_KEY',
|
||||||
'ANTHROPIC_AUTH_TOKEN',
|
'ANTHROPIC_AUTH_TOKEN',
|
||||||
'GEMINI_BASE_URL',
|
'GEMINI_BASE_URL',
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,25 @@ describe('providerRuntimeEnv', () => {
|
||||||
expect(result.CLAUDE_CODE_USE_OPENAI).toBeUndefined();
|
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', () => {
|
it('preserves gemini as a valid team provider id', () => {
|
||||||
expect(resolveTeamProviderId('gemini')).toBe('gemini');
|
expect(resolveTeamProviderId('gemini')).toBe('gemini');
|
||||||
expect(resolveTeamProviderId('codex')).toBe('codex');
|
expect(resolveTeamProviderId('codex')).toBe('codex');
|
||||||
|
|
|
||||||
|
|
@ -392,6 +392,20 @@ describe('TeamProvisioningService prepare/auth behavior', () => {
|
||||||
expect(assignments).toContain("CODEX_HOME='/tmp/codex-connected-home'");
|
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 () => {
|
it('does not flatten Anthropic helper settings into non-Anthropic lead cross-provider args', async () => {
|
||||||
const svc = new TeamProvisioningService();
|
const svc = new TeamProvisioningService();
|
||||||
const helperSettingsPath = path.join(tempRoot, 'team-runtime-auth', 'helper-settings.json');
|
const helperSettingsPath = path.join(tempRoot, 'team-runtime-auth', 'helper-settings.json');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue