2
0
Mohammed Nafees 3 жил өмнө
parent
commit
8715f6975e

+ 86 - 117
api/server/authz/policy/loader_test.go

@@ -1,11 +1,10 @@
 package policy_test
 
 import (
-	"fmt"
+	"encoding/json"
 	"net/http"
 	"testing"
 
-	"github.com/go-test/deep"
 	"github.com/porter-dev/porter/api/server/authz/policy"
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/models"
@@ -13,112 +12,66 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-type basicLoaderTest struct {
-	description      string
-	roleKind         types.RoleKind
-	expErr           bool
-	expErrString     string
-	expErrStatusCode int
-	expPolicy        []*types.PolicyDocument
-}
-
-var basicLoaderTests = []basicLoaderTest{
-	{
-		description: "should load admin policy",
-		roleKind:    types.RoleAdmin,
-		expPolicy:   types.AdminPolicy,
-	},
-	{
-		description: "should load developer policy",
-		roleKind:    types.RoleDeveloper,
-		expPolicy:   types.DeveloperPolicy,
-	},
-	{
-		description: "should load viewer policy",
-		roleKind:    types.RoleViewer,
-		expPolicy:   types.ViewerPolicy,
-	},
-	{
-		description:      "should not load custom policy for basic loader",
-		roleKind:         types.RoleCustom,
-		expErr:           true,
-		expErrStatusCode: http.StatusForbidden,
-		expErrString:     "custom role not supported for user 1, project 1",
-	},
-}
-
 func TestBasicPolicyDocumentLoader(t *testing.T) {
 	assert := assert.New(t)
 
-	for _, basicTest := range basicLoaderTests {
-		// use the in-memory project repo
-		projRepo := test.NewProjectRepository(true)
-		loader := policy.NewBasicPolicyDocumentLoader(projRepo, nil)
-
-		project := &models.Project{
-			Name: "test-project",
-		}
-
-		var err error
-
-		project, err = projRepo.CreateProject(project)
-
-		if err != nil {
-			t.Fatalf("%v", err)
-		}
-
-		_, err = projRepo.CreateProjectRole(project, &models.Role{
-			Role: types.Role{
-				UserID:    1,
-				ProjectID: 1,
-				Kind:      basicTest.roleKind,
-			},
-		})
-
-		if err != nil {
-			t.Fatalf("%v", err)
-		}
-
-		docs, reqErr := loader.LoadPolicyDocuments(&policy.PolicyLoaderOpts{
-			ProjectID: 1,
-			UserID:    1,
-		})
-
-		assert.Equal(
-			reqErr != nil,
-			basicTest.expErr,
-			"[ %s ]: expected error was %t, got %t",
-			basicTest.description,
-			reqErr != nil,
-			basicTest.expErr,
-		)
-
-		if reqErr != nil && basicTest.expErr {
-			readableStr := reqErr.Error()
-			expReadableStr := basicTest.expErrString
-
-			assert.Equal(
-				expReadableStr,
-				readableStr,
-				"[ %s ]: readable string not equal",
-				basicTest.description,
-			)
-
-			// check that external and internal errors are returned as well
-			assert.Equal(
-				basicTest.expErrStatusCode,
-				reqErr.GetStatusCode(),
-				"[ %s ]: status code not equal",
-				basicTest.description,
-			)
-		} else if !basicTest.expErr {
-			if diff := deep.Equal(basicTest.expPolicy, docs); diff != nil {
-				t.Errorf("[ %s ]: policy documents not equal:", basicTest.description)
-				t.Error(diff)
-			}
-		}
+	// use the in-memory project repo
+	projRepo := test.NewProjectRepository(true)
+	projRoleRepo := test.NewProjectRoleRepository(true)
+	policyRepo := test.NewPolicyRepository(true)
+
+	project, err := projRepo.CreateProject(&models.Project{
+		Name: "test-project",
+	})
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	policyBytes, err := json.Marshal(types.AdminPolicy)
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	pol, err := policyRepo.CreatePolicy(&models.Policy{
+		UniqueID:    "test-policy-uid",
+		ProjectID:   project.ID,
+		Name:        "test-policy",
+		PolicyBytes: policyBytes,
+	})
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	role, err := projRoleRepo.CreateProjectRole(&models.ProjectRole{
+		UniqueID:  "1-admin",
+		ProjectID: project.ID,
+		PolicyUID: pol.UniqueID,
+		Name:      "admin",
+	})
 
+	if err != nil {
+		t.Fatalf("%v", err)
 	}
+
+	err = projRoleRepo.UpdateUsersInProjectRole(project.ID, role.UniqueID, []uint{1})
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	loader := policy.NewBasicPolicyDocumentLoader(projRoleRepo, policyRepo)
+
+	docs, reqErr := loader.LoadPolicyDocuments(&policy.PolicyLoaderOpts{
+		ProjectID: 1,
+		UserID:    1,
+	})
+
+	assert.Equal(true, reqErr == nil)
+	assert.Equal(1, len(docs))
+	assert.Equal(types.AdminPolicy[0], docs[0])
 }
 
 func TestErrorForbiddenInvalidRole(t *testing.T) {
@@ -126,26 +79,41 @@ func TestErrorForbiddenInvalidRole(t *testing.T) {
 
 	// use the in-memory project repo
 	projRepo := test.NewProjectRepository(true)
-	loader := policy.NewBasicPolicyDocumentLoader(projRepo, nil)
+	projRoleRepo := test.NewProjectRoleRepository(true)
+	policyRepo := test.NewPolicyRepository(true)
+
+	loader := policy.NewBasicPolicyDocumentLoader(projRoleRepo, policyRepo)
 
-	project := &models.Project{
+	project, err := projRepo.CreateProject(&models.Project{
 		Name: "test-project",
+	})
+
+	if err != nil {
+		t.Fatalf("%v", err)
 	}
 
-	var err error
+	policyBytes, err := json.Marshal(types.RoleAdmin)
 
-	project, err = projRepo.CreateProject(project)
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	pol, err := policyRepo.CreatePolicy(&models.Policy{
+		UniqueID:    "test-policy-uid",
+		ProjectID:   project.ID,
+		Name:        "test-policy",
+		PolicyBytes: policyBytes,
+	})
 
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
 
-	_, err = projRepo.CreateProjectRole(project, &models.Role{
-		Role: types.Role{
-			UserID:    1,
-			ProjectID: 1,
-			Kind:      types.RoleAdmin,
-		},
+	_, err = projRoleRepo.CreateProjectRole(&models.ProjectRole{
+		UniqueID:  "1-admin",
+		ProjectID: project.ID,
+		PolicyUID: pol.UniqueID,
+		Name:      "admin",
 	})
 
 	if err != nil {
@@ -154,7 +122,7 @@ func TestErrorForbiddenInvalidRole(t *testing.T) {
 
 	_, reqErr := loader.LoadPolicyDocuments(&policy.PolicyLoaderOpts{
 		ProjectID: 1,
-		UserID:    2,
+		UserID:    1,
 	})
 
 	if reqErr == nil {
@@ -169,7 +137,7 @@ func TestErrorForbiddenInvalidRole(t *testing.T) {
 	)
 
 	assert.Equal(
-		fmt.Sprintf("user %d does not have a role in project %d", 2, 1),
+		"user does not have any roles assigned in this project",
 		reqErr.Error(),
 		"error message is not correct",
 	)
@@ -179,8 +147,9 @@ func TestErrorCannotQuery(t *testing.T) {
 	assert := assert.New(t)
 
 	// use the in-memory project repo
-	projRepo := test.NewProjectRepository(false)
-	loader := policy.NewBasicPolicyDocumentLoader(projRepo, nil)
+	projRoleRepo := test.NewProjectRoleRepository(false)
+	policyRepo := test.NewPolicyRepository(false)
+	loader := policy.NewBasicPolicyDocumentLoader(projRoleRepo, policyRepo)
 
 	_, reqErr := loader.LoadPolicyDocuments(&policy.PolicyLoaderOpts{
 		ProjectID: 2,

+ 85 - 12
api/server/authz/policy_test.go

@@ -1,6 +1,7 @@
 package authz_test
 
 import (
+	"encoding/json"
 	"fmt"
 	"net/http"
 	"net/http/httptest"
@@ -8,7 +9,6 @@ import (
 
 	"github.com/porter-dev/porter/api/server/authz"
 	"github.com/porter-dev/porter/api/server/authz/policy"
-	"github.com/porter-dev/porter/api/server/handlers/project"
 	"github.com/porter-dev/porter/api/server/shared/apierrors"
 	"github.com/porter-dev/porter/api/server/shared/apitest"
 	"github.com/porter-dev/porter/api/server/shared/config"
@@ -28,14 +28,49 @@ func TestPolicyMiddlewareSuccessfulProjectCluster(t *testing.T) {
 	}, false, false)
 
 	user := apitest.CreateTestUser(t, config, true)
-	_, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
+
+	project, err := config.Repo.Project().CreateProject(&models.Project{
 		Name: "test-project",
-	}, user)
+	})
 
 	if err != nil {
 		t.Fatal(err)
 	}
 
+	policyBytes, err := json.Marshal(types.AdminPolicy)
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	pol, err := config.Repo.Policy().CreatePolicy(&models.Policy{
+		UniqueID:    "test-policy-uid",
+		ProjectID:   project.ID,
+		Name:        "test-policy",
+		PolicyBytes: policyBytes,
+	})
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	role, err := config.Repo.ProjectRole().CreateProjectRole(&models.ProjectRole{
+		UniqueID:  "1-admin",
+		ProjectID: project.ID,
+		PolicyUID: pol.UniqueID,
+		Name:      "admin",
+	})
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	err = config.Repo.ProjectRole().UpdateUsersInProjectRole(project.ID, role.UniqueID, []uint{user.ID})
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
 	req, rr := apitest.GetRequestAndRecorder(t, string(types.HTTPVerbPost), "/api/projects/1/clusters/1", nil)
 
 	req = apitest.WithURLParams(t, req, map[string]string{
@@ -76,14 +111,49 @@ func TestPolicyMiddlewareSuccessfulApplication(t *testing.T) {
 	}, false, false)
 
 	user := apitest.CreateTestUser(t, config, true)
-	_, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
+
+	project, err := config.Repo.Project().CreateProject(&models.Project{
 		Name: "test-project",
-	}, user)
+	})
 
 	if err != nil {
 		t.Fatal(err)
 	}
 
+	policyBytes, err := json.Marshal(types.AdminPolicy)
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	pol, err := config.Repo.Policy().CreatePolicy(&models.Policy{
+		UniqueID:    "test-policy-uid",
+		ProjectID:   project.ID,
+		Name:        "test-policy",
+		PolicyBytes: policyBytes,
+	})
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	role, err := config.Repo.ProjectRole().CreateProjectRole(&models.ProjectRole{
+		UniqueID:  "1-admin",
+		ProjectID: project.ID,
+		PolicyUID: pol.UniqueID,
+		Name:      "admin",
+	})
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
+	err = config.Repo.ProjectRole().UpdateUsersInProjectRole(project.ID, role.UniqueID, []uint{user.ID})
+
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+
 	req, rr := apitest.GetRequestAndRecorder(
 		t,
 		string(types.HTTPVerbPost),
@@ -141,9 +211,10 @@ func TestPolicyMiddlewareInvalidPermissions(t *testing.T) {
 	}, false, true)
 
 	user := apitest.CreateTestUser(t, config, true)
-	_, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
+
+	_, err := config.Repo.Project().CreateProject(&models.Project{
 		Name: "test-project",
-	}, user)
+	})
 
 	if err != nil {
 		t.Fatal(err)
@@ -175,9 +246,10 @@ func TestPolicyMiddlewareFailInvalidLoader(t *testing.T) {
 	}, true, false)
 
 	user := apitest.CreateTestUser(t, config, true)
-	_, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
+
+	_, err := config.Repo.Project().CreateProject(&models.Project{
 		Name: "test-project",
-	}, user)
+	})
 
 	if err != nil {
 		t.Fatal(err)
@@ -208,9 +280,10 @@ func TestPolicyMiddlewareFailBadParam(t *testing.T) {
 	}, true, false)
 
 	user := apitest.CreateTestUser(t, config, true)
-	_, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
+
+	_, err := config.Repo.Project().CreateProject(&models.Project{
 		Name: "test-project",
-	}, user)
+	})
 
 	if err != nil {
 		t.Fatal(err)
@@ -240,7 +313,7 @@ func loadHandlers(
 	shouldLoaderLoadViewer bool,
 ) (*config.Config, http.Handler, *testHandler) {
 	config := apitest.LoadConfig(t)
-	var loader policy.PolicyDocumentLoader = policy.NewBasicPolicyDocumentLoader(config.Repo.Project(), config.Repo.Policy())
+	var loader policy.PolicyDocumentLoader = policy.NewBasicPolicyDocumentLoader(config.Repo.ProjectRole(), config.Repo.Policy())
 
 	if shouldLoaderFail {
 		loader = &failingDocLoader{}

+ 6 - 5
api/server/authz/project_test.go

@@ -5,7 +5,6 @@ import (
 	"testing"
 
 	"github.com/porter-dev/porter/api/server/authz"
-	"github.com/porter-dev/porter/api/server/handlers/project"
 	"github.com/porter-dev/porter/api/server/shared/apitest"
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/api/types"
@@ -18,9 +17,10 @@ func TestProjectMiddlewareSuccessful(t *testing.T) {
 	config, handler, next := loadProjectHandlers(t)
 
 	user := apitest.CreateTestUser(t, config, true)
-	proj, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
+
+	proj, err := config.Repo.Project().CreateProject(&models.Project{
 		Name: "test-project",
-	}, user)
+	})
 
 	if err != nil {
 		t.Fatal(err)
@@ -46,9 +46,10 @@ func TestProjectMiddlewareFailedRead(t *testing.T) {
 	config, _, _ := loadProjectHandlers(t)
 
 	user := apitest.CreateTestUser(t, config, true)
-	_, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
+
+	_, err := config.Repo.Project().CreateProject(&models.Project{
 		Name: "test-project",
-	}, user)
+	})
 
 	if err != nil {
 		t.Fatal(err)

+ 2 - 4
api/server/handlers/project/create.go

@@ -42,11 +42,9 @@ func (p *ProjectCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 	// read the user from context
 	user, _ := r.Context().Value(types.UserScope).(*models.User)
 
-	proj := &models.Project{
+	proj, err := p.Repo().Project().CreateProject(&models.Project{
 		Name: request.Name,
-	}
-
-	proj, err := p.Repo().Project().CreateProject(proj)
+	})
 
 	if err != nil {
 		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))

+ 3 - 59
api/server/handlers/project/create_test.go

@@ -33,15 +33,9 @@ func TestCreateProjectSuccessful(t *testing.T) {
 	handler.ServeHTTP(rr, req)
 
 	expProject := &types.CreateProjectResponse{
-		ID:   1,
-		Name: "test-project",
-		Roles: []*types.Role{
-			{
-				Kind:      types.RoleAdmin,
-				UserID:    user.ID,
-				ProjectID: 1,
-			},
-		},
+		ID:    1,
+		Name:  "test-project",
+		Roles: []*types.Role{},
 	}
 
 	gotProject := &types.CreateProjectResponse{}
@@ -98,53 +92,3 @@ func TestFailingCreateMethod(t *testing.T) {
 
 	apitest.AssertResponseInternalServerError(t, rr)
 }
-
-func TestFailingCreateRoleMethod(t *testing.T) {
-	req, rr := apitest.GetRequestAndRecorder(
-		t,
-		string(types.HTTPVerbPost),
-		"/api/projects",
-		&types.CreateProjectRequest{
-			Name: "test-project",
-		},
-	)
-
-	config := apitest.LoadConfig(t, test.CreateProjectRoleMethod)
-	user := apitest.CreateTestUser(t, config, true)
-	req = apitest.WithAuthenticatedUser(t, req, user)
-
-	handler := project.NewProjectCreateHandler(
-		config,
-		shared.NewDefaultRequestDecoderValidator(config.Logger, config.Alerter),
-		shared.NewDefaultResultWriter(config.Logger, config.Alerter),
-	)
-
-	handler.ServeHTTP(rr, req)
-
-	apitest.AssertResponseInternalServerError(t, rr)
-}
-
-func TestFailingReadMethod(t *testing.T) {
-	req, rr := apitest.GetRequestAndRecorder(
-		t,
-		string(types.HTTPVerbPost),
-		"/api/projects",
-		&types.CreateProjectRequest{
-			Name: "test-project",
-		},
-	)
-
-	config := apitest.LoadConfig(t, test.ReadProjectMethod)
-	user := apitest.CreateTestUser(t, config, true)
-	req = apitest.WithAuthenticatedUser(t, req, user)
-
-	handler := project.NewProjectCreateHandler(
-		config,
-		shared.NewDefaultRequestDecoderValidator(config.Logger, config.Alerter),
-		shared.NewDefaultResultWriter(config.Logger, config.Alerter),
-	)
-
-	handler.ServeHTTP(rr, req)
-
-	apitest.AssertResponseInternalServerError(t, rr)
-}

+ 2 - 30
api/server/handlers/project/delete_role.go

@@ -1,14 +1,13 @@
 package project
 
 import (
+	"fmt"
 	"net/http"
 
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/apierrors"
 	"github.com/porter-dev/porter/api/server/shared/config"
-	"github.com/porter-dev/porter/api/types"
-	"github.com/porter-dev/porter/internal/models"
 )
 
 type RoleDeleteHandler struct {
@@ -26,32 +25,5 @@ func NewRoleDeleteHandler(
 }
 
 func (p *RoleDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
-
-	request := &types.DeleteRoleRequest{}
-
-	ok := p.DecodeAndValidate(w, r, request)
-
-	if !ok {
-		return
-	}
-
-	role, err := p.Repo().Project().ReadLegacyProjectRole(proj.ID, request.UserID)
-
-	if err != nil {
-		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
-		return
-	}
-
-	role, err = p.Repo().Project().DeleteLegacyProjectRole(proj.ID, request.UserID)
-
-	if err != nil {
-		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-	}
-
-	res := &types.DeleteRoleResponse{
-		Role: role.ToRoleType(),
-	}
-
-	p.WriteResult(w, r, res)
+	p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("deprecated"), http.StatusBadRequest))
 }

+ 3 - 2
api/server/handlers/project/get_test.go

@@ -14,9 +14,10 @@ func TestGetProjectSuccessful(t *testing.T) {
 	// create a test project
 	config := apitest.LoadConfig(t)
 	user := apitest.CreateTestUser(t, config, true)
-	proj, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
+
+	proj, err := config.Repo.Project().CreateProject(&models.Project{
 		Name: "test-project",
-	}, user)
+	})
 
 	if err != nil {
 		t.Fatal(err)

+ 0 - 33
api/server/handlers/project/list_collaborators.go

@@ -58,39 +58,6 @@ func (p *CollaboratorsListHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ
 		for _, user := range userCollaboratorMap {
 			res = append(res, user)
 		}
-	} else { // legacy operation
-		legacyRoles, err := p.Repo().Project().ListLegacyProjectRoles(proj.ID)
-
-		if err != nil {
-			p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-			return
-		}
-
-		roleMap := make(map[uint]*models.Role)
-		idArr := make([]uint, 0)
-
-		for _, role := range legacyRoles {
-			roleCp := role
-			roleMap[role.UserID] = &roleCp
-			idArr = append(idArr, role.UserID)
-		}
-
-		users, err := p.Repo().User().ListUsersByIDs(idArr)
-
-		if err != nil {
-			p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-			return
-		}
-
-		for _, user := range users {
-			res = append(res, &types.Collaborator{
-				ID:        roleMap[user.ID].ID,
-				Kind:      string(roleMap[user.ID].Kind),
-				UserID:    roleMap[user.ID].UserID,
-				Email:     user.Email,
-				ProjectID: roleMap[user.ID].ProjectID,
-			})
-		}
 	}
 
 	p.WriteResult(w, r, res)

+ 0 - 74
api/server/handlers/project/list_test.go

@@ -1,74 +0,0 @@
-package project_test
-
-import (
-	"testing"
-
-	"github.com/porter-dev/porter/api/server/handlers/project"
-	"github.com/porter-dev/porter/api/server/shared"
-	"github.com/porter-dev/porter/api/server/shared/apitest"
-	"github.com/porter-dev/porter/api/types"
-	"github.com/porter-dev/porter/internal/models"
-	"github.com/porter-dev/porter/internal/repository/test"
-)
-
-func TestListProjectsSuccessful(t *testing.T) {
-	// create a test project
-	config := apitest.LoadConfig(t)
-	user := apitest.CreateTestUser(t, config, true)
-	proj1, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
-		Name: "test-project",
-	}, user)
-
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	proj2, _, err := project.CreateProjectWithUser(config.Repo.Project(), &models.Project{
-		Name: "test-project-2",
-	}, user)
-
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	req, rr := apitest.GetRequestAndRecorder(t, string(types.HTTPVerbGet), "/api/projects", nil)
-
-	req = apitest.WithAuthenticatedUser(t, req, user)
-
-	handler := project.NewProjectListHandler(
-		config,
-		shared.NewDefaultResultWriter(config.Logger, config.Alerter),
-	)
-
-	handler.ServeHTTP(rr, req)
-
-	expProjects := make([]*types.Project, 0)
-
-	expProjects = append(expProjects, proj1.ToProjectType())
-	expProjects = append(expProjects, proj2.ToProjectType())
-	gotProjects := []*types.Project{}
-
-	apitest.AssertResponseExpected(t, rr, &expProjects, &gotProjects)
-}
-
-func TestFailingListMethod(t *testing.T) {
-	req, rr := apitest.GetRequestAndRecorder(
-		t,
-		string(types.HTTPVerbGet),
-		"/api/projects",
-		nil,
-	)
-
-	config := apitest.LoadConfig(t, test.ListProjectsByUserIDMethod)
-	user := apitest.CreateTestUser(t, config, true)
-	req = apitest.WithAuthenticatedUser(t, req, user)
-
-	handler := project.NewProjectListHandler(
-		config,
-		shared.NewDefaultResultWriter(config.Logger, config.Alerter),
-	)
-
-	handler.ServeHTTP(rr, req)
-
-	apitest.AssertResponseInternalServerError(t, rr)
-}

+ 2 - 33
api/server/handlers/project/update_role.go

@@ -1,14 +1,13 @@
 package project
 
 import (
+	"fmt"
 	"net/http"
 
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/shared"
 	"github.com/porter-dev/porter/api/server/shared/apierrors"
 	"github.com/porter-dev/porter/api/server/shared/config"
-	"github.com/porter-dev/porter/api/types"
-	"github.com/porter-dev/porter/internal/models"
 )
 
 type RoleUpdateHandler struct {
@@ -26,35 +25,5 @@ func NewRoleUpdateHandler(
 }
 
 func (p *RoleUpdateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
-
-	request := &types.UpdateRoleRequest{}
-
-	ok := p.DecodeAndValidate(w, r, request)
-
-	if !ok {
-		return
-	}
-
-	role, err := p.Repo().Project().ReadLegacyProjectRole(proj.ID, request.UserID)
-
-	if err != nil {
-		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
-		return
-	}
-
-	role.Kind = types.RoleKind(request.Kind)
-
-	role, err = p.Repo().Project().UpdateLegacyProjectRole(proj.ID, role)
-
-	if err != nil {
-		p.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-		return
-	}
-
-	var res = types.UpdateRoleResponse{
-		Role: role.ToRoleType(),
-	}
-
-	p.WriteResult(w, r, res)
+	p.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("deprecated"), http.StatusBadRequest))
 }

+ 0 - 18
cmd/migrate/keyrotate/helpers_test.go

@@ -138,24 +138,6 @@ func initProject(tester *tester, t *testing.T) {
 	tester.initProjects = append(tester.initProjects, proj)
 }
 
-func initProjectRole(tester *tester, t *testing.T) {
-	t.Helper()
-
-	role := &models.Role{
-		Role: types.Role{
-			Kind:      types.RoleAdmin,
-			UserID:    tester.initUsers[0].Model.ID,
-			ProjectID: tester.initProjects[0].Model.ID,
-		},
-	}
-
-	role, err := tester.repo.Project().CreateProjectRole(tester.initProjects[0], role)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-}
-
 func initKubeIntegration(tester *tester, t *testing.T) {
 	t.Helper()
 

+ 0 - 18
internal/repository/gorm/helpers_test.go

@@ -188,24 +188,6 @@ func initProject(tester *tester, t *testing.T) {
 	tester.initProjects = append(tester.initProjects, proj)
 }
 
-func initProjectRole(tester *tester, t *testing.T) {
-	t.Helper()
-
-	role := &models.Role{
-		Role: types.Role{
-			Kind:      types.RoleAdmin,
-			UserID:    tester.initUsers[0].Model.ID,
-			ProjectID: tester.initProjects[0].Model.ID,
-		},
-	}
-
-	role, err := tester.repo.Project().CreateProjectRole(tester.initProjects[0], role)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-}
-
 func initKubeIntegration(tester *tester, t *testing.T) {
 	t.Helper()
 

+ 0 - 292
internal/repository/gorm/project_test.go

@@ -3,12 +3,9 @@ package gorm_test
 import (
 	"testing"
 
-	"github.com/go-test/deep"
-	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/models"
 
 	"gorm.io/gorm"
-	orm "gorm.io/gorm"
 )
 
 func TestCreateProject(t *testing.T) {
@@ -45,245 +42,6 @@ func TestCreateProject(t *testing.T) {
 	}
 }
 
-func TestCreateProjectRole(t *testing.T) {
-	tester := &tester{
-		dbFileName: "./porter_create_proj_role.db",
-	}
-
-	setupTestEnv(tester, t)
-	initProject(tester, t)
-	defer cleanup(tester, t)
-
-	role := &models.Role{
-		Role: types.Role{
-			Kind:      types.RoleAdmin,
-			UserID:    0,
-			ProjectID: tester.initProjects[0].Model.ID,
-		},
-	}
-
-	role, err := tester.repo.Project().CreateProjectRole(tester.initProjects[0], role)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	proj, err := tester.repo.Project().ReadProject(tester.initProjects[0].Model.ID)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	// make sure IDs are correct
-	if proj.Model.ID != 1 {
-		t.Errorf("incorrect project ID: expected %d, got %d\n", 1, proj.Model.ID)
-	}
-
-	if len(proj.Roles) != 1 {
-		t.Fatalf("project roles incorrect length: expected %d, got %d\n", 1, len(proj.Roles))
-	}
-
-	if proj.Roles[0].Model.ID != 1 {
-		t.Fatalf("incorrect role ID: expected %d, got %d\n", 1, proj.Roles[0].Model.ID)
-	}
-
-	// make sure data is correct
-	expProj := &models.Project{
-		Name: "project-test",
-		Roles: []models.Role{
-			{
-				Role: types.Role{
-					Kind:      types.RoleAdmin,
-					UserID:    0,
-					ProjectID: 1,
-				},
-			},
-		},
-	}
-
-	copyProj := proj
-
-	// reset fields for reflect.DeepEqual
-	copyProj.Model = orm.Model{}
-	copyProj.Roles[0].Model = orm.Model{}
-
-	if diff := deep.Equal(copyProj, expProj); diff != nil {
-		t.Errorf("incorrect project")
-		t.Error(diff)
-	}
-}
-
-func TestUpdateProjectRole(t *testing.T) {
-	tester := &tester{
-		dbFileName: "./porter_update_proj_role.db",
-	}
-
-	setupTestEnv(tester, t)
-	initProject(tester, t)
-	initUser(tester, t)
-	initProjectRole(tester, t)
-	defer cleanup(tester, t)
-
-	role := &models.Role{
-		Role: types.Role{
-			Kind:      types.RoleViewer,
-			UserID:    tester.initUsers[0].Model.ID,
-			ProjectID: tester.initProjects[0].Model.ID,
-		},
-	}
-
-	role, err := tester.repo.Project().UpdateProjectRole(tester.initProjects[0].Model.ID, role)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	proj, err := tester.repo.Project().ReadProject(tester.initProjects[0].Model.ID)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	// make sure IDs are correct
-	if proj.Model.ID != 1 {
-		t.Errorf("incorrect project ID: expected %d, got %d\n", 1, proj.Model.ID)
-	}
-
-	if len(proj.Roles) != 1 {
-		t.Fatalf("project roles incorrect length: expected %d, got %d\n", 1, len(proj.Roles))
-	}
-
-	if proj.Roles[0].Model.ID != 1 {
-		t.Fatalf("incorrect role ID: expected %d, got %d\n", 1, proj.Roles[0].Model.ID)
-	}
-
-	// make sure data is correct
-	expProj := &models.Project{
-		Name: "project-test",
-		Roles: []models.Role{
-			{
-				Role: types.Role{
-					Kind:      types.RoleViewer,
-					UserID:    1,
-					ProjectID: 1,
-				},
-			},
-		},
-	}
-
-	copyProj := proj
-
-	// reset fields for reflect.DeepEqual
-	copyProj.Model = orm.Model{}
-	copyProj.Roles[0].Model = orm.Model{}
-
-	if diff := deep.Equal(copyProj, expProj); diff != nil {
-		t.Errorf("incorrect project")
-		t.Error(diff)
-	}
-}
-
-func TestListProjectsByUserID(t *testing.T) {
-	tester := &tester{
-		dbFileName: "./list_projects_user_id.db",
-	}
-
-	setupTestEnv(tester, t)
-	initUser(tester, t)
-	// create two projects, same name
-	initProject(tester, t)
-	initProjectRole(tester, t)
-	initProject(tester, t)
-
-	role := &models.Role{
-		Role: types.Role{
-			Kind:   types.RoleAdmin,
-			UserID: 1,
-		},
-	}
-
-	role, err := tester.repo.Project().CreateProjectRole(tester.initProjects[1], role)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	defer cleanup(tester, t)
-
-	projects, err := tester.repo.Project().ListProjectsByUserID(tester.initUsers[0].Model.ID)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	if len(projects) != 2 {
-		t.Fatalf("projects length was not 2\n")
-	}
-
-	for i, project := range projects {
-		// make sure data is correct
-		expProj := &models.Project{
-			Name: "project-test",
-			Roles: []models.Role{
-				{
-					Role: types.Role{
-						Kind:      types.RoleAdmin,
-						UserID:    tester.initUsers[0].Model.ID,
-						ProjectID: uint(i + 1),
-					},
-				},
-			},
-		}
-
-		copyProj := project
-
-		// reset fields for reflect.DeepEqual
-		copyProj.Model = orm.Model{}
-		copyProj.Roles[0].Model = orm.Model{}
-
-		if diff := deep.Equal(copyProj, expProj); diff != nil {
-			t.Errorf("incorrect project")
-			t.Error(diff)
-		}
-	}
-}
-
-func TestReadProjectRole(t *testing.T) {
-	tester := &tester{
-		dbFileName: "./get_project_role.db",
-	}
-
-	setupTestEnv(tester, t)
-	initUser(tester, t)
-
-	// create two projects, same name
-	initProject(tester, t)
-	initProjectRole(tester, t)
-
-	defer cleanup(tester, t)
-
-	role, err := tester.repo.Project().ReadProjectRole(1, 1)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	role.Model = gorm.Model{}
-
-	expRole := &models.Role{
-		Role: types.Role{
-			Kind:      types.RoleAdmin,
-			UserID:    1,
-			ProjectID: 1,
-		},
-	}
-
-	if diff := deep.Equal(role, expRole); diff != nil {
-		t.Errorf("incorrect role")
-		t.Error(diff)
-	}
-}
-
 func TestDeleteProject(t *testing.T) {
 	tester := &tester{
 		dbFileName: "./porter_delete_proj.db",
@@ -306,53 +64,3 @@ func TestDeleteProject(t *testing.T) {
 		t.Fatalf("read should have returned record not found: returned %v\n", err)
 	}
 }
-
-func TestDeleteProjectRole(t *testing.T) {
-	tester := &tester{
-		dbFileName: "./porter_delete_proj_role.db",
-	}
-
-	setupTestEnv(tester, t)
-	initProject(tester, t)
-	initUser(tester, t)
-	initProjectRole(tester, t)
-	defer cleanup(tester, t)
-
-	_, err := tester.repo.Project().DeleteProjectRole(tester.initProjects[0].Model.ID, tester.initUsers[0].Model.ID)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	// attempt to read the project and ensure that the error is gorm.ErrRecordNotFound
-	proj, err := tester.repo.Project().ReadProject(tester.initProjects[0].Model.ID)
-
-	if err != nil {
-		t.Fatalf("%v\n", err)
-	}
-
-	// make sure IDs are correct
-	if proj.Model.ID != 1 {
-		t.Errorf("incorrect project ID: expected %d, got %d\n", 1, proj.Model.ID)
-	}
-
-	if len(proj.Roles) != 0 {
-		t.Fatalf("project roles incorrect length: expected %d, got %d\n", 0, len(proj.Roles))
-	}
-
-	// make sure data is correct
-	expProj := &models.Project{
-		Name:  "project-test",
-		Roles: []models.Role{},
-	}
-
-	copyProj := proj
-
-	// reset fields for reflect.DeepEqual
-	copyProj.Model = orm.Model{}
-
-	if diff := deep.Equal(copyProj, expProj); diff != nil {
-		t.Errorf("incorrect project")
-		t.Error(diff)
-	}
-}

+ 0 - 4
internal/repository/project.go

@@ -10,12 +10,8 @@ type WriteProject func(project *models.Project) (*models.Project, error)
 // ProjectRepository represents the set of queries on the Project model
 type ProjectRepository interface {
 	CreateProject(project *models.Project) (*models.Project, error)
-	CreateLegacyProjectRole(project *models.Project, role *models.Role) (*models.Role, error)
 	UpdateProject(project *models.Project) (*models.Project, error)
-	UpdateLegacyProjectRole(projID uint, role *models.Role) (*models.Role, error)
 	ReadProject(id uint) (*models.Project, error)
-	ReadLegacyProjectRole(projID, userID uint) (*models.Role, error)
-	ListLegacyProjectRoles(projID uint) ([]models.Role, error)
 	ListProjectsByUserID(userID uint) ([]*models.Project, error)
 	DeleteProject(project *models.Project) (*models.Project, error)
 	DeleteLegacyProjectRole(projID, userID uint) (*models.Role, error)

+ 70 - 7
internal/repository/test/policy.go

@@ -1,40 +1,103 @@
 package test
 
 import (
+	"errors"
+
 	"github.com/porter-dev/porter/internal/models"
 	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
 )
 
 type PolicyRepository struct {
 	canQuery bool
+	policies []*models.Policy
 }
 
 // NewPolicyRepository returns a PolicyRepository which uses
 // gorm.DB for querying the database
 func NewPolicyRepository(canQuery bool) repository.PolicyRepository {
-	return &PolicyRepository{canQuery}
+	return &PolicyRepository{
+		canQuery: canQuery,
+	}
 }
 
-func (repo *PolicyRepository) CreatePolicy(a *models.Policy) (*models.Policy, error) {
-	panic("unimplemented")
+func (repo *PolicyRepository) CreatePolicy(policy *models.Policy) (*models.Policy, error) {
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	repo.policies = append(repo.policies, policy)
+	policy.ID = uint(len(repo.policies))
+
+	return policy, nil
 }
 
 func (repo *PolicyRepository) ListPoliciesByProjectID(projectID uint) ([]*models.Policy, error) {
-	panic("unimplemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	var res []*models.Policy
+
+	for _, policy := range repo.policies {
+		if policy.ProjectID == projectID {
+			res = append(res, policy)
+		}
+	}
+
+	return res, nil
 }
 
 func (repo *PolicyRepository) ReadPolicy(projectID uint, uid string) (*models.Policy, error) {
-	panic("unimplemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	for _, policy := range repo.policies {
+		if policy.ProjectID == projectID && policy.UniqueID == uid {
+			return policy, nil
+		}
+	}
+
+	return nil, gorm.ErrRecordNotFound
 }
 
 func (repo *PolicyRepository) UpdatePolicy(
 	policy *models.Policy,
 ) (*models.Policy, error) {
-	panic("unimplemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	for _, p := range repo.policies {
+		if p.ID == policy.ID && p.UniqueID == policy.UniqueID {
+			repo.policies[p.ID-1] = policy
+		}
+	}
+
+	return nil, gorm.ErrRecordNotFound
 }
 
 func (repo *PolicyRepository) DeletePolicy(
 	policy *models.Policy,
 ) (*models.Policy, error) {
-	panic("unimplemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	if policy == nil || int(policy.ID-1) >= len(repo.policies) || repo.policies[policy.ID-1] == nil {
+		return nil, gorm.ErrRecordNotFound
+	}
+
+	var newPolicies []*models.Policy
+
+	for _, p := range repo.policies {
+		if p.UniqueID != policy.UniqueID {
+			newPolicies = append(newPolicies, p)
+		}
+	}
+
+	repo.policies = newPolicies
+
+	return policy, nil
 }

+ 0 - 75
internal/repository/test/project.go

@@ -42,85 +42,10 @@ func (repo *ProjectRepository) CreateProject(project *models.Project) (*models.P
 	return project, nil
 }
 
-// CreateProjectRole appends a role to the existing array of roles
-func (repo *ProjectRepository) CreateLegacyProjectRole(project *models.Project, role *models.Role) (*models.Role, error) {
-	if !repo.canQuery || strings.Contains(repo.failingMethods, CreateProjectRoleMethod) {
-		return nil, errors.New("Cannot write database")
-	}
-
-	if int(project.ID-1) >= len(repo.projects) || repo.projects[project.ID-1] == nil {
-		return nil, gorm.ErrRecordNotFound
-	}
-
-	index := int(project.ID - 1)
-	oldProject := *repo.projects[index]
-	repo.projects[index] = project
-	project.Roles = append(oldProject.Roles, *role)
-
-	return role, nil
-}
-
 func (repo *ProjectRepository) UpdateProject(project *models.Project) (*models.Project, error) {
 	panic("unimplemented")
 }
 
-// CreateProjectRole appends a role to the existing array of roles
-func (repo *ProjectRepository) UpdateLegacyProjectRole(projID uint, role *models.Role) (*models.Role, error) {
-	if !repo.canQuery {
-		return nil, errors.New("Cannot read from database")
-	}
-
-	var foundProject *models.Project
-
-	// find all roles matching
-	for _, project := range repo.projects {
-		if project.ID == projID {
-			foundProject = project
-		}
-	}
-
-	if foundProject == nil {
-		return nil, gorm.ErrRecordNotFound
-	}
-
-	var index int
-
-	for i, _role := range foundProject.Roles {
-		if _role.UserID == role.UserID {
-			index = i
-		}
-	}
-
-	if index == 0 {
-		return nil, gorm.ErrRecordNotFound
-	}
-
-	foundProject.Roles[index] = *role
-	return role, nil
-}
-
-// ReadProject gets a projects specified by a unique id
-func (repo *ProjectRepository) ReadLegacyProjectRole(userID, projID uint) (*models.Role, error) {
-	if !repo.canQuery {
-		return nil, errors.New("Cannot read from database")
-	}
-
-	if int(projID-1) >= len(repo.projects) || repo.projects[projID-1] == nil {
-		return nil, gorm.ErrRecordNotFound
-	}
-
-	// find role in project roles
-	index := int(projID - 1)
-
-	for _, role := range repo.projects[index].Roles {
-		if role.UserID == userID {
-			return &role, nil
-		}
-	}
-
-	return nil, gorm.ErrRecordNotFound
-}
-
 // ReadProject gets a projects specified by a unique id
 func (repo *ProjectRepository) ReadProject(id uint) (*models.Project, error) {
 	if !repo.canQuery || strings.Contains(repo.failingMethods, ReadProjectMethod) {

+ 130 - 10
internal/repository/test/project_role.go

@@ -1,45 +1,165 @@
 package test
 
 import (
+	"errors"
+
 	"github.com/porter-dev/porter/internal/models"
 	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
 )
 
 type ProjectRoleRepository struct {
+	canQuery bool
+	roles    []*models.ProjectRole
 }
 
-func NewProjectRoleRepository() repository.ProjectRoleRepository {
-	return &ProjectRoleRepository{}
+func NewProjectRoleRepository(canQuery bool) repository.ProjectRoleRepository {
+	return &ProjectRoleRepository{
+		canQuery: canQuery,
+	}
 }
 
 func (repo *ProjectRoleRepository) CreateProjectRole(role *models.ProjectRole) (*models.ProjectRole, error) {
-	panic("not implemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	repo.roles = append(repo.roles, role)
+	role.ID = uint(len(repo.roles))
+
+	return role, nil
 }
 
 func (repo *ProjectRoleRepository) ReadProjectRole(projectID uint, roleUID string) (*models.ProjectRole, error) {
-	panic("not implemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	for _, role := range repo.roles {
+		if role.UniqueID == roleUID && role.ProjectID == projectID {
+			return role, nil
+		}
+	}
+
+	return nil, gorm.ErrRecordNotFound
 }
 
 func (repo *ProjectRoleRepository) ListProjectRoles(projectID uint) ([]*models.ProjectRole, error) {
-	panic("not implemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	return repo.roles, nil
 }
 
 func (repo *ProjectRoleRepository) ListAllRolesForUser(projectID, userID uint) ([]*models.ProjectRole, error) {
-	panic("not implemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	var res []*models.ProjectRole
+
+	for _, role := range repo.roles {
+		if role.ProjectID != projectID {
+			continue
+		}
+
+		for _, u := range role.Users {
+			if u.ID == userID {
+				res = append(res, role)
+			}
+		}
+	}
+
+	return res, nil
 }
 
 func (repo *ProjectRoleRepository) UpdateUsersInProjectRole(projectID uint, roleUID string, userIDs []uint) error {
-	panic("not implemented")
+	if !repo.canQuery {
+		return errors.New("cannot write database")
+	}
+
+	var role *models.ProjectRole
+
+	for _, r := range repo.roles {
+		if r.UniqueID == roleUID && r.ProjectID == projectID {
+			role = r
+			break
+		}
+	}
+
+	if role == nil {
+		return gorm.ErrRecordNotFound
+	}
+
+	role.Users = []models.User{}
+
+	for _, userID := range userIDs {
+		role.Users = append(role.Users, models.User{
+			Model: gorm.Model{
+				ID: userID,
+			},
+		})
+	}
+
+	return nil
 }
 
 func (repo *ProjectRoleRepository) ClearUsersInProjectRole(projectID uint, roleUID string) error {
-	panic("not implemented")
+	if !repo.canQuery {
+		return errors.New("cannot write database")
+	}
+
+	var role *models.ProjectRole
+
+	for _, r := range repo.roles {
+		if r.UniqueID == roleUID && r.ProjectID == projectID {
+			role = r
+			break
+		}
+	}
+
+	if role == nil {
+		return gorm.ErrRecordNotFound
+	}
+
+	role.Users = []models.User{}
+
+	return nil
 }
 
 func (repo *ProjectRoleRepository) UpdateProjectRole(role *models.ProjectRole) (*models.ProjectRole, error) {
-	panic("not implemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	if role == nil || int(role.ID-1) >= len(repo.roles) || repo.roles[role.ID-1] == nil {
+		return nil, gorm.ErrRecordNotFound
+	}
+
+	repo.roles[role.ID-1] = role
+
+	return role, nil
 }
 
 func (repo *ProjectRoleRepository) DeleteProjectRole(role *models.ProjectRole) (*models.ProjectRole, error) {
-	panic("not implemented")
+	if !repo.canQuery {
+		return nil, errors.New("cannot write database")
+	}
+
+	if role == nil || int(role.ID-1) >= len(repo.roles) || repo.roles[role.ID-1] == nil {
+		return nil, gorm.ErrRecordNotFound
+	}
+
+	var newRoles []*models.ProjectRole
+
+	for _, r := range repo.roles {
+		if r.UniqueID != role.UniqueID {
+			newRoles = append(newRoles, r)
+		}
+	}
+
+	repo.roles = newRoles
+
+	return role, nil
 }

+ 1 - 0
internal/repository/test/repository.go

@@ -224,6 +224,7 @@ func NewRepository(canQuery bool, failingMethods ...string) repository.Repositor
 		user:                      NewUserRepository(canQuery, failingMethods...),
 		session:                   NewSessionRepository(canQuery, failingMethods...),
 		project:                   NewProjectRepository(canQuery, failingMethods...),
+		projectRole:               NewProjectRoleRepository(canQuery),
 		cluster:                   NewClusterRepository(canQuery),
 		helmRepo:                  NewHelmRepoRepository(canQuery),
 		registry:                  NewRegistryRepository(canQuery),

+ 6 - 4
internal/usage/usage.go

@@ -47,17 +47,19 @@ func GetUsage(opts *GetUsageOpts) (
 	}
 
 	// query for the linked user counts
-	roles, err := opts.Repo.Project().ListLegacyProjectRoles(opts.Project.ID)
+	roles, err := opts.Repo.ProjectRole().ListProjectRoles(opts.Project.ID)
 
 	if err != nil {
 		return nil, nil, nil, err
 	}
 
-	countedRoles := make([]models.Role, 0)
+	countedRoles := make(map[uint]bool)
 
 	for _, role := range roles {
-		if _, exists := opts.WhitelistedUsers[role.UserID]; !exists {
-			countedRoles = append(countedRoles, role)
+		for _, u := range role.Users {
+			if _, exists := opts.WhitelistedUsers[u.ID]; !exists {
+				countedRoles[u.ID] = true
+			}
 		}
 	}