TestAIProviderSettingsMerge exercises the PATCH merge semantics for the write-only Bedrock secrets through a real HTTP client. Because the API never echoes AccessKey or AccessKeySecret back, each subtest reads the provider row directly from the database to confirm what the merge actually persisted.
(t *testing.T)
| 1320 | // subtest reads the provider row directly from the database to |
| 1321 | // confirm what the merge actually persisted. |
| 1322 | func TestAIProviderSettingsMerge(t *testing.T) { |
| 1323 | t.Parallel() |
| 1324 | |
| 1325 | t.Run("OmittedSecretsPreserveExisting", func(t *testing.T) { |
| 1326 | t.Parallel() |
| 1327 | // A PATCH that only rotates non-secret fields must keep the |
| 1328 | // existing AccessKey and AccessKeySecret intact so the provider |
| 1329 | // keeps authenticating after the update. |
| 1330 | client, db := coderdtest.NewWithDatabase(t, nil) |
| 1331 | _ = coderdtest.CreateFirstUser(t, client) |
| 1332 | ctx := testutil.Context(t, testutil.WaitLong) |
| 1333 | |
| 1334 | //nolint:gocritic // Owner role is the audience for this endpoint. |
| 1335 | created, err := client.CreateAIProvider(ctx, codersdk.CreateAIProviderRequest{ |
| 1336 | Type: codersdk.AIProviderTypeAnthropic, |
| 1337 | Name: "merge-omit", |
| 1338 | Enabled: true, |
| 1339 | BaseURL: "https://bedrock-runtime.us-east-1.amazonaws.com/", |
| 1340 | Settings: codersdk.AIProviderSettings{ |
| 1341 | Bedrock: &codersdk.AIProviderBedrockSettings{ |
| 1342 | Region: "us-east-1", |
| 1343 | Model: "anthropic.claude-3-5-sonnet", |
| 1344 | AccessKey: ptr.Ref("AKIA-old"), //nolint:gosec // test fixture, not a real credential |
| 1345 | AccessKeySecret: ptr.Ref("secret-old"), |
| 1346 | }, |
| 1347 | }, |
| 1348 | }) |
| 1349 | require.NoError(t, err) |
| 1350 | |
| 1351 | _, err = client.UpdateAIProvider(ctx, created.Name, codersdk.UpdateAIProviderRequest{ |
| 1352 | Settings: &codersdk.AIProviderSettings{ |
| 1353 | Bedrock: &codersdk.AIProviderBedrockSettings{ |
| 1354 | Region: "us-west-2", |
| 1355 | Model: "anthropic.claude-3-5-haiku", |
| 1356 | }, |
| 1357 | }, |
| 1358 | }) |
| 1359 | require.NoError(t, err) |
| 1360 | |
| 1361 | //nolint:gocritic // Test reads the row to verify write-only fields. |
| 1362 | row, err := db.GetAIProviderByID(dbauthz.AsSystemRestricted(ctx), created.ID) |
| 1363 | require.NoError(t, err) |
| 1364 | persisted, err := db2sdk.AIProviderSettings(row.Settings) |
| 1365 | require.NoError(t, err) |
| 1366 | require.NotNil(t, persisted.Bedrock) |
| 1367 | require.Equal(t, "us-west-2", persisted.Bedrock.Region) |
| 1368 | require.Equal(t, "anthropic.claude-3-5-haiku", persisted.Bedrock.Model) |
| 1369 | require.NotNil(t, persisted.Bedrock.AccessKey) |
| 1370 | require.Equal(t, "AKIA-old", *persisted.Bedrock.AccessKey) |
| 1371 | require.NotNil(t, persisted.Bedrock.AccessKeySecret) |
| 1372 | require.Equal(t, "secret-old", *persisted.Bedrock.AccessKeySecret) |
| 1373 | }) |
| 1374 | |
| 1375 | t.Run("ExplicitEmptyClearsSecrets", func(t *testing.T) { |
| 1376 | t.Parallel() |
| 1377 | // An admin migrating from static AWS credentials to IAM |
| 1378 | // role-based auth needs to clear AccessKey and AccessKeySecret |
| 1379 | // in a single PATCH. Sending the field with an empty string is |
nothing calls this directly
no test coverage detected