From becd101bc6ff4f52e47435dd9c7befed12db162e Mon Sep 17 00:00:00 2001 From: ac Date: Tue, 22 Jul 2025 10:51:39 -0700 Subject: [PATCH] Adding the inference grant to the Claim (#1139) * adding the inference grant to the Claim * Added gateway guid values. These are used when connecting to the PSQL db with metrics and app name * renamed the permission from Admin to Perform * remove gateway guids since the gateway is no longer using a connection to the db --- auth/accesstoken.go | 5 +++ auth/accesstoken_test.go | 6 ++++ auth/grants.go | 43 +++++++++++++++++++---- auth/grants_test.go | 73 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 6 deletions(-) diff --git a/auth/accesstoken.go b/auth/accesstoken.go index abb8e1c..b6804fd 100644 --- a/auth/accesstoken.go +++ b/auth/accesstoken.go @@ -87,6 +87,11 @@ func (t *AccessToken) SetAgentGrant(grant *AgentGrant) *AccessToken { return t } +func (t *AccessToken) SetInferenceGrant(grant *InferenceGrant) *AccessToken { + t.grant.Inference = grant + return t +} + func (t *AccessToken) SetMetadata(md string) *AccessToken { t.grant.Metadata = md return t diff --git a/auth/accesstoken_test.go b/auth/accesstoken_test.go index a91cece..0e0198b 100644 --- a/auth/accesstoken_test.go +++ b/auth/accesstoken_test.go @@ -42,9 +42,13 @@ func TestAccessToken(t *testing.T) { apiKey, secret := apiKeypair() videoGrant := &VideoGrant{RoomJoin: true, Room: "myroom"} sipGrant := &SIPGrant{Admin: true} + agentGrant := &AgentGrant{Admin: true} + inferenceGrant := &InferenceGrant{Perform: true} at := NewAccessToken(apiKey, secret). SetVideoGrant(videoGrant). SetSIPGrant(sipGrant). + SetInferenceGrant(inferenceGrant). + SetAgentGrant(agentGrant). SetValidFor(time.Minute * 5). SetKind(livekit.ParticipantInfo_AGENT). SetIdentity("user") @@ -65,6 +69,8 @@ func TestAccessToken(t *testing.T) { require.EqualValues(t, livekit.ParticipantInfo_AGENT, decodedGrant.GetParticipantKind()) require.EqualValues(t, videoGrant, decodedGrant.Video) require.EqualValues(t, sipGrant, decodedGrant.SIP) + require.EqualValues(t, agentGrant, decodedGrant.Agent) + require.EqualValues(t, inferenceGrant, decodedGrant.Inference) }) t.Run("missing kind should be interpreted as standard", func(t *testing.T) { diff --git a/auth/grants.go b/auth/grants.go index d88ed47..b1b4cd0 100644 --- a/auth/grants.go +++ b/auth/grants.go @@ -162,12 +162,13 @@ func checkOutputForCredentials(output any) error { } type ClaimGrants struct { - Identity string `json:"identity,omitempty"` - Name string `json:"name,omitempty"` - Kind string `json:"kind,omitempty"` - Video *VideoGrant `json:"video,omitempty"` - SIP *SIPGrant `json:"sip,omitempty"` - Agent *AgentGrant `json:"agent,omitempty"` + Identity string `json:"identity,omitempty"` + Name string `json:"name,omitempty"` + Kind string `json:"kind,omitempty"` + Video *VideoGrant `json:"video,omitempty"` + SIP *SIPGrant `json:"sip,omitempty"` + Agent *AgentGrant `json:"agent,omitempty"` + Inference *InferenceGrant `json:"inference,omitempty"` // Room configuration to use if this participant initiates the room RoomConfig *RoomConfiguration `json:"roomConfig,omitempty"` // Cloud-only, config preset to use @@ -203,6 +204,8 @@ func (c *ClaimGrants) Clone() *ClaimGrants { clone := *c clone.Video = c.Video.Clone() clone.SIP = c.SIP.Clone() + clone.Agent = c.Agent.Clone() + clone.Inference = c.Inference.Clone() clone.Attributes = maps.Clone(c.Attributes) clone.RoomConfig = c.RoomConfig.Clone() @@ -218,6 +221,8 @@ func (c *ClaimGrants) MarshalLogObject(e zapcore.ObjectEncoder) error { e.AddString("Kind", c.Kind) e.AddObject("Video", c.Video) e.AddObject("SIP", c.SIP) + e.AddObject("Agent", c.Agent) + e.AddObject("Inference", c.Inference) e.AddObject("RoomConfig", logger.Proto((*livekit.RoomConfiguration)(c.RoomConfig))) e.AddString("RoomPreset", c.RoomPreset) return nil @@ -554,6 +559,32 @@ func (s *AgentGrant) MarshalLogObject(e zapcore.ObjectEncoder) error { // ------------------------------------------------------------------ +type InferenceGrant struct { + // Admin grants to all inference features (LLM, STT, TTS) + Perform bool `json:"perform,omitempty"` +} + +func (s *InferenceGrant) Clone() *InferenceGrant { + if s == nil { + return nil + } + + clone := *s + + return &clone +} + +func (s *InferenceGrant) MarshalLogObject(e zapcore.ObjectEncoder) error { + if s == nil { + return nil + } + + e.AddBool("Perform", s.Perform) + return nil +} + +// ------------------------------------------------------------------ + func sourceToString(source livekit.TrackSource) string { return strings.ToLower(source.String()) } diff --git a/auth/grants_test.go b/auth/grants_test.go index 4188863..b8f0e2f 100644 --- a/auth/grants_test.go +++ b/auth/grants_test.go @@ -32,6 +32,9 @@ func TestGrants(t *testing.T) { clone := grants.Clone() require.NotSame(t, grants, clone) require.Same(t, grants.Video, clone.Video) + require.Same(t, grants.Agent, clone.Agent) + require.Same(t, grants.Inference, clone.Inference) + require.Same(t, grants.SIP, clone.SIP) require.True(t, reflect.DeepEqual(grants, clone)) require.True(t, reflect.DeepEqual(grants.Video, clone.Video)) }) @@ -48,6 +51,16 @@ func TestGrants(t *testing.T) { require.Same(t, grants.Video, clone.Video) require.True(t, reflect.DeepEqual(grants, clone)) require.True(t, reflect.DeepEqual(grants.Video, clone.Video)) + + // require SIP + require.Same(t, grants.SIP, clone.SIP) + require.True(t, reflect.DeepEqual(grants.SIP, clone.SIP)) + // require Agent + require.Same(t, grants.Agent, clone.Agent) + require.True(t, reflect.DeepEqual(grants.Agent, clone.Agent)) + // require Inference + require.Same(t, grants.Inference, clone.Inference) + require.True(t, reflect.DeepEqual(grants.Inference, clone.Inference)) }) t.Run("clone with video", func(t *testing.T) { @@ -84,6 +97,66 @@ func TestGrants(t *testing.T) { require.True(t, reflect.DeepEqual(grants, clone)) require.True(t, reflect.DeepEqual(grants.Video, clone.Video)) }) + + t.Run("clone with SIP", func(t *testing.T) { + sip := &SIPGrant{ + Admin: true, + } + grants := &ClaimGrants{ + Identity: "identity", + Name: "name", + Kind: "kind", + SIP: sip, + Sha256: "sha256", + Metadata: "metadata", + } + clone := grants.Clone() + require.NotSame(t, grants, clone) + require.NotSame(t, grants.SIP, clone.SIP) + require.Equal(t, grants.SIP.Admin, clone.SIP.Admin) + require.True(t, reflect.DeepEqual(grants, clone)) + require.True(t, reflect.DeepEqual(grants.SIP, clone.SIP)) + }) + + t.Run("clone with Agent", func(t *testing.T) { + agent := &AgentGrant{ + Admin: true, + } + grants := &ClaimGrants{ + Identity: "identity", + Name: "name", + Kind: "kind", + Agent: agent, + Sha256: "sha256", + Metadata: "metadata", + } + clone := grants.Clone() + require.NotSame(t, grants, clone) + require.NotSame(t, grants.Agent, clone.Agent) + require.Equal(t, grants.Agent.Admin, clone.Agent.Admin) + require.True(t, reflect.DeepEqual(grants, clone)) + require.True(t, reflect.DeepEqual(grants.Agent, clone.Agent)) + }) + + t.Run("clone with Inference", func(t *testing.T) { + inference := &InferenceGrant{ + Perform: true, + } + grants := &ClaimGrants{ + Identity: "identity", + Name: "name", + Kind: "kind", + Inference: inference, + Sha256: "sha256", + Metadata: "metadata", + } + clone := grants.Clone() + require.NotSame(t, grants, clone) + require.NotSame(t, grants.Inference, clone.Inference) + require.Equal(t, grants.Inference.Perform, clone.Inference.Perform) + require.True(t, reflect.DeepEqual(grants, clone)) + require.True(t, reflect.DeepEqual(grants.Inference, clone.Inference)) + }) } func TestParticipantKind(t *testing.T) {