Skip to content

Commit 49dd486

Browse files
committed
WIP
1 parent 6291783 commit 49dd486

File tree

8 files changed

+81
-14
lines changed

8 files changed

+81
-14
lines changed

coderd/database/dbauthz/customroles_test.go

Lines changed: 14 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,19 @@ func TestUpsertCustomRoles(t *testing.T) {
243243
require.ErrorContains(t, err, tc.errorContains)
244244
} else {
245245
require.NoError(t, err)
246+
247+
roles, err := az.CustomRoles(ctx, database.CustomRolesParams{
248+
LookupRoles: []database.NameOrganizationPair{
249+
{
250+
Name: "test-role",
251+
OrganizationID: tc.organizationID.UUID,
252+
},
253+
},
254+
ExcludeOrgRoles: false,
255+
OrganizationID: uuid.UUID{},
256+
})
257+
require.NoError(t, err)
258+
require.Len(t, roles, 1)
246259
}
247260
})
248261
}

coderd/database/dbmem/dbmem.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,8 +1186,16 @@ 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-
return strings.EqualFold(s, role.Name)
1189+
if !slices.ContainsFunc(arg.LookupRoles, func(s database.NameOrganizationPair) bool {
1190+
if !strings.EqualFold(s.Name, role.Name) {
1191+
return false
1192+
}
1193+
1194+
if s.OrganizationID == uuid.Nil {
1195+
return true
1196+
}
1197+
1198+
return s.OrganizationID == arg.OrganizationID
11911199
}) {
11921200
continue
11931201
}

coderd/database/migrations/000216_org_custom_role_audit.up.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
-- A role does not need to belong to an organization
2+
ALTER TABLE custom_roles ALTER COLUMN organization_id DROP NOT NULL;
3+
14
-- (name) is the primary key, this column is almost exclusively for auditing.
25
ALTER TABLE custom_roles ADD COLUMN id uuid DEFAULT gen_random_uuid() NOT NULL;
36

coderd/database/queries.sql.go

Lines changed: 5 additions & 8 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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ WHERE
77
true
88
-- Lookup roles filter expects the role names to be in the rbac package
99
-- format. Eg: name[:<organization_id>]
10-
AND CASE WHEN array_length(@lookup_roles :: text[], 1) > 0 THEN
11-
name ILIKE ANY(@lookup_roles :: text [])
10+
AND CASE WHEN array_length(@lookup_roles :: name_organization_pair_list[], 1) > 0 THEN
11+
(name, organization_id) ILIKE ANY (@lookup_roles::name_organization_pair_list[])
1212
ELSE true
1313
END
1414
-- Org scoping filter, to only fetch site wide roles

coderd/database/sqlc.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ sql:
2828
emit_enum_valid_method: true
2929
emit_all_enum_values: true
3030
overrides:
31+
- db_type: "name_organization_pair_list"
32+
go_type:
33+
type: "NameOrganizationPair"
3134
- column: "custom_roles.site_permissions"
3235
go_type:
3336
type: "CustomRolePermissions"

coderd/database/types.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,26 @@ func (m StringMapOfInt) Value() (driver.Value, error) {
113113
return json.Marshal(m)
114114
}
115115

116+
// NameOrganizationPair is used as a lookup tuple for custom role rows.
117+
type NameOrganizationPair struct {
118+
Name string `db:"name" json:"name"`
119+
// OrganizationID if unset will assume a null column value
120+
OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"`
121+
}
122+
123+
func (a *NameOrganizationPair) Scan(src interface{}) error {
124+
return xerrors.Errorf("unexpected type %T", src)
125+
}
126+
127+
func (a NameOrganizationPair) Value() (driver.Value, error) {
128+
var orgID interface{} = a.OrganizationID
129+
if a.OrganizationID == uuid.Nil {
130+
orgID = nil
131+
}
132+
133+
return []interface{}{a.Name, orgID}, nil
134+
}
135+
116136
type CustomRolePermissions []CustomRolePermission
117137

118138
func (a *CustomRolePermissions) Scan(src interface{}) error {

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)