Skip to content

Commit

Permalink
DEVPROD-3065: Update directive to handle SetLastRevision permission (e…
Browse files Browse the repository at this point in the history
  • Loading branch information
SupaJoon authored and malikchaya2 committed Apr 10, 2024
1 parent 58899fd commit e23e424
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 21 deletions.
58 changes: 56 additions & 2 deletions graphql/directive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ func setupPermissions(t *testing.T) {

func TestRequireDistroAccess(t *testing.T) {
setupPermissions(t)
require.NoError(t, db.Clear(user.Collection),
"unable to clear user collection")
require.NoError(t, db.ClearCollections(model.ProjectRefCollection, user.Collection),
"unable to clear user or project ref collection")
dbUser := &user.DBUser{
Id: apiUser,
Settings: user.UserSettings{
Expand Down Expand Up @@ -401,6 +401,13 @@ func TestRequireProjectAdmin(t *testing.T) {
ctx = gimlet.AttachUser(ctx, usr)
require.NotNil(t, ctx)

projectRef := model.ProjectRef{
Id: "project_id",
Identifier: "project_identifier",
}
err = projectRef.Insert()
require.NoError(t, err)

// superuser should always be successful, no matter the resolver
err = usr.AddRole("superuser")
require.NoError(t, err)
Expand Down Expand Up @@ -479,6 +486,53 @@ func TestRequireProjectAdmin(t *testing.T) {
require.NoError(t, err)
require.Nil(t, res)
require.Equal(t, 4, callCount)

// SetLastRevision - successful
operationContext = &graphql.OperationContext{
OperationName: SetLastRevisionMutation,
}
ctx = graphql.WithOperationContext(ctx, operationContext)
obj = map[string]interface{}{
"opts": map[string]interface{}{
"projectIdentifier": "project_identifier",
},
}
res, err = config.Directives.RequireProjectAdmin(ctx, obj, next)
require.NoError(t, err)
require.Nil(t, res)
require.Equal(t, 5, callCount)

// SetLastRevision - project not found
operationContext = &graphql.OperationContext{
OperationName: SetLastRevisionMutation,
}
ctx = graphql.WithOperationContext(ctx, operationContext)
obj = map[string]interface{}{
"opts": map[string]interface{}{
"projectIdentifier": "project_whatever",
},
}
res, err = config.Directives.RequireProjectAdmin(ctx, obj, next)
require.EqualError(t, err, "input: project 'project_whatever' not found")
require.Nil(t, res)
require.Equal(t, 5, callCount)

// SetLastRevision - permission denied
operationContext = &graphql.OperationContext{
OperationName: SetLastRevisionMutation,
}
ctx = graphql.WithOperationContext(ctx, operationContext)
obj = map[string]interface{}{
"opts": map[string]interface{}{
"projectIdentifier": "project_identifier",
},
}
require.NoError(t, usr.RemoveRole("admin_project"))
res, err = config.Directives.RequireProjectAdmin(ctx, obj, next)
require.EqualError(t, err, "input: user testuser does not have permission to access the SetLastRevision resolver")
require.Nil(t, res)
require.Equal(t, 5, callCount)

}

func setupUser(t *testing.T) (*user.DBUser, error) {
Expand Down
57 changes: 38 additions & 19 deletions graphql/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@ import (

"github.com/99designs/gqlgen/graphql"
"github.com/evergreen-ci/evergreen"
"github.com/evergreen-ci/evergreen/model"
"github.com/evergreen-ci/evergreen/rest/data"
restModel "github.com/evergreen-ci/evergreen/rest/model"
"github.com/evergreen-ci/gimlet"
"github.com/evergreen-ci/utility"
)

const (
CreateProjectMutation = "CreateProject"
CopyProjectMutation = "CopyProject"
DeleteProjectMutation = "DeleteProject"
CreateProjectMutation = "CreateProject"
CopyProjectMutation = "CopyProject"
DeleteProjectMutation = "DeleteProject"
SetLastRevisionMutation = "SetLastRevision"
)

type Resolver struct {
Expand Down Expand Up @@ -87,11 +89,6 @@ func New(apiURL string) Config {
return next(ctx)
}

// Check for admin permissions for each of the resolvers.
args, isStringMap := obj.(map[string]interface{})
if !isStringMap {
return nil, ResourceNotFound.Send(ctx, "Project not specified")
}
operationContext := graphql.GetOperationContext(ctx).OperationName

if operationContext == CreateProjectMutation {
Expand All @@ -104,17 +101,26 @@ func New(apiURL string) Config {
}
}

getPermissionOpts := func(projectId string) gimlet.PermissionOpts {
return gimlet.PermissionOpts{
Resource: projectId,
ResourceType: evergreen.ProjectResourceType,
Permission: evergreen.PermissionProjectSettings,
RequiredLevel: evergreen.ProjectSettingsEdit.Value,
}
}

args, isStringMap := obj.(map[string]interface{})
if !isStringMap {
return nil, ResourceNotFound.Send(ctx, "Project not specified")
}

if operationContext == CopyProjectMutation {
projectIdToCopy, ok := args["project"].(map[string]interface{})["projectIdToCopy"].(string)
if !ok {
return nil, InternalServerError.Send(ctx, "finding projectIdToCopy for copy project operation")
}
opts := gimlet.PermissionOpts{
Resource: projectIdToCopy,
ResourceType: evergreen.ProjectResourceType,
Permission: evergreen.PermissionProjectSettings,
RequiredLevel: evergreen.ProjectSettingsEdit.Value,
}
opts := getPermissionOpts(projectIdToCopy)
if user.HasPermission(opts) {
return next(ctx)
}
Expand All @@ -125,12 +131,25 @@ func New(apiURL string) Config {
if !ok {
return nil, InternalServerError.Send(ctx, "finding projectId for delete project operation")
}
opts := gimlet.PermissionOpts{
Resource: projectId,
ResourceType: evergreen.ProjectResourceType,
Permission: evergreen.PermissionProjectSettings,
RequiredLevel: evergreen.ProjectSettingsEdit.Value,
opts := getPermissionOpts(projectId)
if user.HasPermission(opts) {
return next(ctx)
}
}

if operationContext == SetLastRevisionMutation {
projectIdentifier, ok := args["opts"].(map[string]interface{})["projectIdentifier"].(string)
if !ok {
return nil, InternalServerError.Send(ctx, "finding projectIdentifier for set last revision operation")
}
project, err := model.FindBranchProjectRef(projectIdentifier)
if err != nil {
return nil, InternalServerError.Send(ctx, fmt.Sprintf("finding project '%s': %s", projectIdentifier, err.Error()))
}
if project == nil {
return nil, ResourceNotFound.Send(ctx, fmt.Sprintf("project '%s' not found", projectIdentifier))
}
opts := getPermissionOpts(project.Id)
if user.HasPermission(opts) {
return next(ctx)
}
Expand Down

0 comments on commit e23e424

Please sign in to comment.