Skip to content

feat: add template RBAC/groups #4235

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 161 commits into from
Oct 10, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
161 commits
Select commit Hold shift + click to select a range
5a47132
feat: Add ACL list support to rego objects
Emyrk Sep 13, 2022
03f69bf
Add unit tests
Emyrk Sep 13, 2022
91a358d
Rename ACL list
Emyrk Sep 13, 2022
8f837b7
Flip rego json to key by user id
Emyrk Sep 15, 2022
8378c9b
feat: add template ACL
sreya Sep 17, 2022
54a0d13
add down migration
sreya Sep 19, 2022
72ea751
remove unused file
sreya Sep 19, 2022
d533a16
undo insert templates query change
sreya Sep 19, 2022
f56fcf9
add patch endpoint tests
sreya Sep 19, 2022
f162694
Unit test use shadowed copied value
Emyrk Sep 19, 2022
ea25c08
Allow wildcards for ACL list
Emyrk Sep 19, 2022
5a081eb
fix authorize bug
sreya Sep 19, 2022
072b3e4
feat: Allow filter to accept objects of multiple types
Emyrk Sep 19, 2022
205c36c
add support for private templates
sreya Sep 19, 2022
ba32928
go.mod
sreya Sep 19, 2022
5c6344f
Merge branch 'main' into resource_acl_list
sreya Sep 19, 2022
ef15908
fix rbac merge woes
sreya Sep 19, 2022
8ab5200
update migration
sreya Sep 19, 2022
c040e8e
fix workspaces_test
sreya Sep 19, 2022
1f4ceee
remove sqlx
sreya Sep 19, 2022
7cc71e1
fix audit
sreya Sep 19, 2022
131d5ed
fix lint
sreya Sep 19, 2022
8c3ee6a
Revert "remove sqlx"
sreya Sep 19, 2022
fe2af91
add test for list templates
sreya Sep 20, 2022
0218c4e
fix error msg
sreya Sep 20, 2022
6883106
fix sqlx woes
sreya Sep 20, 2022
4fbd9be
fix lint
sreya Sep 20, 2022
c96a6ca
fix audit
sreya Sep 20, 2022
57ba8b3
make gen
sreya Sep 20, 2022
c66d247
Merge branch 'main' into resource_acl_list
sreya Sep 20, 2022
0af367a
fix merge woes
sreya Sep 20, 2022
f6c3f51
fix test template
sreya Sep 20, 2022
6e72286
fmt
sreya Sep 20, 2022
44bcbde
Add base layout
BrunoQuaresma Sep 21, 2022
0f80beb
Add table
BrunoQuaresma Sep 21, 2022
d274d62
Add search user
BrunoQuaresma Sep 21, 2022
943c76b
Add user role
BrunoQuaresma Sep 21, 2022
7f7f1d3
Add update and delete
BrunoQuaresma Sep 21, 2022
967a1a9
Fix summary view
BrunoQuaresma Sep 21, 2022
1324991
Merge branch 'resource_acl_list' of github.com:coder/coder into resou…
BrunoQuaresma Sep 21, 2022
bd34d20
Merge branch 'resource_acl_list' of github.com:coder/coder into resou…
sreya Sep 22, 2022
5982dd3
add schema for groups
sreya Sep 22, 2022
c759d99
add skeleton for group API routes
sreya Sep 22, 2022
4169569
add create group endpoint
sreya Sep 22, 2022
a8943c9
add group httpmw
sreya Sep 22, 2022
9fbc15f
add patch group endpoint
sreya Sep 22, 2022
baaf445
add test pkg for opening database
sreya Sep 22, 2022
4f1a308
test: Add unit test to exercise roles query with multiple orgs
Emyrk Sep 22, 2022
f98c3b7
feat: Add group support to rego policy
Emyrk Sep 22, 2022
930cdf6
Add query to include group fetch
Emyrk Sep 22, 2022
b26cd97
Fix auth query
Emyrk Sep 22, 2022
bf13f37
add patch group endpoint w/ tests
sreya Sep 22, 2022
eea0aee
add get group endpoint w/ tests
sreya Sep 22, 2022
d70911b
add groups endpoint with tests
sreya Sep 22, 2022
ba1953a
Add groups to rego objects
Emyrk Sep 22, 2022
7544e37
fix: Group ACL list fixed
Emyrk Sep 22, 2022
ff9d968
add delete group endpoint
sreya Sep 22, 2022
7f2de03
Merge branch 'groups' of github.com:coder/coder into groups
sreya Sep 22, 2022
8cf12e9
Merge remote-tracking branch 'origin/main' into groups
Emyrk Sep 23, 2022
ea84bc6
Fix authorize calls for group endpoints
Emyrk Sep 23, 2022
f28156f
Merge remote-tracking branch 'origin/main' into groups
Emyrk Sep 26, 2022
759bddf
Fix FE errors
BrunoQuaresma Sep 26, 2022
0e2cb22
Fix migration name
BrunoQuaresma Sep 26, 2022
41b79b6
Scopes broke ACL. Fixing unit tests.
Emyrk Sep 26, 2022
7297c3c
fix: Fix acl list rego policy
Emyrk Sep 26, 2022
dc65257
Remove need to be in the org for the group to work in the rego
Emyrk Sep 26, 2022
d50a0c5
Add group ACL unit test
Emyrk Sep 26, 2022
7375484
update uuid -> id
sreya Sep 26, 2022
d70664d
make gen
sreya Sep 26, 2022
3dac95a
Add index page for groups
BrunoQuaresma Sep 26, 2022
5ac06fb
Merge branch 'groups' of github.com:coder/coder into groups
BrunoQuaresma Sep 26, 2022
2c4fd8d
Add create group page
BrunoQuaresma Sep 26, 2022
cb1464f
Remove filter's ability to filter multiple object types
Emyrk Sep 26, 2022
c2e1196
Merge remote-tracking branch 'origin/main' into groups
Emyrk Sep 26, 2022
afe328b
groups changes
sreya Sep 26, 2022
85e05c3
Merge branch 'groups' of github.com:coder/coder into groups
BrunoQuaresma Sep 26, 2022
e0ea8ec
Add user auto complete component
BrunoQuaresma Sep 26, 2022
82b1faf
add groups acl
sreya Sep 27, 2022
6505039
Add member to the group
BrunoQuaresma Sep 27, 2022
7e98ca8
Refactor loader
BrunoQuaresma Sep 27, 2022
4bb1e5f
Add empty state
BrunoQuaresma Sep 27, 2022
cba7065
Remove members from group
BrunoQuaresma Sep 27, 2022
d6b7f42
Merge branch 'main' of github.com:coder/coder into groups
BrunoQuaresma Sep 27, 2022
9dee125
Fix migrations
BrunoQuaresma Sep 27, 2022
883b28c
Merge branch 'groups' of github.com:coder/coder into groups
sreya Sep 27, 2022
a27d364
Update autocomplete and update verbiage
BrunoQuaresma Sep 27, 2022
11690bc
Adjust autocomplete height
BrunoQuaresma Sep 27, 2022
c18379e
Merge branch 'groups' of github.com:coder/coder into groups
sreya Sep 27, 2022
53ff126
prevent duplicate group adds
sreya Sep 27, 2022
5180608
Delete a group
BrunoQuaresma Sep 27, 2022
7770498
Merge branch 'groups' of github.com:coder/coder into groups
BrunoQuaresma Sep 27, 2022
9aa686b
Add group settings
BrunoQuaresma Sep 27, 2022
5e956c1
Fix loader
BrunoQuaresma Sep 27, 2022
d08bd75
Add implied all_users to org members
Emyrk Sep 27, 2022
876a7c7
Move groups to users page with tabs
BrunoQuaresma Sep 27, 2022
9c9e9c0
Improve groups table
BrunoQuaresma Sep 27, 2022
3ee20a3
add all users group
sreya Sep 27, 2022
3ea5793
add endpoints for patching template groups
sreya Sep 27, 2022
fc4c275
Merge branch 'groups' of github.com:coder/coder into groups
sreya Sep 28, 2022
6379c7b
make gen
sreya Sep 28, 2022
6aa1712
Merge branch 'main' into groups
sreya Sep 28, 2022
b0fc388
fix tests
sreya Sep 28, 2022
7d1ce8b
fix migration
sreya Sep 28, 2022
200ea81
fix migration (again)
sreya Sep 28, 2022
9f344fc
feat: move groups/template RBAC to enterprise folder (#4236)
sreya Sep 28, 2022
b763bc2
chore: update TemplateRole names (#4248)
sreya Sep 28, 2022
0ba4465
add custom group access test (#4254)
sreya Sep 29, 2022
9662a3b
refactor all users to behave the same as any other group (#4266)
sreya Sep 29, 2022
58679e5
filter deleted/suspended users (#4271)
sreya Sep 30, 2022
248a3f3
Update FE to use Template ACL and Groups (#4267)
BrunoQuaresma Sep 30, 2022
a0c8571
Merge branch 'main' of github.com:coder/coder into groups
BrunoQuaresma Sep 30, 2022
08805b3
allow org members to read all groups (#4277)
sreya Sep 30, 2022
845d81f
populate template acl group with members (#4279)
sreya Sep 30, 2022
564928e
chore: Minor rego optimization by removing excessive queries (#4275)
Emyrk Sep 30, 2022
38cce76
feat: Add resource_id option to authcheck (#4278)
Emyrk Sep 30, 2022
dac034f
Merge branch 'main' of github.com:coder/coder into groups
BrunoQuaresma Sep 30, 2022
a59138a
Add group for authcheck
Emyrk Oct 3, 2022
a50af85
chore: Update permissions (#4337)
BrunoQuaresma Oct 3, 2022
993ee32
filter deleted/suspended users for groups (#4343)
sreya Oct 3, 2022
a52203d
rm extraneous filter (#4272)
sreya Oct 3, 2022
bfa35e3
merge main into groups (#4349)
sreya Oct 3, 2022
1c461f7
add groups to license entitlements (#4345)
sreya Oct 3, 2022
c5ecbf4
omit all users from groups endpoint (#4350)
sreya Oct 3, 2022
f0f5a93
Add paywall into the entitlements
BrunoQuaresma Oct 4, 2022
efd1ed2
Merge remote-tracking branch 'origin/main' into groups
Emyrk Oct 4, 2022
cbaafca
Fix rego -> SQL in acl cases with string literals
Emyrk Oct 4, 2022
f20b783
Merge branch 'main' of github.com:coder/coder into groups
BrunoQuaresma Oct 4, 2022
cc2138d
Use rego to eval, not custom
Emyrk Oct 4, 2022
fd0b43a
Fix Navbar tests
BrunoQuaresma Oct 4, 2022
5997317
Fix UsersPage test
BrunoQuaresma Oct 4, 2022
0cf3784
Merge branch 'groups' of github.com:coder/coder into groups
BrunoQuaresma Oct 4, 2022
7c76bc0
Fix Template tests
BrunoQuaresma Oct 4, 2022
b77eeaf
Regenerate types
BrunoQuaresma Oct 4, 2022
0afc361
Remove type generation
BrunoQuaresma Oct 4, 2022
461cb8a
Switch to NoACL config as those columns do not exist
Emyrk Oct 4, 2022
620c384
Fix service extension
BrunoQuaresma Oct 4, 2022
e7f72af
Merge branch 'groups' of github.com:coder/coder into groups
BrunoQuaresma Oct 4, 2022
b920801
fix lint
sreya Oct 4, 2022
9bfa415
add test for creating a forbidden template (#4371)
sreya Oct 5, 2022
22db0d2
migrate existing templates (#4353)
sreya Oct 5, 2022
e0c90ef
Fix routes
BrunoQuaresma Oct 5, 2022
f0fd9a0
Add GroupsPage storybook
BrunoQuaresma Oct 6, 2022
20670f1
Add CreateGroupPage stories
BrunoQuaresma Oct 6, 2022
09c6771
Add Settings Group Page stories
BrunoQuaresma Oct 6, 2022
f8a7b7e
Add template permissions stories
BrunoQuaresma Oct 6, 2022
b86abcf
Fix FE
BrunoQuaresma Oct 6, 2022
510287b
Fix repetitive results
BrunoQuaresma Oct 7, 2022
21af86e
feat: Allow users to make files (#4423)
Emyrk Oct 9, 2022
9e199d3
add test for template rbac admin pushing template version (#4438)
sreya Oct 9, 2022
b101ae7
merge main into groups (#4439)
sreya Oct 10, 2022
d715ea6
Revert "merge main into groups (#4439)"
sreya Oct 10, 2022
413b6e1
merge main
sreya Oct 10, 2022
85d0643
fix coderd/license
sreya Oct 9, 2022
262bb45
fix license woes
sreya Oct 9, 2022
a5c6848
remove migration conflict
sreya Oct 9, 2022
a69c018
fix tests
sreya Oct 10, 2022
1809d3e
fix merge conflict
sreya Oct 10, 2022
21c078b
fix ts lint
sreya Oct 10, 2022
c8f6afd
make fmt
sreya Oct 10, 2022
ad02da0
delete old files
sreya Oct 10, 2022
35aef1b
Fix types
BrunoQuaresma Oct 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add patch endpoint tests
  • Loading branch information
sreya committed Sep 19, 2022
commit f56fcf9ff082e70a84e51139a593817e76e2cbf3
3 changes: 2 additions & 1 deletion coderd/database/modelmethods.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ func templateRoleToActions(t TemplateRole) []rbac.Action {
case TemplateRoleWrite:
return []rbac.Action{rbac.ActionRead, rbac.ActionUpdate}
case TemplateRoleAdmin:
return []rbac.Action{rbac.WildcardSymbol}
// TODO: Why does rbac.Wildcard not work here?
return []rbac.Action{rbac.ActionRead, rbac.ActionUpdate, rbac.ActionCreate, rbac.ActionDelete}
}
return nil
}
Expand Down
69 changes: 37 additions & 32 deletions coderd/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,9 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {

// Only users who are able to create templates (aka template admins)
// are able to control user permissions.
// TODO: It'd be nice to also assert delete since a template admin
// should be able to do both.
// TODO: It might be cleaner to control template perms access
// via a separate RBAC resource, and restrict all actions to the template
// admin role.
if len(req.UserPerms) > 0 && !api.Authorize(r, rbac.ActionCreate, template) {
httpapi.ResourceNotFound(rw)
return
Expand All @@ -475,9 +476,23 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
validErrs = append(validErrs, codersdk.ValidationError{Field: "max_ttl_ms", Detail: "Cannot be greater than " + maxTTLDefault.String()})
}

for _, v := range req.UserPerms {
for k, v := range req.UserPerms {
if err := validateTemplateRole(v); err != nil {
validErrs = append(validErrs, codersdk.ValidationError{Field: "user_perms", Detail: err.Error()})
continue
}

userID, err := uuid.Parse(k)
if err != nil {
validErrs = append(validErrs, codersdk.ValidationError{Field: "user_perms", Detail: "User ID " + k + "must be a valid UUID."})
continue
}

// This could get slow if we get a ton of user perm updates.
_, err = api.Database.GetUserByID(r.Context(), userID)
if err != nil {
validErrs = append(validErrs, codersdk.ValidationError{Field: "user_perms", Detail: fmt.Sprintf("Failed to find user with ID %q: %v", k, err.Error())})
continue
}
}

Expand Down Expand Up @@ -509,7 +524,8 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
req.Description == template.Description &&
req.Icon == template.Icon &&
req.MaxTTLMillis == time.Duration(template.MaxTtl).Milliseconds() &&
req.MinAutostartIntervalMillis == time.Duration(template.MinAutostartInterval).Milliseconds() {
req.MinAutostartIntervalMillis == time.Duration(template.MinAutostartInterval).Milliseconds() &&
len(req.UserPerms) == 0 {
return nil
}

Expand All @@ -530,23 +546,12 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
minAutostartInterval = time.Duration(template.MinAutostartInterval)
}

updated, err = tx.UpdateTemplateMetaByID(r.Context(), database.UpdateTemplateMetaByIDParams{
ID: template.ID,
UpdatedAt: database.Now(),
Name: name,
Description: desc,
Icon: icon,
MaxTtl: int64(maxTTL),
MinAutostartInterval: int64(minAutostartInterval),
})
if err != nil {
return err
}

if len(req.UserPerms) > 0 {
userACL := template.UserACL()
for k, v := range req.UserPerms {
if len(v) == 0 {
// A user with an empty string implies
// deletion.
if v == "" {
delete(userACL, k)
continue
}
Expand All @@ -559,6 +564,19 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
}
}

updated, err = tx.UpdateTemplateMetaByID(r.Context(), database.UpdateTemplateMetaByIDParams{
ID: template.ID,
UpdatedAt: database.Now(),
Name: name,
Description: desc,
Icon: icon,
MaxTtl: int64(maxTTL),
MinAutostartInterval: int64(minAutostartInterval),
})
if err != nil {
return err
}

return nil
})
if err != nil {
Expand Down Expand Up @@ -839,22 +857,9 @@ func convertSDKTemplateRole(role codersdk.TemplateRole) database.TemplateRole {
return ""
}

func templateRoleToActions(role codersdk.TemplateRole) []string {
switch role {
case codersdk.TemplateRoleAdmin:
return []string{rbac.WildcardSymbol}
case codersdk.TemplateRoleWrite:
return []string{rbac.ActionRead, rbac.ActionUpdate}
case codersdk.TemplateRoleRead:
return []string{rbac.ActionRead}
}

return nil
}

func validateTemplateRole(role codersdk.TemplateRole) error {
dbRole := convertSDKTemplateRole(role)
if dbRole == "" {
if dbRole == "" && role != codersdk.TemplateRoleDeleted {
return xerrors.Errorf("role %q is not a valid Template role", role)
}

Expand Down
211 changes: 211 additions & 0 deletions coderd/templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,217 @@ func TestPatchTemplateMeta(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, updated.Icon, "")
})

t.Run("UserPerms", func(t *testing.T) {
t.Parallel()

t.Run("OK", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
_, user2 := coderdtest.CreateAnotherUserWithUser(t, client, user.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
req := codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
user2.ID.String(): codersdk.TemplateRoleRead,
},
}

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

template, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.NoError(t, err)

role, ok := template.UserRoles[user2.ID.String()]
require.True(t, ok, "User not contained within user_roles map")
require.Equal(t, codersdk.TemplateRoleRead, role)
})

t.Run("DeleteUser", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
_, user2 := coderdtest.CreateAnotherUserWithUser(t, client, user.OrganizationID)
_, user3 := coderdtest.CreateAnotherUserWithUser(t, client, user.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
req := codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
user2.ID.String(): codersdk.TemplateRoleRead,
user3.ID.String(): codersdk.TemplateRoleWrite,
},
}

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

template, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.NoError(t, err)

role, ok := template.UserRoles[user2.ID.String()]
require.True(t, ok, "User not contained within user_roles map")
require.Equal(t, codersdk.TemplateRoleRead, role)

role, ok = template.UserRoles[user3.ID.String()]
require.True(t, ok, "User not contained within user_roles map")
require.Equal(t, codersdk.TemplateRoleWrite, role)

req = codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
user2.ID.String(): codersdk.TemplateRoleAdmin,
user3.ID.String(): codersdk.TemplateRoleDeleted,
},
}

template, err = client.UpdateTemplateMeta(ctx, template.ID, req)
require.NoError(t, err)

role, ok = template.UserRoles[user2.ID.String()]
require.True(t, ok, "User not contained within user_roles map")
require.Equal(t, codersdk.TemplateRoleAdmin, role)

_, ok = template.UserRoles[user3.ID.String()]
require.False(t, ok, "User should have been deleted from user_roles map")
})

t.Run("InvalidUUID", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
req := codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
"hi": "admin",
},
}

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

_, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.Error(t, err)
cerr, _ := codersdk.AsError(err)
require.Equal(t, http.StatusBadRequest, cerr.StatusCode())
})

t.Run("InvalidUser", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
req := codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
uuid.NewString(): "admin",
},
}

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

_, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.Error(t, err)
cerr, _ := codersdk.AsError(err)
require.Equal(t, http.StatusBadRequest, cerr.StatusCode())
})

t.Run("InvalidRole", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
_, user2 := coderdtest.CreateAnotherUserWithUser(t, client, user.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
req := codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
user2.ID.String(): "updater",
},
}

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

_, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.Error(t, err)
cerr, _ := codersdk.AsError(err)
require.Equal(t, http.StatusBadRequest, cerr.StatusCode())
})

t.Run("RegularUserCannotUpdatePerms", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
client2, user2 := coderdtest.CreateAnotherUserWithUser(t, client, user.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
req := codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
user2.ID.String(): codersdk.TemplateRoleWrite,
},
}

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

template, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.NoError(t, err)

req = codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
user2.ID.String(): codersdk.TemplateRoleAdmin,
},
}

template, err = client2.UpdateTemplateMeta(ctx, template.ID, req)
require.Error(t, err)
cerr, _ := codersdk.AsError(err)
require.Equal(t, http.StatusNotFound, cerr.StatusCode())
})

t.Run("RegularUserWithAdminCanUpdate", func(t *testing.T) {
t.Parallel()

client := coderdtest.New(t, nil)
user := coderdtest.CreateFirstUser(t, client)
client2, user2 := coderdtest.CreateAnotherUserWithUser(t, client, user.OrganizationID)
_, user3 := coderdtest.CreateAnotherUserWithUser(t, client, user.OrganizationID)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil)
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
req := codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
user2.ID.String(): codersdk.TemplateRoleAdmin,
},
}

ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()

template, err := client.UpdateTemplateMeta(ctx, template.ID, req)
require.NoError(t, err)

req = codersdk.UpdateTemplateMeta{
UserPerms: map[string]codersdk.TemplateRole{
user3.ID.String(): codersdk.TemplateRoleRead,
},
}

template, err = client2.UpdateTemplateMeta(ctx, template.ID, req)
require.NoError(t, err)

role, ok := template.UserRoles[user3.ID.String()]
require.True(t, ok, "User not contained within user_roles map")
require.Equal(t, codersdk.TemplateRoleRead, role)
})
})
}

func TestDeleteTemplate(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions coderd/workspaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import (
"github.com/coder/coder/testutil"
)

func TestWorkspace(t *testing.T) {
func TestWorkspaces(t *testing.T) {
t.Parallel()

t.Run("OK", func(t *testing.T) {
t.Run("OKK", func(t *testing.T) {
t.Parallel()
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
Expand Down
5 changes: 5 additions & 0 deletions codersdk/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,8 @@ func IsConnectionErr(err error) bool {

return xerrors.As(err, &dnsErr) || xerrors.As(err, &opErr)
}

func AsError(err error) (*Error, bool) {
var e *Error
return e, xerrors.As(err, &e)
}
7 changes: 4 additions & 3 deletions codersdk/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ type TemplateUserACL map[string]TemplateRole
type TemplateRole string

var (
TemplateRoleAdmin TemplateRole = "admin"
TemplateRoleWrite TemplateRole = "write"
TemplateRoleRead TemplateRole = "read"
TemplateRoleAdmin TemplateRole = "admin"
TemplateRoleWrite TemplateRole = "write"
TemplateRoleRead TemplateRole = "read"
TemplateRoleDeleted TemplateRole = ""
)

type UpdateTemplateMeta struct {
Expand Down