feat: generate STS external ID for Bedrock role assumption (#26869)

Implements:
https://linear.app/codercom/issue/AIGOV-495/add-externalid-to-prevent-confused-deputy-problem

When a Bedrock provider assumes an IAM role via STS, the gateway now
generates a unique external ID for it and sends that value on every
`AssumeRole` call. The external ID guards against the [confused deputy
problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html)
on cross-account role assumption. Per [AWS's
recommendation](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html),
the gateway generates and owns the value rather than accepting one from
the operator; that ownership is what makes it effective, since a party
who knows another's external ID can't induce the gateway to send it.

The external ID is server-owned and read-only over the API. It is
generated once, when a provider first has a `role_arn`, and is stable
thereafter. Clients cannot set it: create rejects any supplied
`external_id`, and update rejects a value that differs from the stored
one. An update may echo the stored value back unchanged, so the normal
read-modify-write flow (GET the provider, change a field, PATCH the full
settings object) keeps working. The value is not a secret and is
returned on GET so operators can copy it into the target role's trust
policy as an `sts:ExternalId` condition.

It is persisted in the existing JSON settings blob, so there is no
migration or audit-table change.
This commit is contained in:
Yevhenii Shcherbina
2026-07-01 20:44:15 +00:00
committed by GitHub
parent 1101a0f974
commit db7f4438b4
13 changed files with 527 additions and 66 deletions
+55
View File
@@ -2,6 +2,7 @@ package coderd
import (
"context"
"crypto/rand"
"database/sql"
"encoding/json"
"errors"
@@ -178,6 +179,9 @@ func (api *API) aiProvidersCreate(rw http.ResponseWriter, r *http.Request) {
return
}
// Generate the server-owned external ID when the provider assumes a role.
ensureBedrockExternalID(&req.Settings)
settings, err := encodeAIProviderSettings(req.Settings)
if err != nil {
api.Logger.Error(ctx, "encode AI provider settings", slog.Error(err))
@@ -318,6 +322,9 @@ func (api *API) aiProvidersUpdate(rw http.ResponseWriter, r *http.Request) {
return xerrors.Errorf("decode existing settings: %w", err)
}
if req.Settings != nil {
if err := validateBedrockExternalIDUnchanged(existing, *req.Settings); err != nil {
return err
}
existing = mergeAIProviderSettings(existing, *req.Settings)
}
// Bedrock settings are only meaningful for anthropic- or
@@ -329,6 +336,9 @@ func (api *API) aiProvidersUpdate(rw http.ResponseWriter, r *http.Request) {
old.Type != database.AIProviderTypeBedrock {
return errAIProviderBedrockTypeMismatch
}
// Generate the server-owned external ID when the provider assumes a role
// and lacks one.
ensureBedrockExternalID(&existing)
settings, err := encodeAIProviderSettings(existing)
if err != nil {
return xerrors.Errorf("encode settings: %w", err)
@@ -400,6 +410,12 @@ func (api *API) aiProvidersUpdate(rw http.ResponseWriter, r *http.Request) {
})
return
}
if errors.Is(err, errAIProviderExternalIDReadOnly) {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "The Bedrock external ID is server-generated and cannot be changed.",
})
return
}
if errors.Is(err, errAIProviderKeyUnknown) {
// Use the sentinel directly so the response message does not
// leak the "execute transaction:" wrapper xerrors added on the
@@ -506,6 +522,12 @@ var errCopilotRejectsAPIKeys = xerrors.New("copilot providers do not accept api_
// the outer handler translates it into a 400.
var errAIProviderBedrockTypeMismatch = xerrors.New("bedrock settings are only valid for type=anthropic or type=bedrock")
// errAIProviderExternalIDReadOnly is the sentinel returned from inside
// the update transaction when a patch tries to change the server-owned
// Bedrock external ID; the outer handler translates it into a 400. A
// patch may echo the stored value but not set a different one.
var errAIProviderExternalIDReadOnly = xerrors.New("external_id is server-generated and cannot be changed")
// errAIProviderInvalidName is returned from lookupAIProvider when the
// idOrName parameter is neither a UUID nor a syntactically-valid name.
// The handler translates this into a 400 so an integrator gets a hint
@@ -772,6 +794,39 @@ func mergeAIProviderSettings(existing, patch codersdk.AIProviderSettings) coders
if merged.AccessKeySecret == nil {
merged.AccessKeySecret = existing.Bedrock.AccessKeySecret
}
// The external ID is server-owned and stable: carry the stored value
// forward so a patch can't change it. A patch that sets a different
// value is rejected upstream.
merged.ExternalID = existing.Bedrock.ExternalID
}
return codersdk.AIProviderSettings{Bedrock: &merged}
}
// validateBedrockExternalIDUnchanged rejects a patch that sets a Bedrock
// external ID different from the stored one. A patch may echo the stored
// value (read-modify-write resends it) but not change it; the value is
// server-owned.
func validateBedrockExternalIDUnchanged(existing, patch codersdk.AIProviderSettings) error {
stored := ""
if existing.Bedrock != nil {
stored = existing.Bedrock.ExternalID
}
provided := ""
if patch.Bedrock != nil {
provided = patch.Bedrock.ExternalID
}
if provided != "" && provided != stored {
return errAIProviderExternalIDReadOnly
}
return nil
}
// ensureBedrockExternalID assigns a server-owned STS external ID when the
// Bedrock provider assumes a role and none is set yet.
func ensureBedrockExternalID(s *codersdk.AIProviderSettings) {
if s.Bedrock != nil && s.Bedrock.RoleARN != "" && s.Bedrock.ExternalID == "" {
s.Bedrock.ExternalID = rand.Text()
}
}
+89
View File
@@ -0,0 +1,89 @@
package coderd
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/codersdk"
)
// TestEnsureBedrockExternalID covers the server-owned external ID generation:
// it generates only when a role is configured and none is set, and never
// overwrites an existing value.
func TestEnsureBedrockExternalID(t *testing.T) {
t.Parallel()
t.Run("NilBedrockIsNoOp", func(t *testing.T) {
t.Parallel()
s := codersdk.AIProviderSettings{}
ensureBedrockExternalID(&s)
require.Nil(t, s.Bedrock)
})
t.Run("NoRoleLeavesEmpty", func(t *testing.T) {
t.Parallel()
s := codersdk.AIProviderSettings{Bedrock: &codersdk.AIProviderBedrockSettings{Region: "us-east-1"}}
ensureBedrockExternalID(&s)
require.Empty(t, s.Bedrock.ExternalID)
})
t.Run("GeneratesWhenRoleSet", func(t *testing.T) {
t.Parallel()
s := codersdk.AIProviderSettings{Bedrock: &codersdk.AIProviderBedrockSettings{
RoleARN: "arn:aws:iam::123456789012:role/BedrockRole",
}}
ensureBedrockExternalID(&s)
// The bounds are a sanity floor and ceiling, not a correctness
// requirement. crypto/rand.Text() currently returns 26 chars, but
// its docs allow future Go versions to return longer text. If a Go
// upgrade trips these bounds, widen them or use different function.
require.GreaterOrEqual(t, len(s.Bedrock.ExternalID), 26)
require.LessOrEqual(t, len(s.Bedrock.ExternalID), 52)
})
t.Run("DoesNotOverwriteExisting", func(t *testing.T) {
t.Parallel()
s := codersdk.AIProviderSettings{Bedrock: &codersdk.AIProviderBedrockSettings{
RoleARN: "arn:aws:iam::123456789012:role/BedrockRole",
ExternalID: "existing-value",
}}
ensureBedrockExternalID(&s)
require.Equal(t, "existing-value", s.Bedrock.ExternalID)
})
t.Run("GeneratesUniqueValues", func(t *testing.T) {
t.Parallel()
seen := make(map[string]struct{})
for range 10 {
s := codersdk.AIProviderSettings{Bedrock: &codersdk.AIProviderBedrockSettings{
RoleARN: "arn:aws:iam::123456789012:role/BedrockRole",
}}
ensureBedrockExternalID(&s)
_, dup := seen[s.Bedrock.ExternalID]
require.False(t, dup, "external IDs must be unique per provider")
seen[s.Bedrock.ExternalID] = struct{}{}
}
})
}
// TestMergeAIProviderSettingsExternalID verifies the external ID is treated as
// server-owned during a PATCH merge: a stored value is carried forward and
// overrides the patch so it can't be changed.
func TestMergeAIProviderSettingsExternalID(t *testing.T) {
t.Parallel()
roleARN := "arn:aws:iam::123456789012:role/BedrockRole"
existing := codersdk.AIProviderSettings{Bedrock: &codersdk.AIProviderBedrockSettings{
RoleARN: roleARN,
ExternalID: "stored-value",
}}
patch := codersdk.AIProviderSettings{Bedrock: &codersdk.AIProviderBedrockSettings{
RoleARN: roleARN,
ExternalID: "client-supplied-value",
}}
merged := mergeAIProviderSettings(existing, patch)
require.NotNil(t, merged.Bedrock)
require.Equal(t, roleARN, merged.Bedrock.RoleARN)
require.Equal(t, "stored-value", merged.Bedrock.ExternalID)
}
+223
View File
@@ -1554,3 +1554,226 @@ func TestAIProviderSettingsMerge(t *testing.T) {
require.Equal(t, "", *persisted.Bedrock.AccessKeySecret)
})
}
// TestAIProvidersBedrockExternalID covers the server-owned STS external ID:
// it is generated when (and only when) the provider assumes a role, is
// rejected when a client tries to set or change it, and is stable across
// PATCHes that echo the stored value.
func TestAIProvidersBedrockExternalID(t *testing.T) {
t.Parallel()
const (
roleARN = "arn:aws:iam::123456789012:role/BedrockRole"
externalIDReadOnlyMsg = "The Bedrock external ID is server-generated and cannot be changed."
)
createBedrock := func(t *testing.T, client *codersdk.Client, name string, b codersdk.AIProviderBedrockSettings) (codersdk.AIProvider, error) {
t.Helper()
ctx := testutil.Context(t, testutil.WaitLong)
//nolint:gocritic // Owner role is the audience for this endpoint.
return client.CreateAIProvider(ctx, codersdk.CreateAIProviderRequest{
Type: codersdk.AIProviderTypeBedrock,
Name: name,
Enabled: true,
BaseURL: "https://bedrock-runtime.us-east-1.amazonaws.com",
Settings: codersdk.AIProviderSettings{Bedrock: &b},
})
}
t.Run("GeneratedWhenRoleSet", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
ctx := testutil.Context(t, testutil.WaitLong)
created, err := createBedrock(t, client, "bedrock-role", codersdk.AIProviderBedrockSettings{
Region: "us-east-1",
RoleARN: roleARN,
})
require.NoError(t, err)
require.NotNil(t, created.Settings.Bedrock)
require.NotEmpty(t, created.Settings.Bedrock.ExternalID, "external ID must be generated when a role is set")
// GET returns the same external ID.
got, err := client.AIProvider(ctx, created.ID.String())
require.NoError(t, err)
require.Equal(t, created.Settings.Bedrock.ExternalID, got.Settings.Bedrock.ExternalID)
})
t.Run("AbsentWithoutRole", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
created, err := createBedrock(t, client, "bedrock-no-role", codersdk.AIProviderBedrockSettings{Region: "us-east-1"})
require.NoError(t, err)
require.NotNil(t, created.Settings.Bedrock)
require.Empty(t, created.Settings.Bedrock.ExternalID, "no external ID without a role to assume")
})
t.Run("RejectsClientValueOnCreate", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
_, err := createBedrock(t, client, "bedrock-client-id", codersdk.AIProviderBedrockSettings{
Region: "us-east-1",
RoleARN: roleARN,
ExternalID: "client-supplied-value",
})
sdkErr := requireSDKError(t, err, http.StatusBadRequest)
require.Contains(t, sdkErr.Validations, codersdk.ValidationError{
Field: "settings.external_id",
Detail: "external_id is server-generated and cannot be set",
})
})
t.Run("StableWhenPatchOmitsValue", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
ctx := testutil.Context(t, testutil.WaitLong)
created, err := createBedrock(t, client, "bedrock-stable", codersdk.AIProviderBedrockSettings{
Region: "us-east-1",
RoleARN: roleARN,
})
require.NoError(t, err)
original := created.Settings.Bedrock.ExternalID
require.NotEmpty(t, original)
updated, err := client.UpdateAIProvider(ctx, created.Name, codersdk.UpdateAIProviderRequest{
Settings: &codersdk.AIProviderSettings{
Bedrock: &codersdk.AIProviderBedrockSettings{Region: "us-west-2", RoleARN: roleARN},
},
})
require.NoError(t, err)
require.Equal(t, "us-west-2", updated.Settings.Bedrock.Region)
require.Equal(t, original, updated.Settings.Bedrock.ExternalID, "external ID must be stable across PATCH")
})
t.Run("StableAcrossRoleRemovalAndReassignment", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
ctx := testutil.Context(t, testutil.WaitLong)
const roleB = "arn:aws:iam::123456789012:role/BedrockRoleB"
created, err := createBedrock(t, client, "bedrock-toggle", codersdk.AIProviderBedrockSettings{
Region: "us-east-1",
RoleARN: roleARN,
})
require.NoError(t, err)
original := created.Settings.Bedrock.ExternalID
require.NotEmpty(t, original)
// Removing the role retains the external ID.
cleared, err := client.UpdateAIProvider(ctx, created.Name, codersdk.UpdateAIProviderRequest{
Settings: &codersdk.AIProviderSettings{
Bedrock: &codersdk.AIProviderBedrockSettings{Region: "us-east-1"},
},
})
require.NoError(t, err)
require.Empty(t, cleared.Settings.Bedrock.RoleARN)
require.Equal(t, original, cleared.Settings.Bedrock.ExternalID)
// Adding a different role reuses the retained ID rather than
// regenerating it, so a trust policy referencing it keeps working.
readded, err := client.UpdateAIProvider(ctx, created.Name, codersdk.UpdateAIProviderRequest{
Settings: &codersdk.AIProviderSettings{
Bedrock: &codersdk.AIProviderBedrockSettings{Region: "us-east-1", RoleARN: roleB},
},
})
require.NoError(t, err)
require.Equal(t, roleB, readded.Settings.Bedrock.RoleARN)
require.Equal(t, original, readded.Settings.Bedrock.ExternalID, "external ID must survive role removal and re-add")
})
t.Run("AllowsEchoedValueOnPatch", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
ctx := testutil.Context(t, testutil.WaitLong)
created, err := createBedrock(t, client, "bedrock-echo", codersdk.AIProviderBedrockSettings{
Region: "us-east-1",
RoleARN: roleARN,
})
require.NoError(t, err)
original := created.Settings.Bedrock.ExternalID
require.NotEmpty(t, original)
// Read-modify-write resends the whole settings, including the stored
// external ID. Echoing the same value is allowed.
updated, err := client.UpdateAIProvider(ctx, created.Name, codersdk.UpdateAIProviderRequest{
Settings: &codersdk.AIProviderSettings{
Bedrock: &codersdk.AIProviderBedrockSettings{Region: "us-west-2", RoleARN: roleARN, ExternalID: original},
},
})
require.NoError(t, err)
require.Equal(t, "us-west-2", updated.Settings.Bedrock.Region)
require.Equal(t, original, updated.Settings.Bedrock.ExternalID)
})
t.Run("RejectsChangedValueOnPatch", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
ctx := testutil.Context(t, testutil.WaitLong)
created, err := createBedrock(t, client, "bedrock-change", codersdk.AIProviderBedrockSettings{
Region: "us-east-1",
RoleARN: roleARN,
})
require.NoError(t, err)
require.NotEmpty(t, created.Settings.Bedrock.ExternalID)
_, err = client.UpdateAIProvider(ctx, created.Name, codersdk.UpdateAIProviderRequest{
Settings: &codersdk.AIProviderSettings{
Bedrock: &codersdk.AIProviderBedrockSettings{Region: "us-east-1", RoleARN: roleARN, ExternalID: "client-tries-to-change-it"},
},
})
sdkErr := requireSDKError(t, err, http.StatusBadRequest)
require.Equal(t, externalIDReadOnlyMsg, sdkErr.Message)
})
t.Run("GeneratedWhenRoleAddedByPatch", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
ctx := testutil.Context(t, testutil.WaitLong)
created, err := createBedrock(t, client, "bedrock-add-role", codersdk.AIProviderBedrockSettings{Region: "us-east-1"})
require.NoError(t, err)
require.Empty(t, created.Settings.Bedrock.ExternalID)
updated, err := client.UpdateAIProvider(ctx, created.Name, codersdk.UpdateAIProviderRequest{
Settings: &codersdk.AIProviderSettings{
Bedrock: &codersdk.AIProviderBedrockSettings{Region: "us-east-1", RoleARN: roleARN},
},
})
require.NoError(t, err)
require.NotEmpty(t, updated.Settings.Bedrock.ExternalID, "external ID must be generated when a role is added by PATCH")
})
t.Run("RejectsClientValueWhenRoleAddedByPatch", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, nil)
_ = coderdtest.CreateFirstUser(t, client)
ctx := testutil.Context(t, testutil.WaitLong)
created, err := createBedrock(t, client, "bedrock-add-role-id", codersdk.AIProviderBedrockSettings{Region: "us-east-1"})
require.NoError(t, err)
require.Empty(t, created.Settings.Bedrock.ExternalID)
// No value is stored yet, so any client value is a change and is rejected.
_, err = client.UpdateAIProvider(ctx, created.Name, codersdk.UpdateAIProviderRequest{
Settings: &codersdk.AIProviderSettings{
Bedrock: &codersdk.AIProviderBedrockSettings{Region: "us-east-1", RoleARN: roleARN, ExternalID: "client-supplied-value"},
},
})
sdkErr := requireSDKError(t, err, http.StatusBadRequest)
require.Equal(t, externalIDReadOnlyMsg, sdkErr.Message)
})
}
+76 -66
View File
@@ -1454,6 +1454,7 @@ type AIProviderKindBedrock struct {
Model string `protobuf:"bytes,4,opt,name=model,proto3" json:"model,omitempty"`
SmallFastModel string `protobuf:"bytes,5,opt,name=small_fast_model,json=smallFastModel,proto3" json:"small_fast_model,omitempty"`
RoleArn string `protobuf:"bytes,6,opt,name=role_arn,json=roleArn,proto3" json:"role_arn,omitempty"`
ExternalId string `protobuf:"bytes,7,opt,name=external_id,json=externalId,proto3" json:"external_id,omitempty"`
}
func (x *AIProviderKindBedrock) Reset() {
@@ -1530,6 +1531,13 @@ func (x *AIProviderKindBedrock) GetRoleArn() string {
return ""
}
func (x *AIProviderKindBedrock) GetExternalId() string {
if x != nil {
return x.ExternalId
}
return ""
}
var File_coderd_aibridged_proto_aibridged_proto protoreflect.FileDescriptor
var file_coderd_aibridged_proto_aibridged_proto_rawDesc = []byte{
@@ -1802,7 +1810,7 @@ var file_coderd_aibridged_proto_aibridged_proto_rawDesc = []byte{
0x6b, 0x65, 0x79, 0x73, 0x12, 0x36, 0x0a, 0x07, 0x62, 0x65, 0x64, 0x72, 0x6f, 0x63, 0x6b, 0x18,
0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x49,
0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4b, 0x69, 0x6e, 0x64, 0x42, 0x65, 0x64, 0x72,
0x6f, 0x63, 0x6b, 0x52, 0x07, 0x62, 0x65, 0x64, 0x72, 0x6f, 0x63, 0x6b, 0x22, 0xd5, 0x01, 0x0a,
0x6f, 0x63, 0x6b, 0x52, 0x07, 0x62, 0x65, 0x64, 0x72, 0x6f, 0x63, 0x6b, 0x22, 0xf6, 0x01, 0x0a,
0x15, 0x41, 0x49, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x4b, 0x69, 0x6e, 0x64, 0x42,
0x65, 0x64, 0x72, 0x6f, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x1d,
@@ -1816,72 +1824,74 @@ var file_coderd_aibridged_proto_aibridged_proto_rawDesc = []byte{
0x64, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x6d, 0x61, 0x6c, 0x6c,
0x46, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x6f, 0x6c,
0x65, 0x5f, 0x61, 0x72, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x6f, 0x6c,
0x65, 0x41, 0x72, 0x6e, 0x32, 0xa9, 0x04, 0x0a, 0x08, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x65,
0x72, 0x12, 0x59, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x17,
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74,
0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73,
0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73,
0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x52,
0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65,
0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50,
0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64,
0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f,
0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52,
0x65, 0x41, 0x72, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x49, 0x64, 0x32, 0xa9, 0x04, 0x0a, 0x08, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64,
0x65, 0x72, 0x12, 0x59, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65,
0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a,
0x17, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e,
0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x6f, 0x72,
0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55,
0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55,
0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11,
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67,
0x65, 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64,
0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72,
0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f,
0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52,
0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65,
0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d,
0x6f, 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x12, 0x20, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x54,
0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d, 0x6f, 0x64, 0x65,
0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x32, 0xeb, 0x01, 0x0a, 0x0f, 0x4d, 0x43, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72,
0x61, 0x74, 0x6f, 0x72, 0x12, 0x5c, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65,
0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x7a, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76,
0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61,
0x74, 0x63, 0x68, 0x12, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d,
0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53,
0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x55,
0x0a, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x72, 0x12, 0x47, 0x0a, 0x0c,
0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x1a, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65,
0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x65, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x4d, 0x0a,
0x0e, 0x47, 0x65, 0x74, 0x41, 0x49, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12,
0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x49, 0x50, 0x72, 0x6f,
0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x49, 0x50, 0x72, 0x6f, 0x76, 0x69,
0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x32, 0x5a, 0x30,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72,
0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x64,
0x2f, 0x61, 0x69, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64,
0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x12, 0x20, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c,
0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d, 0x6f, 0x64,
0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x32, 0xeb, 0x01, 0x0a, 0x0f, 0x4d, 0x43, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75,
0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x5c, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53,
0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65,
0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65,
0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72,
0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42,
0x61, 0x74, 0x63, 0x68, 0x12, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74,
0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50,
0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32,
0x55, 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x72, 0x12, 0x47, 0x0a,
0x0c, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x1a, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a,
0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x65, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x4d,
0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x49, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73,
0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x49, 0x50, 0x72,
0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x49, 0x50, 0x72, 0x6f, 0x76,
0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x32, 0x5a,
0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65,
0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72,
0x64, 0x2f, 0x61, 0x69, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
+1
View File
@@ -193,4 +193,5 @@ message AIProviderKindBedrock {
string model = 4;
string small_fast_model = 5;
string role_arn = 6;
string external_id = 7;
}
@@ -883,6 +883,7 @@ func aiProviderToProto(row database.AIProvider, keys []database.AIProviderKey) (
Model: settings.Bedrock.Model,
SmallFastModel: settings.Bedrock.SmallFastModel,
RoleArn: settings.Bedrock.RoleARN,
ExternalId: settings.Bedrock.ExternalID,
}
}