Skip to content

Commit cc48a4f

Browse files
committed
fix(bedrock): offer the saved AWS credential only on blocks that forward it
Guardrails and Pi spread the shared provider credential fields and inputs but never pass a saved credential to their call, so the AWS Authentication choice and credential picker are now opt-in. Agent, Router, Evaluator, and Translate opt in; Guardrails and Pi keep the fields and catalog schema they had before.
1 parent 1a76159 commit cc48a4f

7 files changed

Lines changed: 171 additions & 84 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { AgentBlock } from '@/blocks/blocks/agent'
3+
import { EvaluatorBlock } from '@/blocks/blocks/evaluator'
4+
import { GuardrailsBlock } from '@/blocks/blocks/guardrails'
5+
import { PiBlock } from '@/blocks/blocks/pi'
6+
import { RouterBlock, RouterV2Block } from '@/blocks/blocks/router'
7+
import { TranslateBlock } from '@/blocks/blocks/translate'
8+
import type { BlockConfig } from '@/blocks/types'
9+
10+
const SAVED_CREDENTIAL_FIELDS = ['bedrockAuthMode', 'bedrockCredential', 'bedrockManualCredential']
11+
const SAVED_CREDENTIAL_INPUTS = ['bedrockAuthMode', 'bedrockCredential']
12+
13+
/** The saved-credential fields and inputs a block publishes to the editor and the block catalog. */
14+
function savedCredentialSurface(block: BlockConfig) {
15+
return {
16+
fields: block.subBlocks
17+
.map((subBlock) => subBlock.id)
18+
.filter((id) => SAVED_CREDENTIAL_FIELDS.includes(id)),
19+
inputs: Object.keys(block.inputs ?? {}).filter((key) => SAVED_CREDENTIAL_INPUTS.includes(key)),
20+
}
21+
}
22+
23+
describe('Bedrock saved AWS credential surface', () => {
24+
// Guardrails never serializes its Bedrock fields and Pi has no Bedrock provider, so a
25+
// saved credential set on either would be dropped and the call signed some other way.
26+
it.each([
27+
['guardrails', GuardrailsBlock],
28+
['pi', PiBlock],
29+
])('is absent from the %s block, which cannot forward a saved credential', (_, block) => {
30+
expect(savedCredentialSurface(block)).toEqual({ fields: [], inputs: [] })
31+
})
32+
33+
it.each([
34+
['agent', AgentBlock],
35+
['router', RouterBlock],
36+
['router_v2', RouterV2Block],
37+
['evaluator', EvaluatorBlock],
38+
['translate', TranslateBlock],
39+
])('is offered by the %s block, which forwards it to the Bedrock call', (_, block) => {
40+
expect(savedCredentialSurface(block)).toEqual({
41+
fields: SAVED_CREDENTIAL_FIELDS,
42+
inputs: SAVED_CREDENTIAL_INPUTS,
43+
})
44+
})
45+
})

‎apps/sim/blocks/blocks/agent.ts‎

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getModelFallbackSubBlock, MODEL_FALLBACK_INPUTS } from '@/blocks/model-
44
import type { BlockConfig } from '@/blocks/types'
55
import { AuthMode, IntegrationType } from '@/blocks/types'
66
import {
7+
BEDROCK_SAVED_CREDENTIAL_INPUTS,
78
getAgentModelOptions,
89
getModelCapabilityCondition,
910
getProviderCredentialSubBlocks,
@@ -136,7 +137,7 @@ Return ONLY the JSON array.`,
136137
options: getAgentModelOptions,
137138
commandSearchable: true,
138139
},
139-
...getProviderCredentialSubBlocks(),
140+
...getProviderCredentialSubBlocks({ bedrockSavedCredential: true }),
140141
{
141142
id: 'evaluationState',
142143
title: 'State',
@@ -559,15 +560,7 @@ Return ONLY the JSON array.`,
559560
bedrockAccessKeyId: { type: 'string', description: 'AWS Access Key ID for Bedrock' },
560561
bedrockSecretKey: { type: 'string', description: 'AWS Secret Access Key for Bedrock' },
561562
bedrockRegion: { type: 'string', description: 'AWS region for Bedrock' },
562-
bedrockAuthMode: {
563-
type: 'string',
564-
description: "How Bedrock authenticates: 'access_keys' (default) or 'credential'",
565-
},
566-
bedrockCredential: {
567-
type: 'string',
568-
description:
569-
"Saved AWS credential ID for Bedrock, used instead of access keys when bedrockAuthMode is 'credential'",
570-
},
563+
...BEDROCK_SAVED_CREDENTIAL_INPUTS,
571564
responseFormat: {
572565
type: 'json',
573566
description: 'JSON response format schema',

‎apps/sim/blocks/blocks/evaluator.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ChartBarIcon } from '@/components/icons'
33
import { getModelFallbackSubBlock, MODEL_FALLBACK_INPUTS } from '@/blocks/model-fallbacks'
44
import type { BlockConfig, ParamType } from '@/blocks/types'
55
import {
6+
BEDROCK_SAVED_CREDENTIAL_INPUTS,
67
getModelOptions,
78
getProviderCredentialSubBlocks,
89
getSerializedModelProviderId,
@@ -170,7 +171,7 @@ export const EvaluatorBlock: BlockConfig = {
170171
defaultValue: 'claude-sonnet-5-5',
171172
options: getModelOptions,
172173
},
173-
...getProviderCredentialSubBlocks(),
174+
...getProviderCredentialSubBlocks({ bedrockSavedCredential: true }),
174175
getModelFallbackSubBlock(),
175176
{
176177
id: 'temperature',
@@ -277,6 +278,7 @@ export const EvaluatorBlock: BlockConfig = {
277278
},
278279
model: { type: 'string' as ParamType, description: 'AI model to use' },
279280
...PROVIDER_CREDENTIAL_INPUTS,
281+
...BEDROCK_SAVED_CREDENTIAL_INPUTS,
280282
...MODEL_FALLBACK_INPUTS,
281283
temperature: {
282284
type: 'number' as ParamType,

‎apps/sim/blocks/blocks/router.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ConnectIcon } from '@/components/icons'
22
import { getModelFallbackSubBlock, MODEL_FALLBACK_INPUTS } from '@/blocks/model-fallbacks'
33
import { AuthMode, type BlockConfig } from '@/blocks/types'
44
import {
5+
BEDROCK_SAVED_CREDENTIAL_INPUTS,
56
getModelOptions,
67
getProviderCredentialSubBlocks,
78
getSerializedModelProviderId,
@@ -163,7 +164,7 @@ export const RouterBlock: BlockConfig = {
163164
defaultValue: 'claude-sonnet-5-5',
164165
options: getModelOptions,
165166
},
166-
...getProviderCredentialSubBlocks(),
167+
...getProviderCredentialSubBlocks({ bedrockSavedCredential: true }),
167168
getModelFallbackSubBlock(),
168169
{
169170
id: 'temperature',
@@ -200,6 +201,7 @@ export const RouterBlock: BlockConfig = {
200201
prompt: { type: 'string', description: 'Routing prompt content' },
201202
model: { type: 'string', description: 'AI model to use' },
202203
...PROVIDER_CREDENTIAL_INPUTS,
204+
...BEDROCK_SAVED_CREDENTIAL_INPUTS,
203205
...MODEL_FALLBACK_INPUTS,
204206
temperature: {
205207
type: 'number',
@@ -254,7 +256,7 @@ export const RouterV2Block: BlockConfig = {
254256
defaultValue: 'claude-sonnet-5-5',
255257
options: getModelOptions,
256258
},
257-
...getProviderCredentialSubBlocks(),
259+
...getProviderCredentialSubBlocks({ bedrockSavedCredential: true }),
258260
getModelFallbackSubBlock(),
259261
],
260262
tools: {
@@ -275,6 +277,7 @@ export const RouterV2Block: BlockConfig = {
275277
routes: { type: 'json', description: 'Route definitions with descriptions' },
276278
model: { type: 'string', description: 'AI model to use' },
277279
...PROVIDER_CREDENTIAL_INPUTS,
280+
...BEDROCK_SAVED_CREDENTIAL_INPUTS,
278281
...MODEL_FALLBACK_INPUTS,
279282
},
280283
outputs: {

‎apps/sim/blocks/blocks/translate.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { TranslateIcon } from '@/components/icons'
22
import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types'
33
import {
4+
BEDROCK_SAVED_CREDENTIAL_INPUTS,
45
getModelOptions,
56
getProviderCredentialSubBlocks,
67
getSelectedBedrockCredential,
@@ -53,7 +54,7 @@ export const TranslateBlock: BlockConfig = {
5354
required: true,
5455
options: getModelOptions,
5556
},
56-
...getProviderCredentialSubBlocks(),
57+
...getProviderCredentialSubBlocks({ bedrockSavedCredential: true }),
5758
{
5859
id: 'systemPrompt',
5960
title: 'System Prompt',
@@ -89,6 +90,7 @@ export const TranslateBlock: BlockConfig = {
8990
context: { type: 'string', description: 'Text to translate' },
9091
targetLanguage: { type: 'string', description: 'Target language' },
9192
...PROVIDER_CREDENTIAL_INPUTS,
93+
...BEDROCK_SAVED_CREDENTIAL_INPUTS,
9294
systemPrompt: { type: 'string', description: 'Translation instructions' },
9395
},
9496
outputs: {

‎apps/sim/blocks/utils.test.ts‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,11 @@ describe('Bedrock credential fields', () => {
115115
'bedrockRegion',
116116
]
117117

118-
const visibleBedrockFields = (values: Record<string, unknown>) =>
119-
getProviderCredentialSubBlocks()
118+
const visibleBedrockFields = (
119+
values: Record<string, unknown>,
120+
subBlocks = getProviderCredentialSubBlocks({ bedrockSavedCredential: true })
121+
) =>
122+
subBlocks
120123
.filter((subBlock) => BEDROCK_FIELDS.includes(subBlock.id))
121124
.filter((subBlock) => evaluateSubBlockCondition(subBlock.condition, values))
122125
.map((subBlock) => subBlock.id)
@@ -139,6 +142,15 @@ describe('Bedrock credential fields', () => {
139142
it('shows no Bedrock field for a model of another provider', () => {
140143
expect(visibleBedrockFields({ model: 'gpt-4o', bedrockAuthMode: 'credential' })).toEqual([])
141144
})
145+
146+
it('offers no saved credential, and keeps the access keys, for a block that cannot forward one', () => {
147+
expect(
148+
visibleBedrockFields(
149+
{ model: 'bedrock/my-inference-profile', bedrockAuthMode: 'credential' },
150+
getProviderCredentialSubBlocks()
151+
)
152+
).toEqual(['bedrockAccessKeyId', 'bedrockSecretKey', 'bedrockRegion'])
153+
})
142154
})
143155

144156
describe('getSelectedBedrockCredential', () => {
@@ -165,7 +177,7 @@ describe('getSelectedBedrockCredential', () => {
165177
})
166178

167179
it('signs with a credential exactly when the block shows and serializes the credential picker', () => {
168-
const picker = getProviderCredentialSubBlocks().find(
180+
const picker = getProviderCredentialSubBlocks({ bedrockSavedCredential: true }).find(
169181
(subBlock) => subBlock.id === 'bedrockCredential'
170182
)
171183
const cases: Record<string, unknown>[] = [

0 commit comments

Comments
 (0)