Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 44678dc

Browse filesBrowse files
committed
feat(coderd): org-scope chat model config schema
Stage 1 of CODAGT-709: chat_model_configs gains organization_id (FK organizations, ON DELETE CASCADE) backfilled to the default org, plus inert group_acl/user_acl jsonb columns seeded with the everyone-in-org read entry. The single-default partial unique index moves from ON ((1)) to ON (organization_id) with its predicate unchanged, and an org lookup index is added. Runtime behavior stays deployment-wide: the chatd default-config cache is keyed by org with a default-org fallback (removed at the cutover), old create/update/delete handlers pin every write to the default org, and authorization checks are unchanged. The per-org query variants (GetDefaultChatModelConfig, UnsetDefaultChatModelConfigs, GetEnabledChatModelConfigsByOrg) are consumed by chatd so orgs stop leaking into each other's resolution once rows diverge at the explosion stage. Refs CODAGT-709
1 parent d57965e commit 44678dc
Copy full SHA for 44678dc

30 files changed

+1,374-202Lines changed: 1374 additions & 202 deletions
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎coderd/database/check_constraint.go‎

Copy file name to clipboardExpand all lines: coderd/database/check_constraint.go
+2Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Collapse file

‎coderd/database/dbauthz/dbauthz.go‎

Copy file name to clipboardExpand all lines: coderd/database/dbauthz/dbauthz.go
+17-6Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,10 @@ var (
790790
rbac.ResourceWorkspace.Type: {policy.ActionRead, policy.ActionUpdate},
791791
rbac.ResourceDeploymentConfig.Type: {policy.ActionRead},
792792
rbac.ResourceUser.Type: {policy.ActionReadPersonal},
793+
// Org-scoped resolution paths read the default
794+
// organization to apply the pre-cutover
795+
// default-org fallback (removed in M3).
796+
rbac.ResourceOrganization.Type: {policy.ActionRead},
793797
}),
794798
User: []rbac.Permission{},
795799
ByOrgID: map[string]rbac.OrgPermissions{},
@@ -3743,17 +3747,17 @@ func (q *querier) GetDatabaseNow(ctx context.Context) (time.Time, error) {
37433747
return q.db.GetDatabaseNow(ctx)
37443748
}
37453749

3746-
func (q *querier) GetDefaultChatModelConfig(ctx context.Context) (database.ChatModelConfig, error) {
3750+
func (q *querier) GetDefaultChatModelConfig(ctx context.Context, organizationID uuid.UUID) (database.ChatModelConfig, error) {
37473751
// Reading the default model config is needed for chat creation.
3748-
// TODO(CODAGT-161): scope this check when org context is available.
3749-
// This function has no org context to scope the check, and
3752+
// TODO(CODAGT-161): scope this check to the organization once an
3753+
// org-scoped RBAC resource for model configs exists.
37503754
// ResourceDeploymentConfig is too restrictive (admin-only).
37513755
// The handler layer gates chat creation via ActionCreate on
37523756
// the org-scoped ResourceChat.
37533757
if _, ok := ActorFromContext(ctx); !ok {
37543758
return database.ChatModelConfig{}, ErrNoActor
37553759
}
3756-
return q.db.GetDefaultChatModelConfig(ctx)
3760+
return q.db.GetDefaultChatModelConfig(ctx, organizationID)
37573761
}
37583762

37593763
func (q *querier) GetDefaultOrganization(ctx context.Context) (database.Organization, error) {
@@ -3802,6 +3806,13 @@ func (q *querier) GetEnabledChatModelConfigs(ctx context.Context) ([]database.Ge
38023806
return q.db.GetEnabledChatModelConfigs(ctx)
38033807
}
38043808

3809+
func (q *querier) GetEnabledChatModelConfigsByOrganization(ctx context.Context, organizationID uuid.UUID) ([]database.GetEnabledChatModelConfigsByOrganizationRow, error) {
3810+
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceDeploymentConfig); err != nil {
3811+
return nil, err
3812+
}
3813+
return q.db.GetEnabledChatModelConfigsByOrganization(ctx, organizationID)
3814+
}
3815+
38053816
func (q *querier) GetEnabledMCPServerConfigs(ctx context.Context) ([]database.MCPServerConfig, error) {
38063817
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceDeploymentConfig); err != nil {
38073818
return nil, err
@@ -7254,11 +7265,11 @@ func (q *querier) UnpinChatByID(ctx context.Context, id uuid.UUID) error {
72547265
return q.db.UnpinChatByID(ctx, id)
72557266
}
72567267

7257-
func (q *querier) UnsetDefaultChatModelConfigs(ctx context.Context) error {
7268+
func (q *querier) UnsetDefaultChatModelConfigs(ctx context.Context, organizationID uuid.UUID) error {
72587269
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil {
72597270
return err
72607271
}
7261-
return q.db.UnsetDefaultChatModelConfigs(ctx)
7272+
return q.db.UnsetDefaultChatModelConfigs(ctx, organizationID)
72627273
}
72637274

72647275
func (q *querier) UpdateAIBridgeInterceptionEnded(ctx context.Context, params database.UpdateAIBridgeInterceptionEndedParams) (database.AIBridgeInterception, error) {
Collapse file

‎coderd/database/dbauthz/dbauthz_test.go‎

Copy file name to clipboardExpand all lines: coderd/database/dbauthz/dbauthz_test.go
+13-4Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,8 +1130,8 @@ func (s *MethodTestSuite) TestChats() {
11301130
}))
11311131
s.Run("GetDefaultChatModelConfig", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
11321132
config := testutil.Fake(s.T(), faker, database.ChatModelConfig{})
1133-
dbm.EXPECT().GetDefaultChatModelConfig(gomock.Any()).Return(config, nil).AnyTimes()
1134-
check.Asserts().Returns(config)
1133+
dbm.EXPECT().GetDefaultChatModelConfig(gomock.Any(), config.OrganizationID).Return(config, nil).AnyTimes()
1134+
check.Args(config.OrganizationID).Asserts().Returns(config)
11351135
}))
11361136
s.Run("GetChatModelConfigs", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
11371137
configA := testutil.Fake(s.T(), faker, database.ChatModelConfig{})
@@ -1257,6 +1257,14 @@ func (s *MethodTestSuite) TestChats() {
12571257
check.Args().Asserts(rbac.ResourceDeploymentConfig, policy.ActionRead).Returns([]database.GetEnabledChatModelConfigsRow{rowA, rowB})
12581258
}))
12591259

1260+
s.Run("GetEnabledChatModelConfigsByOrganization", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
1261+
orgID := uuid.New()
1262+
rowA := testutil.Fake(s.T(), faker, database.GetEnabledChatModelConfigsByOrganizationRow{})
1263+
rowB := testutil.Fake(s.T(), faker, database.GetEnabledChatModelConfigsByOrganizationRow{})
1264+
dbm.EXPECT().GetEnabledChatModelConfigsByOrganization(gomock.Any(), orgID).Return([]database.GetEnabledChatModelConfigsByOrganizationRow{rowA, rowB}, nil).AnyTimes()
1265+
check.Args(orgID).Asserts(rbac.ResourceDeploymentConfig, policy.ActionRead).Returns([]database.GetEnabledChatModelConfigsByOrganizationRow{rowA, rowB})
1266+
}))
1267+
12601268
s.Run("GetStaleChats", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
12611269
threshold := dbtime.Now()
12621270
chats := []database.Chat{testutil.Fake(s.T(), faker, database.Chat{})}
@@ -1580,8 +1588,9 @@ func (s *MethodTestSuite) TestChats() {
15801588
check.Args(arg).Asserts(chat, policy.ActionUpdate).Returns(updatedChat)
15811589
}))
15821590
s.Run("UnsetDefaultChatModelConfigs", s.Mocked(func(dbm *dbmock.MockStore, _ *gofakeit.Faker, check *expects) {
1583-
dbm.EXPECT().UnsetDefaultChatModelConfigs(gomock.Any()).Return(nil).AnyTimes()
1584-
check.Args().Asserts(rbac.ResourceSystem, policy.ActionUpdate)
1591+
orgID := uuid.New()
1592+
dbm.EXPECT().UnsetDefaultChatModelConfigs(gomock.Any(), orgID).Return(nil).AnyTimes()
1593+
check.Args(orgID).Asserts(rbac.ResourceSystem, policy.ActionUpdate)
15851594
}))
15861595
s.Run("UpsertChatDiffStatus", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
15871596
chat := testutil.Fake(s.T(), faker, database.Chat{})
Collapse file

‎coderd/database/dbgen/dbgen.go‎

Copy file name to clipboardExpand all lines: coderd/database/dbgen/dbgen.go
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,24 @@ func ChatModelConfig(t testing.TB, db database.Store, seed database.ChatModelCon
178178
}
179179
aiProviderID = uuid.NullUUID{UUID: provider.ID, Valid: true}
180180
}
181+
organizationID := seed.OrganizationID
182+
if organizationID == uuid.Nil {
183+
defaultOrg, err := db.GetDefaultOrganization(genCtx)
184+
require.NoError(t, err, "get default organization")
185+
organizationID = defaultOrg.ID
186+
}
187+
groupACL := seed.GroupACL
188+
if groupACL == nil {
189+
groupACL = database.ChatACL{}
190+
}
191+
groupACLRaw, err := json.Marshal(groupACL)
192+
require.NoError(t, err, "marshal group ACL")
193+
userACL := seed.UserACL
194+
if userACL == nil {
195+
userACL = database.ChatACL{}
196+
}
197+
userACLRaw, err := json.Marshal(userACL)
198+
require.NoError(t, err, "marshal user ACL")
181199
params := database.InsertChatModelConfigParams{
182200
Model: takeFirst(seed.Model, "gpt-4o-mini"),
183201
DisplayName: takeFirst(seed.DisplayName, "Test Model"),
@@ -189,6 +207,9 @@ func ChatModelConfig(t testing.TB, db database.Store, seed database.ChatModelCon
189207
CompressionThreshold: takeFirst(seed.CompressionThreshold, defaultChatModelCompressionThreshold),
190208
Options: takeFirstSlice(seed.Options, json.RawMessage(`{}`)),
191209
AIProviderID: aiProviderID,
210+
OrganizationID: organizationID,
211+
GroupACL: groupACLRaw,
212+
UserACL: userACLRaw,
192213
}
193214
for _, fn := range munge {
194215
fn(&params)
Collapse file

‎coderd/database/dbmetrics/querymetrics.go‎

Copy file name to clipboardExpand all lines: coderd/database/dbmetrics/querymetrics.go
+12-4Lines changed: 12 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Collapse file

‎coderd/database/dbmock/dbmock.go‎

Copy file name to clipboardExpand all lines: coderd/database/dbmock/dbmock.go
+23-8Lines changed: 23 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Collapse file

‎coderd/database/dump.sql‎

Copy file name to clipboardExpand all lines: coderd/database/dump.sql
+12-2Lines changed: 12 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Collapse file

‎coderd/database/foreign_key_constraint.go‎

Copy file name to clipboardExpand all lines: coderd/database/foreign_key_constraint.go
+1Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Collapse file
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
ALTER TABLE chat_model_configs
2+
DROP CONSTRAINT chat_model_configs_user_acl_is_object,
3+
DROP CONSTRAINT chat_model_configs_group_acl_is_object,
4+
DROP COLUMN user_acl,
5+
DROP COLUMN group_acl;
6+
7+
DROP INDEX idx_chat_model_configs_single_default;
8+
CREATE UNIQUE INDEX idx_chat_model_configs_single_default
9+
ON chat_model_configs ((1))
10+
WHERE is_default = true AND deleted = false;
11+
12+
DROP INDEX idx_chat_model_configs_organization_id;
13+
14+
ALTER TABLE chat_model_configs DROP COLUMN organization_id;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.