mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(coderd): allow non-admin users to list chat model configs (#22407)
## Problem Non-admin users of the Agents (chat) feature send `model_config_id: "00000000-0000-0000-0000-000000000000"` (nil UUID) when creating chats, because the `GET /api/experimental/chats/model-configs` endpoint requires `policy.ActionRead` on `rbac.ResourceDeploymentConfig`, which is only granted to admins. The flow: 1. `AgentsPage.tsx` calls `useQuery(chatModelConfigs())` → hits `listChatModelConfigs` 2. Non-admin users get a **403 Forbidden** response 3. `chatModelConfigsQuery.data` is `undefined`, so the `modelConfigIDByModelID` map is empty 4. `handleCreateChat` falls back to `nilUUID` for `model_config_id` 5. The backend rejects the nil UUID: `"Invalid model config ID."` ## Fix Changed `listChatModelConfigs` to allow all authenticated users to read model configs: - **Admin users** continue to see all configs (including disabled ones) for management via `GetChatModelConfigs` - **Non-admin users** now see only enabled configs via `GetEnabledChatModelConfigs` with a system context, which is sufficient for using the chat feature This follows the same pattern as `listChatModels`, which already uses `dbauthz.AsSystemRestricted(ctx)` to allow all authenticated users to see available models. Write endpoints (create/update/delete) retain their existing `ResourceDeploymentConfig` authorization. ## Testing - Updated `TestListChatModelConfigs/ForbiddenForOrganizationMember` → `SuccessForOrganizationMember` to verify non-admin users can list enabled model configs - All existing chat tests continue to pass
This commit is contained in:
+13
-5
@@ -2444,12 +2444,20 @@ func (api *API) deleteChatProvider(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (api *API) listChatModelConfigs(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
if !api.Authorize(r, policy.ActionRead, rbac.ResourceDeploymentConfig) {
|
||||
httpapi.Forbidden(rw)
|
||||
return
|
||||
}
|
||||
|
||||
configs, err := api.Database.GetChatModelConfigs(ctx)
|
||||
// Admin users can see all model configs (including disabled ones)
|
||||
// for management purposes. Non-admin users see only enabled
|
||||
// configs, which is sufficient for using the chat feature.
|
||||
isAdmin := api.Authorize(r, policy.ActionRead, rbac.ResourceDeploymentConfig)
|
||||
|
||||
var configs []database.ChatModelConfig
|
||||
var err error
|
||||
if isAdmin {
|
||||
configs, err = api.Database.GetChatModelConfigs(ctx)
|
||||
} else {
|
||||
//nolint:gocritic // All authenticated users need to read enabled model configs to use the chat feature.
|
||||
configs, err = api.Database.GetEnabledChatModelConfigs(dbauthz.AsSystemRestricted(ctx))
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to list chat model configs.",
|
||||
|
||||
+16
-3
@@ -818,16 +818,29 @@ func TestListChatModelConfigs(t *testing.T) {
|
||||
require.True(t, found)
|
||||
})
|
||||
|
||||
t.Run("ForbiddenForOrganizationMember", func(t *testing.T) {
|
||||
t.Run("SuccessForOrganizationMember", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitLong)
|
||||
adminClient := newChatClient(t)
|
||||
firstUser := coderdtest.CreateFirstUser(t, adminClient)
|
||||
modelConfig := createChatModelConfig(t, adminClient)
|
||||
memberClient, _ := coderdtest.CreateAnotherUser(t, adminClient, firstUser.OrganizationID)
|
||||
|
||||
_, err := memberClient.ListChatModelConfigs(ctx)
|
||||
requireSDKError(t, err, http.StatusForbidden)
|
||||
// Non-admin users should see only enabled model configs.
|
||||
configs, err := memberClient.ListChatModelConfigs(ctx)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, configs)
|
||||
|
||||
found := false
|
||||
for _, config := range configs {
|
||||
if config.ID == modelConfig.ID {
|
||||
found = true
|
||||
require.Equal(t, "openai", config.Provider)
|
||||
require.Equal(t, "gpt-4o-mini", config.Model)
|
||||
}
|
||||
}
|
||||
require.True(t, found)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user