Skip to content

Commit bd1aab6

Browse files
committed
fix: add partial credential guard for Bedrock provider
Reject configurations where only one of bedrockAccessKeyId or bedrockSecretKey is provided, preventing silent fallback to the default credential chain with a potentially different identity. Add tests covering all credential configuration scenarios. Signed-off-by: majiayu000 <1835304752@qq.com>
1 parent 845a19a commit bd1aab6

File tree

2 files changed

+119
-0
lines changed

2 files changed

+119
-0
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { beforeEach, describe, expect, it, vi } from 'vitest'
5+
6+
const mockSend = vi.fn()
7+
8+
vi.mock('@aws-sdk/client-bedrock-runtime', () => ({
9+
BedrockRuntimeClient: vi.fn().mockImplementation((config: any) => {
10+
mockSend._lastConfig = config
11+
return { send: mockSend }
12+
}),
13+
ConverseCommand: vi.fn(),
14+
ConverseStreamCommand: vi.fn(),
15+
}))
16+
17+
vi.mock('@/providers/bedrock/utils', () => ({
18+
getBedrockInferenceProfileId: vi.fn().mockReturnValue('us.anthropic.claude-3-5-sonnet-20241022-v2:0'),
19+
checkForForcedToolUsage: vi.fn(),
20+
createReadableStreamFromBedrockStream: vi.fn(),
21+
generateToolUseId: vi.fn().mockReturnValue('tool-1'),
22+
}))
23+
24+
vi.mock('@/providers/models', () => ({
25+
getProviderModels: vi.fn().mockReturnValue([]),
26+
getProviderDefaultModel: vi.fn().mockReturnValue('us.anthropic.claude-3-5-sonnet-20241022-v2:0'),
27+
}))
28+
29+
vi.mock('@/providers/utils', () => ({
30+
calculateCost: vi.fn().mockReturnValue({ input: 0, output: 0, total: 0, pricing: null }),
31+
prepareToolExecution: vi.fn(),
32+
prepareToolsWithUsageControl: vi.fn(),
33+
sumToolCosts: vi.fn().mockReturnValue(0),
34+
}))
35+
36+
vi.mock('@/tools', () => ({
37+
executeTool: vi.fn(),
38+
}))
39+
40+
import { BedrockRuntimeClient } from '@aws-sdk/client-bedrock-runtime'
41+
import { bedrockProvider } from '@/providers/bedrock/index'
42+
43+
describe('bedrockProvider credential handling', () => {
44+
beforeEach(() => {
45+
vi.clearAllMocks()
46+
mockSend.mockResolvedValue({
47+
output: { message: { content: [{ text: 'response' }] } },
48+
usage: { inputTokens: 10, outputTokens: 5 },
49+
})
50+
})
51+
52+
const baseRequest = {
53+
model: 'us.anthropic.claude-3-5-sonnet-20241022-v2:0',
54+
systemPrompt: 'You are helpful.',
55+
messages: [{ role: 'user' as const, content: 'Hello' }],
56+
}
57+
58+
it('throws when only bedrockAccessKeyId is provided', async () => {
59+
await expect(
60+
bedrockProvider.executeRequest({
61+
...baseRequest,
62+
bedrockAccessKeyId: 'AKIAIOSFODNN7EXAMPLE',
63+
})
64+
).rejects.toThrow('Both bedrockAccessKeyId and bedrockSecretKey must be provided together')
65+
})
66+
67+
it('throws when only bedrockSecretKey is provided', async () => {
68+
await expect(
69+
bedrockProvider.executeRequest({
70+
...baseRequest,
71+
bedrockSecretKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
72+
})
73+
).rejects.toThrow('Both bedrockAccessKeyId and bedrockSecretKey must be provided together')
74+
})
75+
76+
it('creates client with explicit credentials when both are provided', async () => {
77+
await bedrockProvider.executeRequest({
78+
...baseRequest,
79+
bedrockAccessKeyId: 'AKIAIOSFODNN7EXAMPLE',
80+
bedrockSecretKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
81+
})
82+
83+
expect(BedrockRuntimeClient).toHaveBeenCalledWith({
84+
region: 'us-east-1',
85+
credentials: {
86+
accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
87+
secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
88+
},
89+
})
90+
})
91+
92+
it('creates client without credentials when neither is provided', async () => {
93+
await bedrockProvider.executeRequest(baseRequest)
94+
95+
expect(BedrockRuntimeClient).toHaveBeenCalledWith({
96+
region: 'us-east-1',
97+
})
98+
})
99+
100+
it('uses custom region when provided', async () => {
101+
await bedrockProvider.executeRequest({
102+
...baseRequest,
103+
bedrockRegion: 'eu-west-1',
104+
})
105+
106+
expect(BedrockRuntimeClient).toHaveBeenCalledWith({
107+
region: 'eu-west-1',
108+
})
109+
})
110+
})

apps/sim/providers/bedrock/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ export const bedrockProvider: ProviderConfig = {
5959
region,
6060
})
6161

62+
const hasAccessKey = Boolean(request.bedrockAccessKeyId)
63+
const hasSecretKey = Boolean(request.bedrockSecretKey)
64+
if (hasAccessKey !== hasSecretKey) {
65+
throw new Error(
66+
'Both bedrockAccessKeyId and bedrockSecretKey must be provided together. ' +
67+
'Provide both for explicit credentials, or omit both to use the AWS default credential chain.'
68+
)
69+
}
70+
6271
const clientConfig: {
6372
region: string
6473
credentials?: { accessKeyId: string; secretAccessKey: string }

0 commit comments

Comments
 (0)