@@ -20,6 +20,11 @@ const (
20
20
orgMember string = "organization-member"
21
21
)
22
22
23
+ func init () {
24
+ // Always load defaults
25
+ ReloadBuiltinRoles (nil )
26
+ }
27
+
23
28
// RoleNames is a list of user assignable role names. The role names must be
24
29
// in the builtInRoles map. Any non-user assignable roles will generate an
25
30
// error on Expand.
@@ -62,6 +67,33 @@ func RoleOrgMember(organizationID uuid.UUID) string {
62
67
return roleName (orgMember , organizationID .String ())
63
68
}
64
69
70
+ func allPermsExcept (excepts ... Object ) []Permission {
71
+ resources := AllResources ()
72
+ var perms []Permission
73
+ skip := make (map [string ]bool )
74
+ for _ , e := range excepts {
75
+ skip [e .Type ] = true
76
+ }
77
+
78
+ for _ , r := range resources {
79
+ // Exceptions
80
+ if skip [r .Type ] {
81
+ continue
82
+ }
83
+ // Do not include the wildcard
84
+ if r .Type == ResourceWildcard .Type {
85
+ continue
86
+ }
87
+ // Owners can do everything else
88
+ perms = append (perms , Permission {
89
+ Negate : false ,
90
+ ResourceType : r .Type ,
91
+ Action : WildcardSymbol ,
92
+ })
93
+ }
94
+ return perms
95
+ }
96
+
65
97
// builtInRoles are just a hard coded set for now. Ideally we store these in
66
98
// the database. Right now they are functions because the org id should scope
67
99
// certain roles. When we store them in the database, each organization should
@@ -70,162 +102,162 @@ func RoleOrgMember(organizationID uuid.UUID) string {
70
102
//
71
103
// This map will be replaced by database storage defined by this ticket.
72
104
// https://github.com/coder/coder/issues/1194
73
- var builtInRoles = map [string ]func (orgID string ) Role {
74
- // admin grants all actions to all resources.
75
- owner : func (_ string ) Role {
76
- return Role {
77
- Name : owner ,
78
- DisplayName : "Owner" ,
79
- Site : func () []Permission {
80
- // Owner can do all actions on all resources, minus some exceptions.
81
- resources := AllResources ()
82
- var perms []Permission
83
-
84
- for _ , r := range resources {
85
- // Exceptions
86
- if r .Equal (ResourceWildcard ) ||
87
- r .Equal (ResourceWorkspaceExecution ) {
88
- continue
89
- }
90
- // Owners can do everything else
91
- perms = append (perms , Permission {
92
- Negate : false ,
93
- ResourceType : r .Type ,
94
- Action : WildcardSymbol ,
95
- })
96
- }
97
- return perms
98
- }(),
99
- Org : map [string ][]Permission {},
100
- User : []Permission {},
101
- }
102
- },
105
+ var builtInRoles map [string ]func (orgID string ) Role
103
106
104
- // member grants all actions to all resources owned by the user
105
- member : func (_ string ) Role {
106
- return Role {
107
- Name : member ,
108
- DisplayName : "" ,
109
- Site : Permissions (map [string ][]Action {
110
- // All users can read all other users and know they exist.
111
- ResourceUser .Type : {ActionRead },
112
- ResourceRoleAssignment .Type : {ActionRead },
113
- // All users can see the provisioner daemons.
114
- ResourceProvisionerDaemon .Type : {ActionRead },
115
- }),
116
- Org : map [string ][]Permission {},
117
- User : Permissions (map [string ][]Action {
118
- ResourceWildcard .Type : {WildcardSymbol },
119
- }),
120
- }
121
- },
122
-
123
- // auditor provides all permissions required to effectively read and understand
124
- // audit log events.
125
- // TODO: Finish the auditor as we add resources.
126
- auditor : func (_ string ) Role {
127
- return Role {
128
- Name : auditor ,
129
- DisplayName : "Auditor" ,
130
- Site : Permissions (map [string ][]Action {
131
- // Should be able to read all template details, even in orgs they
132
- // are not in.
133
- ResourceTemplate .Type : {ActionRead },
134
- ResourceAuditLog .Type : {ActionRead },
135
- }),
136
- Org : map [string ][]Permission {},
137
- User : []Permission {},
138
- }
139
- },
107
+ type RoleOptions struct {
108
+ NoOwnerWorkspaceExec bool
109
+ }
140
110
141
- templateAdmin : func (_ string ) Role {
142
- return Role {
143
- Name : templateAdmin ,
144
- DisplayName : "Template Admin" ,
145
- Site : Permissions (map [string ][]Action {
146
- ResourceTemplate .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
147
- // CRUD all files, even those they did not upload.
148
- ResourceFile .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
149
- ResourceWorkspace .Type : {ActionRead },
150
- // CRUD to provisioner daemons for now.
151
- ResourceProvisionerDaemon .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
152
- // Needs to read all organizations since
153
- ResourceOrganization .Type : {ActionRead },
154
- }),
155
- Org : map [string ][]Permission {},
156
- User : []Permission {},
157
- }
158
- },
111
+ // ReloadBuiltinRoles loads the static roles into the builtInRoles map.
112
+ // This can be called again with a different config to change the behavior.
113
+ //
114
+ // TODO: @emyrk This would be great if it was instanced to a coderd rather
115
+ // than a global. But that is a much larger refactor right now.
116
+ // Essentially we did not foresee different deployments needing slightly
117
+ // different role permissions.
118
+ func ReloadBuiltinRoles (opts * RoleOptions ) {
119
+ if opts == nil {
120
+ opts = & RoleOptions {}
121
+ }
159
122
160
- userAdmin : func (_ string ) Role {
161
- return Role {
162
- Name : userAdmin ,
163
- DisplayName : "User Admin" ,
164
- Site : Permissions (map [string ][]Action {
165
- ResourceRoleAssignment .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
166
- ResourceUser .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
167
- // Full perms to manage org members
168
- ResourceOrganizationMember .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
169
- ResourceGroup .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
170
- }),
171
- Org : map [string ][]Permission {},
172
- User : []Permission {},
173
- }
174
- },
123
+ var ownerAndAdminExceptions []Object
124
+ if opts .NoOwnerWorkspaceExec {
125
+ ownerAndAdminExceptions = append (ownerAndAdminExceptions , ResourceWorkspaceExecution )
126
+ }
175
127
176
- // orgAdmin returns a role with all actions allows in a given
177
- // organization scope.
178
- orgAdmin : func (organizationID string ) Role {
179
- return Role {
180
- Name : roleName (orgAdmin , organizationID ),
181
- DisplayName : "Organization Admin" ,
182
- Site : []Permission {},
183
- Org : map [string ][]Permission {
184
- organizationID : {
185
- {
186
- Negate : false ,
187
- ResourceType : "*" ,
188
- Action : "*" ,
189
- },
128
+ builtInRoles = map [string ]func (orgID string ) Role {
129
+ // admin grants all actions to all resources.
130
+ owner : func (_ string ) Role {
131
+ return Role {
132
+ Name : owner ,
133
+ DisplayName : "Owner" ,
134
+ Site : allPermsExcept (ownerAndAdminExceptions ... ),
135
+ Org : map [string ][]Permission {},
136
+ User : []Permission {},
137
+ }
138
+ },
139
+
140
+ // member grants all actions to all resources owned by the user
141
+ member : func (_ string ) Role {
142
+ return Role {
143
+ Name : member ,
144
+ DisplayName : "" ,
145
+ Site : Permissions (map [string ][]Action {
146
+ // All users can read all other users and know they exist.
147
+ ResourceUser .Type : {ActionRead },
148
+ ResourceRoleAssignment .Type : {ActionRead },
149
+ // All users can see the provisioner daemons.
150
+ ResourceProvisionerDaemon .Type : {ActionRead },
151
+ }),
152
+ Org : map [string ][]Permission {},
153
+ User : Permissions (map [string ][]Action {
154
+ ResourceWildcard .Type : {WildcardSymbol },
155
+ }),
156
+ }
157
+ },
158
+
159
+ // auditor provides all permissions required to effectively read and understand
160
+ // audit log events.
161
+ // TODO: Finish the auditor as we add resources.
162
+ auditor : func (_ string ) Role {
163
+ return Role {
164
+ Name : auditor ,
165
+ DisplayName : "Auditor" ,
166
+ Site : Permissions (map [string ][]Action {
167
+ // Should be able to read all template details, even in orgs they
168
+ // are not in.
169
+ ResourceTemplate .Type : {ActionRead },
170
+ ResourceAuditLog .Type : {ActionRead },
171
+ }),
172
+ Org : map [string ][]Permission {},
173
+ User : []Permission {},
174
+ }
175
+ },
176
+
177
+ templateAdmin : func (_ string ) Role {
178
+ return Role {
179
+ Name : templateAdmin ,
180
+ DisplayName : "Template Admin" ,
181
+ Site : Permissions (map [string ][]Action {
182
+ ResourceTemplate .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
183
+ // CRUD all files, even those they did not upload.
184
+ ResourceFile .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
185
+ ResourceWorkspace .Type : {ActionRead },
186
+ // CRUD to provisioner daemons for now.
187
+ ResourceProvisionerDaemon .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
188
+ // Needs to read all organizations since
189
+ ResourceOrganization .Type : {ActionRead },
190
+ }),
191
+ Org : map [string ][]Permission {},
192
+ User : []Permission {},
193
+ }
194
+ },
195
+
196
+ userAdmin : func (_ string ) Role {
197
+ return Role {
198
+ Name : userAdmin ,
199
+ DisplayName : "User Admin" ,
200
+ Site : Permissions (map [string ][]Action {
201
+ ResourceRoleAssignment .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
202
+ ResourceUser .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
203
+ // Full perms to manage org members
204
+ ResourceOrganizationMember .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
205
+ ResourceGroup .Type : {ActionCreate , ActionRead , ActionUpdate , ActionDelete },
206
+ }),
207
+ Org : map [string ][]Permission {},
208
+ User : []Permission {},
209
+ }
210
+ },
211
+
212
+ // orgAdmin returns a role with all actions allows in a given
213
+ // organization scope.
214
+ orgAdmin : func (organizationID string ) Role {
215
+ return Role {
216
+ Name : roleName (orgAdmin , organizationID ),
217
+ DisplayName : "Organization Admin" ,
218
+ Site : []Permission {},
219
+ Org : map [string ][]Permission {
220
+ // Org admins should not have workspace exec perms.
221
+ organizationID : allPermsExcept (ResourceWorkspaceExecution ),
190
222
},
191
- },
192
- User : [] Permission {},
193
- }
194
- },
195
-
196
- // orgMember has an empty set of permissions, this just implies their membership
197
- // in an organization.
198
- orgMember : func ( organizationID string ) Role {
199
- return Role {
200
- Name : roleName ( orgMember , organizationID ) ,
201
- DisplayName : "" ,
202
- Site : [] Permission {},
203
- Org : map [ string ][] Permission {
204
- organizationID : {
205
- {
206
- // All org members can read the other members in their org.
207
- ResourceType : ResourceOrganizationMember . Type ,
208
- Action : ActionRead ,
209
- },
210
- {
211
- // All org members can read the organization
212
- ResourceType : ResourceOrganization . Type ,
213
- Action : ActionRead ,
214
- },
215
- {
216
- // Can read available roles.
217
- ResourceType : ResourceOrgRoleAssignment . Type ,
218
- Action : ActionRead ,
219
- },
220
- {
221
- ResourceType : ResourceGroup . Type ,
222
- Action : ActionRead ,
223
+ User : [] Permission { },
224
+ }
225
+ },
226
+
227
+ // orgMember has an empty set of permissions, this just implies their membership
228
+ // in an organization.
229
+ orgMember : func ( organizationID string ) Role {
230
+ return Role {
231
+ Name : roleName ( orgMember , organizationID ),
232
+ DisplayName : "" ,
233
+ Site : [] Permission {} ,
234
+ Org : map [ string ][] Permission {
235
+ organizationID : {
236
+ {
237
+ // All org members can read the other members in their org.
238
+ ResourceType : ResourceOrganizationMember . Type ,
239
+ Action : ActionRead ,
240
+ } ,
241
+ {
242
+ // All org members can read the organization
243
+ ResourceType : ResourceOrganization . Type ,
244
+ Action : ActionRead ,
245
+ } ,
246
+ {
247
+ // Can read available roles.
248
+ ResourceType : ResourceOrgRoleAssignment . Type ,
249
+ Action : ActionRead ,
250
+ } ,
251
+ {
252
+ ResourceType : ResourceGroup . Type ,
253
+ Action : ActionRead ,
254
+ } ,
223
255
},
224
256
},
225
- },
226
- User : [] Permission {},
227
- }
228
- },
257
+ User : [] Permission { },
258
+ }
259
+ },
260
+ }
229
261
}
230
262
231
263
// assignRoles is a map of roles that can be assigned if a user has a given
0 commit comments