fix(enterprise/coderd): reject case variants of built-in role names

Custom role names are stored lowercase, so a custom role named Agents-Access became an agents-access role that the built-in role shadowed and that could not be deleted.
This commit is contained in:
Michael Suchacz
2026-09-27 06:25:05 +00:00
parent a6fef66b3f
commit fb441dfae5
2 changed files with 13 additions and 2 deletions
+3 -2
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"strings"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
@@ -291,8 +292,8 @@ func sdkPermissionToDB(p codersdk.Permission) database.CustomRolePermission {
func validOrganizationRoleRequest(ctx context.Context, req codersdk.CustomRoleRequest, rw http.ResponseWriter) bool {
// This check is not ideal, but we cannot enforce a unique role name in the db against
// the built-in role names.
if rbac.ReservedRoleName(req.Name) {
// the built-in role names. Custom role names are stored lowercase.
if rbac.ReservedRoleName(strings.ToLower(req.Name)) {
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
Message: "Reserved role name",
Detail: fmt.Sprintf("%q is a reserved role name, and not allowed to be used", req.Name),
+10
View File
@@ -225,6 +225,16 @@ func TestCustomOrganizationRole(t *testing.T) {
OrganizationID: first.OrganizationID.String(),
})
require.ErrorContains(t, err, "Reserved")
// Custom role names are stored lowercase, so a case variant would
// shadow the built-in role.
//nolint:gocritic // owner is required for this
_, err = owner.CreateOrganizationRole(ctx, codersdk.Role{
Name: "Agents-Access",
DisplayName: "Testing Purposes",
OrganizationID: first.OrganizationID.String(),
})
require.ErrorContains(t, err, "Reserved")
})
// Attempt to add site & user permissions, which is not allowed