@@ -2,6 +2,7 @@ package chatprovider_test
22
33import (
44 "encoding/json"
5+ "io"
56 "net/http"
67 "net/http/httptest"
78 "testing"
@@ -967,6 +968,87 @@ func TestModelFromConfig_Bedrock(t *testing.T) {
967968 })
968969}
969970
971+ // TestModelFromConfig_BedrockStripsAnthropicHeaders is a regression test
972+ // for a bug where the Anthropic SDK reads ANTHROPIC_API_KEY from the
973+ // process environment and adds X-Api-Key and Anthropic-Version headers to
974+ // every request. On Bedrock, these headers conflict with SigV4 signing and
975+ // cause auth failures. The SDK's Bedrock middleware strips them before
976+ // signing. This test verifies the outgoing request shape with both
977+ // Anthropic and AWS credentials present.
978+ func TestModelFromConfig_BedrockStripsAnthropicHeaders (t * testing.T ) {
979+ ctx := testutil .Context (t , testutil .WaitShort )
980+
981+ t .Setenv ("ANTHROPIC_API_KEY" , "anthropic-env-key" )
982+ t .Setenv ("AWS_REGION" , "us-east-2" )
983+ t .Setenv ("AWS_ACCESS_KEY_ID" , "test-access-key" )
984+ t .Setenv ("AWS_SECRET_ACCESS_KEY" , "test-secret-key" )
985+ t .Setenv ("AWS_SESSION_TOKEN" , "test-session-token" )
986+
987+ type requestCapture struct {
988+ Authorization string
989+ AnthropicVersion string
990+ XAPIKey string
991+ Body string
992+ ReadError error
993+ }
994+
995+ requests := make (chan requestCapture , 1 )
996+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
997+ body , err := io .ReadAll (r .Body )
998+
999+ requests <- requestCapture {
1000+ Authorization : r .Header .Get ("Authorization" ),
1001+ AnthropicVersion : r .Header .Get ("Anthropic-Version" ),
1002+ XAPIKey : r .Header .Get ("X-Api-Key" ),
1003+ Body : string (body ),
1004+ ReadError : err ,
1005+ }
1006+
1007+ w .Header ().Set ("Content-Type" , "application/json" )
1008+ _ = json .NewEncoder (w ).Encode (bedrockNonStreamingResponse ())
1009+ }))
1010+ defer server .Close ()
1011+
1012+ model , err := chatprovider .ModelFromConfig (
1013+ fantasybedrock .Name ,
1014+ "anthropic.claude-opus-4-6-v1" ,
1015+ chatprovider.ProviderAPIKeys {
1016+ ByProvider : map [string ]string {
1017+ fantasybedrock .Name : "" ,
1018+ },
1019+ BaseURLByProvider : map [string ]string {
1020+ fantasybedrock .Name : server .URL ,
1021+ },
1022+ },
1023+ chatprovider .UserAgent (),
1024+ nil ,
1025+ nil ,
1026+ )
1027+ require .NoError (t , err )
1028+ require .NotNil (t , model )
1029+
1030+ _ , err = model .Generate (ctx , fantasy.Call {
1031+ Prompt : []fantasy.Message {
1032+ {
1033+ Role : fantasy .MessageRoleUser ,
1034+ Content : []fantasy.MessagePart {
1035+ fantasy.TextPart {Text : "hello" },
1036+ },
1037+ },
1038+ },
1039+ })
1040+ require .NoError (t , err )
1041+
1042+ got := testutil .TryReceive (ctx , t , requests )
1043+ require .NoError (t , got .ReadError )
1044+ require .Empty (t , got .AnthropicVersion )
1045+ require .Empty (t , got .XAPIKey )
1046+ require .Contains (t , got .Authorization , "AWS4-HMAC-SHA256" )
1047+ require .NotContains (t , got .Authorization , "anthropic-version" )
1048+ require .NotContains (t , got .Authorization , "x-api-key" )
1049+ require .Contains (t , got .Body , `"anthropic_version":"bedrock-2023-05-31"` )
1050+ }
1051+
9701052func bedrockNonStreamingResponse () map [string ]any {
9711053 return map [string ]any {
9721054 "id" : "msg_01Test" ,
0 commit comments