fix(site/src/pages/AISettingsPage): allow Bedrock IAM-role setup by dannykopping · Pull Request #26400 · coder/coder · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { Button } from "#/components/Button/Button";
import { ConfirmDialog } from "#/components/Dialogs/ConfirmDialog/ConfirmDialog";
import { Form, FormFields } from "#/components/Form/Form";
import { FormField } from "#/components/FormField/FormField";
import { Link as DocsLink } from "#/components/Link/Link";
import { Spinner } from "#/components/Spinner/Spinner";
import { useUnsavedChangesPrompt } from "#/hooks/useUnsavedChangesPrompt";
import { docs } from "#/utils/docs";
import { getFormHelpers } from "#/utils/formUtils";
import { CredentialField } from "./CredentialField";

Expand Down Expand Up @@ -68,6 +70,17 @@ const defaultInitialValues: ProviderFormValues = {
enabled: true,
};

// Bedrock model defaults mirror codersdk/deployment.go's
// aiGatewayBedrockModel and aiGatewayBedrockSmallFastModel defaults
// so the create form lands on the same models the env-seeded path
// uses. Update both sides together when AWS publishes new model IDs.
const BEDROCK_DEFAULT_MODEL =
"global.anthropic.claude-sonnet-4-5-20250929-v1:0";
const BEDROCK_DEFAULT_SMALL_FAST_MODEL =
"global.anthropic.claude-haiku-4-5-20251001-v1:0";
const BEDROCK_MODEL_CARDS_URL =
"https://docs.aws.amazon.com/bedrock/latest/userguide/model-cards.html";

const providerDefaults: Partial<
Record<AIProviderType, Partial<ProviderFormValues>>
> = {
Expand All @@ -76,6 +89,8 @@ const providerDefaults: Partial<
bedrock: {
name: "bedrock",
baseUrl: "https://bedrock-runtime.us-east-2.amazonaws.com",
model: BEDROCK_DEFAULT_MODEL,
smallFastModel: BEDROCK_DEFAULT_SMALL_FAST_MODEL,
},
azure: {
name: "azure",
Expand Down Expand Up @@ -129,6 +144,13 @@ const credentialFilled = (value: string | undefined): boolean => {
return trimmed !== "" && trimmed !== SAVED_CREDENTIAL_MASK;
};

const BEDROCK_ACCESS_KEY_PAIRED_MESSAGE =
"Enter both access key and secret, or leave both blank to use AWS environment credentials.";

// Bedrock access keys are optional: when both are blank the server
// falls back to ambient AWS credentials (IAM role, AWS_PROFILE, IRSA,
// instance profile). Yup still requires them to be supplied as a pair
// so a half-typed rotation does not slip through.
const makeBedrockSchema = (editing: boolean) =>
Yup.object({
type: Yup.string()
Expand All @@ -146,24 +168,18 @@ const makeBedrockSchema = (editing: boolean) =>
apiKey: Yup.string(),
model: Yup.string().required("Model is required"),
smallFastModel: Yup.string().required("Small-fast model is required"),
accessKey: (editing
? Yup.string()
: Yup.string().required("Access key is required")
).test(
accessKey: Yup.string().test(
"access-key-paired",
"Enter both access key and secret to rotate credentials.",
BEDROCK_ACCESS_KEY_PAIRED_MESSAGE,
function (value) {
const secret = (this.parent as { accessKeySecret?: string })
.accessKeySecret;
return !(credentialFilled(secret) && !credentialFilled(value));
},
),
accessKeySecret: (editing
? Yup.string()
: Yup.string().required("Access key secret is required")
).test(
accessKeySecret: Yup.string().test(
"access-key-secret-paired",
"Enter both access key and secret to rotate credentials.",
BEDROCK_ACCESS_KEY_PAIRED_MESSAGE,
function (value) {
const accessKey = (this.parent as { accessKey?: string }).accessKey;
return !(credentialFilled(accessKey) && !credentialFilled(value));
Expand Down Expand Up @@ -460,34 +476,56 @@ export const ProviderForm: FC<ProviderFormProps> = ({
field={getFieldHelpers("model")}
label="Model"
className="w-full"
placeholder="anthropic.claude-3-5-sonnet-20241022-v2:0"
placeholder={BEDROCK_DEFAULT_MODEL}
/>
<FormField
required
field={getFieldHelpers("smallFastModel")}
label="Small-fast model"
className="w-full"
placeholder="anthropic.claude-3-haiku-20240307-v1:0"
placeholder={BEDROCK_DEFAULT_SMALL_FAST_MODEL}
/>
</div>
<p className="text-xs text-content-secondary m-0">
Find available Bedrock model IDs in the{" "}
<DocsLink
size="sm"
href={BEDROCK_MODEL_CARDS_URL}
target="_blank"
rel="noreferrer"
>
AWS Bedrock model cards
</DocsLink>
.
</p>
<div className="grid grid-cols-2 items-start gap-4">
<CredentialField
required
label="Access key"
helpers={getFieldHelpers("accessKey")}
onBlur={() => handleCredentialBlur("accessKey")}
onFocus={() => handleCredentialFocus("accessKey")}
autoComplete="new-password"
/>
<CredentialField
required
label="Access key secret"
helpers={getFieldHelpers("accessKeySecret")}
onBlur={() => handleCredentialBlur("accessKeySecret")}
onFocus={() => handleCredentialFocus("accessKeySecret")}
autoComplete="new-password"
/>
</div>
<p className="text-xs text-content-secondary m-0">
Optional. Leave both fields blank to authenticate with the AWS
environment (IAM role, instance profile, AWS_PROFILE).{" "}
<DocsLink
size="sm"
href={docs("/ai-coder/ai-gateway/providers#amazon-bedrock")}
target="_blank"
rel="noreferrer"
>
View docs
</DocsLink>
</p>
</>
)}

Expand Down
Loading