- Notifications
You must be signed in to change notification settings - Fork928
feat: Add user roles, but do not yet enforce them#1200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Currently can't remove roles. So be careful
coderd/coderd.go Outdated
// TODO: @emyrk Might want to move these to a /roles group instead of /user. | ||
//As we include more roles like org roles, it makes less sense to scope these here. | ||
r.Put("/roles", api.putUserRoles) | ||
r.Get("/roles", api.getUserRoles) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'd rather not bikeshed this url placement atm. I'll move the path when I talk with FE. I know the mvp for endpoints, and will change them in another PR.
Really just trying to get some footing for roles so I can start enforcing them without breaking things.
codecovbot commentedApr 27, 2022 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Codecov Report
@@ Coverage Diff @@## main #1200 +/- ##==========================================+ Coverage 65.45% 65.59% +0.14%========================================== Files 268 269 +1 Lines 17029 17337 +308 Branches 162 162 ==========================================+ Hits 11147 11373 +226- Misses 4710 4772 +62- Partials 1172 1192 +20
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
All minor things. I'll approve once we resolve some of the outstanding q's.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
orgAdmin string = "organization-admin" | ||
orgMember string = "organization-member" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Could we reuse theadmin
andmember
strings? From what I can tell, it'll be scoped to an organization anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We totally can, they are scoped. I was adding theorganization
prefix because I imagine in the UI they will strip the "scopeID" when assigning roles. I kinda like the fact org roles have an org prefix to prevent any misunderstanding.
Eg: A dropdown list of roles you can add to a org member, will sayorganization-member
, notorganization-member:00000000-00000000-00000000-00000000
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We probably wouldn't have a single dropdown to show organization and site-level roles though, because that'd easily be misinterpreted by users IMO.
Uh oh!
There was an error while loading.Please reload this page.
coderd/rbac/builtin.go Outdated
// ListSiteRoles lists all roles that can be applied to a user. | ||
// Note: This should be a list in a database, but until then we build | ||
// the list from the builtins. | ||
func ListSiteRoles() []string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Doesn't seem this is used anywhere right now!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
It's not, but it will be when I add the endpoints for retrieving roles that can applied. I wrote this to show how to get the roles for that endpoint in this design.
When we go to a database model, these won't be dynamic lists, so all this looping goes away. I'll drop this and bring it back in my next pr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
That makes sense, thanks for the context!
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
UPDATE | ||
users | ||
SET | ||
rbac_roles = ARRAY ['member', 'organization-member:' || (SELECT id FROM organizations LIMIT 1)]; | ||
-- Give the first user created the admin role | ||
UPDATE | ||
users | ||
SET | ||
rbac_roles = rbac_roles || ARRAY ['admin'] | ||
WHERE | ||
id = (SELECT id FROM users ORDER BY created_at ASC LIMIT 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We might not want to update this data in a migration right now. I'm concerned that changing this behavior will be difficult down the road, so I'd prefer if we just straight-up broke the schema right now (eg. add therbac_roles
directly to thebase.up
migration. I'm not strict on this though, and it's just a hunch. Any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I think we should try to not break migrations, lest we become comfortable in the habit and it bite us squarely where we sit down the line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Is anyone running a persistent V2? If we are only running in dev mode, I'll drop all this.
I just didn't want to break any current deployments. But if that's cool, I'm more than happy to drop this code to assign roles in the migration 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Apparently we have a dev and QA instance, so this will be required to not totally break those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Fair enough fair enough
- Remove string type alias, use string- Drop unused funcs- Fix down migration
- UpdateRoles vs Grant/RemoveRoles- UpdateRoles and UpdateMemberRoles
@@ -0,0 +1,18 @@ | |||
ALTER TABLE ONLY users | |||
ADD COLUMN IF NOT EXISTS rbac_roles text[] DEFAULT '{}' NOT NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
TIL postgres supports native text arrays 😄
organization_members | ||
SET | ||
-- Remove all duplicates from the roles. | ||
roles = ARRAY(SELECT DISTINCT UNNEST(@granted_roles :: text[])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Neat trick! For posterity here,UNNEST
turns an array into a one-row temporary table,SELECT DISTINCT
removes duplicates, and then it just becomes an array again.
coderd/members.go Outdated
func (api *api) putMemberRoles(rw http.ResponseWriter, r *http.Request) { | ||
// User is the user to modify | ||
// TODO: Until rbac authorize is implemented, only be able to change your | ||
//own roles. This also means you can grant yourself whatever roles you want. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
nit: formatting, also "only be able to change your own roles"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yea, sinceauthorize
is not yet used, I let you change your roles to w/e you want. This is what we are doing for a lot of user endpoints atm
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
} | ||
// UpdateOrganizationMemberRoles grants the userID the specified roles in an org. | ||
// Include ALL roles the user has. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
clarification: if a user has roles{A, B, C}
and we callUpdateUserRoles
with{D}
, does this mean the user ends up with just{D}
and not{A, B, C, D}
? That seems like a sharp edge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is correct. I actually had it asgrant D
before, but if we match the current UI, it actually makes sense to pass{A, B, C, D}
.
The alternative is to run the diff from the UI as 2 requests.
PUT
{D}
DELETE
{A, B, C}
I think we can implement this logic better in the BE. I could add a route/query param to "Add" the role vs update for example. I think this is something we can make easier once the UI needs are better understood too. But w/e the end result is, the database call is ok to do anALL
, and let the Golang figure out the diffs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The separation of user and organization roles in the API feels really nice. Great work 🥳🥳🥳
* chore: Rework roles to be expandable by name alone
What this does
Adds some builtin roles and assigns them to users and org members. This does not implement enforcing roles at this time.
Granting user's roles was added to test the api. See how to grant roles from the SDK. The "strange" part is that the
rbac
library is used to find the role name. In practice, there will be an endpoint to list all roles that can be granted, and the user will select from a list. The code for this exists, but I want to add this in future PRs as I work with the FE on endpoint format.coder/coderd/users_test.go
Lines 326 to 330 ina643670
Future Work