Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: Implement list roles & enforce authorize examples #1273

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 16 commits into from
May 3, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Fix broken tests
  • Loading branch information
Emyrk committed May 3, 2022
commit db04d67fc7465a608aaa4bc2f113fc68f56845ea
14 changes: 14 additions & 0 deletions coderd/coderd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ package coderd_test

import (
"context"
"fmt"
"net/http"
"testing"

"github.com/coder/coder/coderd"
"github.com/go-chi/chi/v5"

"go.uber.org/goleak"

"github.com/stretchr/testify/require"
Expand All @@ -24,3 +29,12 @@ func TestBuildInfo(t *testing.T) {
require.Equal(t, buildinfo.ExternalURL(), buildInfo.ExternalURL, "external URL")
require.Equal(t, buildinfo.Version(), buildInfo.Version, "version")
}

func TestWalk(t *testing.T) {
r, _ := coderd.New(&coderd.Options{})
chiRouter := r.(chi.Router)
chi.Walk(chiRouter, func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
fmt.Println(method, route)
return nil
})
}
3 changes: 2 additions & 1 deletion coderd/rbac/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ func IsOrgRole(roleName string) (string, bool) {
// the list from the builtins.
func OrganizationRoles(organizationID uuid.UUID) []string {
var roles []string
for role := range builtInRoles {
for _, roleF := range builtInRoles {
role := roleF(organizationID.String()).Name
_, scope, err := roleSplit(role)
if err != nil {
// This should never happen
Expand Down
5 changes: 4 additions & 1 deletion coderd/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package coderd
import (
"net/http"

"github.com/coder/coder/coderd/httpmw"

"github.com/coder/coder/coderd/httpapi"
"github.com/coder/coder/coderd/rbac"
)
Expand All @@ -19,6 +21,7 @@ func (api *api) assignableSiteRoles(rw http.ResponseWriter, r *http.Request) {
func (api *api) assignableOrgRoles(rw http.ResponseWriter, r *http.Request) {
// TODO: @emyrk in the future, allow granular subsets of roles to be returned based on the
// role of the user.
roles := rbac.SiteRoles()
organization := httpmw.OrganizationParam(r)
roles := rbac.OrganizationRoles(organization.ID)
httpapi.Write(rw, http.StatusOK, roles)
}
50 changes: 25 additions & 25 deletions coderd/roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,12 @@ import (
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/coderd/rbac"
"github.com/coder/coder/codersdk"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)

func TestListRoles(t *testing.T) {
t.Parallel()

requireUnauthorized := func(t *testing.T, err error) {
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode())
require.Contains(t, apiErr.Message, "unauthorized")
}

ctx := context.Background()
client := coderdtest.New(t, nil)
// Create admin, member, and org admin
Expand All @@ -41,73 +33,78 @@ func TestListRoles(t *testing.T) {
)
require.NoError(t, err, "update org member roles")

otherOrg, err := client.CreateOrganization(ctx, admin.UserID, codersdk.CreateOrganizationRequest{
Name: "other",
})
require.NoError(t, err, "create org")

const unauth = "unauthorized"
const notMember = "not a member of the organization"

testCases := []struct {
Name string
Client *codersdk.Client
APICall func() ([]string, error)
ExpectedRoles []string
Authorized bool
Name string
Client *codersdk.Client
APICall func() ([]string, error)
ExpectedRoles []string
AuthorizedError string
}{
{
Name: "MemberListSite",
APICall: func() ([]string, error) {
x, err := member.ListSiteRoles(ctx)
return x, err
},
Authorized: false,
AuthorizedError: unauth,
},
{
Name: "OrgMemberListOrg",
APICall: func() ([]string, error) {
return member.ListOrganizationRoles(ctx, admin.OrganizationID)
},
Authorized: false,
AuthorizedError: unauth,
},
{
Name: "NonOrgMemberListOrg",
APICall: func() ([]string, error) {
return member.ListOrganizationRoles(ctx, uuid.New())
return member.ListOrganizationRoles(ctx, otherOrg.ID)
},
Authorized: false,
AuthorizedError: notMember,
},
// Org admin
{
Name: "OrgAdminListSite",
APICall: func() ([]string, error) {
return orgAdmin.ListSiteRoles(ctx)
},
Authorized: false,
AuthorizedError: unauth,
},
{
Name: "OrgAdminListOrg",
APICall: func() ([]string, error) {
return orgAdmin.ListOrganizationRoles(ctx, admin.OrganizationID)
},
Authorized: true,
ExpectedRoles: rbac.OrganizationRoles(admin.OrganizationID),
},
{
Name: "OrgAdminListOtherOrg",
APICall: func() ([]string, error) {
return orgAdmin.ListOrganizationRoles(ctx, uuid.New())
return orgAdmin.ListOrganizationRoles(ctx, otherOrg.ID)
},
Authorized: false,
AuthorizedError: notMember,
},
// Admin
{
Name: "AdminListSite",
APICall: func() ([]string, error) {
return client.ListSiteRoles(ctx)
},
Authorized: true,
ExpectedRoles: rbac.SiteRoles(),
},
{
Name: "AdminListOrg",
APICall: func() ([]string, error) {
return client.ListOrganizationRoles(ctx, admin.OrganizationID)
},
Authorized: true,
ExpectedRoles: rbac.OrganizationRoles(admin.OrganizationID),
},
}
Expand All @@ -117,8 +114,11 @@ func TestListRoles(t *testing.T) {
t.Run(c.Name, func(t *testing.T) {
t.Parallel()
roles, err := c.APICall()
if !c.Authorized {
requireUnauthorized(t, err)
if c.AuthorizedError != "" {
var apiErr *codersdk.Error
require.ErrorAs(t, err, &apiErr)
require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode())
require.Contains(t, apiErr.Message, c.AuthorizedError)
} else {
require.NoError(t, err)
require.Equal(t, c.ExpectedRoles, roles)
Expand Down
2 changes: 1 addition & 1 deletion codersdk/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (c *Client) ListSiteRoles(ctx context.Context) ([]string, error) {
}

func (c *Client) ListOrganizationRoles(ctx context.Context, org uuid.UUID) ([]string, error) {
res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/members/roles", org.String()), nil)
res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/organizations/%s/members/roles/", org.String()), nil)
if err != nil {
return nil, err
}
Expand Down