Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
3ff9069
feat: enable Coder Agents for organization members
ibetitsmike Aug 14, 2026
3c49c50
fix(coderd): promote queued message from a terminal chat status in me…
ibetitsmike Aug 25, 2026
9460577
fix: keep RoleAgentsAccess as a deprecated compatibility alias
ibetitsmike Aug 25, 2026
f0548ea
docs(docs/ai-coder/agents): document model access lists as the Coder …
ibetitsmike Aug 25, 2026
dca5c57
refactor(coderd/rbac): track retired role names in a legacy set
ibetitsmike Aug 25, 2026
478dc27
fix(site/src/pages/AgentsPage): align settings story assertion with c…
ibetitsmike Aug 25, 2026
7e1a2c6
refactor(coderd): drop agents-access cleanup migration
ibetitsmike Aug 25, 2026
f5291e2
Merge remote-tracking branch 'origin/main' into HEAD
ibetitsmike Aug 25, 2026
cbdad54
fix(coderd): drop retired role names in rolestore expansion and API r…
ibetitsmike Aug 25, 2026
e6f8311
fix(site/src/pages/AgentsPage): make chat access denied copy permissi…
ibetitsmike Aug 25, 2026
861c378
docs(docs/ai-coder/agents): reflow prerequisites bullet to one senten…
ibetitsmike Aug 25, 2026
73e1352
fix(coderd): reject explicit grants of retired role names
ibetitsmike Aug 25, 2026
6889238
fix(coderd): extend retired-role rejection to org defaults and assign…
ibetitsmike Aug 25, 2026
af0ab29
docs(docs/ai-coder/agents): exclude service accounts from chat permis…
ibetitsmike Aug 25, 2026
e1e6f9f
fix(coderd): hide retired role names from the user-roles response
ibetitsmike Aug 25, 2026
f429c4c
fix: hide retired roles in user payloads and keep retired custom role…
ibetitsmike Aug 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(coderd): drop retired role names in rolestore expansion and API r…
…esponses
  • Loading branch information
ibetitsmike committed Aug 25, 2026
commit cbdad541b41d934694fe76569c72b4af1bd0f923
13 changes: 8 additions & 5 deletions coderd/database/db2sdk/db2sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -919,11 +919,14 @@ func Organization(organization database.Organization) codersdk.Organization {
DisplayName: organization.DisplayName,
Icon: organization.Icon,
},
Description: organization.Description,
CreatedAt: organization.CreatedAt,
UpdatedAt: organization.UpdatedAt,
IsDefault: organization.IsDefault,
DefaultOrgMemberRoles: organization.DefaultOrgMemberRoles,
Description: organization.Description,
CreatedAt: organization.CreatedAt,
UpdatedAt: organization.UpdatedAt,
IsDefault: organization.IsDefault,
// Stored default role lists may retain retired built-in role names
// until a cleanup migration lands. Hide them so settings forms do
// not display or resubmit them.
DefaultOrgMemberRoles: slices.DeleteFunc(slices.Clone(organization.DefaultOrgMemberRoles), rbac.IsLegacyRoleName),
}
}

Expand Down
8 changes: 7 additions & 1 deletion coderd/members.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"database/sql"
"fmt"
"net/http"
"slices"

"github.com/google/uuid"
"golang.org/x/xerrors"
Expand Down Expand Up @@ -510,12 +511,17 @@ func convertOrganizationMembers(ctx context.Context, db database.Store, mems []d
roleLookup := make([]database.NameOrganizationPair, 0)

for _, m := range mems {
// Stored role arrays may retain retired built-in role names until a
// cleanup migration lands. They grant nothing, so hide them from
// responses to keep role editors from displaying or resubmitting
// them.
activeRoles := slices.DeleteFunc(slices.Clone(m.Roles), rbac.IsLegacyRoleName)
converted = append(converted, codersdk.OrganizationMember{
UserID: m.UserID,
OrganizationID: m.OrganizationID,
CreatedAt: m.CreatedAt,
UpdatedAt: m.UpdatedAt,
Roles: slice.List(m.Roles, func(r string) codersdk.SlimRole {
Roles: slice.List(activeRoles, func(r string) codersdk.SlimRole {
// If it is a built-in role, no lookups are needed.
rbacRole, err := rbac.RoleByName(rbac.RoleIdentifier{Name: r, OrganizationID: m.OrganizationID})
if err == nil {
Expand Down
18 changes: 18 additions & 0 deletions coderd/members_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ func TestMembersWithLegacyRole(t *testing.T) {
// org's default member roles. The stale default must not fail it.
coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)

// Membership responses hide the stale grant so role editors do not
// display or resubmit it.
members, err := client.OrganizationMembers(ctx, owner.OrganizationID)
require.NoError(t, err)
for _, m := range members {
if m.UserID != member.ID {
continue
}
for _, role := range m.Roles {
require.NotEqual(t, "agents-access", role.Name)
}
}

// Organization responses hide the stale default role the same way.
orgResp, err := client.Organization(ctx, owner.OrganizationID)
require.NoError(t, err)
require.NotContains(t, orgResp.DefaultOrgMemberRoles, "agents-access")

// Restore the defaults so the stale grant is no longer implied and the
// next update must validate its removal.
updateOrg.DefaultOrgMemberRoles = org.DefaultOrgMemberRoles
Expand Down
8 changes: 8 additions & 0 deletions coderd/rbac/rolestore/rolestore.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ func Expand(ctx context.Context, db database.Store, names []rbac.RoleIdentifier)
roles := make([]rbac.Role, 0, len(names))

for _, name := range names {
if rbac.IsLegacyRoleName(name.Name) {
// Retired built-in role names may linger in stored role arrays
// until a cleanup migration lands. They grant nothing and stay
// reserved, so skip them instead of falling through to the
// custom-role lookup, which could resurrect an unrelated
// pre-reservation custom role with the same name.
continue
}
// Remove any built in roles
expanded, err := rbac.RoleByName(name)
if err == nil {
Expand Down
24 changes: 24 additions & 0 deletions coderd/rbac/rolestore/rolestore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,30 @@ func TestExpandCustomRoleRoles(t *testing.T) {
require.Len(t, roles, 1, "role found")
}

func TestExpandLegacyRoleName(t *testing.T) {
t.Parallel()

db, _ := dbtestutil.NewDB(t)

org := dbgen.Organization(t, db, database.Organization{})

// Simulate a custom role that took the name before it became a
// reserved built-in role name. Expanding a stored grant of the
// retired name must not resurrect the custom role.
dbgen.CustomRole(t, db, database.CustomRole{
Name: "agents-access",
OrganizationID: uuid.NullUUID{
UUID: org.ID,
Valid: true,
},
})

ctx := testutil.Context(t, testutil.WaitShort)
roles, err := rolestore.Expand(ctx, db, []rbac.RoleIdentifier{{Name: "agents-access", OrganizationID: org.ID}})
require.NoError(t, err)
require.Empty(t, roles, "retired role names expand to nothing")
}

func TestPrefetchCustomRoles(t *testing.T) {
t.Parallel()

Expand Down