Decouple each campaign from the live access-review sources it was started with by introducing a per-campaign source snapshot table (access_review_campaign_sources). The snapshot captures the source name, category, and connector at start time, so a review remains coherent even after the underlying source is edited or deleted. Fetch tracking becomes an append-only log (access_review_campaign_source_fetch_attempts) that preserves every attempt with its own status and error rather than overwriting a single row. Rename the shared access-review tables and enums to use a consistent access_review_ prefix throughout: access_entries → access_review_entries access_sources → access_review_sources access_source_category → access_review_source_category access_entry_* → access_review_entry_* The same rename propagates to every coredata type, service, GraphQL schema, MCP specification, CLI command, frontend component, and e2e test. The accessreview package gains dedicated actions.go and policies.go files for its own IAM policy set, mirroring the agentrun package pattern. Signed-off-by: Bryan Frimin <bryan@probo.com>
1443 lines
42 KiB
Go
1443 lines
42 KiB
Go
// Copyright (c) 2025-2026 Probo Inc <hello@probo.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 (
|
|
"strings"
|
|
"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 }
|
|
}
|
|
}
|
|
}`
|
|
|
|
createThirdPartyMutation = `
|
|
mutation CreateThirdParty($input: CreateThirdPartyInput!) {
|
|
createThirdParty(input: $input) {
|
|
thirdPartyEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updateThirdPartyMutation = `
|
|
mutation UpdateThirdParty($input: UpdateThirdPartyInput!) {
|
|
updateThirdParty(input: $input) {
|
|
thirdParty { id }
|
|
}
|
|
}`
|
|
|
|
deleteThirdPartyMutation = `
|
|
mutation DeleteThirdParty($input: DeleteThirdPartyInput!) {
|
|
deleteThirdParty(input: $input) {
|
|
deletedThirdPartyId
|
|
}
|
|
}`
|
|
|
|
listThirdPartiesQuery = `
|
|
query GetThirdParties($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
thirdParties(first: 10) { totalCount }
|
|
}
|
|
}
|
|
}`
|
|
|
|
createAccessReviewSourceMutation = `
|
|
mutation CreateAccessReviewSource($input: CreateAccessReviewSourceInput!) {
|
|
createAccessReviewSource(input: $input) {
|
|
accessReviewSourceEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updateAccessReviewSourceMutation = `
|
|
mutation UpdateAccessReviewSource($input: UpdateAccessReviewSourceInput!) {
|
|
updateAccessReviewSource(input: $input) {
|
|
accessReviewSource { id }
|
|
}
|
|
}`
|
|
|
|
deleteAccessReviewSourceMutation = `
|
|
mutation DeleteAccessReviewSource($input: DeleteAccessReviewSourceInput!) {
|
|
deleteAccessReviewSource(input: $input) {
|
|
deletedAccessReviewSourceId
|
|
}
|
|
}`
|
|
|
|
listAccessReviewSourcesQuery = `
|
|
query GetAccessReviewSources($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
accessReviewSources(first: 10) { totalCount }
|
|
}
|
|
}
|
|
}`
|
|
|
|
createAccessReviewCampaignMutation = `
|
|
mutation CreateCampaign($input: CreateAccessReviewCampaignInput!) {
|
|
createAccessReviewCampaign(input: $input) {
|
|
accessReviewCampaignEdge { node { id } }
|
|
}
|
|
}`
|
|
|
|
updateAccessReviewCampaignMutation = `
|
|
mutation UpdateCampaign($input: UpdateAccessReviewCampaignInput!) {
|
|
updateAccessReviewCampaign(input: $input) {
|
|
accessReviewCampaign { id }
|
|
}
|
|
}`
|
|
|
|
deleteAccessReviewCampaignMutation = `
|
|
mutation DeleteCampaign($input: DeleteAccessReviewCampaignInput!) {
|
|
deleteAccessReviewCampaign(input: $input) {
|
|
deletedAccessReviewCampaignId
|
|
}
|
|
}`
|
|
|
|
listAccessReviewCampaignsQuery = `
|
|
query GetCampaigns($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
accessReviewCampaigns(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
|
|
}
|
|
}
|
|
}`
|
|
|
|
listUsersQuery = `
|
|
query GetProfiles($id: ID!) {
|
|
node(id: $id) {
|
|
... on Organization {
|
|
profiles(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()
|
|
thirdPartyID := factory.NewThirdParty(owner).WithName("RBAC Test ThirdParty").Create()
|
|
accessReviewSourceID := factory.NewAccessReviewSource(owner, owner.GetOrganizationID().String()).WithName("RBAC Test Source").Create()
|
|
accessReviewCampaignID := factory.NewAccessReviewCampaign(owner, owner.GetOrganizationID().String()).WithName("RBAC Test Campaign").Create()
|
|
|
|
tests := []struct {
|
|
name string
|
|
role string
|
|
client *testutil.Client
|
|
query string
|
|
variables func() map[string]any
|
|
shouldAllow bool
|
|
useConnect bool // use connect API instead of console API
|
|
}{
|
|
{
|
|
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"), "bestPractice": true, "maturityLevel": "INITIAL"}}
|
|
},
|
|
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"), "bestPractice": true, "maturityLevel": "INITIAL"}}
|
|
},
|
|
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"), "bestPractice": true, "maturityLevel": "INITIAL"}}
|
|
},
|
|
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"), "priority": "MEDIUM"}}
|
|
},
|
|
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"), "priority": "MEDIUM"}}
|
|
},
|
|
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"), "priority": "MEDIUM"}}
|
|
},
|
|
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 thirdParty",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createThirdPartyMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("ThirdParty")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create thirdParty",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createThirdPartyMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("ThirdParty")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create thirdParty",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createThirdPartyMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("ThirdParty")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can update thirdParty",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateThirdPartyMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": thirdPartyID, "name": factory.SafeName("Updated ThirdParty")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update thirdParty",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateThirdPartyMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": thirdPartyID, "name": factory.SafeName("Updated ThirdParty")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update thirdParty",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateThirdPartyMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"id": thirdPartyID, "name": factory.SafeName("Updated ThirdParty")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can delete thirdParty",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deleteThirdPartyMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewThirdParty(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"thirdPartyId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete thirdParty",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deleteThirdPartyMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewThirdParty(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"thirdPartyId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot delete thirdParty",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: deleteThirdPartyMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewThirdParty(owner).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"thirdPartyId": id}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
{
|
|
name: "owner can list third parties",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listThirdPartiesQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list third parties",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listThirdPartiesQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list third parties",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listThirdPartiesQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
// Access Source - Create
|
|
{
|
|
name: "owner can create access source",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createAccessReviewSourceMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("AccessReviewSource")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create access source",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createAccessReviewSourceMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("AccessReviewSource")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create access source",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createAccessReviewSourceMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("AccessReviewSource")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
// Access Source - Update
|
|
{
|
|
name: "owner can update access source",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateAccessReviewSourceMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"accessReviewSourceId": accessReviewSourceID, "name": factory.SafeName("Updated Source")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update access source",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateAccessReviewSourceMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"accessReviewSourceId": accessReviewSourceID, "name": factory.SafeName("Updated Source")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update access source",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateAccessReviewSourceMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"accessReviewSourceId": accessReviewSourceID, "name": factory.SafeName("Updated Source")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
// Access Source - Delete
|
|
{
|
|
name: "owner can delete access source",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deleteAccessReviewSourceMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewAccessReviewSource(owner, owner.GetOrganizationID().String()).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"accessReviewSourceId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete access source",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deleteAccessReviewSourceMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewAccessReviewSource(owner, owner.GetOrganizationID().String()).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"accessReviewSourceId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot delete access source",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: deleteAccessReviewSourceMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewAccessReviewSource(owner, owner.GetOrganizationID().String()).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"accessReviewSourceId": id}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
// Access Source - List
|
|
{
|
|
name: "owner can list access sources",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listAccessReviewSourcesQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list access sources",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listAccessReviewSourcesQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list access sources",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listAccessReviewSourcesQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
// Access Review Campaign - Create
|
|
{
|
|
name: "owner can create access review campaign",
|
|
role: "owner",
|
|
client: owner,
|
|
query: createAccessReviewCampaignMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Campaign")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can create access review campaign",
|
|
role: "admin",
|
|
client: admin,
|
|
query: createAccessReviewCampaignMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Campaign")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot create access review campaign",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: createAccessReviewCampaignMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"organizationId": owner.GetOrganizationID().String(), "name": factory.SafeName("Campaign")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
// Access Review Campaign - Update
|
|
{
|
|
name: "owner can update access review campaign",
|
|
role: "owner",
|
|
client: owner,
|
|
query: updateAccessReviewCampaignMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"accessReviewCampaignId": accessReviewCampaignID, "name": factory.SafeName("Updated Campaign")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can update access review campaign",
|
|
role: "admin",
|
|
client: admin,
|
|
query: updateAccessReviewCampaignMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"accessReviewCampaignId": accessReviewCampaignID, "name": factory.SafeName("Updated Campaign")}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot update access review campaign",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: updateAccessReviewCampaignMutation,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"input": map[string]any{"accessReviewCampaignId": accessReviewCampaignID, "name": factory.SafeName("Updated Campaign")}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
// Access Review Campaign - Delete
|
|
{
|
|
name: "owner can delete access review campaign",
|
|
role: "owner",
|
|
client: owner,
|
|
query: deleteAccessReviewCampaignMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewAccessReviewCampaign(owner, owner.GetOrganizationID().String()).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"accessReviewCampaignId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can delete access review campaign",
|
|
role: "admin",
|
|
client: admin,
|
|
query: deleteAccessReviewCampaignMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewAccessReviewCampaign(owner, owner.GetOrganizationID().String()).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"accessReviewCampaignId": id}}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer cannot delete access review campaign",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: deleteAccessReviewCampaignMutation,
|
|
variables: func() map[string]any {
|
|
id := factory.NewAccessReviewCampaign(owner, owner.GetOrganizationID().String()).WithName(factory.SafeName("ToDelete")).Create()
|
|
return map[string]any{"input": map[string]any{"accessReviewCampaignId": id}}
|
|
},
|
|
shouldAllow: false,
|
|
},
|
|
// Access Review Campaign - List
|
|
{
|
|
name: "owner can list access review campaigns",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listAccessReviewCampaignsQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "admin can list access review campaigns",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listAccessReviewCampaignsQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
},
|
|
{
|
|
name: "viewer can list access review campaigns",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listAccessReviewCampaignsQuery,
|
|
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,
|
|
useConnect: 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,
|
|
useConnect: 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,
|
|
useConnect: true,
|
|
},
|
|
{
|
|
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,
|
|
useConnect: 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,
|
|
useConnect: 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,
|
|
useConnect: true,
|
|
},
|
|
{
|
|
name: "owner can list users",
|
|
role: "owner",
|
|
client: owner,
|
|
query: listUsersQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
useConnect: true,
|
|
},
|
|
{
|
|
name: "admin can list users",
|
|
role: "admin",
|
|
client: admin,
|
|
query: listUsersQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
useConnect: true,
|
|
},
|
|
{
|
|
name: "viewer can list users",
|
|
role: "viewer",
|
|
client: viewer,
|
|
query: listUsersQuery,
|
|
variables: func() map[string]any {
|
|
return map[string]any{"id": owner.GetOrganizationID().String()}
|
|
},
|
|
shouldAllow: true,
|
|
useConnect: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(
|
|
tt.name,
|
|
func(t *testing.T) {
|
|
var err error
|
|
if tt.useConnect {
|
|
_, err = tt.client.DoConnect(tt.query, tt.variables())
|
|
} else {
|
|
_, 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)
|
|
// Connect API uses a different error format - check either code or message
|
|
code := gqlErrors[0].Code()
|
|
msg := gqlErrors[0].Message
|
|
isForbidden := code == "FORBIDDEN" || (code == "" && (strings.Contains(msg, "does not have sufficient permissions") || strings.Contains(msg, "insufficient permissions")))
|
|
require.True(t, isForbidden, "expected FORBIDDEN error, got code=%q message=%q", code, msg)
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|