Skip to content
Closed
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
1,711 changes: 878 additions & 833 deletions api/client/proto/authservice.pb.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions api/client/webclient/webclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ type ProxySettings struct {
// TLSRoutingEnabled indicates that proxy supports ALPN SNI server where
// all proxy services are exposed on a single TLS listener (Proxy Web Listener).
TLSRoutingEnabled bool `json:"tls_routing_enabled"`
// AssistEnabled is true when Teleport Assist is enabled.
AssistEnabled bool `json:"assist_enabled"`
}

// KubeProxySettings is kubernetes proxy settings
Expand Down
192 changes: 107 additions & 85 deletions api/gen/proto/go/teleport/plugins/v1/plugin_service.pb.go

Large diffs are not rendered by default.

699 changes: 540 additions & 159 deletions api/gen/proto/go/usageevents/v1/usageevents.pb.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions api/proto/teleport/legacy/client/proto/authservice.proto
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,8 @@ message Features {
bool AutomaticUpgrades = 16 [(gogoproto.jsontag) = "automatic_upgrades"];
// IsUsageBased enables some usage-based billing features
bool IsUsageBased = 17 [(gogoproto.jsontag) = "is_usage_based"];
// Assist enables the Assistant feature
bool Assist = 18 [(gogoproto.jsontag) = "assist"];
}

// DeleteUserRequest is the input value for the DeleteUser method.
Expand Down
22 changes: 22 additions & 0 deletions api/proto/teleport/legacy/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5052,6 +5052,8 @@ message PluginSpecV1 {
PluginSlackAccessSettings slack_access_plugin = 1;
// Settings for the Opsgenie access plugin
PluginOpsgenieAccessSettings opsgenie = 2;
// Settings for OpenAI plugin
PluginOpenAISettings openai = 3;
}
}

Expand All @@ -5074,9 +5076,15 @@ message PluginOpsgenieAccessSettings {
repeated string default_schedules = 4;
}

// Defines settings for the OpenAI plugin. Currently there are no settings.
message PluginOpenAISettings {
option (gogoproto.equal) = true;
}

message PluginBootstrapCredentialsV1 {
oneof credentials {
PluginOAuth2AuthorizationCodeCredentials oauth2_authorization_code = 1;
PluginBearerTokenCredentials bearer_token = 2;
}
}

Expand Down Expand Up @@ -5111,6 +5119,7 @@ enum PluginStatusCode {
message PluginCredentialsV1 {
oneof credentials {
PluginOAuth2AccessTokenCredentials oauth2_access_token = 1;
PluginBearerTokenCredentials bearer_token = 2;
}
}

Expand All @@ -5123,6 +5132,19 @@ message PluginOAuth2AccessTokenCredentials {
];
}

message PluginBearerTokenCredentials {
// Token is the literal bearer token to be submitted to the 3rd-party API provider.
string token = 1;

// TokenFile is a path to the local file containing a bearer token.
// This takes precedence over Token, and is currently only used by
// OpenAI plugin in Cloud, where by default a Teleport-owned key is used.
// This avoids exposing the token itself to the cluster.
// The file must exist and be readable on whatever runs the plugin
// (in the OpenAI case, it is the Proxy).
string token_file = 2;
}

// PluginList represents a list of plugin resources
message PluginListV1 {
// Plugins is a list of plugin resources.
Expand Down
6 changes: 6 additions & 0 deletions api/proto/teleport/plugins/v1/plugin_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ message CreatePluginRequest {
message GetPluginRequest {
// Name is the name of the plugin instance.
string name = 1;

// WithSecrets indicates whether plugin secrets (credentials) are requested
bool with_secrets = 2;
}

// ListPluginsRequest is a paginated request to list all plugin instances.
Expand All @@ -59,6 +62,9 @@ message ListPluginsRequest {
// StartKey is the value of NextKey received in the last ListPluginsResponse.
// When making the initial request, this should be left empty.
string start_key = 2;

// WithSecrets indicates whether plugin secrets (credentials) are requested
bool with_secrets = 3;
}

// ListPluginsResponse is a paginated response to a ListPluginsRequest.
Expand Down
13 changes: 13 additions & 0 deletions api/proto/teleport/usageevents/v1/usageevents.proto
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,18 @@ message UICreateNewRoleCancelClickEvent {}
// UICreateNewRoleViewDocumentationClickEvent is an event that can be triggered during custom role creation
message UICreateNewRoleViewDocumentationClickEvent {}

// AssistCompletionEvent is an event that is emitted when a completion occurs in the Assistant
message AssistCompletionEvent {
// ConversationId is the UUID that identifies a single Assist conversation
string conversation_id = 1;
// TotalTokens is the total amount of token used to satisfy this request
int64 total_tokens = 2;
// PromptTokens is the amount of estimated tokens used by the prompt
int64 prompt_tokens = 3;
// CompletionTokens is the amount of tokens that the completion response consists of
int64 completion_tokens = 4;
}

// UsageEventOneOf is a message that can accept a oneof of any supported
// external usage event.
message UsageEventOneOf {
Expand Down Expand Up @@ -336,6 +348,7 @@ message UsageEventOneOf {
UIDiscoverIntegrationAWSOIDCConnectEvent ui_discover_integration_aws_oidc_connect_event = 27;
UIDiscoverDatabaseRDSEnrollEvent ui_discover_database_rds_enroll_event = 28;
UICallToActionClickEvent ui_call_to_action_click_event = 29;
AssistCompletionEvent assist_completion = 30;
}
reserved 2; //UIOnboardGetStartedClickEvent
reserved "ui_onboard_get_started_click";
Expand Down
15 changes: 15 additions & 0 deletions api/types/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const (
PluginTypeUnknown PluginType = ""
// PluginTypeSlack is the Slack access request plugin
PluginTypeSlack = "slack"
// PluginTypeOpenAI is the OpenAI plugin
PluginTypeOpenAI = "openai"
)

// Plugin represents a plugin instance
Expand Down Expand Up @@ -98,6 +100,17 @@ func (p *PluginV1) CheckAndSetDefaults() error {
if err := p.Credentials.GetOauth2AccessToken().CheckAndSetDefaults(); err != nil {
return trace.Wrap(err)
}
case *PluginSpecV1_Openai:
if p.Credentials == nil {
return trace.BadParameter("credentials must be set")
}
bearer := p.Credentials.GetBearerToken()
if bearer == nil {
return trace.BadParameter("openai plugin must be used with the bearer token credential type")
}
if (bearer.Token == "") == (bearer.TokenFile == "") {
return trace.BadParameter("exactly one of Token and TokenFile must be specified")
}
default:
return trace.BadParameter("settings are not set or have an unknown type")
}
Expand Down Expand Up @@ -228,6 +241,8 @@ func (p *PluginV1) GetType() PluginType {
switch p.Spec.Settings.(type) {
case *PluginSpecV1_SlackAccessPlugin:
return PluginTypeSlack
case *PluginSpecV1_Openai:
return PluginTypeOpenAI
default:
return PluginTypeUnknown
}
Expand Down
75 changes: 75 additions & 0 deletions api/types/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"testing"
"time"

"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
)

Expand All @@ -46,3 +47,77 @@ func TestPluginWithoutSecrets(t *testing.T) {
plugin = plugin.WithoutSecrets().(*PluginV1)
require.Nil(t, plugin.Credentials)
}

func TestPluginOpenAIValidation(t *testing.T) {
spec := PluginSpecV1{
Settings: &PluginSpecV1_Openai{},
}
testCases := []struct {
name string
creds *PluginCredentialsV1
assertErr require.ErrorAssertionFunc
}{
{
name: "no credentials",
creds: nil,
assertErr: func(t require.TestingT, err error, args ...any) {
require.Error(t, err)
require.True(t, trace.IsBadParameter(err))
require.Contains(t, err.Error(), "credentials must be set")
},
},
{
name: "no credentials inner",
creds: &PluginCredentialsV1{},
assertErr: func(t require.TestingT, err error, args ...any) {
require.Error(t, err)
require.True(t, trace.IsBadParameter(err))
require.Contains(t, err.Error(), "must be used with the bearer token credential type")
},
},
{
name: "invalid credential type (oauth2)",
creds: &PluginCredentialsV1{
Credentials: &PluginCredentialsV1_Oauth2AccessToken{},
},
assertErr: func(t require.TestingT, err error, args ...any) {
require.Error(t, err)
require.True(t, trace.IsBadParameter(err))
require.Contains(t, err.Error(), "must be used with the bearer token credential type")
},
},
{
name: "valid credentials (token)",
creds: &PluginCredentialsV1{
Credentials: &PluginCredentialsV1_BearerToken{
BearerToken: &PluginBearerTokenCredentials{
Token: "xxx-abc",
},
},
},
assertErr: func(t require.TestingT, err error, args ...any) {
require.NoError(t, err)
},
},
{
name: "valid credentials (token file)",
creds: &PluginCredentialsV1{
Credentials: &PluginCredentialsV1_BearerToken{
BearerToken: &PluginBearerTokenCredentials{
TokenFile: "/var/lib/secrets/openai_token",
},
},
},
assertErr: func(t require.TestingT, err error, args ...any) {
require.NoError(t, err)
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
plugin := NewPluginV1(Metadata{Name: "foobar"}, spec, tc.creds)
tc.assertErr(t, plugin.CheckAndSetDefaults())
})
}
}
Loading