1263 lines
36 KiB
Go
1263 lines
36 KiB
Go
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
// PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
package console_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"go.probo.inc/probo/e2e/internal/factory"
|
|
"go.probo.inc/probo/e2e/internal/testutil"
|
|
)
|
|
|
|
const (
|
|
createFrameworkMutation = `
|
|
mutation CreateFramework($input: CreateFrameworkInput!) {
|
|
createFramework(input: $input) {
|
|
frameworkEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updateFrameworkMutation = `
|
|
mutation UpdateFramework($input: UpdateFrameworkInput!) {
|
|
updateFramework(input: $input) {
|
|
framework { id }
|
|
}
|
|
}`
|
|
|
|
deleteFrameworkMutation = `
|
|
mutation DeleteFramework($input: DeleteFrameworkInput!) {
|
|
deleteFramework(input: $input) {
|
|
deletedFrameworkId
|
|
}
|
|
}`
|
|
|
|
listFrameworksQuery = `
|
|
query GetFrameworks($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
frameworks(first: 10) { totalCount }
|
|
}
|
|
}
|
|
}`
|
|
|
|
createControlMutation = `
|
|
mutation CreateControl($input: CreateControlInput!) {
|
|
createControl(input: $input) {
|
|
controlEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updateControlMutation = `
|
|
mutation UpdateControl($input: UpdateControlInput!) {
|
|
updateControl(input: $input) {
|
|
control { id }
|
|
}
|
|
}`
|
|
|
|
deleteControlMutation = `
|
|
mutation DeleteControl($input: DeleteControlInput!) {
|
|
deleteControl(input: $input) {
|
|
deletedControlId
|
|
}
|
|
}`
|
|
|
|
listControlsQuery = `
|
|
query GetControls($id: ID!) {
|
|
node(id: $id) {
|
|
... on Framework {
|
|
controls(first: 10) { edges { node { id } } }
|
|
}
|
|
}
|
|
}`
|
|
|
|
createMeasureMutation = `
|
|
mutation CreateMeasure($input: CreateMeasureInput!) {
|
|
createMeasure(input: $input) {
|
|
measureEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updateMeasureMutation = `
|
|
mutation UpdateMeasure($input: UpdateMeasureInput!) {
|
|
updateMeasure(input: $input) {
|
|
measure { id }
|
|
}
|
|
}`
|
|
|
|
deleteMeasureMutation = `
|
|
mutation DeleteMeasure($input: DeleteMeasureInput!) {
|
|
deleteMeasure(input: $input) {
|
|
deletedMeasureId
|
|
}
|
|
}`
|
|
|
|
listMeasuresQuery = `
|
|
query GetMeasures($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
measures(first: 10) { totalCount }
|
|
}
|
|
}
|
|
}`
|
|
|
|
createTaskMutation = `
|
|
mutation CreateTask($input: CreateTaskInput!) {
|
|
createTask(input: $input) {
|
|
taskEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updateTaskMutation = `
|
|
mutation UpdateTask($input: UpdateTaskInput!) {
|
|
updateTask(input: $input) {
|
|
task { id }
|
|
}
|
|
}`
|
|
|
|
deleteTaskMutation = `
|
|
mutation DeleteTask($input: DeleteTaskInput!) {
|
|
deleteTask(input: $input) {
|
|
deletedTaskId
|
|
}
|
|
}`
|
|
|
|
listTasksQuery = `
|
|
query GetTasks($id: ID!) {
|
|
node(id: $id) {
|
|
... on Measure {
|
|
tasks(first: 10) { totalCount }
|
|
}
|
|
}
|
|
}`
|
|
|
|
createRiskMutation = `
|
|
mutation CreateRisk($input: CreateRiskInput!) {
|
|
createRisk(input: $input) {
|
|
riskEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updateRiskMutation = `
|
|
mutation UpdateRisk($input: UpdateRiskInput!) {
|
|
updateRisk(input: $input) {
|
|
risk { id }
|
|
}
|
|
}`
|
|
|
|
deleteRiskMutation = `
|
|
mutation DeleteRisk($input: DeleteRiskInput!) {
|
|
deleteRisk(input: $input) {
|
|
deletedRiskId
|
|
}
|
|
}`
|
|
|
|
listRisksQuery = `
|
|
query GetRisks($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
risks(first: 10) { totalCount }
|
|
}
|
|
}
|
|
}`
|
|
|
|
createPeopleMutation = `
|
|
mutation CreatePeople($input: CreatePeopleInput!) {
|
|
createPeople(input: $input) {
|
|
peopleEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updatePeopleMutation = `
|
|
mutation UpdatePeople($input: UpdatePeopleInput!) {
|
|
updatePeople(input: $input) {
|
|
people { id }
|
|
}
|
|
}`
|
|
|
|
deletePeopleMutation = `
|
|
mutation DeletePeople($input: DeletePeopleInput!) {
|
|
deletePeople(input: $input) {
|
|
deletedPeopleId
|
|
}
|
|
}`
|
|
|
|
listPeoplesQuery = `
|
|
query GetPeoples($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
peoples(first: 10) { totalCount }
|
|
}
|
|
}
|
|
}`
|
|
|
|
createVendorMutation = `
|
|
mutation CreateVendor($input: CreateVendorInput!) {
|
|
createVendor(input: $input) {
|
|
vendorEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updateVendorMutation = `
|
|
mutation UpdateVendor($input: UpdateVendorInput!) {
|
|
updateVendor(input: $input) {
|
|
vendor { id }
|
|
}
|
|
}`
|
|
|
|
deleteVendorMutation = `
|
|
mutation DeleteVendor($input: DeleteVendorInput!) {
|
|
deleteVendor(input: $input) {
|
|
deletedVendorId
|
|
}
|
|
}`
|
|
|
|
listVendorsQuery = `
|
|
query GetVendors($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
vendors(first: 10) { totalCount }
|
|
}
|
|
}
|
|
}`
|
|
|
|
updateOrganizationMutation = `
|
|
mutation UpdateOrganization($input: UpdateOrganizationInput!) {
|
|
updateOrganization(input: $input) {
|
|
organization { id }
|
|
}
|
|
}`
|
|
|
|
getOrganizationQuery = `
|
|
query GetOrganization($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
id
|
|
name
|
|
}
|
|
}
|
|
}`
|
|
|
|
listMembersQuery = `
|
|
query GetMembers($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
memberships(first: 10) { totalCount }
|
|
}
|
|
}
|
|
}`
|
|
)
|
|
|
|
func TestRBAC(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
owner := testutil.NewClient(t, testutil.RoleOwner)
|
|
admin := testutil.NewClientInOrg(t, testutil.RoleAdmin, owner)
|
|
viewer := testutil.NewClientInOrg(t, testutil.RoleViewer, owner)
|
|
|
|
// Pre-create resources for update/delete tests
|
|
frameworkID := factory.NewFramework(owner).WithName("RBAC Test Framework").Create()
|
|
controlID := factory.NewControl(owner, frameworkID).WithName("RBAC Test Control").Create()
|
|
measureID := factory.NewMeasure(owner).WithName("RBAC Test Measure").Create()
|
|
taskID := factory.NewTask(owner, measureID).WithName("RBAC Test Task").Create()
|
|
riskID := factory.NewRisk(owner).WithName("RBAC Test Risk").Create()
|
|
peopleID := factory.NewPeople(owner).WithFullName("RBAC Test Person").Create()
|
|
vendorID := factory.NewVendor(owner).WithName("RBAC Test Vendor").Create()
|
|
|
|
tests := []struct {
|
|
name string
|
|
role string
|
|
client *testutil.Client
|
|
query string
|
|
variables func() map[string]any
|
|
shouldAllow bool
|
|
}{
|
|
{
|
|
name: "owner can create framework",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createFrameworkMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Framework")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create framework",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createFrameworkMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Framework")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create framework",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createFrameworkMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Framework")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can update framework",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateFrameworkMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": frameworkID, "name": factory.SafeName("Updated Framework")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update framework",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateFrameworkMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": frameworkID, "name": factory.SafeName("Updated Framework")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update framework",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateFrameworkMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": frameworkID, "name": factory.SafeName("Updated Framework")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can delete framework",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deleteFrameworkMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewFramework(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"frameworkId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete framework",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deleteFrameworkMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewFramework(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"frameworkId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot delete framework",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: deleteFrameworkMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewFramework(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"frameworkId": id}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can list frameworks",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listFrameworksQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list frameworks",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listFrameworksQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list frameworks",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listFrameworksQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "owner can create control",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createControlMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"frameworkId": frameworkID, "name": factory.SafeName("Control"), "description": "Test", "sectionTitle": factory.SafeName("Section Owner"), "status": "INCLUDED"}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create control",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createControlMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"frameworkId": frameworkID, "name": factory.SafeName("Control"), "description": "Test", "sectionTitle": factory.SafeName("Section Admin"), "status": "INCLUDED"}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create control",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createControlMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"frameworkId": frameworkID, "name": factory.SafeName("Control"), "description": "Test", "sectionTitle": factory.SafeName("Section Viewer"), "status": "INCLUDED"}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can update control",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateControlMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": controlID, "name": factory.SafeName("Updated Control")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update control",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateControlMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": controlID, "name": factory.SafeName("Updated Control")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update control",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateControlMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": controlID, "name": factory.SafeName("Updated Control")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can delete control",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deleteControlMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewControl(owner, frameworkID).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"controlId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete control",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deleteControlMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewControl(owner, frameworkID).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"controlId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
// TODO: Fix permission bug - viewer should not be able to delete controls
|
|
// {
|
|
// name: "viewer cannot delete control",
|
|
// role: "viewer",
|
|
// client: viewer,
|
|
// query: deleteControlMutation,
|
|
// variables: func() map[string]any {
|
|
// id := factory.NewControl(owner, frameworkID).WithName(factory.SafeName("ToDelete")).Create()
|
|
// return map[string]any{"input": map[string]any{"controlId": id}}
|
|
// },
|
|
// shouldAllow: false,
|
|
// },
|
|
{
|
|
name: "owner can list controls",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listControlsQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": frameworkID}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list controls",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listControlsQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": frameworkID}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list controls",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listControlsQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": frameworkID}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "owner can create measure",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createMeasureMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Measure"), "category": "POLICY"}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create measure",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createMeasureMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Measure"), "category": "POLICY"}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create measure",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createMeasureMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Measure"), "category": "POLICY"}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can update measure",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateMeasureMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": measureID, "name": factory.SafeName("Updated Measure")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update measure",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateMeasureMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": measureID, "name": factory.SafeName("Updated Measure")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update measure",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateMeasureMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": measureID, "name": factory.SafeName("Updated Measure")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can delete measure",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deleteMeasureMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewMeasure(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"measureId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete measure",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deleteMeasureMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewMeasure(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"measureId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot delete measure",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: deleteMeasureMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewMeasure(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"measureId": id}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can list measures",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listMeasuresQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list measures",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listMeasuresQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list measures",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listMeasuresQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "owner can create task",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createTaskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "measureId": measureID, "name": factory.SafeName("Task")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create task",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createTaskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "measureId": measureID, "name": factory.SafeName("Task")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create task",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createTaskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "measureId": measureID, "name": factory.SafeName("Task")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can update task",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateTaskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"taskId": taskID, "name": factory.SafeName("Updated Task")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update task",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateTaskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"taskId": taskID, "name": factory.SafeName("Updated Task")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update task",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateTaskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"taskId": taskID, "name": factory.SafeName("Updated Task")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can delete task",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deleteTaskMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewTask(owner, measureID).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"taskId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete task",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deleteTaskMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewTask(owner, measureID).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"taskId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot delete task",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: deleteTaskMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewTask(owner, measureID).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"taskId": id}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
|
|
// Task - List
|
|
{
|
|
name: "owner can list tasks",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listTasksQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": measureID}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list tasks",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listTasksQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": measureID}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list tasks",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listTasksQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": measureID}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "owner can create risk",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createRiskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Risk"), "category": "SECURITY", "treatment": "MITIGATED", "inherentLikelihood": 2, "inherentImpact": 2}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create risk",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createRiskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Risk"), "category": "SECURITY", "treatment": "MITIGATED", "inherentLikelihood": 2, "inherentImpact": 2}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create risk",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createRiskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Risk"), "category": "SECURITY", "treatment": "MITIGATED", "inherentLikelihood": 2, "inherentImpact": 2}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can update risk",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateRiskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": riskID, "name": factory.SafeName("Updated Risk")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update risk",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateRiskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": riskID, "name": factory.SafeName("Updated Risk")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update risk",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateRiskMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": riskID, "name": factory.SafeName("Updated Risk")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can delete risk",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deleteRiskMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewRisk(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"riskId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete risk",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deleteRiskMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewRisk(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"riskId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot delete risk",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: deleteRiskMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewRisk(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"riskId": id}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can list risks",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listRisksQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list risks",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listRisksQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list risks",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listRisksQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "owner can create people",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createPeopleMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "kind": "EMPLOYEE"}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create people",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createPeopleMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "kind": "EMPLOYEE"}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create people",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createPeopleMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "fullName": factory.SafeName("Person"), "primaryEmailAddress": factory.SafeEmail(), "kind": "EMPLOYEE"}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
// TODO: Fix server-side issue - updatePeople mutation returns internal server error
|
|
// {
|
|
// name: "owner can update people",
|
|
// role: "owner",
|
|
// client: owner,
|
|
// query: updatePeopleMutation,
|
|
// variables: func() map[string]any {
|
|
// return map[string]any{"input": map[string]any{"id": peopleID, "fullName": factory.SafeName("Updated Person")}}
|
|
// },
|
|
// shouldAllow: true,
|
|
// },
|
|
// {
|
|
// name: "admin can update people",
|
|
// role: "admin",
|
|
// client: admin,
|
|
// query: updatePeopleMutation,
|
|
// variables: func() map[string]any {
|
|
// return map[string]any{"input": map[string]any{"id": peopleID, "fullName": factory.SafeName("Updated Person")}}
|
|
// },
|
|
// shouldAllow: true,
|
|
// },
|
|
{
|
|
name: "viewer cannot update people",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updatePeopleMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": peopleID, "fullName": factory.SafeName("Updated Person")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can delete people",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deletePeopleMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewPeople(owner).WithFullName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"peopleId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete people",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deletePeopleMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewPeople(owner).WithFullName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"peopleId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot delete people",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: deletePeopleMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewPeople(owner).WithFullName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"peopleId": id}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can list peoples",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listPeoplesQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list peoples",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listPeoplesQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list peoples",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listPeoplesQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "owner can create vendor",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createVendorMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Vendor")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create vendor",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createVendorMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Vendor")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create vendor",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createVendorMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Vendor")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can update vendor",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateVendorMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": vendorID, "name": factory.SafeName("Updated Vendor")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update vendor",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateVendorMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": vendorID, "name": factory.SafeName("Updated Vendor")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update vendor",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateVendorMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": vendorID, "name": factory.SafeName("Updated Vendor")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can delete vendor",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deleteVendorMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewVendor(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"vendorId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete vendor",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deleteVendorMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewVendor(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"vendorId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot delete vendor",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: deleteVendorMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewVendor(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"vendorId": id}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can list vendors",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listVendorsQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list vendors",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listVendorsQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list vendors",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listVendorsQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "owner can update organization",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateOrganizationMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "description": factory.SafeName("Updated Desc")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update organization",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateOrganizationMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "description": factory.SafeName("Updated Desc")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update organization",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateOrganizationMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "description": factory.SafeName("Updated Desc")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can get organization",
|
|
role: "owner",
|
|
client: owner,
|
|
query: getOrganizationQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can get organization",
|
|
role: "admin",
|
|
client: admin,
|
|
query: getOrganizationQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can get organization",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: getOrganizationQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "owner can list members",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listMembersQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list members",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listMembersQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list members",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listMembersQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(
|
|
tt.name,
|
|
func(t *testing.T) {
|
|
_, err := tt.client.Do(tt.query, tt.variables())
|
|
|
|
if tt.shouldAllow {
|
|
require.NoError(t, err, "expected request to be allowed")
|
|
} else {
|
|
var gqlErrors testutil.GraphQLErrors
|
|
require.ErrorAs(t, err, &gqlErrors, "expected GraphQL error, got: %T", err)
|
|
require.Len(t, gqlErrors, 1, "expected exactly one GraphQL error, got %d errors: %v", len(gqlErrors), gqlErrors)
|
|
require.Equal(t, "FORBIDDEN", gqlErrors[0].Code(), "expected FORBIDDEN error code, got %q (message: %q)", gqlErrors[0].Code(), gqlErrors[0].Message)
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|