Skip to content

Commit 8e98cea

Browse files
committed
chore: sql parameter to custom roles to be a (name,org) tuple
1 parent 8f62311 commit 8e98cea

File tree

7 files changed

+86
-28
lines changed

7 files changed

+86
-28
lines changed

coderd/database/dbauthz/customroles_test.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func TestUpsertCustomRoles(t *testing.T) {
3838
Name: "can-assign",
3939
DisplayName: "",
4040
Site: rbac.Permissions(map[string][]policy.Action{
41-
rbac.ResourceAssignRole.Type: {policy.ActionCreate},
41+
rbac.ResourceAssignRole.Type: {policy.ActionRead, policy.ActionCreate},
4242
}),
4343
}
4444

@@ -243,6 +243,20 @@ func TestUpsertCustomRoles(t *testing.T) {
243243
require.ErrorContains(t, err, tc.errorContains)
244244
} else {
245245
require.NoError(t, err)
246+
247+
// Verify we can fetch the role
248+
roles, err := az.CustomRoles(ctx, database.CustomRolesParams{
249+
LookupRoles: []database.NameOrganizationPair{
250+
{
251+
Name: "test-role",
252+
OrganizationID: tc.organizationID.UUID,
253+
},
254+
},
255+
ExcludeOrgRoles: false,
256+
OrganizationID: uuid.UUID{},
257+
})
258+
require.NoError(t, err)
259+
require.Len(t, roles, 1)
246260
}
247261
})
248262
}

coderd/database/dbmem/dbmem.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,12 +1186,17 @@ func (q *FakeQuerier) CustomRoles(_ context.Context, arg database.CustomRolesPar
11861186
for _, role := range q.data.customRoles {
11871187
role := role
11881188
if len(arg.LookupRoles) > 0 {
1189-
if !slices.ContainsFunc(arg.LookupRoles, func(s string) bool {
1190-
roleName := rbac.RoleName(role.Name, "")
1191-
if role.OrganizationID.UUID != uuid.Nil {
1192-
roleName = rbac.RoleName(role.Name, role.OrganizationID.UUID.String())
1189+
if !slices.ContainsFunc(arg.LookupRoles, func(pair database.NameOrganizationPair) bool {
1190+
if !strings.EqualFold(pair.Name, role.Name) {
1191+
return false
11931192
}
1194-
return strings.EqualFold(s, roleName)
1193+
1194+
if role.OrganizationID.Valid {
1195+
// Expect org match
1196+
return role.OrganizationID.UUID == pair.OrganizationID
1197+
}
1198+
// Expect no org
1199+
return pair.OrganizationID == uuid.Nil
11951200
}) {
11961201
continue
11971202
}

coderd/database/queries.sql.go

Lines changed: 8 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/roles.sql

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,16 @@ FROM
55
custom_roles
66
WHERE
77
true
8-
-- Lookup roles filter expects the role names to be in the rbac package
9-
-- format. Eg: name[:<organization_id>]
10-
AND CASE WHEN array_length(@lookup_roles :: text[], 1) > 0 THEN
11-
-- Case insensitive lookup with org_id appended (if non-null).
12-
-- This will return just the name if org_id is null. It'll append
13-
-- the org_id if not null
14-
concat(name, NULLIF(concat(':', organization_id), ':')) ILIKE ANY(@lookup_roles :: text [])
15-
ELSE true
8+
-- @lookup_roles will filter for exact (role_name, org_id) pairs
9+
AND CASE WHEN array_length(@lookup_roles :: name_organization_pair_list[], 1) > 0 THEN
10+
(name, organization_id) ILIKE ANY (@lookup_roles::name_organization_pair_list[])
1611
END
17-
-- Org scoping filter, to only fetch site wide roles
12+
-- This allows fetching all roles, or just site wide roles
1813
AND CASE WHEN @exclude_org_roles :: boolean THEN
1914
organization_id IS null
2015
ELSE true
2116
END
17+
-- Allows fetching all roles to a particular organization
2218
AND CASE WHEN @organization_id :: uuid != '00000000-0000-0000-0000-000000000000'::uuid THEN
2319
organization_id = @organization_id
2420
ELSE true

coderd/database/sqlc.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ sql:
2828
emit_enum_valid_method: true
2929
emit_all_enum_values: true
3030
overrides:
31+
# Used in 'CustomRoles' query to filter by (name,organization_id)
32+
- db_type: "name_organization_pair_list"
33+
go_type:
34+
type: "NameOrganizationPair"
3135
- column: "custom_roles.site_permissions"
3236
go_type:
3337
type: "CustomRolePermissions"

coderd/database/types.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,23 @@ func (a CustomRolePermission) String() string {
142142
}
143143
return str
144144
}
145+
146+
// NameOrganizationPair is used as a lookup tuple for custom role rows.
147+
type NameOrganizationPair struct {
148+
Name string `db:"name" json:"name"`
149+
// OrganizationID if unset will assume a null column value
150+
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
151+
}
152+
153+
func (a *NameOrganizationPair) Scan(_ interface{}) error {
154+
return xerrors.Errorf("this should never happen, type 'NameOrganizationPair' should only be used as a parameter")
155+
}
156+
157+
func (a NameOrganizationPair) Value() (driver.Value, error) {
158+
var orgID interface{} = a.OrganizationID
159+
if a.OrganizationID == uuid.Nil {
160+
orgID = nil
161+
}
162+
163+
return []interface{}{a.Name, orgID}, nil
164+
}

coderd/rbac/rolestore/rolestore.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,34 @@ func Expand(ctx context.Context, db database.Store, names []string) (rbac.Roles,
6969
}
7070

7171
if len(lookup) > 0 {
72+
// The set of roles coming in are formatted as 'rolename[:<org_id>]'.
73+
// In the database, org roles are scoped with an organization column.
74+
lookupArgs := make([]database.NameOrganizationPair, 0, len(lookup))
75+
for _, name := range lookup {
76+
roleName, orgID, err := rbac.RoleSplit(name)
77+
if err != nil {
78+
continue
79+
}
80+
81+
parsedOrgID := uuid.Nil // Default to no org ID
82+
if orgID != "" {
83+
parsedOrgID, err = uuid.Parse(orgID)
84+
if err != nil {
85+
continue
86+
}
87+
}
88+
89+
lookupArgs = append(lookupArgs, database.NameOrganizationPair{
90+
Name: roleName,
91+
OrganizationID: parsedOrgID,
92+
})
93+
}
94+
7295
// If some roles are missing from the database, they are omitted from
7396
// the expansion. These roles are no-ops. Should we raise some kind of
7497
// warning when this happens?
7598
dbroles, err := db.CustomRoles(ctx, database.CustomRolesParams{
76-
LookupRoles: lookup,
99+
LookupRoles: lookupArgs,
77100
ExcludeOrgRoles: false,
78101
OrganizationID: uuid.Nil,
79102
})

0 commit comments

Comments
 (0)