mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
fix: grant AsAIBridged ResourceSystem.ActionCreate for UpsertAISeatState (#24603)
Related coder/internal#1444
This commit is contained in:
@@ -622,6 +622,7 @@ var (
|
|||||||
},
|
},
|
||||||
rbac.ResourceApiKey.Type: {policy.ActionRead}, // Validate API keys.
|
rbac.ResourceApiKey.Type: {policy.ActionRead}, // Validate API keys.
|
||||||
rbac.ResourceAibridgeInterception.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
|
rbac.ResourceAibridgeInterception.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
|
||||||
|
rbac.ResourceSystem.Type: {policy.ActionCreate}, // Required for UpsertAISeatState.
|
||||||
}),
|
}),
|
||||||
User: []rbac.Permission{},
|
User: []rbac.Permission{},
|
||||||
ByOrgID: map[string]rbac.OrgPermissions{},
|
ByOrgID: map[string]rbac.OrgPermissions{},
|
||||||
|
|||||||
@@ -5,14 +5,19 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"cdr.dev/slog/v3/sloggers/slogtest"
|
||||||
agplaiseats "github.com/coder/coder/v2/coderd/aiseats"
|
agplaiseats "github.com/coder/coder/v2/coderd/aiseats"
|
||||||
"github.com/coder/coder/v2/coderd/audit"
|
"github.com/coder/coder/v2/coderd/audit"
|
||||||
|
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||||
"github.com/coder/coder/v2/coderd/database"
|
"github.com/coder/coder/v2/coderd/database"
|
||||||
|
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
||||||
"github.com/coder/coder/v2/coderd/database/dbgen"
|
"github.com/coder/coder/v2/coderd/database/dbgen"
|
||||||
"github.com/coder/coder/v2/coderd/database/dbtestutil"
|
"github.com/coder/coder/v2/coderd/database/dbtestutil"
|
||||||
"github.com/coder/coder/v2/coderd/database/dbtime"
|
"github.com/coder/coder/v2/coderd/database/dbtime"
|
||||||
|
"github.com/coder/coder/v2/coderd/rbac"
|
||||||
enterpriseaiseats "github.com/coder/coder/v2/enterprise/aiseats"
|
enterpriseaiseats "github.com/coder/coder/v2/enterprise/aiseats"
|
||||||
"github.com/coder/coder/v2/testutil"
|
"github.com/coder/coder/v2/testutil"
|
||||||
"github.com/coder/quartz"
|
"github.com/coder/quartz"
|
||||||
@@ -37,6 +42,38 @@ func TestSeatTrackerDB(t *testing.T) {
|
|||||||
require.EqualValues(t, 1, count)
|
require.EqualValues(t, 1, count)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Regression test for coder/internal#1444: UpsertAISeatState must
|
||||||
|
// succeed when called through the AsAIBridged RBAC subject. The
|
||||||
|
// aibridged daemon context was missing ResourceSystem.ActionCreate,
|
||||||
|
// which caused the very first RecordUsage call per user to fail
|
||||||
|
// with "unauthorized: rbac: forbidden".
|
||||||
|
t.Run("AsAIBridgedRBAC", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
rawDB, _ := dbtestutil.NewDB(t)
|
||||||
|
authz := rbac.NewStrictAuthorizer(prometheus.NewRegistry())
|
||||||
|
authzDB := dbauthz.New(rawDB, authz, slogtest.Make(t, nil), coderdtest.AccessControlStorePointer())
|
||||||
|
|
||||||
|
ctx := testutil.Context(t, testutil.WaitShort)
|
||||||
|
clock := quartz.NewMock(t)
|
||||||
|
tracker := enterpriseaiseats.New(authzDB, testutil.Logger(t), clock, nil)
|
||||||
|
|
||||||
|
// Insert a user directly in the raw DB so it exists for the
|
||||||
|
// foreign key reference.
|
||||||
|
user := dbgen.User(t, rawDB, database.User{Status: database.UserStatusActive})
|
||||||
|
|
||||||
|
// Call RecordUsage with the AIBridged context, mirroring the
|
||||||
|
// production call path in aibridgedserver.RecordInterception.
|
||||||
|
aibridgedCtx := dbauthz.AsAIBridged(ctx)
|
||||||
|
tracker.RecordUsage(aibridgedCtx, user.ID, agplaiseats.ReasonAIBridge("provider=test, model=test"))
|
||||||
|
|
||||||
|
// Verify the seat was actually recorded. A count of 0 means
|
||||||
|
// the upsert was silently rejected by RBAC.
|
||||||
|
count, err := rawDB.GetActiveAISeatCount(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 1, count, "AI seat should be recorded when using AsAIBridged context")
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("InactiveUsersExcluded", func(t *testing.T) {
|
t.Run("InactiveUsersExcluded", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user