mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: migrate agents-access to org-scoped system role for proper chat RBAC (#24438)
The agents-access role previously granted chat permissions at user
scope, but chats are org-scoped objects. Rego skips user-level perms
when org_owner is set, making the grants invisible. Handler-level
band-aids used synthetic non-org-scoped objects as a workaround.
- Migrates agents-access from users.rbac_roles (site-level) to
organization_members.roles (org-scoped) via DB migration
- Redefines agents-access as a predefined org-scoped builtin role
alongside organization-admin, organization-auditor, etc., with
Member permissions granting chat create/read/update
- Excludes ResourceChat from OrgMemberPermissions so org membership
alone no longer grants chat access
- Fixes handler Authorize checks to use org-scoped objects with
semantically correct actions (ActionUpdate for message/tool operations)
- Grants org admins the ability to assign agents-access
Closes #24250
Fixes CODAGT-174
Note: this does not update the "Usage" endpoints. Tracked by CODAGT-161.
> 🤖
This commit is contained in:
@@ -1137,14 +1137,13 @@ func TestCreateChatNonDefaultOrg(t *testing.T) {
|
||||
// Create a second (non-default) org via the API.
|
||||
secondOrg := coderdenttest.CreateOrganization(t, client, coderdenttest.CreateOrganizationOptions{})
|
||||
|
||||
// Create a member in the default org, then add them to the second org.
|
||||
// Create a member with agents-access in both orgs.
|
||||
memberClientRaw, member := coderdtest.CreateAnotherUser(
|
||||
t, client, firstUser.OrganizationID, rbac.RoleAgentsAccess(),
|
||||
t, client, firstUser.OrganizationID,
|
||||
rbac.ScopedRoleAgentsAccess(firstUser.OrganizationID),
|
||||
rbac.ScopedRoleAgentsAccess(secondOrg.ID),
|
||||
)
|
||||
_, err = client.PostOrganizationMember(ctx, secondOrg.ID, member.Username)
|
||||
require.NoError(t, err)
|
||||
memberClient := codersdk.NewExperimentalClient(memberClientRaw)
|
||||
|
||||
// Create a chat in the non-default org.
|
||||
chat, err := memberClient.CreateChat(ctx, codersdk.CreateChatRequest{
|
||||
OrganizationID: secondOrg.ID,
|
||||
@@ -1215,14 +1214,13 @@ func TestListChats_OrgAdminOnlySeesOwnChats(t *testing.T) {
|
||||
// Create a second (non-default) org.
|
||||
secondOrg := coderdenttest.CreateOrganization(t, client, coderdenttest.CreateOrganizationOptions{})
|
||||
|
||||
// Create a regular member with agents access in the second org.
|
||||
memberClientRaw, member := coderdtest.CreateAnotherUser(
|
||||
t, client, firstUser.OrganizationID, rbac.RoleAgentsAccess(),
|
||||
// Create a member with agents-access in both orgs.
|
||||
memberClientRaw, _ := coderdtest.CreateAnotherUser(
|
||||
t, client, firstUser.OrganizationID,
|
||||
rbac.ScopedRoleAgentsAccess(firstUser.OrganizationID),
|
||||
rbac.ScopedRoleAgentsAccess(secondOrg.ID),
|
||||
)
|
||||
_, err = client.PostOrganizationMember(ctx, secondOrg.ID, member.Username)
|
||||
require.NoError(t, err)
|
||||
memberExp := codersdk.NewExperimentalClient(memberClientRaw)
|
||||
|
||||
// Member creates a chat in the second org.
|
||||
memberChat, err := memberExp.CreateChat(ctx, codersdk.CreateChatRequest{
|
||||
OrganizationID: secondOrg.ID,
|
||||
@@ -1239,7 +1237,7 @@ func TestListChats_OrgAdminOnlySeesOwnChats(t *testing.T) {
|
||||
// Create an org admin in the second org with agents access.
|
||||
adminClientRaw, _ := coderdtest.CreateAnotherUser(
|
||||
t, client, firstUser.OrganizationID,
|
||||
rbac.ScopedRoleOrgAdmin(secondOrg.ID), rbac.RoleAgentsAccess(),
|
||||
rbac.ScopedRoleOrgAdmin(secondOrg.ID), rbac.ScopedRoleAgentsAccess(secondOrg.ID),
|
||||
)
|
||||
adminExp := codersdk.NewExperimentalClient(adminClientRaw)
|
||||
|
||||
|
||||
@@ -493,7 +493,6 @@ func TestListRoles(t *testing.T) {
|
||||
{Name: codersdk.RoleAuditor}: false,
|
||||
{Name: codersdk.RoleTemplateAdmin}: false,
|
||||
{Name: codersdk.RoleUserAdmin}: false,
|
||||
{Name: codersdk.RoleAgentsAccess}: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -507,6 +506,7 @@ func TestListRoles(t *testing.T) {
|
||||
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: false,
|
||||
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: false,
|
||||
{Name: codersdk.RoleOrganizationWorkspaceCreationBan, OrganizationID: owner.OrganizationID}: false,
|
||||
{Name: codersdk.RoleAgentsAccess, OrganizationID: owner.OrganizationID}: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -527,7 +527,6 @@ func TestListRoles(t *testing.T) {
|
||||
{Name: codersdk.RoleAuditor}: false,
|
||||
{Name: codersdk.RoleTemplateAdmin}: false,
|
||||
{Name: codersdk.RoleUserAdmin}: false,
|
||||
{Name: codersdk.RoleAgentsAccess}: false,
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -541,6 +540,7 @@ func TestListRoles(t *testing.T) {
|
||||
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationWorkspaceCreationBan, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleAgentsAccess, OrganizationID: owner.OrganizationID}: true,
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -561,7 +561,6 @@ func TestListRoles(t *testing.T) {
|
||||
{Name: codersdk.RoleAuditor}: true,
|
||||
{Name: codersdk.RoleTemplateAdmin}: true,
|
||||
{Name: codersdk.RoleUserAdmin}: true,
|
||||
{Name: codersdk.RoleAgentsAccess}: true,
|
||||
}),
|
||||
},
|
||||
{
|
||||
@@ -575,6 +574,7 @@ func TestListRoles(t *testing.T) {
|
||||
{Name: codersdk.RoleOrganizationTemplateAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationUserAdmin, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleOrganizationWorkspaceCreationBan, OrganizationID: owner.OrganizationID}: true,
|
||||
{Name: codersdk.RoleAgentsAccess, OrganizationID: owner.OrganizationID}: true,
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user