diff --git a/pkg/coredata/api_key_membership.go b/pkg/coredata/api_key_membership.go deleted file mode 100644 index 3dde5e7c7..000000000 --- a/pkg/coredata/api_key_membership.go +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright (c) 2025 Probo Inc . -// -// 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 coredata - -import ( - "context" - "fmt" - "maps" - "time" - - "github.com/jackc/pgx/v5" - "go.gearno.de/kit/pg" - "go.probo.inc/probo/pkg/gid" -) - -type ( - PersonalAPIKeyMembership struct { - ID gid.GID `db:"id"` - PersonalAPIKeyID gid.GID `db:"personal_api_key_id"` - MembershipID gid.GID `db:"membership_id"` - Role APIRole `db:"role"` - OrganizationID gid.GID `db:"organization_id"` - OrganizationName string `db:"organization_name"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` - } - - PersonalAPIKeyMemberships []*PersonalAPIKeyMembership -) - -func (a *PersonalAPIKeyMembership) Insert( - ctx context.Context, - conn pg.Conn, - scope Scoper, -) error { - q := ` -INSERT INTO - iam_personal_api_key_memberships (id, tenant_id, personal_api_key_id, membership_id, role, organization_id, created_at, updated_at) -VALUES ( - @id, - @tenant_id, - @personal_api_key_id, - @membership_id, - @role, - @organization_id, - @created_at, - @updated_at -) -` - - args := pgx.StrictNamedArgs{ - "id": a.ID, - "tenant_id": scope.GetTenantID(), - "personal_api_key_id": a.PersonalAPIKeyID, - "membership_id": a.MembershipID, - "role": a.Role, - "organization_id": a.OrganizationID, - "created_at": a.CreatedAt, - "updated_at": a.UpdatedAt, - } - - _, err := conn.Exec(ctx, q, args) - if err != nil { - return fmt.Errorf("cannot insert personal api key membership: %w", err) - } - - return nil -} - -func (a *PersonalAPIKeyMemberships) LoadByPersonalAPIKeyID( - ctx context.Context, - conn pg.Conn, - scope Scoper, - personalAPIKeyID gid.GID, -) error { - q := ` -SELECT - akm.id, - akm.personal_api_key_id, - akm.membership_id, - akm.role, - akm.created_at, - akm.updated_at, - m.organization_id, - o.name as organization_name -FROM - iam_personal_api_key_memberships akm -JOIN - iam_memberships m ON akm.membership_id = m.id -JOIN - organizations o ON m.organization_id = o.id -WHERE - akm.personal_api_key_id = @personal_api_key_id - AND m.%s -ORDER BY akm.created_at DESC -` - - q = fmt.Sprintf(q, scope.SQLFragment()) - - args := pgx.StrictNamedArgs{ - "personal_api_key_id": personalAPIKeyID, - } - maps.Copy(args, scope.SQLArguments()) - - rows, err := conn.Query(ctx, q, args) - if err != nil { - return fmt.Errorf("cannot query personal api key memberships: %w", err) - } - - memberships, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[PersonalAPIKeyMembership]) - if err != nil { - return fmt.Errorf("cannot collect personal api key memberships: %w", err) - } - - *a = memberships - - return nil -} - -// LoadRoleByAPIKeyAndEntityID loads an API key's role by querying any entity to extract its organization_id -func (a *PersonalAPIKeyMembership) LoadRoleByAPIKeyAndEntityID( - ctx context.Context, - conn pg.Conn, - scope Scoper, - apiKeyID gid.GID, - entityID gid.GID, -) error { - entityType := entityID.EntityType() - - // For organization, the entity ID is the organization ID - if entityType == OrganizationEntityType { - return a.LoadByAPIKeyIDAndOrganizationID(ctx, conn, scope, apiKeyID, entityID) - } - - tableName, ok := EntityTable(entityType) - if !ok { - return fmt.Errorf("unsupported entity type for API key role lookup: %d", entityType) - } - - query := fmt.Sprintf(` -SELECT - akm.id, - akm.personal_api_key_id, - akm.membership_id, - akm.role, - akm.created_at, - akm.updated_at -FROM - iam_personal_api_key_memberships akm - INNER JOIN iam_memberships m ON m.id = akm.membership_id - INNER JOIN %s e ON e.id = @entity_id -WHERE - %s - AND akm.personal_api_key_id = @api_key_id - AND m.organization_id = e.organization_id -LIMIT 1; -`, tableName, scope.SQLFragment()) - - args := pgx.NamedArgs{ - "api_key_id": apiKeyID, - "entity_id": entityID, - } - maps.Copy(args, scope.SQLArguments()) - - rows, err := conn.Query(ctx, query, args) - if err != nil { - return fmt.Errorf("cannot query API key membership by entity: %w", err) - } - defer rows.Close() - - if !rows.Next() { - return fmt.Errorf("API key membership not found for key %s and entity %s", apiKeyID, entityID) - } - - var membership PersonalAPIKeyMembership - err = rows.Scan( - &membership.ID, - &membership.PersonalAPIKeyID, - &membership.MembershipID, - &membership.Role, - &membership.CreatedAt, - &membership.UpdatedAt, - ) - - if err != nil { - return fmt.Errorf("cannot scan API key membership: %w", err) - } - - *a = membership - return nil -} - -func (a *PersonalAPIKeyMembership) LoadByAPIKeyIDAndOrganizationID( - ctx context.Context, - conn pg.Conn, - scope Scoper, - apiKeyID gid.GID, - organizationID gid.GID, -) error { - q := ` -SELECT - akm.id, - akm.personal_api_key_id, - akm.membership_id, - akm.role, - akm.created_at, - akm.updated_at, - m.organization_id, - o.name as organization_name -FROM - iam_personal_api_key_memberships akm -JOIN - iam_memberships m ON akm.membership_id = m.id -JOIN - organizations o ON m.organization_id = o.id -WHERE - akm.personal_api_key_id = @api_key_id - AND m.organization_id = @organization_id - AND m.%s -` - - q = fmt.Sprintf(q, scope.SQLFragment()) - - args := pgx.StrictNamedArgs{ - "api_key_id": apiKeyID, - "organization_id": organizationID, - } - maps.Copy(args, scope.SQLArguments()) - - rows, err := conn.Query(ctx, q, args) - if err != nil { - return fmt.Errorf("cannot query personal api key membership: %w", err) - } - - membership, err := pgx.CollectExactlyOneRow(rows, pgx.RowToStructByName[PersonalAPIKeyMembership]) - if err != nil { - if err == pgx.ErrNoRows { - return fmt.Errorf("API key does not have access to organization") - } - return fmt.Errorf("cannot collect personal api key membership: %w", err) - } - - *a = membership - return nil -} - -func (a *PersonalAPIKeyMembership) Delete( - ctx context.Context, - conn pg.Conn, - scope Scoper, -) error { - q := ` -DELETE FROM - iam_personal_api_key_memberships -WHERE - id = @id - AND %s -` - - q = fmt.Sprintf(q, scope.SQLFragment()) - - args := pgx.StrictNamedArgs{ - "id": a.ID, - } - maps.Copy(args, scope.SQLArguments()) - - _, err := conn.Exec(ctx, q, args) - if err != nil { - return fmt.Errorf("cannot delete personal api key membership: %w", err) - } - - return nil -} - -func (a *PersonalAPIKeyMemberships) LoadByMembershipID( - ctx context.Context, - conn pg.Conn, - scope Scoper, - membershipID gid.GID, -) error { - q := ` -SELECT - akm.id, - akm.personal_api_key_id, - akm.membership_id, - akm.role, - akm.created_at, - akm.updated_at, - m.organization_id, - o.name as organization_name -FROM - iam_personal_api_key_memberships akm -JOIN - iam_memberships m ON akm.membership_id = m.id -JOIN - organizations o ON m.organization_id = o.id -WHERE - akm.membership_id = @membership_id - AND m.%s -ORDER BY akm.created_at DESC -` - - q = fmt.Sprintf(q, scope.SQLFragment()) - - args := pgx.StrictNamedArgs{ - "membership_id": membershipID, - } - maps.Copy(args, scope.SQLArguments()) - - rows, err := conn.Query(ctx, q, args) - if err != nil { - return fmt.Errorf("cannot query personal api key memberships by membership id: %w", err) - } - - memberships, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[PersonalAPIKeyMembership]) - if err != nil { - return fmt.Errorf("cannot collect personal api key memberships: %w", err) - } - - *a = memberships - - return nil -} - -func DeleteAllPersonalAPIKeyMembershipsByPersonalAPIKeyID( - ctx context.Context, - conn pg.Conn, - personalAPIKeyID gid.GID, -) error { - q := ` -DELETE FROM - iam_personal_api_key_memberships -WHERE - personal_api_key_id = @personal_api_key_id -` - - args := pgx.StrictNamedArgs{ - "personal_api_key_id": personalAPIKeyID, - } - - _, err := conn.Exec(ctx, q, args) - if err != nil { - return fmt.Errorf("cannot delete personal api key memberships: %w", err) - } - - return nil -} diff --git a/pkg/coredata/api_role.go b/pkg/coredata/api_role.go deleted file mode 100644 index ab7ac32d7..000000000 --- a/pkg/coredata/api_role.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2025 Probo Inc . -// -// 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 coredata - -import ( - "database/sql/driver" - "fmt" -) - -type APIRole string - -const ( - APIRoleFull APIRole = "FULL" -) - -func (r APIRole) String() string { - return string(r) -} - -func (r *APIRole) Scan(value any) error { - var s string - switch v := value.(type) { - case string: - s = v - case []byte: - s = string(v) - default: - return fmt.Errorf("unsupported type for APIRole: %T", value) - } - - switch s { - case "FULL": - *r = APIRoleFull - default: - return fmt.Errorf("invalid APIRole value: %q", s) - } - return nil -} - -func (r APIRole) Value() (driver.Value, error) { - return r.String(), nil -} diff --git a/pkg/coredata/entity_type_reg.go b/pkg/coredata/entity_type_reg.go index 8055661b0..659ffbd9d 100644 --- a/pkg/coredata/entity_type_reg.go +++ b/pkg/coredata/entity_type_reg.go @@ -65,7 +65,7 @@ const ( TrustCenterFileEntityType uint16 = 41 SAMLConfigurationEntityType uint16 = 42 PersonalAPIKeyEntityType uint16 = 43 - PersonalAPIKeyMembershipEntityType uint16 = 44 + _ uint16 = 44 // PersonalAPIKeyMembershipEntityType - removed MeetingEntityType uint16 = 45 DataProtectionImpactAssessmentEntityType uint16 = 46 TransferImpactAssessmentEntityType uint16 = 47 @@ -257,10 +257,6 @@ var entityRegistry = map[uint16]EntityInfo{ Model: "PersonalAPIKey", Table: "iam_personal_api_keys", }, - PersonalAPIKeyMembershipEntityType: { - Model: "PersonalAPIKeyMembership", - Table: "iam_personal_api_key_memberships", - }, MeetingEntityType: { Model: "Meeting", Table: "meetings", diff --git a/pkg/coredata/migrations/20251222T150000Z.sql b/pkg/coredata/migrations/20251222T150000Z.sql new file mode 100644 index 000000000..ee3b46dbe --- /dev/null +++ b/pkg/coredata/migrations/20251222T150000Z.sql @@ -0,0 +1,3 @@ +DELETE FROM iam_personal_api_key_memberships; +DROP TABLE iam_personal_api_key_memberships; + diff --git a/pkg/iam/access_management_service.go b/pkg/iam/access_management_service.go index 32a4c2d6a..d48dd61cb 100644 --- a/pkg/iam/access_management_service.go +++ b/pkg/iam/access_management_service.go @@ -12,9 +12,20 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -// LEGACY: This is the legacy access management service that is used to authorize actions on entities. -// It is deprecated and will be removed in the future. -// Use the Authorizer instead. +// LEGACY ACCESS MANAGEMENT SERVICE - DEPRECATED +// +// This service implements the legacy authorization model that uses the Permissions +// map from permissions.go to check if a principal can perform an action. +// +// It is being replaced by Authorizer which uses a policy-based evaluation system. +// During migration, this service is still used for: +// - API key authorization (intersection semantics between user and API key roles) +// - Fallback for any unmapped legacy actions +// +// Once all actions are migrated and API key authorization is implemented in the +// new system, this service will be removed. +// +// Deprecated: Use Authorizer.Authorize() instead for new code. package iam import ( @@ -148,18 +159,21 @@ func (s *AccessManagementService) loadAPIKeyRoleForEntity( apiKeyID gid.GID, entityID gid.GID, ) (Role, error) { - var akm coredata.PersonalAPIKeyMembership - if err := akm.LoadRoleByAPIKeyAndEntityID(ctx, conn, scope, apiKeyID, entityID); err != nil { - return "", err + // Load the API key to get the identity + apiKey := &coredata.PersonalAPIKey{} + if err := apiKey.LoadByID(ctx, conn, apiKeyID); err != nil { + return "", fmt.Errorf("cannot load api key: %w", err) } - // Strict API key semantics: FULL only matches RoleFull explicitly. - switch akm.Role { - case coredata.APIRoleFull: - return RoleFull, nil - default: - return "", fmt.Errorf("unsupported api key role: %s", akm.Role) + // Use the Identity's membership role for authorization + var m coredata.Membership + if err := m.LoadRoleByIdentityAndEntityID(ctx, conn, scope, apiKey.IdentityID, entityID); err != nil { + if errors.Is(err, coredata.ErrResourceNotFound) { + return "", err + } + return "", err } + return Role(m.Role.String()), nil } // requiredRoleNamesContain is a temporary evaluator for the current in-code permissions registry diff --git a/pkg/iam/authorizer.go b/pkg/iam/authorizer.go index 7ee7ade9d..6d197d186 100644 --- a/pkg/iam/authorizer.go +++ b/pkg/iam/authorizer.go @@ -17,7 +17,9 @@ package iam import ( "context" "errors" + "fmt" "maps" + "slices" "go.gearno.de/kit/pg" "go.probo.inc/probo/pkg/coredata" @@ -32,24 +34,28 @@ type Authorizer struct { policySet *PolicySet } -// NewAuthorizer creates a new authorizer with the given PolicySet. -// The PolicySet should contain all role-based and self-management policies -// from all services that need authorization. +// NewAuthorizer creates a new authorizer. +// Services register their policies by calling RegisterPolicySet. // // Example: // -// policySet := iam.IAMPolicySet(). -// Merge(documents.DocumentPolicySet()). -// Merge(risks.RiskPolicySet()) -// authorizer := iam.NewAuthorizer(pgClient, policySet) -func NewAuthorizer(pgClient *pg.Client, policySet *PolicySet) *Authorizer { +// authorizer := iam.NewAuthorizer(pgClient) +// authorizer.RegisterPolicySet(iam.IAMPolicySet()) +// authorizer.RegisterPolicySet(probo.ProboPolicySet()) +func NewAuthorizer(pgClient *pg.Client) *Authorizer { return &Authorizer{ pg: pgClient, evaluator: policy.NewEvaluator(), - policySet: policySet, + policySet: NewPolicySet(), } } +// RegisterPolicySet merges policies from another service into this authorizer. +// Services call this method to register their policies. +func (a *Authorizer) RegisterPolicySet(policySet *PolicySet) { + a.policySet.Merge(policySet) +} + // AuthorizeParams contains all parameters for an authorization check. type AuthorizeParams struct { // Principal is the user requesting access. @@ -66,6 +72,53 @@ type AuthorizeParams struct { ResourceAttributes map[string]string } +func (a *Authorizer) GetPermissionsForMembership(ctx context.Context, identityID gid.GID, membershipID gid.GID) (map[string]map[Action]bool, error) { + var ( + scope = coredata.NewScopeFromObjectID(membershipID) + membership = &coredata.Membership{} + ) + + err := a.pg.WithConn( + ctx, + func(conn pg.Conn) error { + err := membership.LoadByID(ctx, conn, scope, membershipID) + if err != nil { + if err == coredata.ErrResourceNotFound { + return NewMembershipNotFoundError(membershipID) + } + + return fmt.Errorf("cannot load membership: %w", err) + } + + return nil + }, + ) + if err != nil { + return nil, err + } + + permissions := make(map[string]map[Action]bool) + + for entityType, actions := range Permissions { + entityTypeName, ok := coredata.EntityModel(entityType) + if !ok { + continue + } + + if permissions[entityTypeName] == nil { + permissions[entityTypeName] = make(map[Action]bool) + } + + for action, allowedRoles := range actions { + if slices.Contains(allowedRoles, Role(membership.Role)) { + permissions[entityTypeName][action] = true + } + } + } + + return permissions, nil +} + // Authorize checks if the principal can perform the action on the resource. // It combines self-management policies with role-based policies. func (a *Authorizer) Authorize(ctx context.Context, params AuthorizeParams) error { diff --git a/pkg/iam/iam_actions.go b/pkg/iam/iam_actions.go index 0887d50d4..08eda79f8 100644 --- a/pkg/iam/iam_actions.go +++ b/pkg/iam/iam_actions.go @@ -32,12 +32,13 @@ const ( ActionIAMOrganizationListInvitations = "iam:organization:list-invitations" // Identity actions - ActionIAMIdentityGet = "iam:identity:get" - ActionIAMIdentityUpdate = "iam:identity:update" - ActionIAMIdentityDelete = "iam:identity:delete" - ActionIAMIdentityListMemberships = "iam:identity:list-memberships" - ActionIAMIdentityListInvitations = "iam:identity:list-invitations" - ActionIAMIdentityListSessions = "iam:identity:list-sessions" + ActionIAMIdentityGet = "iam:identity:get" + ActionIAMIdentityUpdate = "iam:identity:update" + ActionIAMIdentityDelete = "iam:identity:delete" + ActionIAMIdentityListMemberships = "iam:identity:list-memberships" + ActionIAMIdentityListInvitations = "iam:identity:list-invitations" + ActionIAMIdentityListSessions = "iam:identity:list-sessions" + ActionIAMIdentityListPersonalAPIKeys = "iam:identity:list-personal-api-keys" // Session actions ActionIAMSessionGet = "iam:session:get" @@ -52,4 +53,17 @@ const ( // Membership actions ActionIAMMembershipGet = "iam:membership:get" ActionIAMMembershipUpdate = "iam:membership:update" + + // Personal API Key actions + ActionIAMPersonalAPIKeyCreate = "iam:personal-api-key:create" + ActionIAMPersonalAPIKeyGet = "iam:personal-api-key:get" + ActionIAMPersonalAPIKeyUpdate = "iam:personal-api-key:update" + ActionIAMPersonalAPIKeyDelete = "iam:personal-api-key:delete" + + // SAML Configuration actions + ActionIAMSAMLConfigurationCreate = "iam:saml-configuration:create" + ActionIAMSAMLConfigurationGet = "iam:saml-configuration:get" + ActionIAMSAMLConfigurationUpdate = "iam:saml-configuration:update" + ActionIAMSAMLConfigurationDelete = "iam:saml-configuration:delete" + ActionIAMSAMLConfigurationList = "iam:saml-configuration:list" ) diff --git a/pkg/iam/iam_policies.go b/pkg/iam/iam_policies.go index a7817db9c..c77c611de 100644 --- a/pkg/iam/iam_policies.go +++ b/pkg/iam/iam_policies.go @@ -34,14 +34,15 @@ var IAMSelfManageIdentityPolicy = policy.NewPolicy( ).WithSID("manage-own-identity"). When(policy.Equals("principal.id", "resource.id")), - // Users can list their own memberships and invitations + // Users can list their own memberships, invitations, sessions, and API keys policy.Allow( ActionIAMIdentityListMemberships, ActionIAMIdentityListInvitations, ActionIAMIdentityListSessions, + ActionIAMIdentityListPersonalAPIKeys, ).WithSID("list-own-associations"). When(policy.Equals("principal.id", "resource.id")), -).WithDescription("Allows users to manage their own identity, sessions, and view their memberships") +).WithDescription("Allows users to manage their own identity, sessions, API keys, and view their memberships") // IAMSelfManageSessionPolicy allows users to manage their own sessions. var IAMSelfManageSessionPolicy = policy.NewPolicy( @@ -79,6 +80,20 @@ var IAMSelfManageMembershipPolicy = policy.NewPolicy( When(policy.Equals("principal.id", "resource.user_id")), ).WithDescription("Allows users to view their organization memberships") +// IAMSelfManagePersonalAPIKeyPolicy allows users to manage their own API keys. +var IAMSelfManagePersonalAPIKeyPolicy = policy.NewPolicy( + "iam:self-manage-personal-api-key", + "Self-Manage Personal API Keys", + // Users can create, view, update, and delete their own API keys + policy.Allow( + ActionIAMPersonalAPIKeyCreate, + ActionIAMPersonalAPIKeyGet, + ActionIAMPersonalAPIKeyUpdate, + ActionIAMPersonalAPIKeyDelete, + ).WithSID("manage-own-api-keys"). + When(policy.Equals("principal.id", "resource.user_id")), +).WithDescription("Allows users to manage their own personal API keys") + // IAMOwnerPolicy defines permissions for organization owners. var IAMOwnerPolicy = policy.NewPolicy( "iam:owner", @@ -92,6 +107,8 @@ var IAMOwnerPolicy = policy.NewPolicy( ActionIAMInvitationGet, ActionIAMInvitationDelete, ).WithSID("manage-invitations"), + // Full access to SAML configuration management + policy.Allow("iam:saml-configuration:*").WithSID("full-saml-access"), ).WithDescription("Full IAM access for organization owners") // IAMAdminPolicy defines permissions for organization admins. @@ -116,11 +133,22 @@ var IAMAdminPolicy = policy.NewPolicy( ActionIAMInvitationGet, ActionIAMInvitationDelete, ).WithSID("invitation-admin-access"), + // Can view SAML configurations + policy.Allow( + ActionIAMSAMLConfigurationGet, + ActionIAMSAMLConfigurationList, + ).WithSID("saml-viewer-access"), // Cannot delete organization policy.Deny(ActionIAMOrganizationDelete).WithSID("deny-org-delete"), // Cannot remove members (only owner can) policy.Deny(ActionIAMOrganizationRemoveMember).WithSID("deny-remove-member"), -).WithDescription("IAM admin access - can manage members but cannot delete organization") + // Cannot manage SAML configurations (only owner can) + policy.Deny( + ActionIAMSAMLConfigurationCreate, + ActionIAMSAMLConfigurationUpdate, + ActionIAMSAMLConfigurationDelete, + ).WithSID("deny-saml-management"), +).WithDescription("IAM admin access - can manage members but cannot delete organization or manage SAML") // IAMViewerPolicy defines permissions for organization viewers. var IAMViewerPolicy = policy.NewPolicy( diff --git a/pkg/iam/permissions.go b/pkg/iam/permissions.go index 11de98ab2..9a6abc3dc 100644 --- a/pkg/iam/permissions.go +++ b/pkg/iam/permissions.go @@ -12,9 +12,25 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -// LEGACY: This is the legacy access management service that is used to authorize actions on entities. -// It is deprecated and will be removed in the future. -// Use the Authorizer instead. +// LEGACY PERMISSION SYSTEM - DEPRECATED +// +// This file contains the legacy permission system that maps entity types and actions +// to allowed roles. It is being replaced by a policy-based authorization system. +// +// Migration path: +// - New actions are defined in core_actions.go with namespaced format (e.g., "core:asset:get") +// - New policies are defined in core_policies.go and iam_policies.go +// - The action_mapping.go file provides a bridge between legacy and new actions +// - The Authorizer in authorizer.go evaluates policies using the new system +// +// During the migration period, the MustBeAuthorized function in resolvers will: +// 1. Attempt to map legacy actions to new namespaced actions +// 2. Use the new Authorizer if mapping succeeds +// 3. Fall back to LegacyAccessManagementService for unmapped actions or API key requests +// +// Once migration is complete, this file and access_management_service.go will be removed. +// +// Deprecated: Use Authorizer.Authorize() with new namespaced actions instead. package iam import ( diff --git a/pkg/iam/policy_set.go b/pkg/iam/policy_set.go index c5e238f7b..e7ac2e96f 100644 --- a/pkg/iam/policy_set.go +++ b/pkg/iam/policy_set.go @@ -67,5 +67,6 @@ func IAMPolicySet() *PolicySet { IAMSelfManageSessionPolicy, IAMSelfManageInvitationPolicy, IAMSelfManageMembershipPolicy, + IAMSelfManagePersonalAPIKeyPolicy, ) } diff --git a/pkg/iam/service.go b/pkg/iam/service.go index e3856ce76..778ceaa92 100644 --- a/pkg/iam/service.go +++ b/pkg/iam/service.go @@ -60,7 +60,6 @@ type ( Certificate *x509.Certificate PrivateKey *rsa.PrivateKey Logger *log.Logger - PolicySet *PolicySet TracerProvider trace.TracerProvider DomainVerificationInterval time.Duration DomainVerificationResolverAddr string @@ -113,15 +112,8 @@ func NewService( svc.APIKeyService = NewAPIKeyService(svc) svc.LegacyAccessManagementService = NewAccessManagementService(svc) - // Use provided PolicySet or default to IAM-only policies - policySet := NewPolicySet() - if cfg.PolicySet != nil { - policySet = cfg.PolicySet - } - - policySet.Merge(IAMPolicySet()) - - svc.Authorizer = NewAuthorizer(pgClient, policySet) + svc.Authorizer = NewAuthorizer(pgClient) + svc.Authorizer.RegisterPolicySet(IAMPolicySet()) samlService, err := saml.NewService(svc.pg, svc.encryptionKey, svc.baseURL, svc.certificate, svc.privateKey, cfg.Logger) if err != nil { diff --git a/pkg/probo/action_mapping.go b/pkg/probo/action_mapping.go new file mode 100644 index 000000000..838e6b36f --- /dev/null +++ b/pkg/probo/action_mapping.go @@ -0,0 +1,394 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 probo + +import ( + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/iam" +) + +// legacyActionMapping maps entity types to a mapping of legacy actions to new namespaced actions. +// This is used during the migration period to translate old action strings to new policy actions. +var legacyActionMapping = map[uint16]map[iam.Action]iam.Action{ + coredata.OrganizationEntityType: { + iam.ActionGet: ActionOrganizationGet, + iam.ActionGetLogoUrl: ActionOrganizationGetLogoUrl, + iam.ActionGetHorizontalLogoUrl: ActionOrganizationGetHorizontalLogoUrl, + iam.ActionListDocuments: ActionDocumentList, + iam.ActionListSignableDocuments: ActionDocumentList, + iam.ActionPeoples: ActionPeopleList, + iam.ActionTotalCount: ActionOrganizationGet, + iam.ActionListFrameworks: ActionFrameworkList, + iam.ActionListControls: ActionControlList, + iam.ActionListVendors: ActionVendorList, + iam.ActionListPeople: ActionPeopleList, + iam.ActionListMeasures: ActionMeasureList, + iam.ActionListRisks: ActionRiskList, + iam.ActionListAssets: ActionAssetList, + iam.ActionListData: ActionDatumList, + iam.ActionListAudits: ActionAuditList, + iam.ActionListNonconformities: ActionNonconformityList, + iam.ActionListObligations: ActionObligationList, + iam.ActionListContinualImprovements: ActionContinualImprovementList, + iam.ActionListProcessingActivities: ActionProcessingActivityList, + iam.ActionListSnapshots: ActionSnapshotList, + iam.ActionAcceptInvitation: iam.ActionIAMInvitationAccept, + iam.ActionListTrustCenterFiles: ActionTrustCenterFileList, + iam.ActionGetTrustCenter: ActionTrustCenterGet, + iam.ActionMemberships: iam.ActionIAMOrganizationListMembers, + iam.ActionListMembers: iam.ActionIAMOrganizationListMembers, + iam.ActionListInvitations: iam.ActionIAMOrganizationListInvitations, + iam.ActionListSlackConnections: ActionSlackConnectionList, + iam.ActionGetCustomDomain: ActionCustomDomainGet, + iam.ActionListMeetings: ActionMeetingList, + iam.ActionListTasks: ActionTaskList, + iam.ActionUpdateOrganization: ActionOrganizationGet, + iam.ActionDeleteOrganizationHorizontalLogo: ActionOrganizationGet, + iam.ActionCreateTrustCenter: ActionTrustCenterGet, + iam.ActionInviteUser: iam.ActionIAMOrganizationInviteMember, + iam.ActionUpdateMembership: iam.ActionIAMMembershipUpdate, + iam.ActionCreatePeople: ActionPeopleCreate, + iam.ActionCreateVendor: ActionVendorCreate, + iam.ActionCreateFramework: ActionFrameworkCreate, + iam.ActionImportFramework: ActionFrameworkImport, + iam.ActionCreateControl: ActionControlCreate, + iam.ActionCreateMeasure: ActionMeasureCreate, + iam.ActionImportMeasure: ActionMeasureImport, + iam.ActionCreateMeeting: ActionMeetingCreate, + iam.ActionCreateTask: ActionTaskCreate, + iam.ActionCreateRisk: ActionRiskCreate, + iam.ActionCreateDocument: ActionDocumentCreate, + iam.ActionCreateAsset: ActionAssetCreate, + iam.ActionCreateDatum: ActionDatumCreate, + iam.ActionCreateAudit: ActionAuditCreate, + iam.ActionCreateNonconformity: ActionNonconformityCreate, + iam.ActionCreateObligation: ActionObligationCreate, + iam.ActionCreateContinualImprovement: ActionContinualImprovementCreate, + iam.ActionCreateProcessingActivity: ActionProcessingActivityCreate, + iam.ActionCreateSnapshot: ActionSnapshotCreate, + iam.ActionCreateTrustCenterFile: ActionTrustCenterFileCreate, + iam.ActionSendSigningNotifications: ActionDocumentSendSigningNotifications, + iam.ActionRemoveMember: iam.ActionIAMOrganizationRemoveMember, + iam.ActionCreateCustomDomain: ActionCustomDomainCreate, + iam.ActionDeleteCustomDomain: ActionCustomDomainDelete, + }, + coredata.TrustCenterEntityType: { + iam.ActionGet: ActionTrustCenterGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionUpdateTrustCenter: ActionTrustCenterUpdate, + iam.ActionUploadTrustCenterNDA: ActionTrustCenterNonDisclosureAgreementUpload, + iam.ActionDeleteTrustCenterNDA: ActionTrustCenterNonDisclosureAgreementDelete, + iam.ActionCreateTrustCenterAccess: ActionTrustCenterAccessCreate, + iam.ActionCreateTrustCenterReference: ActionTrustCenterReferenceCreate, + }, + coredata.TrustCenterAccessEntityType: { + iam.ActionUpdateTrustCenterAccess: ActionTrustCenterAccessUpdate, + iam.ActionDeleteTrustCenterAccess: ActionTrustCenterAccessDelete, + }, + coredata.TrustCenterReferenceEntityType: { + iam.ActionUpdateTrustCenterReference: ActionTrustCenterReferenceUpdate, + iam.ActionDeleteTrustCenterReference: ActionTrustCenterReferenceDelete, + }, + coredata.TrustCenterFileEntityType: { + iam.ActionUpdateTrustCenterFile: ActionTrustCenterFileUpdate, + iam.ActionDeleteTrustCenterFile: ActionTrustCenterFileDelete, + }, + coredata.IdentityEntityType: { + iam.ActionGet: iam.ActionIAMIdentityGet, + }, + coredata.MembershipEntityType: { + iam.ActionGet: iam.ActionIAMMembershipGet, + iam.ActionGetAuthMethod: iam.ActionIAMMembershipGet, + }, + coredata.InvitationEntityType: { + iam.ActionGet: iam.ActionIAMInvitationGet, + iam.ActionGetOrganization: iam.ActionIAMInvitationGet, + iam.ActionDeleteInvitation: iam.ActionIAMInvitationDelete, + }, + coredata.PeopleEntityType: { + iam.ActionGet: ActionPeopleGet, + iam.ActionUpdatePeople: ActionPeopleUpdate, + iam.ActionDeletePeople: ActionPeopleDelete, + }, + coredata.VendorEntityType: { + iam.ActionGet: ActionVendorList, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionGetBusinessOwner: ActionPeopleGet, + iam.ActionGetSecurityOwner: ActionPeopleGet, + iam.ActionUpdateVendor: ActionVendorUpdate, + iam.ActionDeleteVendor: ActionVendorDelete, + iam.ActionCreateVendorContact: ActionVendorContactCreate, + iam.ActionCreateVendorService: ActionVendorServiceCreate, + iam.ActionUploadVendorComplianceReport: ActionVendorComplianceReportUpload, + iam.ActionUploadVendorBusinessAssociateAgreement: ActionVendorBusinessAssociateAgreementUpload, + iam.ActionDeleteVendorBusinessAssociateAgreement: ActionVendorBusinessAssociateAgreementDelete, + iam.ActionUploadVendorDataPrivacyAgreement: ActionVendorDataPrivacyAgreementUpload, + iam.ActionCreateVendorRiskAssessment: ActionVendorRiskAssessmentCreate, + iam.ActionAssessVendor: ActionVendorAssess, + }, + coredata.VendorComplianceReportEntityType: { + iam.ActionGet: ActionVendorList, + iam.ActionGetVendor: ActionVendorList, + iam.ActionDeleteVendorComplianceReport: ActionVendorComplianceReportDelete, + }, + coredata.VendorBusinessAssociateAgreementEntityType: { + iam.ActionGet: ActionVendorList, + iam.ActionGetVendor: ActionVendorList, + iam.ActionGetFileUrl: ActionFileDownloadUrl, + iam.ActionUpdateVendorBusinessAssociateAgreement: ActionVendorBusinessAssociateAgreementUpdate, + iam.ActionDeleteVendorBusinessAssociateAgreement: ActionVendorBusinessAssociateAgreementDelete, + }, + coredata.VendorContactEntityType: { + iam.ActionGet: ActionVendorList, + iam.ActionGetVendor: ActionVendorList, + iam.ActionUpdateVendorContact: ActionVendorContactUpdate, + iam.ActionDeleteVendorContact: ActionVendorContactDelete, + }, + coredata.VendorServiceEntityType: { + iam.ActionGet: ActionVendorList, + iam.ActionGetVendor: ActionVendorList, + iam.ActionUpdateVendorService: ActionVendorServiceUpdate, + iam.ActionDeleteVendorService: ActionVendorServiceDelete, + }, + coredata.VendorDataPrivacyAgreementEntityType: { + iam.ActionGet: ActionVendorList, + iam.ActionGetVendor: ActionVendorList, + iam.ActionGetFileUrl: ActionFileDownloadUrl, + iam.ActionUpdateVendorDataPrivacyAgreement: ActionVendorDataPrivacyAgreementUpdate, + iam.ActionDeleteVendorDataPrivacyAgreement: ActionVendorDataPrivacyAgreementDelete, + }, + coredata.VendorRiskAssessmentEntityType: { + iam.ActionGet: ActionVendorList, + }, + coredata.FrameworkEntityType: { + iam.ActionGet: ActionFrameworkGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionListControls: ActionControlList, + iam.ActionCreateControl: ActionControlCreate, + iam.ActionUpdateFramework: ActionFrameworkUpdate, + iam.ActionDeleteFramework: ActionFrameworkDelete, + iam.ActionGenerateFrameworkStateOfApplicability: ActionFrameworkStateOfApplicabilityGenerate, + iam.ActionExportFramework: ActionFrameworkExport, + }, + coredata.ControlEntityType: { + iam.ActionGet: ActionControlList, + iam.ActionGetFramework: ActionFrameworkGet, + iam.ActionListMeasures: ActionMeasureList, + iam.ActionListDocuments: ActionDocumentList, + iam.ActionListAudits: ActionAuditList, + iam.ActionListSnapshots: ActionSnapshotList, + iam.ActionUpdateControl: ActionControlUpdate, + iam.ActionDeleteControl: ActionControlDelete, + iam.ActionCreateControlMeasureMapping: ActionControlMeasureMappingCreate, + iam.ActionCreateControlDocumentMapping: ActionControlDocumentMappingCreate, + iam.ActionDeleteControlMeasureMapping: ActionControlMeasureMappingDelete, + iam.ActionDeleteControlDocumentMapping: ActionControlDocumentMappingDelete, + iam.ActionCreateControlAuditMapping: ActionControlAuditMappingCreate, + iam.ActionDeleteControlAuditMapping: ActionControlAuditMappingDelete, + iam.ActionCreateControlSnapshotMapping: ActionControlSnapshotMappingCreate, + iam.ActionDeleteControlSnapshotMapping: ActionControlSnapshotMappingDelete, + }, + coredata.MeasureEntityType: { + iam.ActionGet: ActionMeasureGet, + iam.ActionListTasks: ActionTaskList, + iam.ActionListEvidences: ActionEvidenceList, + iam.ActionListRisks: ActionRiskList, + iam.ActionListControls: ActionControlList, + iam.ActionTotalCount: ActionMeasureList, + iam.ActionUpdateMeasure: ActionMeasureUpdate, + iam.ActionDeleteMeasure: ActionMeasureDelete, + iam.ActionUploadMeasureEvidence: ActionMeasureEvidenceUpload, + }, + coredata.TaskEntityType: { + iam.ActionGet: ActionTaskGet, + iam.ActionGetAssignedTo: ActionPeopleGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionGetMeasure: ActionMeasureGet, + iam.ActionListEvidences: ActionEvidenceList, + iam.ActionUpdateTask: ActionTaskUpdate, + iam.ActionDeleteTask: ActionTaskDelete, + iam.ActionAssignTask: ActionTaskAssign, + iam.ActionUnassignTask: ActionTaskUnassign, + }, + coredata.EvidenceEntityType: { + iam.ActionGet: ActionEvidenceList, + iam.ActionGetFile: ActionFileGet, + iam.ActionGetTask: ActionTaskGet, + iam.ActionGetMeasure: ActionMeasureList, + iam.ActionDeleteEvidence: ActionEvidenceDelete, + }, + coredata.DocumentEntityType: { + iam.ActionGet: ActionDocumentGet, + iam.ActionGetOwner: ActionPeopleGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionGetSigned: ActionDocumentList, + iam.ActionGetSignableDocument: ActionDocumentList, + iam.ActionListSignableDocumentVersion: ActionDocumentList, + iam.ActionBulkExportDocuments: ActionDocumentList, + iam.ActionTotalCount: ActionDocumentList, + iam.ActionListControls: ActionControlList, + iam.ActionListVersions: ActionDocumentVersionList, + iam.ActionUpdateDocument: ActionDocumentUpdate, + iam.ActionDeleteDocument: ActionDocumentDelete, + iam.ActionBulkDeleteDocuments: ActionDocumentDelete, + iam.ActionPublishDocumentVersion: ActionDocumentVersionPublish, + iam.ActionBulkPublishDocumentVersions: ActionDocumentVersionPublish, + iam.ActionGenerateDocumentChangelog: ActionDocumentChangelogGenerate, + iam.ActionCreateDraftDocumentVersion: ActionDocumentDraftVersionCreate, + iam.ActionDeleteDraftDocumentVersion: ActionDocumentVersionDeleteDraft, + iam.ActionUpdateDocumentVersion: ActionDocumentVersionUpdate, + iam.ActionRequestSignature: ActionDocumentVersionSignatureRequest, + iam.ActionBulkRequestSignatures: ActionDocumentVersionSignatureRequest, + iam.ActionSendSigningNotifications: ActionDocumentSendSigningNotifications, + iam.ActionCancelSignatureRequest: ActionDocumentVersionCancelSignature, + }, + coredata.DocumentVersionEntityType: { + iam.ActionGet: ActionDocumentVersionGet, + iam.ActionGetFile: ActionFileGet, + iam.ActionGetOwner: ActionPeopleGet, + iam.ActionGetDocument: ActionDocumentGet, + iam.ActionGetSigned: ActionDocumentVersionGet, + iam.ActionSignatures: ActionDocumentVersionSignatureList, + iam.ActionExportDocumentVersionPDF: ActionDocumentVersionExportPDF, + iam.ActionExportSignableVersionDocumentPDF: ActionDocumentVersionExportSignable, + iam.ActionSignDocument: ActionDocumentVersionSign, + iam.ActionUpdateDocumentVersion: ActionDocumentVersionUpdate, + iam.ActionRequestSignature: ActionDocumentVersionSignatureRequest, + iam.ActionDeleteDraftDocumentVersion: ActionDocumentVersionDeleteDraft, + }, + coredata.DocumentVersionSignatureEntityType: { + iam.ActionGet: ActionDocumentVersionSignatureList, + iam.ActionDocumentVersion: ActionDocumentVersionGet, + iam.ActionSignedBy: ActionPeopleGet, + }, + coredata.RiskEntityType: { + iam.ActionGet: ActionRiskList, + iam.ActionGetOwner: ActionPeopleGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionTotalCount: ActionRiskList, + iam.ActionListControls: ActionControlList, + iam.ActionListMeasures: ActionMeasureList, + iam.ActionListDocuments: ActionDocumentList, + iam.ActionListObligations: ActionObligationList, + iam.ActionUpdateRisk: ActionRiskUpdate, + iam.ActionDeleteRisk: ActionRiskDelete, + iam.ActionCreateRiskMeasureMapping: ActionRiskMeasureMappingCreate, + iam.ActionDeleteRiskMeasureMapping: ActionRiskMeasureMappingDelete, + iam.ActionCreateRiskDocumentMapping: ActionRiskDocumentMappingCreate, + iam.ActionDeleteRiskDocumentMapping: ActionRiskDocumentMappingDelete, + iam.ActionCreateRiskObligationMapping: ActionRiskObligationMappingCreate, + iam.ActionDeleteRiskObligationMapping: ActionRiskObligationMappingDelete, + }, + coredata.AssetEntityType: { + iam.ActionGet: ActionAssetList, + iam.ActionGetOwner: ActionPeopleGet, + iam.ActionListVendors: ActionVendorList, + iam.ActionGetAssetType: ActionAssetList, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionUpdateAsset: ActionAssetUpdate, + iam.ActionDeleteAsset: ActionAssetDelete, + }, + coredata.DatumEntityType: { + iam.ActionGet: ActionDatumList, + iam.ActionGetOwner: ActionPeopleGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionListVendors: ActionVendorList, + iam.ActionUpdateDatum: ActionDatumUpdate, + iam.ActionDeleteDatum: ActionDatumDelete, + }, + coredata.AuditEntityType: { + iam.ActionGet: ActionAuditGet, + iam.ActionGetFile: ActionFileGet, + iam.ActionGetFramework: ActionFrameworkGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionReport: ActionAuditList, + iam.ActionReportUrl: ActionAuditList, + iam.ActionListControls: ActionControlList, + iam.ActionUpdateAudit: ActionAuditUpdate, + iam.ActionDeleteAudit: ActionAuditDelete, + iam.ActionUploadAuditReport: ActionAuditReportUpload, + iam.ActionDeleteAuditReport: ActionAuditReportDelete, + }, + coredata.ReportEntityType: { + iam.ActionGet: ActionReportGet, + iam.ActionGetAudit: ActionAuditGet, + iam.ActionGetFile: ActionFileGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionGetSnapshot: ActionSnapshotList, + iam.ActionDownloadUrl: ActionReportDownloadUrlGet, + }, + coredata.NonconformityEntityType: { + iam.ActionGet: ActionNonconformityList, + iam.ActionGetOwner: ActionPeopleGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionAudit: ActionAuditList, + iam.ActionUpdateNonconformity: ActionNonconformityUpdate, + iam.ActionDeleteNonconformity: ActionNonconformityDelete, + }, + coredata.ObligationEntityType: { + iam.ActionGet: ActionObligationList, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionGetOwner: ActionPeopleGet, + iam.ActionListRisks: ActionRiskList, + iam.ActionUpdateObligation: ActionObligationUpdate, + iam.ActionDeleteObligation: ActionObligationDelete, + }, + coredata.ContinualImprovementEntityType: { + iam.ActionGet: ActionContinualImprovementList, + iam.ActionGetOwner: ActionPeopleGet, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionUpdateContinualImprovement: ActionContinualImprovementUpdate, + iam.ActionDeleteContinualImprovement: ActionContinualImprovementDelete, + }, + coredata.ProcessingActivityEntityType: { + iam.ActionGet: ActionProcessingActivityList, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionListVendors: ActionVendorList, + iam.ActionUpdateProcessingActivity: ActionProcessingActivityUpdate, + iam.ActionDeleteProcessingActivity: ActionProcessingActivityDelete, + }, + coredata.SnapshotEntityType: { + iam.ActionGet: ActionSnapshotList, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionListControls: ActionControlList, + iam.ActionDeleteSnapshot: ActionSnapshotDelete, + }, + coredata.CustomDomainEntityType: { + iam.ActionGet: ActionCustomDomainGet, + iam.ActionDeleteCustomDomain: ActionCustomDomainDelete, + }, + coredata.FileEntityType: { + iam.ActionGet: ActionFileGet, + iam.ActionDownloadUrl: ActionFileDownloadUrl, + }, + coredata.MeetingEntityType: { + iam.ActionGet: ActionMeetingList, + iam.ActionGetOrganization: ActionOrganizationGet, + iam.ActionTotalCount: ActionMeetingList, + iam.ActionUpdateMeeting: ActionMeetingUpdate, + iam.ActionDeleteMeeting: ActionMeetingDelete, + }, +} + +// MapLegacyAction converts a legacy action string to a new namespaced action. +// Returns the new action and true if found, or empty string and false if not mapped. +func MapLegacyAction(entityType uint16, legacyAction iam.Action) (iam.Action, bool) { + if entityActions, ok := legacyActionMapping[entityType]; ok { + if newAction, ok := entityActions[legacyAction]; ok { + return newAction, true + } + } + return "", false +} diff --git a/pkg/probo/actions.go b/pkg/probo/actions.go new file mode 100644 index 000000000..c5ebbdd46 --- /dev/null +++ b/pkg/probo/actions.go @@ -0,0 +1,281 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 probo + +// Probo Service Actions +// Format: core:: +const ( + // Organization actions + ActionOrganizationGet = "core:organization:get" + ActionOrganizationGetLogoUrl = "core:organization:get-logo-url" + ActionOrganizationGetHorizontalLogoUrl = "core:organization:get-horizontal-logo-url" + + // OrganizationContext actions + ActionOrganizationContextGet = "core:organization-context:get" + ActionOrganizationContextUpdate = "core:organization-context:update" + + // TrustCenter actions + ActionTrustCenterGet = "core:trust-center:get" + ActionTrustCenterUpdate = "core:trust-center:update" + ActionTrustCenterNonDisclosureAgreementUpload = "core:trust-center:upload-nda" + ActionTrustCenterNonDisclosureAgreementDelete = "core:trust-center:delete-nda" + ActionTrustCenterAccessCreate = "core:trust-center:create-access" + ActionTrustCenterReferenceCreate = "core:trust-center:create-reference" + + // TrustCenterAccess actions + ActionTrustCenterAccessUpdate = "core:trust-center-access:update" + ActionTrustCenterAccessDelete = "core:trust-center-access:delete" + + // TrustCenterReference actions + ActionTrustCenterReferenceUpdate = "core:trust-center-reference:update" + ActionTrustCenterReferenceDelete = "core:trust-center-reference:delete" + + // TrustCenterFile actions + ActionTrustCenterFileGet = "core:trust-center-file:get" + ActionTrustCenterFileList = "core:trust-center-file:list" + ActionTrustCenterFileUpdate = "core:trust-center-file:update" + ActionTrustCenterFileDelete = "core:trust-center-file:delete" + ActionTrustCenterFileCreate = "core:trust-center-file:create" + + // People actions + ActionPeopleGet = "core:people:get" + ActionPeopleList = "core:people:list" + ActionPeopleCreate = "core:people:create" + ActionPeopleUpdate = "core:people:update" + ActionPeopleDelete = "core:people:delete" + + // Vendor actions + ActionVendorList = "core:vendor:list" + ActionVendorGet = "core:vendor:get" + ActionVendorCreate = "core:vendor:create" + ActionVendorUpdate = "core:vendor:update" + ActionVendorDelete = "core:vendor:delete" + ActionVendorAssess = "core:vendor:assess" + + // VendorContact actions + ActionVendorContactCreate = "core:vendor-contact:create" + ActionVendorContactUpdate = "core:vendor-contact:update" + ActionVendorContactDelete = "core:vendor-contact:delete" + + // VendorService actions + ActionVendorServiceCreate = "core:vendor-service:create" + ActionVendorServiceUpdate = "core:vendor-service:update" + ActionVendorServiceDelete = "core:vendor-service:delete" + + // VendorComplianceReport actions + ActionVendorComplianceReportUpload = "core:vendor-compliance-report:upload" + ActionVendorComplianceReportDelete = "core:vendor-compliance-report:delete" + + // VendorBusinessAssociateAgreement actions + ActionVendorBusinessAssociateAgreementUpload = "core:vendor-business-associate-agreement:upload" + ActionVendorBusinessAssociateAgreementUpdate = "core:vendor-business-associate-agreement:update" + ActionVendorBusinessAssociateAgreementDelete = "core:vendor-business-associate-agreement:delete" + + // VendorDataPrivacyAgreement actions + ActionVendorDataPrivacyAgreementUpload = "core:vendor-data-privacy-agreement:upload" + ActionVendorDataPrivacyAgreementUpdate = "core:vendor-data-privacy-agreement:update" + ActionVendorDataPrivacyAgreementDelete = "core:vendor-data-privacy-agreement:delete" + + // VendorRiskAssessment actions + ActionVendorRiskAssessmentCreate = "core:vendor-risk-assessment:create" + + // Framework actions + ActionFrameworkGet = "core:framework:get" + ActionFrameworkList = "core:framework:list" + ActionFrameworkCreate = "core:framework:create" + ActionFrameworkUpdate = "core:framework:update" + ActionFrameworkDelete = "core:framework:delete" + ActionFrameworkStateOfApplicabilityGenerate = "core:framework:generate-state-of-applicability" + ActionFrameworkExport = "core:framework:export" + ActionFrameworkImport = "core:framework:import" + + // Control actions + ActionControlList = "core:control:list" + ActionControlCreate = "core:control:create" + ActionControlUpdate = "core:control:update" + ActionControlDelete = "core:control:delete" + ActionControlMeasureMappingCreate = "core:control:create-measure-mapping" + ActionControlMeasureMappingDelete = "core:control:delete-measure-mapping" + ActionControlDocumentMappingCreate = "core:control:create-document-mapping" + ActionControlDocumentMappingDelete = "core:control:delete-document-mapping" + ActionControlAuditMappingCreate = "core:control:create-audit-mapping" + ActionControlAuditMappingDelete = "core:control:delete-audit-mapping" + ActionControlSnapshotMappingCreate = "core:control:create-snapshot-mapping" + ActionControlSnapshotMappingDelete = "core:control:delete-snapshot-mapping" + + // Measure actions + ActionMeasureGet = "core:measure:get" + ActionMeasureList = "core:measure:list" + ActionMeasureCreate = "core:measure:create" + ActionMeasureUpdate = "core:measure:update" + ActionMeasureDelete = "core:measure:delete" + ActionMeasureEvidenceUpload = "core:measure:upload-evidence" + ActionMeasureImport = "core:measure:import" + + // Task actions + ActionTaskGet = "core:task:get" + ActionTaskList = "core:task:list" + ActionTaskCreate = "core:task:create" + ActionTaskUpdate = "core:task:update" + ActionTaskDelete = "core:task:delete" + ActionTaskAssign = "core:task:assign" + ActionTaskUnassign = "core:task:unassign" + + // Evidence actions + ActionEvidenceList = "core:evidence:list" + ActionEvidenceDelete = "core:evidence:delete" + + // Document actions + ActionDocumentGet = "core:document:get" + ActionDocumentList = "core:document:list" + ActionDocumentCreate = "core:document:create" + ActionDocumentUpdate = "core:document:update" + ActionDocumentDelete = "core:document:delete" + ActionDocumentChangelogGenerate = "core:document:generate-changelog" + ActionDocumentDraftVersionCreate = "core:document:create-draft-version" + ActionDocumentSendSigningNotifications = "core:document:send-signing-notifications" + + // DocumentVersion actions + ActionDocumentVersionGet = "core:document-version:get" + ActionDocumentVersionList = "core:document-version:list" + ActionDocumentVersionExportPDF = "core:document-version:export-pdf" + ActionDocumentVersionExportSignable = "core:document-version:export-signable-pdf" + ActionDocumentVersionSign = "core:document-version:sign" + ActionDocumentVersionUpdate = "core:document-version:update" + ActionDocumentVersionSignatureRequest = "core:document-version:request-signature" + ActionDocumentVersionDeleteDraft = "core:document-version:delete-draft" + ActionDocumentVersionPublish = "core:document-version:publish" + ActionDocumentVersionCancelSignature = "core:document-version:cancel-signature" + ActionDocumentVersionExport = "core:document-version:export" + + // DocumentVersionSignature actions + ActionDocumentVersionSignatureList = "core:document-version-signature:list" + + // Risk actions + ActionRiskList = "core:risk:list" + ActionRiskCreate = "core:risk:create" + ActionRiskUpdate = "core:risk:update" + ActionRiskDelete = "core:risk:delete" + ActionRiskMeasureMappingCreate = "core:risk:create-measure-mapping" + ActionRiskMeasureMappingDelete = "core:risk:delete-measure-mapping" + ActionRiskDocumentMappingCreate = "core:risk:create-document-mapping" + ActionRiskDocumentMappingDelete = "core:risk:delete-document-mapping" + ActionRiskObligationMappingCreate = "core:risk:create-obligation-mapping" + ActionRiskObligationMappingDelete = "core:risk:delete-obligation-mapping" + + // Asset actions + ActionAssetList = "core:asset:list" + ActionAssetCreate = "core:asset:create" + ActionAssetUpdate = "core:asset:update" + ActionAssetDelete = "core:asset:delete" + + // Datum actions + ActionDatumList = "core:datum:list" + ActionDatumCreate = "core:datum:create" + ActionDatumUpdate = "core:datum:update" + ActionDatumDelete = "core:datum:delete" + + // Audit actions + ActionAuditGet = "core:audit:get" + ActionAuditList = "core:audit:list" + ActionAuditCreate = "core:audit:create" + ActionAuditUpdate = "core:audit:update" + ActionAuditDelete = "core:audit:delete" + ActionAuditReportUpload = "core:audit:upload-report" + ActionAuditReportDelete = "core:audit:delete-report" + + // Report actions + ActionReportGet = "core:report:get" + ActionReportGetReportUrl = "core:report:get-report-url" + ActionReportDownloadUrlGet = "core:report:get-download-url" + + // Nonconformity actions + ActionNonconformityList = "core:nonconformity:list" + ActionNonconformityCreate = "core:nonconformity:create" + ActionNonconformityUpdate = "core:nonconformity:update" + ActionNonconformityDelete = "core:nonconformity:delete" + + // Obligation actions + ActionObligationList = "core:obligation:list" + ActionObligationCreate = "core:obligation:create" + ActionObligationUpdate = "core:obligation:update" + ActionObligationDelete = "core:obligation:delete" + + // ContinualImprovement actions + ActionContinualImprovementList = "core:continual-improvement:list" + ActionContinualImprovementCreate = "core:continual-improvement:create" + ActionContinualImprovementUpdate = "core:continual-improvement:update" + ActionContinualImprovementDelete = "core:continual-improvement:delete" + + // ProcessingActivity actions + ActionProcessingActivityList = "core:processing-activity:list" + ActionProcessingActivityGet = "core:processing-activity:get" + ActionProcessingActivityCreate = "core:processing-activity:create" + ActionProcessingActivityUpdate = "core:processing-activity:update" + ActionProcessingActivityDelete = "core:processing-activity:delete" + ActionProcessingActivityExport = "core:processing-activity:export" + + // Snapshot actions + ActionSnapshotList = "core:snapshot:list" + ActionSnapshotCreate = "core:snapshot:create" + ActionSnapshotDelete = "core:snapshot:delete" + + // CustomDomain actions + ActionCustomDomainGet = "core:custom-domain:get" + ActionCustomDomainCreate = "core:custom-domain:create" + ActionCustomDomainDelete = "core:custom-domain:delete" + + // File actions + ActionFileGet = "core:file:get" + ActionFileDownloadUrl = "core:file:download-url" + + // Meeting actions + ActionMeetingList = "core:meeting:list" + ActionMeetingCreate = "core:meeting:create" + ActionMeetingUpdate = "core:meeting:update" + ActionMeetingDelete = "core:meeting:delete" + + // SlackConnection actions + ActionSlackConnectionList = "core:slack-connection:list" + + ActionDataProtectionImpactAssessmentList = "core:data-protection-impact-assessment:list" + ActionDataProtectionImpactAssessmentCreate = "core:data-protection-impact-assessment:create" + ActionDataProtectionImpactAssessmentUpdate = "core:data-protection-impact-assessment:update" + ActionDataProtectionImpactAssessmentDelete = "core:data-protection-impact-assessment:delete" + + ActionTransferImpactAssessmentList = "core:transfer-impact-assessment:list" + ActionTransferImpactAssessmentCreate = "core:transfer-impact-assessment:create" + ActionTransferImpactAssessmentUpdate = "core:transfer-impact-assessment:update" + ActionTransferImpactAssessmentDelete = "core:transfer-impact-assessment:delete" + + ActionDataProtectionOfficerList = "core:data-protection-officer:list" + + ActionRightsRequesList = "core:rights-request:list" + + ActionStateOfApplicabilityList = "core:state-of-applicability:list" + ActionStateOfApplicabilityGet = "core:state-of-applicability:get" + ActionStateOfApplicabilityCreate = "core:state-of-applicability:create" + ActionStateOfApplicabilityUpdate = "core:state-of-applicability:update" + ActionStateOfApplicabilityDelete = "core:state-of-applicability:delete" + ActionStateOfApplicabilityExport = "core:state-of-applicability:export" + + ActionStateOfApplicabilityControlMappingList = "core:state-of-applicability-control-mapping:list" + ActionStateOfApplicabilityControlMappingCreate = "core:state-of-applicability-control-mapping:create" + ActionStateOfApplicabilityControlMappingDelete = "core:state-of-applicability-control-mapping:delete" + + ActionControlObligationMappingList = "core:control-obligation-mapping:list" + ActionControlObligationMappingCreate = "core:control-obligation-mapping:create" + ActionControlObligationMappingDelete = "core:control-obligation-mapping:delete" +) diff --git a/pkg/probo/policies.go b/pkg/probo/policies.go new file mode 100644 index 000000000..5e0425040 --- /dev/null +++ b/pkg/probo/policies.go @@ -0,0 +1,169 @@ +// Copyright (c) 2025 Probo Inc . +// +// 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 probo + +import ( + "go.probo.inc/probo/pkg/iam" + "go.probo.inc/probo/pkg/iam/policy" +) + +// OwnerPolicy defines permissions for organization owners. +var OwnerPolicy = policy.NewPolicy( + "probo:owner", + "Probo Owner", + // Full access to all probo resources + policy.Allow("core:*").WithSID("full-core-access"), +).WithDescription("Full probo access for organization owners") + +// AdminPolicy defines permissions for organization admins. +var AdminPolicy = policy.NewPolicy( + "probo:admin", + "Probo Admin", + // Full access to all probo resources (same as owner for core entities) + policy.Allow("core:*").WithSID("full-core-access"), +).WithDescription("Probo admin access - can manage core entities") + +// ViewerPolicy defines read-only permissions for organization viewers. +var ViewerPolicy = policy.NewPolicy( + "probo:viewer", + "Probo Viewer", + // Organization read actions + policy.Allow( + ActionOrganizationGet, + ActionOrganizationGetLogoUrl, + ActionOrganizationGetHorizontalLogoUrl, + ).WithSID("org-read-access"), + + // Entity read actions + policy.Allow( + ActionPeopleGet, ActionPeopleList, + ActionVendorList, + ActionFrameworkGet, ActionFrameworkList, + ActionControlList, + ActionMeasureGet, ActionMeasureList, + ActionTaskGet, ActionTaskList, + ActionEvidenceList, + ActionDocumentGet, ActionDocumentList, + ActionDocumentVersionGet, ActionDocumentVersionList, + ActionDocumentVersionSignatureList, + ActionRiskList, + ActionAssetList, + ActionDatumList, + ActionAuditGet, ActionAuditList, + ActionReportGet, ActionReportGetReportUrl, ActionReportDownloadUrlGet, + ActionNonconformityList, + ActionObligationList, + ActionContinualImprovementList, + ActionProcessingActivityList, + ActionSnapshotList, + ActionMeetingList, + ActionFileGet, ActionFileDownloadUrl, + ActionSlackConnectionList, + ).WithSID("entity-read-access"), + + // TrustCenter read actions + policy.Allow( + ActionTrustCenterGet, + ActionTrustCenterFileGet, ActionTrustCenterFileList, + ).WithSID("trust-center-read-access"), + + // CustomDomain read actions + policy.Allow(ActionCustomDomainGet).WithSID("custom-domain-read"), + + // OrganizationContext read actions + policy.Allow(ActionOrganizationContextGet).WithSID("organization-context-read"), + + // Document signing actions + policy.Allow( + ActionDocumentVersionExportPDF, ActionDocumentVersionExportSignable, ActionDocumentVersionSign, + ).WithSID("document-signing"), +).WithDescription("Read-only probo access for organization viewers") + +// AuditorPolicy defines permissions for auditor role. +// Auditors have read access to non-employee content plus some specific auditor features. +var AuditorPolicy = policy.NewPolicy( + "probo:auditor", + "Probo Auditor", + // Same as viewer but without employee-specific content + policy.Allow( + ActionOrganizationGet, + ActionOrganizationGetLogoUrl, + ActionOrganizationGetHorizontalLogoUrl, + ).WithSID("org-read-access"), + + // Entity read access (same as viewer) + policy.Allow( + ActionPeopleGet, ActionPeopleList, + ActionVendorList, + ActionFrameworkGet, ActionFrameworkList, + ActionControlList, + ActionMeasureGet, ActionMeasureList, + ActionEvidenceList, + ActionDocumentGet, ActionDocumentList, + ActionDocumentVersionGet, ActionDocumentVersionList, + ActionDocumentVersionSignatureList, + ActionRiskList, + ActionAssetList, + ActionDatumList, + ActionAuditGet, ActionAuditList, + ActionReportGet, ActionReportGetReportUrl, ActionReportDownloadUrlGet, + ActionNonconformityList, + ActionObligationList, + ActionContinualImprovementList, + ActionProcessingActivityList, + ActionSnapshotList, + ActionFileGet, ActionFileDownloadUrl, + ).WithSID("entity-read-access"), + + // Document signing actions + policy.Allow( + ActionDocumentVersionExportPDF, ActionDocumentVersionExportSignable, ActionDocumentVersionSign, + ).WithSID("document-signing"), +).WithDescription("Read-only probo access for auditors (excludes internal/employee content)") + +// EmployeePolicy defines permissions for employee role. +// Employees have access to internal documents and some limited read access. +var EmployeePolicy = policy.NewPolicy( + "probo:employee", + "Probo Employee", + // Basic organization access + policy.Allow( + ActionOrganizationGet, + ActionOrganizationGetLogoUrl, + ).WithSID("org-basic-access"), + + // Document signing access + policy.Allow( + ActionDocumentGet, ActionDocumentList, + ).WithSID("document-signing-access"), + + // Document version signing + policy.Allow( + ActionDocumentVersionGet, ActionDocumentVersionList, + ActionDocumentVersionSign, + ActionDocumentVersionExportSignable, + ).WithSID("document-version-signing"), +).WithDescription("Employee access - can sign documents and view internal content") + +// ProboPolicySet returns the PolicySet for the probo service. +// This is registered with the IAM Authorizer when probo.Service is created. +func ProboPolicySet() *iam.PolicySet { + return iam.NewPolicySet(). + AddRolePolicy("OWNER", OwnerPolicy). + AddRolePolicy("ADMIN", AdminPolicy). + AddRolePolicy("VIEWER", ViewerPolicy). + AddRolePolicy("AUDITOR", AuditorPolicy). + AddRolePolicy("EMPLOYEE", EmployeePolicy) +} diff --git a/pkg/probo/service.go b/pkg/probo/service.go index e8436870f..f46f34b42 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -31,6 +31,7 @@ import ( "go.probo.inc/probo/pkg/filevalidation" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/html2pdf" + "go.probo.inc/probo/pkg/iam" "go.probo.inc/probo/pkg/mail" "go.probo.inc/probo/pkg/slack" ) @@ -135,11 +136,14 @@ func NewService( fileManagerService *filemanager.Service, logger *log.Logger, slackService *slack.Service, + iamService *iam.Service, ) (*Service, error) { if bucket == "" { return nil, fmt.Errorf("bucket is required") } + iamService.Authorizer.RegisterPolicySet(ProboPolicySet()) + svc := &Service{ pg: pgClient, s3: s3Client, diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index 9768b930d..7ef207791 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -388,6 +388,7 @@ func (impl *Implm) Run( fileManagerService, l.Named("probo"), slackService, + iamService, ) if err != nil { return fmt.Errorf("cannot create probo service: %w", err) diff --git a/pkg/server/api/connect/v1/schema.graphql b/pkg/server/api/connect/v1/schema.graphql index f39a2f447..c47ef4803 100644 --- a/pkg/server/api/connect/v1/schema.graphql +++ b/pkg/server/api/connect/v1/schema.graphql @@ -230,7 +230,7 @@ type Membership implements Node { profile: MembershipProfile @goField(forceResolver: true) @isViewer organization: Organization @goField(forceResolver: true) role: MembershipRole! - permissions: [Permission!]! + permissions: [Permission!] @goField(forceResolver: true) lastSession: Session @goField(forceResolver: true) @isViewer } @@ -276,11 +276,6 @@ type Permission implements Node { principalId: ID! } -type PermissionGrant { - application: Application! - accessLevel: AccessLevel! -} - type Application { id: ApplicationId! name: String! @@ -303,7 +298,6 @@ type SAMLConfiguration implements Node { spMetadataUrl: String! testLoginUrl: String! attributeMappings: SAMLAttributeMappings! - defaultPermissions: [PermissionGrant!]! } type SAMLAttributeMappings { diff --git a/pkg/server/api/connect/v1/schema/schema.go b/pkg/server/api/connect/v1/schema/schema.go index fcf80cc07..3f15f646e 100644 --- a/pkg/server/api/connect/v1/schema/schema.go +++ b/pkg/server/api/connect/v1/schema/schema.go @@ -267,11 +267,6 @@ type ComplexityRoot struct { PrincipalType func(childComplexity int) int } - PermissionGrant struct { - AccessLevel func(childComplexity int) int - Application func(childComplexity int) int - } - PersonalAPIKey struct { CreatedAt func(childComplexity int) int ExpiresAt func(childComplexity int) int @@ -335,7 +330,6 @@ type ComplexityRoot struct { AttributeMappings func(childComplexity int) int AutoSignupEnabled func(childComplexity int) int CreatedAt func(childComplexity int) int - DefaultPermissions func(childComplexity int) int DomainVerificationToken func(childComplexity int) int DomainVerifiedAt func(childComplexity int) int EmailDomain func(childComplexity int) int @@ -438,6 +432,7 @@ type MembershipResolver interface { Profile(ctx context.Context, obj *types.Membership) (*types.MembershipProfile, error) Organization(ctx context.Context, obj *types.Membership) (*types.Organization, error) + Permissions(ctx context.Context, obj *types.Membership) ([]*types.Permission, error) LastSession(ctx context.Context, obj *types.Membership) (*types.Session, error) } type MembershipConnectionResolver interface { @@ -1385,19 +1380,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin return e.complexity.Permission.PrincipalType(childComplexity), true - case "PermissionGrant.accessLevel": - if e.complexity.PermissionGrant.AccessLevel == nil { - break - } - - return e.complexity.PermissionGrant.AccessLevel(childComplexity), true - case "PermissionGrant.application": - if e.complexity.PermissionGrant.Application == nil { - break - } - - return e.complexity.PermissionGrant.Application(childComplexity), true - case "PersonalAPIKey.createdAt": if e.complexity.PersonalAPIKey.CreatedAt == nil { break @@ -1593,12 +1575,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.SAMLConfiguration.CreatedAt(childComplexity), true - case "SAMLConfiguration.defaultPermissions": - if e.complexity.SAMLConfiguration.DefaultPermissions == nil { - break - } - - return e.complexity.SAMLConfiguration.DefaultPermissions(childComplexity), true case "SAMLConfiguration.domainVerificationToken": if e.complexity.SAMLConfiguration.DomainVerificationToken == nil { break @@ -2219,7 +2195,7 @@ type Membership implements Node { profile: MembershipProfile @goField(forceResolver: true) @isViewer organization: Organization @goField(forceResolver: true) role: MembershipRole! - permissions: [Permission!]! + permissions: [Permission!] @goField(forceResolver: true) lastSession: Session @goField(forceResolver: true) @isViewer } @@ -2265,11 +2241,6 @@ type Permission implements Node { principalId: ID! } -type PermissionGrant { - application: Application! - accessLevel: AccessLevel! -} - type Application { id: ApplicationId! name: String! @@ -2292,7 +2263,6 @@ type SAMLConfiguration implements Node { spMetadataUrl: String! testLoginUrl: String! attributeMappings: SAMLAttributeMappings! - defaultPermissions: [PermissionGrant!]! } type SAMLAttributeMappings { @@ -5132,12 +5102,12 @@ func (ec *executionContext) _Membership_permissions(ctx context.Context, field g field, ec.fieldContext_Membership_permissions, func(ctx context.Context) (any, error) { - return obj.Permissions, nil + return ec.resolvers.Membership().Permissions(ctx, obj) }, nil, - ec.marshalNPermission2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermissionᚄ, - true, + ec.marshalOPermission2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermissionᚄ, true, + false, ) } @@ -5145,8 +5115,8 @@ func (ec *executionContext) fieldContext_Membership_permissions(_ context.Contex fc = &graphql.FieldContext{ Object: "Membership", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { case "id": @@ -8107,74 +8077,6 @@ func (ec *executionContext) fieldContext_Permission_principalId(_ context.Contex return fc, nil } -func (ec *executionContext) _PermissionGrant_application(ctx context.Context, field graphql.CollectedField, obj *types.PermissionGrant) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_PermissionGrant_application, - func(ctx context.Context) (any, error) { - return obj.Application, nil - }, - nil, - ec.marshalNApplication2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐApplication, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_PermissionGrant_application(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "PermissionGrant", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Application_id(ctx, field) - case "name": - return ec.fieldContext_Application_name(ctx, field) - case "description": - return ec.fieldContext_Application_description(ctx, field) - case "availableAccessLevels": - return ec.fieldContext_Application_availableAccessLevels(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Application", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _PermissionGrant_accessLevel(ctx context.Context, field graphql.CollectedField, obj *types.PermissionGrant) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_PermissionGrant_accessLevel, - func(ctx context.Context) (any, error) { - return obj.AccessLevel, nil - }, - nil, - ec.marshalNAccessLevel2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐAccessLevel, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_PermissionGrant_accessLevel(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "PermissionGrant", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type AccessLevel does not have child fields") - }, - } - return fc, nil -} - func (ec *executionContext) _PersonalAPIKey_id(ctx context.Context, field graphql.CollectedField, obj *types.PersonalAPIKey) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -9623,41 +9525,6 @@ func (ec *executionContext) fieldContext_SAMLConfiguration_attributeMappings(_ c return fc, nil } -func (ec *executionContext) _SAMLConfiguration_defaultPermissions(ctx context.Context, field graphql.CollectedField, obj *types.SAMLConfiguration) (ret graphql.Marshaler) { - return graphql.ResolveField( - ctx, - ec.OperationContext, - field, - ec.fieldContext_SAMLConfiguration_defaultPermissions, - func(ctx context.Context) (any, error) { - return obj.DefaultPermissions, nil - }, - nil, - ec.marshalNPermissionGrant2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermissionGrantᚄ, - true, - true, - ) -} - -func (ec *executionContext) fieldContext_SAMLConfiguration_defaultPermissions(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "SAMLConfiguration", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "application": - return ec.fieldContext_PermissionGrant_application(ctx, field) - case "accessLevel": - return ec.fieldContext_PermissionGrant_accessLevel(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type PermissionGrant", field.Name) - }, - } - return fc, nil -} - func (ec *executionContext) _SAMLConfigurationConnection_edges(ctx context.Context, field graphql.CollectedField, obj *types.SAMLConfigurationConnection) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -9813,8 +9680,6 @@ func (ec *executionContext) fieldContext_SAMLConfigurationEdge_node(_ context.Co return ec.fieldContext_SAMLConfiguration_testLoginUrl(ctx, field) case "attributeMappings": return ec.fieldContext_SAMLConfiguration_attributeMappings(ctx, field) - case "defaultPermissions": - return ec.fieldContext_SAMLConfiguration_defaultPermissions(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type SAMLConfiguration", field.Name) }, @@ -10736,8 +10601,6 @@ func (ec *executionContext) fieldContext_UpdateSAMLConfigurationPayload_samlConf return ec.fieldContext_SAMLConfiguration_testLoginUrl(ctx, field) case "attributeMappings": return ec.fieldContext_SAMLConfiguration_attributeMappings(ctx, field) - case "defaultPermissions": - return ec.fieldContext_SAMLConfiguration_defaultPermissions(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type SAMLConfiguration", field.Name) }, @@ -14543,10 +14406,38 @@ func (ec *executionContext) _Membership(ctx context.Context, sel ast.SelectionSe atomic.AddUint32(&out.Invalids, 1) } case "permissions": - out.Values[i] = ec._Membership_permissions(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&out.Invalids, 1) + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Membership_permissions(ctx, field, obj) + return res } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "lastSession": field := field @@ -15387,50 +15278,6 @@ func (ec *executionContext) _Permission(ctx context.Context, sel ast.SelectionSe return out } -var permissionGrantImplementors = []string{"PermissionGrant"} - -func (ec *executionContext) _PermissionGrant(ctx context.Context, sel ast.SelectionSet, obj *types.PermissionGrant) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, permissionGrantImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("PermissionGrant") - case "application": - out.Values[i] = ec._PermissionGrant_application(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - case "accessLevel": - out.Values[i] = ec._PermissionGrant_accessLevel(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - var personalAPIKeyImplementors = []string{"PersonalAPIKey", "Node"} func (ec *executionContext) _PersonalAPIKey(ctx context.Context, sel ast.SelectionSet, obj *types.PersonalAPIKey) graphql.Marshaler { @@ -16096,11 +15943,6 @@ func (ec *executionContext) _SAMLConfiguration(ctx context.Context, sel ast.Sele if out.Values[i] == graphql.Null { out.Invalids++ } - case "defaultPermissions": - out.Values[i] = ec._SAMLConfiguration_defaultPermissions(ctx, field, obj) - if out.Values[i] == graphql.Null { - out.Invalids++ - } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -17767,50 +17609,6 @@ func (ec *executionContext) marshalNPageInfo2goᚗproboᚗincᚋproboᚋpkgᚋse return ec._PageInfo(ctx, sel, &v) } -func (ec *executionContext) marshalNPermission2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermissionᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.Permission) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNPermission2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermission(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - func (ec *executionContext) marshalNPermission2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermission(ctx context.Context, sel ast.SelectionSet, v *types.Permission) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -17821,60 +17619,6 @@ func (ec *executionContext) marshalNPermission2ᚖgoᚗproboᚗincᚋproboᚋpkg return ec._Permission(ctx, sel, v) } -func (ec *executionContext) marshalNPermissionGrant2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermissionGrantᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.PermissionGrant) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNPermissionGrant2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermissionGrant(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalNPermissionGrant2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermissionGrant(ctx context.Context, sel ast.SelectionSet, v *types.PermissionGrant) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - graphql.AddErrorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._PermissionGrant(ctx, sel, v) -} - func (ec *executionContext) marshalNPersonalAPIKey2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPersonalAPIKey(ctx context.Context, sel ast.SelectionSet, v *types.PersonalAPIKey) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -18878,6 +18622,53 @@ func (ec *executionContext) marshalOOrganization2ᚖgoᚗproboᚗincᚋproboᚋp return ec._Organization(ctx, sel, v) } +func (ec *executionContext) marshalOPermission2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermissionᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.Permission) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPermission2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPermission(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + func (ec *executionContext) marshalOPersonalAPIKey2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐPersonalAPIKey(ctx context.Context, sel ast.SelectionSet, v *types.PersonalAPIKey) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/pkg/server/api/connect/v1/types/types.go b/pkg/server/api/connect/v1/types/types.go index 730a9ed31..c63136ae3 100644 --- a/pkg/server/api/connect/v1/types/types.go +++ b/pkg/server/api/connect/v1/types/types.go @@ -200,7 +200,7 @@ type Membership struct { Profile *MembershipProfile `json:"profile,omitempty"` Organization *Organization `json:"organization,omitempty"` Role coredata.MembershipRole `json:"role"` - Permissions []*Permission `json:"permissions"` + Permissions []*Permission `json:"permissions,omitempty"` LastSession *Session `json:"lastSession,omitempty"` } @@ -278,11 +278,6 @@ type Permission struct { func (Permission) IsNode() {} func (this Permission) GetID() gid.GID { return this.ID } -type PermissionGrant struct { - Application *Application `json:"application"` - AccessLevel AccessLevel `json:"accessLevel"` -} - type PersonalAPIKey struct { ID gid.GID `json:"id"` Name string `json:"name"` @@ -378,7 +373,6 @@ type SAMLConfiguration struct { SpMetadataURL string `json:"spMetadataUrl"` TestLoginURL string `json:"testLoginUrl"` AttributeMappings *SAMLAttributeMappings `json:"attributeMappings"` - DefaultPermissions []*PermissionGrant `json:"defaultPermissions"` } func (SAMLConfiguration) IsNode() {} diff --git a/pkg/server/api/connect/v1/v1_resolver.go b/pkg/server/api/connect/v1/v1_resolver.go index 4d3ff5b79..e883aeab1 100644 --- a/pkg/server/api/connect/v1/v1_resolver.go +++ b/pkg/server/api/connect/v1/v1_resolver.go @@ -233,6 +233,11 @@ func (r *membershipResolver) Organization(ctx context.Context, obj *types.Member return types.NewOrganization(organization), nil } +// Permissions is the resolver for the permissions field. +func (r *membershipResolver) Permissions(ctx context.Context, obj *types.Membership) ([]*types.Permission, error) { + panic("not implemented") +} + // LastSession is the resolver for the lastSession field. func (r *membershipResolver) LastSession(ctx context.Context, obj *types.Membership) (*types.Session, error) { session := SessionFromContext(ctx) diff --git a/pkg/server/api/console/v1/resolver.go b/pkg/server/api/console/v1/resolver.go index c97a4915c..4b56844cb 100644 --- a/pkg/server/api/console/v1/resolver.go +++ b/pkg/server/api/console/v1/resolver.go @@ -316,16 +316,23 @@ func GetTenantService(ctx context.Context, proboSvc *probo.Service, tenantID gid return proboSvc.WithTenant(tenantID) } -func (r *Resolver) MustBeAuthorized(ctx context.Context, entityID gid.GID, action iam.Action) { +func (r *Resolver) MustAuthorize(ctx context.Context, entityID gid.GID, action iam.Action) { user := connect_v1.IdentityFromContext(ctx) - apiKey := connect_v1.APIKeyFromContext(ctx) + // apiKey := connect_v1.APIKeyFromContext(ctx) - var credentialID *gid.GID - if apiKey != nil { - credentialID = &apiKey.ID - } + // var credentialID *gid.GID + // if apiKey != nil { + // credentialID = &apiKey.ID + // } - err := r.iam.LegacyAccessManagementService.Authorize(ctx, user.ID, credentialID, entityID, action) + err := r.iam.Authorizer.Authorize( + ctx, + iam.AuthorizeParams{ + Principal: user.ID, + Resource: entityID, + Action: action, + }, + ) if err != nil { panic(err) } diff --git a/pkg/server/api/console/v1/schema/schema.go b/pkg/server/api/console/v1/schema/schema.go index 1777c28cb..943945f59 100644 --- a/pkg/server/api/console/v1/schema/schema.go +++ b/pkg/server/api/console/v1/schema/schema.go @@ -252,6 +252,7 @@ type ComplexityRoot struct { Measures func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) int Name func(childComplexity int) int Obligations func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) int + Organization func(childComplexity int) int SectionTitle func(childComplexity int) int Snapshots func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) int StateOfApplicabilityControls func(childComplexity int, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.StateOfApplicabilityOrderBy) int @@ -1932,6 +1933,8 @@ type ContinualImprovementConnectionResolver interface { TotalCount(ctx context.Context, obj *types.ContinualImprovementConnection) (int, error) } type ControlResolver interface { + Organization(ctx context.Context, obj *types.Control) (*types.Organization, error) + Framework(ctx context.Context, obj *types.Control) (*types.Framework, error) Measures(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) Documents(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) @@ -2926,6 +2929,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.Control.Obligations(childComplexity, args["first"].(*int), args["after"].(*page.CursorKey), args["last"].(*int), args["before"].(*page.CursorKey), args["orderBy"].(*types.ObligationOrderBy), args["filter"].(*types.ObligationFilter)), true + case "Control.organization": + if e.complexity.Control.Organization == nil { + break + } + + return e.complexity.Control.Organization(childComplexity), true case "Control.sectionTitle": if e.complexity.Control.SectionTitle == nil { break @@ -11762,6 +11771,7 @@ type Framework implements Node { type Control implements Node { id: ID! + organization: Organization @goField(forceResolver: true) sectionTitle: String! name: String! description: String @@ -21218,6 +21228,109 @@ func (ec *executionContext) fieldContext_Control_id(_ context.Context, field gra return fc, nil } +func (ec *executionContext) _Control_organization(ctx context.Context, field graphql.CollectedField, obj *types.Control) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + ec.fieldContext_Control_organization, + func(ctx context.Context) (any, error) { + return ec.resolvers.Control().Organization(ctx, obj) + }, + nil, + ec.marshalOOrganization2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐOrganization, + true, + false, + ) +} + +func (ec *executionContext) fieldContext_Control_organization(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Control", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Organization_id(ctx, field) + case "name": + return ec.fieldContext_Organization_name(ctx, field) + case "logoUrl": + return ec.fieldContext_Organization_logoUrl(ctx, field) + case "horizontalLogoUrl": + return ec.fieldContext_Organization_horizontalLogoUrl(ctx, field) + case "description": + return ec.fieldContext_Organization_description(ctx, field) + case "websiteUrl": + return ec.fieldContext_Organization_websiteUrl(ctx, field) + case "email": + return ec.fieldContext_Organization_email(ctx, field) + case "headquarterAddress": + return ec.fieldContext_Organization_headquarterAddress(ctx, field) + case "context": + return ec.fieldContext_Organization_context(ctx, field) + case "slackConnections": + return ec.fieldContext_Organization_slackConnections(ctx, field) + case "frameworks": + return ec.fieldContext_Organization_frameworks(ctx, field) + case "controls": + return ec.fieldContext_Organization_controls(ctx, field) + case "vendors": + return ec.fieldContext_Organization_vendors(ctx, field) + case "peoples": + return ec.fieldContext_Organization_peoples(ctx, field) + case "documents": + return ec.fieldContext_Organization_documents(ctx, field) + case "meetings": + return ec.fieldContext_Organization_meetings(ctx, field) + case "statesOfApplicability": + return ec.fieldContext_Organization_statesOfApplicability(ctx, field) + case "measures": + return ec.fieldContext_Organization_measures(ctx, field) + case "risks": + return ec.fieldContext_Organization_risks(ctx, field) + case "tasks": + return ec.fieldContext_Organization_tasks(ctx, field) + case "assets": + return ec.fieldContext_Organization_assets(ctx, field) + case "data": + return ec.fieldContext_Organization_data(ctx, field) + case "audits": + return ec.fieldContext_Organization_audits(ctx, field) + case "nonconformities": + return ec.fieldContext_Organization_nonconformities(ctx, field) + case "obligations": + return ec.fieldContext_Organization_obligations(ctx, field) + case "continualImprovements": + return ec.fieldContext_Organization_continualImprovements(ctx, field) + case "rightsRequests": + return ec.fieldContext_Organization_rightsRequests(ctx, field) + case "processingActivities": + return ec.fieldContext_Organization_processingActivities(ctx, field) + case "dataProtectionImpactAssessments": + return ec.fieldContext_Organization_dataProtectionImpactAssessments(ctx, field) + case "transferImpactAssessments": + return ec.fieldContext_Organization_transferImpactAssessments(ctx, field) + case "snapshots": + return ec.fieldContext_Organization_snapshots(ctx, field) + case "trustCenterFiles": + return ec.fieldContext_Organization_trustCenterFiles(ctx, field) + case "trustCenter": + return ec.fieldContext_Organization_trustCenter(ctx, field) + case "customDomain": + return ec.fieldContext_Organization_customDomain(ctx, field) + case "createdAt": + return ec.fieldContext_Organization_createdAt(ctx, field) + case "updatedAt": + return ec.fieldContext_Organization_updatedAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Organization", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Control_sectionTitle(ctx context.Context, field graphql.CollectedField, obj *types.Control) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -21951,6 +22064,8 @@ func (ec *executionContext) fieldContext_ControlEdge_node(_ context.Context, fie switch field.Name { case "id": return ec.fieldContext_Control_id(ctx, field) + case "organization": + return ec.fieldContext_Control_organization(ctx, field) case "sectionTitle": return ec.fieldContext_Control_sectionTitle(ctx, field) case "name": @@ -51012,6 +51127,8 @@ func (ec *executionContext) fieldContext_UpdateControlPayload_control(_ context. switch field.Name { case "id": return ec.fieldContext_Control_id(ctx, field) + case "organization": + return ec.fieldContext_Control_organization(ctx, field) case "sectionTitle": return ec.fieldContext_Control_sectionTitle(ctx, field) case "name": @@ -67994,6 +68111,39 @@ func (ec *executionContext) _Control(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "organization": + field := field + + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Control_organization(ctx, field, obj) + return res + } + + if field.Deferrable != nil { + dfs, ok := deferred[field.Deferrable.Label] + di := 0 + if ok { + dfs.AddField(field) + di = len(dfs.Values) - 1 + } else { + dfs = graphql.NewFieldSet([]graphql.CollectedField{field}) + deferred[field.Deferrable.Label] = dfs + } + dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler { + return innerFunc(ctx, dfs) + }) + + // don't run the out.Concurrently() call below + out.Values[i] = graphql.Null + continue + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) case "sectionTitle": out.Values[i] = ec._Control_sectionTitle(ctx, field, obj) if out.Values[i] == graphql.Null { diff --git a/pkg/server/api/console/v1/types/control.go b/pkg/server/api/console/v1/types/control.go index 67a98adf9..ae8ad3278 100644 --- a/pkg/server/api/console/v1/types/control.go +++ b/pkg/server/api/console/v1/types/control.go @@ -51,6 +51,9 @@ func NewControlEdge(control *coredata.Control, orderField coredata.ControlOrderF func NewControl(control *coredata.Control) *Control { return &Control{ ID: control.ID, + Organization: &Organization{ + ID: control.OrganizationID, + }, Framework: &Framework{ ID: control.FrameworkID, }, diff --git a/pkg/server/api/console/v1/types/types.go b/pkg/server/api/console/v1/types/types.go index 0f89851d4..a331bbc20 100644 --- a/pkg/server/api/console/v1/types/types.go +++ b/pkg/server/api/console/v1/types/types.go @@ -168,6 +168,7 @@ type ContinualImprovementFilter struct { type Control struct { ID gid.GID `json:"id"` + Organization *Organization `json:"organization,omitempty"` SectionTitle string `json:"sectionTitle"` Name string `json:"name"` Description *string `json:"description,omitempty"` diff --git a/pkg/server/api/console/v1/v1_resolver.go b/pkg/server/api/console/v1/v1_resolver.go index 32d624352..48d9ab145 100644 --- a/pkg/server/api/console/v1/v1_resolver.go +++ b/pkg/server/api/console/v1/v1_resolver.go @@ -26,19 +26,11 @@ import ( // Owner is the resolver for the owner field. func (r *assetResolver) Owner(ctx context.Context, obj *types.Asset) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOwner) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - asset, err := prb.Assets.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - panic(fmt.Errorf("cannot get asset: %w", err)) - } - - owner, err := prb.Peoples.Get(ctx, asset.OwnerID) + owner, err := prb.Peoples.Get(ctx, obj.Owner.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) @@ -52,7 +44,7 @@ func (r *assetResolver) Owner(ctx context.Context, obj *types.Asset) (*types.Peo // Vendors is the resolver for the vendors field. func (r *assetResolver) Vendors(ctx context.Context, obj *types.Asset, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListVendors) + r.MustAuthorize(ctx, obj.ID, probo.ActionVendorList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -79,7 +71,7 @@ func (r *assetResolver) Vendors(ctx context.Context, obj *types.Asset, first *in // Organization is the resolver for the organization field. func (r *assetResolver) Organization(ctx context.Context, obj *types.Asset) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -103,7 +95,7 @@ func (r *assetResolver) Organization(ctx context.Context, obj *types.Asset) (*ty // TotalCount is the resolver for the totalCount field. func (r *assetConnectionResolver) TotalCount(ctx context.Context, obj *types.AssetConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionAssetList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -126,20 +118,11 @@ func (r *assetConnectionResolver) TotalCount(ctx context.Context, obj *types.Ass // Organization is the resolver for the organization field. func (r *auditResolver) Organization(ctx context.Context, obj *types.Audit) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - audit, err := prb.Audits.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - - panic(fmt.Errorf("cannot load audit: %w", err)) - } - - organization, err := prb.Organizations.Get(ctx, audit.OrganizationID) + organization, err := prb.Organizations.Get(ctx, obj.Organization.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) @@ -153,20 +136,11 @@ func (r *auditResolver) Organization(ctx context.Context, obj *types.Audit) (*ty // Framework is the resolver for the framework field. func (r *auditResolver) Framework(ctx context.Context, obj *types.Audit) (*types.Framework, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetFramework) + r.MustAuthorize(ctx, obj.ID, probo.ActionFrameworkGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - audit, err := prb.Audits.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - - panic(fmt.Errorf("cannot load audit: %w", err)) - } - - framework, err := prb.Frameworks.Get(ctx, audit.FrameworkID) + framework, err := prb.Frameworks.Get(ctx, obj.Framework.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) @@ -180,25 +154,17 @@ func (r *auditResolver) Framework(ctx context.Context, obj *types.Audit) (*types // Report is the resolver for the report field. func (r *auditResolver) Report(ctx context.Context, obj *types.Audit) (*types.Report, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionReport) + r.MustAuthorize(ctx, obj.ID, probo.ActionReportGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - audit, err := prb.Audits.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - - panic(fmt.Errorf("cannot load audit: %w", err)) - } - - if audit.ReportID == nil { + if obj.Report == nil { return nil, nil } - report, err := prb.Reports.Get(ctx, *audit.ReportID) + report, err := prb.Reports.Get(ctx, obj.Report.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot load report: %w", err)) } @@ -207,7 +173,7 @@ func (r *auditResolver) Report(ctx context.Context, obj *types.Audit) (*types.Re // ReportURL is the resolver for the reportUrl field. func (r *auditResolver) ReportURL(ctx context.Context, obj *types.Audit) (*string, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionReportUrl) + r.MustAuthorize(ctx, obj.ID, probo.ActionReportGetReportUrl) if obj.Report == nil { return nil, nil @@ -225,7 +191,7 @@ func (r *auditResolver) ReportURL(ctx context.Context, obj *types.Audit) (*strin // Controls is the resolver for the controls field. func (r *auditResolver) Controls(ctx context.Context, obj *types.Audit, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListControls) + r.MustAuthorize(ctx, obj.ID, probo.ActionControlList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -257,7 +223,9 @@ func (r *auditResolver) Controls(ctx context.Context, obj *types.Audit, first *i // TotalCount is the resolver for the totalCount field. func (r *auditConnectionResolver) TotalCount(ctx context.Context, obj *types.AuditConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionAuditList) + + // TODO missing switch case prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -270,16 +238,11 @@ func (r *auditConnectionResolver) TotalCount(ctx context.Context, obj *types.Aud // Organization is the resolver for the organization field. func (r *continualImprovementResolver) Organization(ctx context.Context, obj *types.ContinualImprovement) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - continualImprovement, err := prb.ContinualImprovements.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get continual improvement: %w", err)) - } - - organization, err := prb.Organizations.Get(ctx, continualImprovement.OrganizationID) + organization, err := prb.Organizations.Get(ctx, obj.Organization.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) @@ -293,16 +256,11 @@ func (r *continualImprovementResolver) Organization(ctx context.Context, obj *ty // Owner is the resolver for the owner field. func (r *continualImprovementResolver) Owner(ctx context.Context, obj *types.ContinualImprovement) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOwner) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - continualImprovement, err := prb.ContinualImprovements.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get continual improvement: %w", err)) - } - - people, err := prb.Peoples.Get(ctx, continualImprovement.OwnerID) + people, err := prb.Peoples.Get(ctx, obj.Owner.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) @@ -316,7 +274,7 @@ func (r *continualImprovementResolver) Owner(ctx context.Context, obj *types.Con // TotalCount is the resolver for the totalCount field. func (r *continualImprovementConnectionResolver) TotalCount(ctx context.Context, obj *types.ContinualImprovementConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionContinualImprovementList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -334,30 +292,28 @@ func (r *continualImprovementConnectionResolver) TotalCount(ctx context.Context, return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } +// Organization is the resolver for the organization field. +func (r *controlResolver) Organization(ctx context.Context, obj *types.Control) (*types.Organization, error) { + panic(fmt.Errorf("not implemented: Organization - organization")) +} + // Framework is the resolver for the framework field. func (r *controlResolver) Framework(ctx context.Context, obj *types.Control) (*types.Framework, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetFramework) + r.MustAuthorize(ctx, obj.ID, probo.ActionFrameworkGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - control, err := prb.Controls.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - - panic(fmt.Errorf("cannot get control: %w", err)) - } - - framework, err := prb.Frameworks.Get(ctx, control.FrameworkID) + framework, err := prb.Frameworks.Get(ctx, obj.Framework.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get framework: %w", err)) } @@ -366,7 +322,7 @@ func (r *controlResolver) Framework(ctx context.Context, obj *types.Control) (*t // Measures is the resolver for the measures field. func (r *controlResolver) Measures(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListMeasures) + r.MustAuthorize(ctx, obj.ID, probo.ActionMeasureList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -390,6 +346,7 @@ func (r *controlResolver) Measures(ctx context.Context, obj *types.Control, firs page, err := prb.Measures.ListForControlID(ctx, obj.ID, cursor, measureFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list measures: %w", err)) } @@ -398,7 +355,7 @@ func (r *controlResolver) Measures(ctx context.Context, obj *types.Control, firs // Documents is the resolver for the documents field. func (r *controlResolver) Documents(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListDocuments) + r.MustAuthorize(ctx, obj.ID, probo.ActionDocumentList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -430,7 +387,7 @@ func (r *controlResolver) Documents(ctx context.Context, obj *types.Control, fir // Audits is the resolver for the audits field. func (r *controlResolver) Audits(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) (*types.AuditConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListAudits) + r.MustAuthorize(ctx, obj.ID, probo.ActionAuditList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -457,7 +414,7 @@ func (r *controlResolver) Audits(ctx context.Context, obj *types.Control, first // Obligations is the resolver for the obligations field. func (r *controlResolver) Obligations(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) (*types.ObligationConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListObligations) + r.MustAuthorize(ctx, obj.ID, probo.ActionObligationList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -489,7 +446,7 @@ func (r *controlResolver) Obligations(ctx context.Context, obj *types.Control, f // Snapshots is the resolver for the snapshots field. func (r *controlResolver) Snapshots(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) (*types.SnapshotConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListSnapshots) + r.MustAuthorize(ctx, obj.ID, probo.ActionSnapshotList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -517,7 +474,7 @@ func (r *controlResolver) Snapshots(ctx context.Context, obj *types.Control, fir // StateOfApplicabilityControls is the resolver for the stateOfApplicabilityControls field. func (r *controlResolver) StateOfApplicabilityControls(ctx context.Context, obj *types.Control, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.StateOfApplicabilityOrderBy) (*types.StateOfApplicabilityControlConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListStatesOfApplicability) + r.MustAuthorize(ctx, obj.ID, probo.ActionStateOfApplicabilityList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -544,8 +501,9 @@ func (r *controlResolver) StateOfApplicabilityControls(ctx context.Context, obj // TotalCount is the resolver for the totalCount field. func (r *controlConnectionResolver) TotalCount(ctx context.Context, obj *types.ControlConnection) (int, error) { + r.MustAuthorize(ctx, obj.ParentID, probo.ActionControlList) + prb := r.ProboService(ctx, obj.ParentID.TenantID()) - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) switch obj.Resolver.(type) { case *organizationResolver: @@ -591,7 +549,7 @@ func (r *controlConnectionResolver) TotalCount(ctx context.Context, obj *types.C // ProcessingActivity is the resolver for the processingActivity field. func (r *dataProtectionImpactAssessmentResolver) ProcessingActivity(ctx context.Context, obj *types.DataProtectionImpactAssessment) (*types.ProcessingActivity, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGet) + r.MustAuthorize(ctx, obj.ID, probo.ActionProcessingActivityList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -610,7 +568,7 @@ func (r *dataProtectionImpactAssessmentResolver) ProcessingActivity(ctx context. // Organization is the resolver for the organization field. func (r *dataProtectionImpactAssessmentResolver) Organization(ctx context.Context, obj *types.DataProtectionImpactAssessment) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -632,7 +590,7 @@ func (r *dataProtectionImpactAssessmentResolver) Organization(ctx context.Contex // TotalCount is the resolver for the totalCount field. func (r *dataProtectionImpactAssessmentConnectionResolver) TotalCount(ctx context.Context, obj *types.DataProtectionImpactAssessmentConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionDataProtectionImpactAssessmentList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -650,16 +608,11 @@ func (r *dataProtectionImpactAssessmentConnectionResolver) TotalCount(ctx contex // Owner is the resolver for the owner field. func (r *datumResolver) Owner(ctx context.Context, obj *types.Datum) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOwner) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - data, err := prb.Data.Get(ctx, obj.ID) - if err != nil { - return nil, fmt.Errorf("cannot get datum: %w", err) - } - - people, err := prb.Peoples.Get(ctx, data.OwnerID) + people, err := prb.Peoples.Get(ctx, obj.Owner.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) @@ -673,7 +626,7 @@ func (r *datumResolver) Owner(ctx context.Context, obj *types.Datum) (*types.Peo // Vendors is the resolver for the vendors field. func (r *datumResolver) Vendors(ctx context.Context, obj *types.Datum, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListVendors) + r.MustAuthorize(ctx, obj.ID, probo.ActionVendorList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -692,6 +645,7 @@ func (r *datumResolver) Vendors(ctx context.Context, obj *types.Datum, first *in page, err := prb.Data.ListVendors(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list data vendors: %w", err)) } @@ -700,7 +654,7 @@ func (r *datumResolver) Vendors(ctx context.Context, obj *types.Datum, first *in // Organization is the resolver for the organization field. func (r *datumResolver) Organization(ctx context.Context, obj *types.Datum) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -710,6 +664,7 @@ func (r *datumResolver) Organization(ctx context.Context, obj *types.Datum) (*ty return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get organization: %w", err)) } @@ -718,7 +673,7 @@ func (r *datumResolver) Organization(ctx context.Context, obj *types.Datum) (*ty // TotalCount is the resolver for the totalCount field. func (r *datumConnectionResolver) TotalCount(ctx context.Context, obj *types.DatumConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionDatumList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -736,31 +691,24 @@ func (r *datumConnectionResolver) TotalCount(ctx context.Context, obj *types.Dat return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // Owner is the resolver for the owner field. func (r *documentResolver) Owner(ctx context.Context, obj *types.Document) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOwner) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - document, err := prb.Documents.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - - panic(fmt.Errorf("cannot get document: %w", err)) - } - // Get the owner - owner, err := prb.Peoples.Get(ctx, document.OwnerID) + owner, err := prb.Peoples.Get(ctx, obj.Owner.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get owner: %w", err)) } @@ -769,25 +717,17 @@ func (r *documentResolver) Owner(ctx context.Context, obj *types.Document) (*typ // Organization is the resolver for the organization field. func (r *documentResolver) Organization(ctx context.Context, obj *types.Document) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - document, err := prb.Documents.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - - panic(fmt.Errorf("cannot get document: %w", err)) - } - - organization, err := prb.Organizations.Get(ctx, document.OrganizationID) + organization, err := prb.Organizations.Get(ctx, obj.Organization.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get organization: %w", err)) } @@ -796,7 +736,7 @@ func (r *documentResolver) Organization(ctx context.Context, obj *types.Document // Versions is the resolver for the versions field. func (r *documentResolver) Versions(ctx context.Context, obj *types.Document, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionOrderBy, filter *types.DocumentVersionFilter) (*types.DocumentVersionConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListVersions) + r.MustAuthorize(ctx, obj.ID, probo.ActionDocumentVersionList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -817,6 +757,7 @@ func (r *documentResolver) Versions(ctx context.Context, obj *types.Document, fi page, err := prb.Documents.ListVersions(ctx, obj.ID, cursor, versionFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list document versions: %w", err)) } @@ -825,7 +766,7 @@ func (r *documentResolver) Versions(ctx context.Context, obj *types.Document, fi // Controls is the resolver for the controls field. func (r *documentResolver) Controls(ctx context.Context, obj *types.Document, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListControls) + r.MustAuthorize(ctx, obj.ID, probo.ActionControlList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -849,6 +790,7 @@ func (r *documentResolver) Controls(ctx context.Context, obj *types.Document, fi page, err := prb.Controls.ListForDocumentID(ctx, obj.ID, cursor, controlFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list document controls: %w", err)) } @@ -857,50 +799,51 @@ func (r *documentResolver) Controls(ctx context.Context, obj *types.Document, fi // TotalCount is the resolver for the totalCount field. func (r *documentConnectionResolver) TotalCount(ctx context.Context, obj *types.DocumentConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionDocumentList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) + switch obj.Resolver.(type) { case *controlResolver: count, err := prb.Documents.CountForControlID(ctx, obj.ParentID, obj.Filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count controls: %w", err)) } return count, nil case *organizationResolver: count, err := prb.Documents.CountForOrganizationID(ctx, obj.ParentID, obj.Filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count documents: %w", err)) } return count, nil case *riskResolver: count, err := prb.Documents.CountForRiskID(ctx, obj.ParentID, obj.Filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count risks: %w", err)) } return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // Document is the resolver for the document field. func (r *documentVersionResolver) Document(ctx context.Context, obj *types.DocumentVersion) (*types.Document, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetDocument) + r.MustAuthorize(ctx, obj.ID, probo.ActionDocumentGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - documentVersion, err := prb.Documents.GetVersion(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get document version: %w", err)) - } - - document, err := prb.Documents.Get(ctx, documentVersion.DocumentID) + document, err := prb.Documents.Get(ctx, obj.Document.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get document: %w", err)) } @@ -909,21 +852,17 @@ func (r *documentVersionResolver) Document(ctx context.Context, obj *types.Docum // Owner is the resolver for the owner field. func (r *documentVersionResolver) Owner(ctx context.Context, obj *types.DocumentVersion) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOwner) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - documentVersion, err := prb.Documents.GetVersion(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get document version: %w", err)) - } - - owner, err := prb.Peoples.Get(ctx, documentVersion.OwnerID) + owner, err := prb.Peoples.Get(ctx, obj.Owner.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get owner: %w", err)) } @@ -932,7 +871,7 @@ func (r *documentVersionResolver) Owner(ctx context.Context, obj *types.Document // Signatures is the resolver for the signatures field. func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.DocumentVersion, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentVersionSignatureOrder, filter *types.DocumentVersionSignatureFilter) (*types.DocumentVersionSignatureConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionSignatures) + r.MustAuthorize(ctx, obj.ID, probo.ActionDocumentVersionSignatureList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -957,6 +896,7 @@ func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.Doc page, err := prb.Documents.ListSignatures(ctx, obj.ID, cursor, signatureFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list document version signatures: %w", err)) } @@ -965,16 +905,15 @@ func (r *documentVersionResolver) Signatures(ctx context.Context, obj *types.Doc // Signed is the resolver for the signed field. func (r *documentVersionResolver) Signed(ctx context.Context, obj *types.DocumentVersion) (bool, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetSigned) + r.MustAuthorize(ctx, obj.ID, probo.ActionDocumentVersionGet) identity := connect_v1.IdentityFromContext(ctx) - if identity == nil { - panic(fmt.Errorf("user not found in context")) - } prb := r.ProboService(ctx, obj.ID.TenantID()) + signed, err := prb.Documents.IsVersionSignedByUserEmail(ctx, obj.ID, identity.EmailAddress) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot check if document version is signed: %w", err)) } @@ -983,17 +922,13 @@ func (r *documentVersionResolver) Signed(ctx context.Context, obj *types.Documen // DocumentVersion is the resolver for the documentVersion field. func (r *documentVersionSignatureResolver) DocumentVersion(ctx context.Context, obj *types.DocumentVersionSignature) (*types.DocumentVersion, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionDocumentVersion) + r.MustAuthorize(ctx, obj.ID, probo.ActionDocumentVersionGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - documentVersionSignature, err := prb.Documents.GetVersionSignature(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get document version signature: %w", err)) - } - - documentVersion, err := prb.Documents.GetVersion(ctx, documentVersionSignature.DocumentVersionID) + documentVersion, err := prb.Documents.GetVersion(ctx, obj.DocumentVersion.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get document version: %w", err)) } @@ -1002,21 +937,17 @@ func (r *documentVersionSignatureResolver) DocumentVersion(ctx context.Context, // SignedBy is the resolver for the signedBy field. func (r *documentVersionSignatureResolver) SignedBy(ctx context.Context, obj *types.DocumentVersionSignature) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionSignedBy) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - documentVersionSignature, err := prb.Documents.GetVersionSignature(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get document version signature: %w", err)) - } - - people, err := prb.Peoples.Get(ctx, documentVersionSignature.SignedBy) + people, err := prb.Peoples.Get(ctx, obj.SignedBy.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get people: %w", err)) } @@ -1025,20 +956,15 @@ func (r *documentVersionSignatureResolver) SignedBy(ctx context.Context, obj *ty // File is the resolver for the file field. func (r *evidenceResolver) File(ctx context.Context, obj *types.Evidence) (*types.File, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetFile) + r.MustAuthorize(ctx, obj.ID, probo.ActionFileGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - evidence, err := prb.Evidences.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot load evidence: %w", err)) - } - - if evidence.EvidenceFileId == nil { + if obj.File == nil { return nil, nil } - file, err := prb.Files.Get(ctx, *evidence.EvidenceFileId) + file, err := prb.Files.Get(ctx, obj.File.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) @@ -1052,25 +978,21 @@ func (r *evidenceResolver) File(ctx context.Context, obj *types.Evidence) (*type // Task is the resolver for the task field. func (r *evidenceResolver) Task(ctx context.Context, obj *types.Evidence) (*types.Task, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetTask) + r.MustAuthorize(ctx, obj.ID, probo.ActionTaskGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - evidence, err := prb.Evidences.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot load evidence: %w", err)) - } - - if evidence.TaskID == nil { + if obj.Task == nil { panic(fmt.Errorf("evidence is not associated with a task")) } - task, err := prb.Tasks.Get(ctx, *evidence.TaskID) + task, err := prb.Tasks.Get(ctx, obj.Task.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot load task: %w", err)) } @@ -1079,21 +1001,17 @@ func (r *evidenceResolver) Task(ctx context.Context, obj *types.Evidence) (*type // Measure is the resolver for the measure field. func (r *evidenceResolver) Measure(ctx context.Context, obj *types.Evidence) (*types.Measure, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetMeasure) + r.MustAuthorize(ctx, obj.ID, probo.ActionMeasureGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - evidence, err := prb.Evidences.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot load evidence: %w", err)) - } - - measure, err := prb.Measures.Get(ctx, evidence.MeasureID) + measure, err := prb.Measures.Get(ctx, obj.Measure.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot load measure: %w", err)) } @@ -1102,7 +1020,7 @@ func (r *evidenceResolver) Measure(ctx context.Context, obj *types.Evidence) (*t // TotalCount is the resolver for the totalCount field. func (r *evidenceConnectionResolver) TotalCount(ctx context.Context, obj *types.EvidenceConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionEvidenceList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -1110,55 +1028,52 @@ func (r *evidenceConnectionResolver) TotalCount(ctx context.Context, obj *types. case *measureResolver: count, err := prb.Evidences.CountForMeasureID(ctx, obj.ParentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count tasks: %w", err)) } return count, nil case *taskResolver: count, err := prb.Evidences.CountForTaskID(ctx, obj.ParentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count tasks: %w", err)) } return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // DownloadURL is the resolver for the downloadUrl field. func (r *fileResolver) DownloadURL(ctx context.Context, obj *types.File) (string, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionDownloadUrl) + r.MustAuthorize(ctx, obj.ID, probo.ActionFileDownloadUrl) prb := r.ProboService(ctx, obj.ID.TenantID()) downloadUrl, err := prb.Files.GenerateFileTempURL(ctx, obj.ID, 60*time.Second) if err != nil { + // TODO no panic use gqlutils.InternalError return "", fmt.Errorf("cannot generate download url: %w", err) } + // TODO no panic use gqlutils.InternalError return downloadUrl, nil } // Organization is the resolver for the organization field. func (r *frameworkResolver) Organization(ctx context.Context, obj *types.Framework) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - framework, err := prb.Frameworks.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - - panic(fmt.Errorf("cannot load framework: %w", err)) - } - - organization, err := prb.Organizations.Get(ctx, framework.OrganizationID) + organization, err := prb.Organizations.Get(ctx, obj.Organization.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot load organization: %w", err)) } @@ -1167,7 +1082,7 @@ func (r *frameworkResolver) Organization(ctx context.Context, obj *types.Framewo // Controls is the resolver for the controls field. func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListControls) + r.MustAuthorize(ctx, obj.ID, probo.ActionControlList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -1191,6 +1106,7 @@ func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, page, err := prb.Controls.ListForFrameworkID(ctx, obj.ID, cursor, controlFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list controls: %w", err)) } @@ -1199,7 +1115,7 @@ func (r *frameworkResolver) Controls(ctx context.Context, obj *types.Framework, // LightLogoURL is the resolver for the lightLogoURL field. func (r *frameworkResolver) LightLogoURL(ctx context.Context, obj *types.Framework) (*string, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetLogoUrl) + r.MustAuthorize(ctx, obj.ID, probo.ActionFrameworkGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -1208,7 +1124,7 @@ func (r *frameworkResolver) LightLogoURL(ctx context.Context, obj *types.Framewo // DarkLogoURL is the resolver for the darkLogoURL field. func (r *frameworkResolver) DarkLogoURL(ctx context.Context, obj *types.Framework) (*string, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetLogoUrl) + r.MustAuthorize(ctx, obj.ID, probo.ActionFrameworkGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -1217,7 +1133,7 @@ func (r *frameworkResolver) DarkLogoURL(ctx context.Context, obj *types.Framewor // TotalCount is the resolver for the totalCount field. func (r *frameworkConnectionResolver) TotalCount(ctx context.Context, obj *types.FrameworkConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionFrameworkList) switch obj.Resolver.(type) { case *organizationResolver: @@ -1225,17 +1141,19 @@ func (r *frameworkConnectionResolver) TotalCount(ctx context.Context, obj *types count, err := prb.Frameworks.CountForOrganizationID(ctx, obj.ParentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count frameworks: %w", err)) } return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // Evidences is the resolver for the evidences field. func (r *measureResolver) Evidences(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.EvidenceOrderBy) (*types.EvidenceConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListEvidences) + r.MustAuthorize(ctx, obj.ID, probo.ActionEvidenceList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -1254,6 +1172,7 @@ func (r *measureResolver) Evidences(ctx context.Context, obj *types.Measure, fir page, err := prb.Evidences.ListForMeasureID(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list measure evidences: %w", err)) } @@ -1262,7 +1181,7 @@ func (r *measureResolver) Evidences(ctx context.Context, obj *types.Measure, fir // Tasks is the resolver for the tasks field. func (r *measureResolver) Tasks(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) (*types.TaskConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListTasks) + r.MustAuthorize(ctx, obj.ID, probo.ActionTaskList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -1281,6 +1200,7 @@ func (r *measureResolver) Tasks(ctx context.Context, obj *types.Measure, first * page, err := prb.Tasks.ListForMeasureID(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list measure tasks: %w", err)) } @@ -1289,7 +1209,7 @@ func (r *measureResolver) Tasks(ctx context.Context, obj *types.Measure, first * // Risks is the resolver for the risks field. func (r *measureResolver) Risks(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) (*types.RiskConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListRisks) + r.MustAuthorize(ctx, obj.ID, probo.ActionRiskList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -1313,6 +1233,7 @@ func (r *measureResolver) Risks(ctx context.Context, obj *types.Measure, first * page, err := prb.Risks.ListForMeasureID(ctx, obj.ID, cursor, riskFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list measure risks: %w", err)) } @@ -1321,7 +1242,7 @@ func (r *measureResolver) Risks(ctx context.Context, obj *types.Measure, first * // Controls is the resolver for the controls field. func (r *measureResolver) Controls(ctx context.Context, obj *types.Measure, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListControls) + r.MustAuthorize(ctx, obj.ID, probo.ActionControlList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -1345,6 +1266,7 @@ func (r *measureResolver) Controls(ctx context.Context, obj *types.Measure, firs page, err := prb.Controls.ListForMeasureID(ctx, obj.ID, cursor, controlFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list measure controls: %w", err)) } @@ -1353,7 +1275,7 @@ func (r *measureResolver) Controls(ctx context.Context, obj *types.Measure, firs // TotalCount is the resolver for the totalCount field. func (r *measureConnectionResolver) TotalCount(ctx context.Context, obj *types.MeasureConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionMeasureList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -1361,32 +1283,41 @@ func (r *measureConnectionResolver) TotalCount(ctx context.Context, obj *types.M case *organizationResolver: count, err := prb.Measures.CountForOrganizationID(ctx, obj.ParentID, obj.Filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count measures: %w", err)) } return count, nil case *controlResolver: count, err := prb.Measures.CountForControlID(ctx, obj.ParentID, obj.Filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count measures: %w", err)) } return count, nil case *riskResolver: count, err := prb.Measures.CountForRiskID(ctx, obj.ParentID, obj.Filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count measures: %w", err)) } return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // Attendees is the resolver for the attendees field. func (r *meetingResolver) Attendees(ctx context.Context, obj *types.Meeting) ([]*types.People, error) { + // TODO bug must be paginated + + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleList) + prb := r.ProboService(ctx, obj.ID.TenantID()) attendees, err := prb.Meetings.GetAttendees(ctx, obj.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot load meeting attendees: %w", err)) } @@ -1404,23 +1335,17 @@ func (r *meetingResolver) Attendees(ctx context.Context, obj *types.Meeting) ([] // Organization is the resolver for the organization field. func (r *meetingResolver) Organization(ctx context.Context, obj *types.Meeting) (*types.Organization, error) { + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) + prb := r.ProboService(ctx, obj.ID.TenantID()) - meeting, err := prb.Meetings.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - - panic(fmt.Errorf("cannot load meeting: %w", err)) - } - - organization, err := prb.Organizations.Get(ctx, meeting.OrganizationID) + organization, err := prb.Organizations.Get(ctx, obj.Organization.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot load organization: %w", err)) } @@ -1429,22 +1354,28 @@ func (r *meetingResolver) Organization(ctx context.Context, obj *types.Meeting) // TotalCount is the resolver for the totalCount field. func (r *meetingConnectionResolver) TotalCount(ctx context.Context, obj *types.MeetingConnection) (int, error) { + r.MustAuthorize(ctx, obj.ParentID, probo.ActionMeetingList) + prb := r.ProboService(ctx, obj.ParentID.TenantID()) switch obj.Resolver.(type) { case *organizationResolver: count, err := prb.Meetings.CountForOrganizationID(ctx, obj.ParentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count meetings: %w", err)) } return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // UpdateOrganizationContext is the resolver for the updateOrganizationContext field. func (r *mutationResolver) UpdateOrganizationContext(ctx context.Context, input types.UpdateOrganizationContextInput) (*types.UpdateOrganizationContextPayload, error) { + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionOrganizationContextUpdate) + prb := r.ProboService(ctx, input.OrganizationID.TenantID()) req := probo.UpdateOrganizationContextRequest{ @@ -1454,6 +1385,7 @@ func (r *mutationResolver) UpdateOrganizationContext(ctx context.Context, input organizationContext, err := prb.Organizations.UpdateContext(ctx, req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update organization context: %w", err)) } @@ -1464,15 +1396,19 @@ func (r *mutationResolver) UpdateOrganizationContext(ctx context.Context, input // UpdateTrustCenter is the resolver for the updateTrustCenter field. func (r *mutationResolver) UpdateTrustCenter(ctx context.Context, input types.UpdateTrustCenterInput) (*types.UpdateTrustCenterPayload, error) { - r.MustBeAuthorized(ctx, input.TrustCenterID, iam.ActionUpdateTrustCenter) + r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionTrustCenterUpdate) prb := r.ProboService(ctx, input.TrustCenterID.TenantID()) - trustCenter, file, err := prb.TrustCenters.Update(ctx, &probo.UpdateTrustCenterRequest{ - ID: input.TrustCenterID, - Active: input.Active, - }) + trustCenter, file, err := prb.TrustCenters.Update( + ctx, + &probo.UpdateTrustCenterRequest{ + ID: input.TrustCenterID, + Active: input.Active, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update trust center: %w", err)) } @@ -1483,16 +1419,20 @@ func (r *mutationResolver) UpdateTrustCenter(ctx context.Context, input types.Up // UploadTrustCenterNda is the resolver for the uploadTrustCenterNDA field. func (r *mutationResolver) UploadTrustCenterNda(ctx context.Context, input types.UploadTrustCenterNDAInput) (*types.UploadTrustCenterNDAPayload, error) { - r.MustBeAuthorized(ctx, input.TrustCenterID, iam.ActionUploadTrustCenterNDA) + r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionTrustCenterNonDisclosureAgreementUpload) prb := r.ProboService(ctx, input.TrustCenterID.TenantID()) - trustCenter, file, err := prb.TrustCenters.UploadNDA(ctx, &probo.UploadTrustCenterNDARequest{ - TrustCenterID: input.TrustCenterID, - File: input.File.File, - FileName: input.FileName, - }) + trustCenter, file, err := prb.TrustCenters.UploadNDA( + ctx, + &probo.UploadTrustCenterNDARequest{ + TrustCenterID: input.TrustCenterID, + File: input.File.File, + FileName: input.FileName, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot upload trust center NDA: %w", err)) } @@ -1503,12 +1443,13 @@ func (r *mutationResolver) UploadTrustCenterNda(ctx context.Context, input types // DeleteTrustCenterNda is the resolver for the deleteTrustCenterNDA field. func (r *mutationResolver) DeleteTrustCenterNda(ctx context.Context, input types.DeleteTrustCenterNDAInput) (*types.DeleteTrustCenterNDAPayload, error) { - r.MustBeAuthorized(ctx, input.TrustCenterID, iam.ActionDeleteTrustCenterNDA) + r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionTrustCenterNonDisclosureAgreementDelete) prb := r.ProboService(ctx, input.TrustCenterID.TenantID()) trustCenter, file, err := prb.TrustCenters.DeleteNDA(ctx, input.TrustCenterID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete trust center NDA: %w", err)) } @@ -1519,20 +1460,24 @@ func (r *mutationResolver) DeleteTrustCenterNda(ctx context.Context, input types // CreateTrustCenterAccess is the resolver for the createTrustCenterAccess field. func (r *mutationResolver) CreateTrustCenterAccess(ctx context.Context, input types.CreateTrustCenterAccessInput) (*types.CreateTrustCenterAccessPayload, error) { - r.MustBeAuthorized(ctx, input.TrustCenterID, iam.ActionCreateTrustCenterAccess) + r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionTrustCenterAccessCreate) prb := r.ProboService(ctx, input.TrustCenterID.TenantID()) - access, err := prb.TrustCenterAccesses.Create(ctx, &probo.CreateTrustCenterAccessRequest{ - TrustCenterID: input.TrustCenterID, - Email: input.Email, - Name: input.Name, - }) + access, err := prb.TrustCenterAccesses.Create( + ctx, + &probo.CreateTrustCenterAccessRequest{ + TrustCenterID: input.TrustCenterID, + Email: input.Email, + Name: input.Name, + }, + ) if err != nil { if errors.Is(err, coredata.ErrResourceAlreadyExists) { return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create trust center access: %w", err)) } @@ -1543,7 +1488,7 @@ func (r *mutationResolver) CreateTrustCenterAccess(ctx context.Context, input ty // UpdateTrustCenterAccess is the resolver for the updateTrustCenterAccess field. func (r *mutationResolver) UpdateTrustCenterAccess(ctx context.Context, input types.UpdateTrustCenterAccessInput) (*types.UpdateTrustCenterAccessPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateTrustCenterAccess) + r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterAccessUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -1568,15 +1513,19 @@ func (r *mutationResolver) UpdateTrustCenterAccess(ctx context.Context, input ty Status: fileAccess.Status, }) } - access, err := prb.TrustCenterAccesses.Update(ctx, &probo.UpdateTrustCenterAccessRequest{ - ID: input.ID, - Name: input.Name, - Active: input.Active, - DocumentAccesses: documentAccesses, - ReportAccesses: reportAccesses, - TrustCenterFileAccesses: fileAccesses, - }) + access, err := prb.TrustCenterAccesses.Update( + ctx, + &probo.UpdateTrustCenterAccessRequest{ + ID: input.ID, + Name: input.Name, + Active: input.Active, + DocumentAccesses: documentAccesses, + ReportAccesses: reportAccesses, + TrustCenterFileAccesses: fileAccesses, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update trust center access: %w", err)) } @@ -1587,12 +1536,13 @@ func (r *mutationResolver) UpdateTrustCenterAccess(ctx context.Context, input ty // DeleteTrustCenterAccess is the resolver for the deleteTrustCenterAccess field. func (r *mutationResolver) DeleteTrustCenterAccess(ctx context.Context, input types.DeleteTrustCenterAccessInput) (*types.DeleteTrustCenterAccessPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionDeleteTrustCenterAccess) + r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterAccessDelete) prb := r.ProboService(ctx, input.ID.TenantID()) err := prb.TrustCenterAccesses.Delete(ctx, input.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete trust center access: %w", err)) } @@ -1603,23 +1553,27 @@ func (r *mutationResolver) DeleteTrustCenterAccess(ctx context.Context, input ty // CreateTrustCenterReference is the resolver for the createTrustCenterReference field. func (r *mutationResolver) CreateTrustCenterReference(ctx context.Context, input types.CreateTrustCenterReferenceInput) (*types.CreateTrustCenterReferencePayload, error) { - r.MustBeAuthorized(ctx, input.TrustCenterID, iam.ActionCreateTrustCenterReference) + r.MustAuthorize(ctx, input.TrustCenterID, probo.ActionTrustCenterReferenceCreate) prb := r.ProboService(ctx, input.TrustCenterID.TenantID()) - reference, err := prb.TrustCenterReferences.Create(ctx, &probo.CreateTrustCenterReferenceRequest{ - TrustCenterID: input.TrustCenterID, - Name: input.Name, - Description: input.Description, - WebsiteURL: input.WebsiteURL, - LogoFile: probo.File{ - Content: input.LogoFile.File, - Filename: input.LogoFile.Filename, - Size: input.LogoFile.Size, - ContentType: input.LogoFile.ContentType, + reference, err := prb.TrustCenterReferences.Create( + ctx, + &probo.CreateTrustCenterReferenceRequest{ + TrustCenterID: input.TrustCenterID, + Name: input.Name, + Description: input.Description, + WebsiteURL: input.WebsiteURL, + LogoFile: probo.File{ + Content: input.LogoFile.File, + Filename: input.LogoFile.Filename, + Size: input.LogoFile.Size, + ContentType: input.LogoFile.ContentType, + }, }, - }) + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create trust center reference: %w", err)) } @@ -1630,7 +1584,7 @@ func (r *mutationResolver) CreateTrustCenterReference(ctx context.Context, input // UpdateTrustCenterReference is the resolver for the updateTrustCenterReference field. func (r *mutationResolver) UpdateTrustCenterReference(ctx context.Context, input types.UpdateTrustCenterReferenceInput) (*types.UpdateTrustCenterReferencePayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateTrustCenterReference) + r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterReferenceUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -1653,6 +1607,7 @@ func (r *mutationResolver) UpdateTrustCenterReference(ctx context.Context, input reference, err := prb.TrustCenterReferences.Update(ctx, req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update trust center reference: %w", err)) } @@ -1663,12 +1618,13 @@ func (r *mutationResolver) UpdateTrustCenterReference(ctx context.Context, input // DeleteTrustCenterReference is the resolver for the deleteTrustCenterReference field. func (r *mutationResolver) DeleteTrustCenterReference(ctx context.Context, input types.DeleteTrustCenterReferenceInput) (*types.DeleteTrustCenterReferencePayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionDeleteTrustCenterReference) + r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterReferenceDelete) prb := r.ProboService(ctx, input.ID.TenantID()) err := prb.TrustCenterReferences.Delete(ctx, input.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete trust center reference: %w", err)) } @@ -1679,23 +1635,27 @@ func (r *mutationResolver) DeleteTrustCenterReference(ctx context.Context, input // CreateTrustCenterFile is the resolver for the createTrustCenterFile field. func (r *mutationResolver) CreateTrustCenterFile(ctx context.Context, input types.CreateTrustCenterFileInput) (*types.CreateTrustCenterFilePayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateTrustCenterFile) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionTrustCenterFileCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) - file, err := prb.TrustCenterFiles.Create(ctx, &probo.CreateTrustCenterFileRequest{ - OrganizationID: input.OrganizationID, - Name: input.Name, - Category: input.Category, - File: probo.File{ - Content: input.File.File, - Filename: input.File.Filename, - Size: input.File.Size, - ContentType: input.File.ContentType, + file, err := prb.TrustCenterFiles.Create( + ctx, + &probo.CreateTrustCenterFileRequest{ + OrganizationID: input.OrganizationID, + Name: input.Name, + Category: input.Category, + File: probo.File{ + Content: input.File.File, + Filename: input.File.Filename, + Size: input.File.Size, + ContentType: input.File.ContentType, + }, + TrustCenterVisibility: input.TrustCenterVisibility, }, - TrustCenterVisibility: input.TrustCenterVisibility, - }) + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create trust center file: %w", err)) } @@ -1706,17 +1666,21 @@ func (r *mutationResolver) CreateTrustCenterFile(ctx context.Context, input type // UpdateTrustCenterFile is the resolver for the updateTrustCenterFile field. func (r *mutationResolver) UpdateTrustCenterFile(ctx context.Context, input types.UpdateTrustCenterFileInput) (*types.UpdateTrustCenterFilePayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateTrustCenterFile) + r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterFileUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) - file, err := prb.TrustCenterFiles.Update(ctx, &probo.UpdateTrustCenterFileRequest{ - ID: input.ID, - Name: input.Name, - Category: input.Category, - TrustCenterVisibility: input.TrustCenterVisibility, - }) + file, err := prb.TrustCenterFiles.Update( + ctx, + &probo.UpdateTrustCenterFileRequest{ + ID: input.ID, + Name: input.Name, + Category: input.Category, + TrustCenterVisibility: input.TrustCenterVisibility, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update trust center file: %w", err)) } @@ -1727,11 +1691,13 @@ func (r *mutationResolver) UpdateTrustCenterFile(ctx context.Context, input type // GetTrustCenterFile is the resolver for the getTrustCenterFile field. func (r *mutationResolver) GetTrustCenterFile(ctx context.Context, input types.GetTrustCenterFileInput) (*types.GetTrustCenterFilePayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionGetTrustCenterFile) + r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterFileGet) + prb := r.ProboService(ctx, input.ID.TenantID()) file, err := prb.TrustCenterFiles.Get(ctx, input.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get trust center file: %w", err)) } @@ -1742,12 +1708,13 @@ func (r *mutationResolver) GetTrustCenterFile(ctx context.Context, input types.G // DeleteTrustCenterFile is the resolver for the deleteTrustCenterFile field. func (r *mutationResolver) DeleteTrustCenterFile(ctx context.Context, input types.DeleteTrustCenterFileInput) (*types.DeleteTrustCenterFilePayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionDeleteTrustCenterFile) + r.MustAuthorize(ctx, input.ID, probo.ActionTrustCenterFileDelete) prb := r.ProboService(ctx, input.ID.TenantID()) err := prb.TrustCenterFiles.Delete(ctx, input.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete trust center file: %w", err)) } @@ -1758,32 +1725,30 @@ func (r *mutationResolver) DeleteTrustCenterFile(ctx context.Context, input type // CreatePeople is the resolver for the createPeople field. func (r *mutationResolver) CreatePeople(ctx context.Context, input types.CreatePeopleInput) (*types.CreatePeoplePayload, error) { - user := connect_v1.IdentityFromContext(ctx) - - r.iam.Authorizer.Authorize(ctx, iam.AuthorizeParams{ - Principal: user.ID, - Resource: input.OrganizationID, - Action: iam.ActionCreatePeople, - }) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionPeopleCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) - people, err := prb.Peoples.Create(ctx, probo.CreatePeopleRequest{ - OrganizationID: input.OrganizationID, - FullName: input.FullName, - PrimaryEmailAddress: input.PrimaryEmailAddress, - AdditionalEmailAddresses: input.AdditionalEmailAddresses, - Kind: input.Kind, - Position: input.Position, - ContractStartDate: input.ContractStartDate, - ContractEndDate: input.ContractEndDate, - }) + people, err := prb.Peoples.Create( + ctx, + probo.CreatePeopleRequest{ + OrganizationID: input.OrganizationID, + FullName: input.FullName, + PrimaryEmailAddress: input.PrimaryEmailAddress, + AdditionalEmailAddresses: input.AdditionalEmailAddresses, + Kind: input.Kind, + Position: input.Position, + ContractStartDate: input.ContractStartDate, + ContractEndDate: input.ContractEndDate, + }, + ) if err != nil { if errors.Is(err, coredata.ErrResourceAlreadyExists) { return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create people: %w", err)) } @@ -1794,7 +1759,7 @@ func (r *mutationResolver) CreatePeople(ctx context.Context, input types.CreateP // UpdatePeople is the resolver for the updatePeople field. func (r *mutationResolver) UpdatePeople(ctx context.Context, input types.UpdatePeopleInput) (*types.UpdatePeoplePayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdatePeople) + r.MustAuthorize(ctx, input.ID, probo.ActionPeopleUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -1812,6 +1777,7 @@ func (r *mutationResolver) UpdatePeople(ctx context.Context, input types.UpdateP }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update people: %w", err)) } @@ -1822,7 +1788,7 @@ func (r *mutationResolver) UpdatePeople(ctx context.Context, input types.UpdateP // DeletePeople is the resolver for the deletePeople field. func (r *mutationResolver) DeletePeople(ctx context.Context, input types.DeletePeopleInput) (*types.DeletePeoplePayload, error) { - r.MustBeAuthorized(ctx, input.PeopleID, iam.ActionDeletePeople) + r.MustAuthorize(ctx, input.PeopleID, probo.ActionPeopleDelete) prb := r.ProboService(ctx, input.PeopleID.TenantID()) @@ -1832,6 +1798,7 @@ func (r *mutationResolver) DeletePeople(ctx context.Context, input types.DeleteP return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete people: %w", err)) } @@ -1842,7 +1809,7 @@ func (r *mutationResolver) DeletePeople(ctx context.Context, input types.DeleteP // CreateVendor is the resolver for the createVendor field. func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateVendorInput) (*types.CreateVendorPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateVendor) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionVendorCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -1876,6 +1843,7 @@ func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateV return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError return nil, fmt.Errorf("cannot create vendor: %w", err) } return &types.CreateVendorPayload{ @@ -1885,34 +1853,38 @@ func (r *mutationResolver) CreateVendor(ctx context.Context, input types.CreateV // UpdateVendor is the resolver for the updateVendor field. func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateVendorInput) (*types.UpdateVendorPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateVendor) + r.MustAuthorize(ctx, input.ID, probo.ActionVendorUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) - vendor, err := prb.Vendors.Update(ctx, probo.UpdateVendorRequest{ - ID: input.ID, - Name: input.Name, - Description: gqlutils.UnwrapOmittable(input.Description), - StatusPageURL: gqlutils.UnwrapOmittable(input.StatusPageURL), - TermsOfServiceURL: gqlutils.UnwrapOmittable(input.TermsOfServiceURL), - PrivacyPolicyURL: gqlutils.UnwrapOmittable(input.PrivacyPolicyURL), - ServiceLevelAgreementURL: gqlutils.UnwrapOmittable(input.ServiceLevelAgreementURL), - DataProcessingAgreementURL: gqlutils.UnwrapOmittable(input.DataProcessingAgreementURL), - BusinessAssociateAgreementURL: gqlutils.UnwrapOmittable(input.BusinessAssociateAgreementURL), - SubprocessorsListURL: gqlutils.UnwrapOmittable(input.SubprocessorsListURL), - SecurityPageURL: gqlutils.UnwrapOmittable(input.SecurityPageURL), - TrustPageURL: gqlutils.UnwrapOmittable(input.TrustPageURL), - HeadquarterAddress: gqlutils.UnwrapOmittable(input.HeadquarterAddress), - LegalName: gqlutils.UnwrapOmittable(input.LegalName), - WebsiteURL: gqlutils.UnwrapOmittable(input.WebsiteURL), - Category: input.Category, - Certifications: input.Certifications, - BusinessOwnerID: gqlutils.UnwrapOmittable(input.BusinessOwnerID), - SecurityOwnerID: gqlutils.UnwrapOmittable(input.SecurityOwnerID), - ShowOnTrustCenter: input.ShowOnTrustCenter, - Countries: input.Countries, - }) + vendor, err := prb.Vendors.Update( + ctx, + probo.UpdateVendorRequest{ + ID: input.ID, + Name: input.Name, + Description: gqlutils.UnwrapOmittable(input.Description), + StatusPageURL: gqlutils.UnwrapOmittable(input.StatusPageURL), + TermsOfServiceURL: gqlutils.UnwrapOmittable(input.TermsOfServiceURL), + PrivacyPolicyURL: gqlutils.UnwrapOmittable(input.PrivacyPolicyURL), + ServiceLevelAgreementURL: gqlutils.UnwrapOmittable(input.ServiceLevelAgreementURL), + DataProcessingAgreementURL: gqlutils.UnwrapOmittable(input.DataProcessingAgreementURL), + BusinessAssociateAgreementURL: gqlutils.UnwrapOmittable(input.BusinessAssociateAgreementURL), + SubprocessorsListURL: gqlutils.UnwrapOmittable(input.SubprocessorsListURL), + SecurityPageURL: gqlutils.UnwrapOmittable(input.SecurityPageURL), + TrustPageURL: gqlutils.UnwrapOmittable(input.TrustPageURL), + HeadquarterAddress: gqlutils.UnwrapOmittable(input.HeadquarterAddress), + LegalName: gqlutils.UnwrapOmittable(input.LegalName), + WebsiteURL: gqlutils.UnwrapOmittable(input.WebsiteURL), + Category: input.Category, + Certifications: input.Certifications, + BusinessOwnerID: gqlutils.UnwrapOmittable(input.BusinessOwnerID), + SecurityOwnerID: gqlutils.UnwrapOmittable(input.SecurityOwnerID), + ShowOnTrustCenter: input.ShowOnTrustCenter, + Countries: input.Countries, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError return nil, fmt.Errorf("cannot update vendor: %w", err) } @@ -1923,12 +1895,13 @@ func (r *mutationResolver) UpdateVendor(ctx context.Context, input types.UpdateV // DeleteVendor is the resolver for the deleteVendor field. func (r *mutationResolver) DeleteVendor(ctx context.Context, input types.DeleteVendorInput) (*types.DeleteVendorPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionDeleteVendor) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorDelete) prb := r.ProboService(ctx, input.VendorID.TenantID()) err := prb.Vendors.Delete(ctx, input.VendorID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete vendor: %w", err)) } @@ -1939,7 +1912,7 @@ func (r *mutationResolver) DeleteVendor(ctx context.Context, input types.DeleteV // CreateVendorContact is the resolver for the createVendorContact field. func (r *mutationResolver) CreateVendorContact(ctx context.Context, input types.CreateVendorContactInput) (*types.CreateVendorContactPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionCreateVendorContact) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorContactCreate) prb := r.ProboService(ctx, input.VendorID.TenantID()) @@ -1953,6 +1926,7 @@ func (r *mutationResolver) CreateVendorContact(ctx context.Context, input types. vendorContact, err := prb.VendorContacts.Create(ctx, req) if err != nil { + // TODO no panic use gqlutils.InternalError return nil, fmt.Errorf("cannot create vendor contact: %w", err) } @@ -1963,7 +1937,7 @@ func (r *mutationResolver) CreateVendorContact(ctx context.Context, input types. // UpdateVendorContact is the resolver for the updateVendorContact field. func (r *mutationResolver) UpdateVendorContact(ctx context.Context, input types.UpdateVendorContactInput) (*types.UpdateVendorContactPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateVendorContact) + r.MustAuthorize(ctx, input.ID, probo.ActionVendorContactUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -1977,6 +1951,7 @@ func (r *mutationResolver) UpdateVendorContact(ctx context.Context, input types. vendorContact, err := prb.VendorContacts.Update(ctx, req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update vendor contact: %w", err)) } @@ -1987,12 +1962,13 @@ func (r *mutationResolver) UpdateVendorContact(ctx context.Context, input types. // DeleteVendorContact is the resolver for the deleteVendorContact field. func (r *mutationResolver) DeleteVendorContact(ctx context.Context, input types.DeleteVendorContactInput) (*types.DeleteVendorContactPayload, error) { - r.MustBeAuthorized(ctx, input.VendorContactID, iam.ActionDeleteVendorContact) + r.MustAuthorize(ctx, input.VendorContactID, probo.ActionVendorContactDelete) prb := r.ProboService(ctx, input.VendorContactID.TenantID()) err := prb.VendorContacts.Delete(ctx, input.VendorContactID) if err != nil { + // TODO no panic use gqlutils.InternalError return nil, fmt.Errorf("cannot delete vendor contact: %w", err) } @@ -2003,7 +1979,7 @@ func (r *mutationResolver) DeleteVendorContact(ctx context.Context, input types. // CreateVendorService is the resolver for the createVendorService field. func (r *mutationResolver) CreateVendorService(ctx context.Context, input types.CreateVendorServiceInput) (*types.CreateVendorServicePayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionCreateVendorService) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorServiceCreate) prb := r.ProboService(ctx, input.VendorID.TenantID()) @@ -2015,6 +1991,7 @@ func (r *mutationResolver) CreateVendorService(ctx context.Context, input types. vendorService, err := prb.VendorServices.Create(ctx, req) if err != nil { + // TODO no panic use gqlutils.InternalError return nil, fmt.Errorf("cannot create vendor service: %w", err) } @@ -2025,7 +2002,7 @@ func (r *mutationResolver) CreateVendorService(ctx context.Context, input types. // UpdateVendorService is the resolver for the updateVendorService field. func (r *mutationResolver) UpdateVendorService(ctx context.Context, input types.UpdateVendorServiceInput) (*types.UpdateVendorServicePayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateVendorService) + r.MustAuthorize(ctx, input.ID, probo.ActionVendorServiceUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -2037,6 +2014,7 @@ func (r *mutationResolver) UpdateVendorService(ctx context.Context, input types. vendorService, err := prb.VendorServices.Update(ctx, req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update vendor service: %w", err)) } @@ -2047,12 +2025,13 @@ func (r *mutationResolver) UpdateVendorService(ctx context.Context, input types. // DeleteVendorService is the resolver for the deleteVendorService field. func (r *mutationResolver) DeleteVendorService(ctx context.Context, input types.DeleteVendorServiceInput) (*types.DeleteVendorServicePayload, error) { - r.MustBeAuthorized(ctx, input.VendorServiceID, iam.ActionDeleteVendorService) + r.MustAuthorize(ctx, input.VendorServiceID, probo.ActionVendorServiceDelete) prb := r.ProboService(ctx, input.VendorServiceID.TenantID()) err := prb.VendorServices.Delete(ctx, input.VendorServiceID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete vendor service: %w", err)) } @@ -2063,15 +2042,19 @@ func (r *mutationResolver) DeleteVendorService(ctx context.Context, input types. // CreateFramework is the resolver for the createFramework field. func (r *mutationResolver) CreateFramework(ctx context.Context, input types.CreateFrameworkInput) (*types.CreateFrameworkPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateFramework) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionFrameworkCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) - framework, err := prb.Frameworks.Create(ctx, probo.CreateFrameworkRequest{ - OrganizationID: input.OrganizationID, - Name: input.Name, - }) + framework, err := prb.Frameworks.Create( + ctx, + probo.CreateFrameworkRequest{ + OrganizationID: input.OrganizationID, + Name: input.Name, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError return nil, fmt.Errorf("cannot create framework: %w", err) } @@ -2082,16 +2065,20 @@ func (r *mutationResolver) CreateFramework(ctx context.Context, input types.Crea // UpdateFramework is the resolver for the updateFramework field. func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.UpdateFrameworkInput) (*types.UpdateFrameworkPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateFramework) + r.MustAuthorize(ctx, input.ID, probo.ActionFrameworkUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) - framework, err := prb.Frameworks.Update(ctx, probo.UpdateFrameworkRequest{ - ID: input.ID, - Name: input.Name, - Description: gqlutils.UnwrapOmittable(input.Description), - }) + framework, err := prb.Frameworks.Update( + ctx, + probo.UpdateFrameworkRequest{ + ID: input.ID, + Name: input.Name, + Description: gqlutils.UnwrapOmittable(input.Description), + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError return nil, fmt.Errorf("cannot update framework: %w", err) } @@ -2102,7 +2089,7 @@ func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.Upda // ImportFramework is the resolver for the importFramework field. func (r *mutationResolver) ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionImportFramework) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionFrameworkImport) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -2117,6 +2104,7 @@ func (r *mutationResolver) ImportFramework(ctx context.Context, input types.Impo return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot import framework: %w", err)) } @@ -2127,12 +2115,13 @@ func (r *mutationResolver) ImportFramework(ctx context.Context, input types.Impo // DeleteFramework is the resolver for the deleteFramework field. func (r *mutationResolver) DeleteFramework(ctx context.Context, input types.DeleteFrameworkInput) (*types.DeleteFrameworkPayload, error) { - r.MustBeAuthorized(ctx, input.FrameworkID, iam.ActionDeleteFramework) + r.MustAuthorize(ctx, input.FrameworkID, probo.ActionFrameworkDelete) prb := r.ProboService(ctx, input.FrameworkID.TenantID()) err := prb.Frameworks.Delete(ctx, input.FrameworkID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete framework: %w", err)) } @@ -2143,12 +2132,13 @@ func (r *mutationResolver) DeleteFramework(ctx context.Context, input types.Dele // GenerateFrameworkStateOfApplicability is the resolver for the generateFrameworkStateOfApplicability field. func (r *mutationResolver) GenerateFrameworkStateOfApplicability(ctx context.Context, input types.GenerateFrameworkStateOfApplicabilityInput) (*types.GenerateFrameworkStateOfApplicabilityPayload, error) { - r.MustBeAuthorized(ctx, input.FrameworkID, iam.ActionGenerateFrameworkStateOfApplicability) + r.MustAuthorize(ctx, input.FrameworkID, probo.ActionFrameworkStateOfApplicabilityGenerate) prb := r.ProboService(ctx, input.FrameworkID.TenantID()) soa, err := prb.Frameworks.StateOfApplicability(ctx, input.FrameworkID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot generate framework SOA: %w", err)) } @@ -2162,7 +2152,7 @@ func (r *mutationResolver) GenerateFrameworkStateOfApplicability(ctx context.Con // ExportFramework is the resolver for the exportFramework field. func (r *mutationResolver) ExportFramework(ctx context.Context, input types.ExportFrameworkInput) (*types.ExportFrameworkPayload, error) { - r.MustBeAuthorized(ctx, input.FrameworkID, iam.ActionExportFramework) + r.MustAuthorize(ctx, input.FrameworkID, probo.ActionFrameworkExport) prb := r.ProboService(ctx, input.FrameworkID.TenantID()) identity := connect_v1.IdentityFromContext(ctx) @@ -2174,6 +2164,7 @@ func (r *mutationResolver) ExportFramework(ctx context.Context, input types.Expo identity.FullName, ) if exportErr != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot export framework: %w", exportErr)) } @@ -2184,24 +2175,28 @@ func (r *mutationResolver) ExportFramework(ctx context.Context, input types.Expo // CreateControl is the resolver for the createControl field. func (r *mutationResolver) CreateControl(ctx context.Context, input types.CreateControlInput) (*types.CreateControlPayload, error) { - r.MustBeAuthorized(ctx, input.FrameworkID, iam.ActionCreateControl) + r.MustAuthorize(ctx, input.FrameworkID, probo.ActionControlCreate) prb := r.ProboService(ctx, input.FrameworkID.TenantID()) - control, err := prb.Controls.Create(ctx, probo.CreateControlRequest{ - FrameworkID: input.FrameworkID, - Name: input.Name, - Description: input.Description, - SectionTitle: input.SectionTitle, - Status: &input.Status, - ExclusionJustification: input.ExclusionJustification, - BestPractice: input.BestPractice, - }) + control, err := prb.Controls.Create( + ctx, + probo.CreateControlRequest{ + FrameworkID: input.FrameworkID, + Name: input.Name, + Description: input.Description, + SectionTitle: input.SectionTitle, + Status: &input.Status, + ExclusionJustification: input.ExclusionJustification, + BestPractice: input.BestPractice, + }, + ) if err != nil { if errors.Is(err, coredata.ErrResourceAlreadyExists) { return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create control: %w", err)) } @@ -2212,25 +2207,29 @@ func (r *mutationResolver) CreateControl(ctx context.Context, input types.Create // UpdateControl is the resolver for the updateControl field. func (r *mutationResolver) UpdateControl(ctx context.Context, input types.UpdateControlInput) (*types.UpdateControlPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateControl) + r.MustAuthorize(ctx, input.ID, probo.ActionControlUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) - control, err := prb.Controls.Update(ctx, probo.UpdateControlRequest{ - ID: input.ID, - Name: input.Name, - Description: gqlutils.UnwrapOmittable(input.Description), - SectionTitle: input.SectionTitle, - Status: input.Status, - ExclusionJustification: input.ExclusionJustification, - BestPractice: input.BestPractice, - }) + control, err := prb.Controls.Update( + ctx, + probo.UpdateControlRequest{ + ID: input.ID, + Name: input.Name, + Description: gqlutils.UnwrapOmittable(input.Description), + SectionTitle: input.SectionTitle, + Status: input.Status, + ExclusionJustification: input.ExclusionJustification, + BestPractice: input.BestPractice, + }, + ) if err != nil { if errors.Is(err, coredata.ErrResourceAlreadyExists) { return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update control: %w", err)) } @@ -2241,12 +2240,16 @@ func (r *mutationResolver) UpdateControl(ctx context.Context, input types.Update // DeleteControl is the resolver for the deleteControl field. func (r *mutationResolver) DeleteControl(ctx context.Context, input types.DeleteControlInput) (*types.DeleteControlPayload, error) { + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlDelete) + prb := r.ProboService(ctx, input.ControlID.TenantID()) err := prb.Controls.Delete(ctx, input.ControlID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete control: %w", err)) } + return &types.DeleteControlPayload{ DeletedControlID: input.ControlID, }, nil @@ -2254,16 +2257,19 @@ func (r *mutationResolver) DeleteControl(ctx context.Context, input types.Delete // // CreateMeasure is the resolver for the createMeasure field. func (r *mutationResolver) CreateMeasure(ctx context.Context, input types.CreateMeasureInput) (*types.CreateMeasurePayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateMeasure) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionMeasureCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) - measure, err := prb.Measures.Create(ctx, probo.CreateMeasureRequest{ - OrganizationID: input.OrganizationID, - Name: input.Name, - Description: input.Description, - Category: input.Category, - }) + measure, err := prb.Measures.Create( + ctx, + probo.CreateMeasureRequest{ + OrganizationID: input.OrganizationID, + Name: input.Name, + Description: input.Description, + Category: input.Category, + }, + ) if err != nil { if errors.Is(err, coredata.ErrResourceAlreadyExists) { return nil, gqlutils.Conflict(err) @@ -2279,18 +2285,22 @@ func (r *mutationResolver) CreateMeasure(ctx context.Context, input types.Create // UpdateMeasure is the resolver for the updateMeasure field. func (r *mutationResolver) UpdateMeasure(ctx context.Context, input types.UpdateMeasureInput) (*types.UpdateMeasurePayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateMeasure) + r.MustAuthorize(ctx, input.ID, probo.ActionMeasureUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) - measure, err := prb.Measures.Update(ctx, probo.UpdateMeasureRequest{ - ID: input.ID, - Name: input.Name, - Description: gqlutils.UnwrapOmittable(input.Description), - Category: input.Category, - State: input.State, - }) + measure, err := prb.Measures.Update( + ctx, + probo.UpdateMeasureRequest{ + ID: input.ID, + Name: input.Name, + Description: gqlutils.UnwrapOmittable(input.Description), + Category: input.Category, + State: input.State, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update measure: %w", err)) } @@ -2301,17 +2311,19 @@ func (r *mutationResolver) UpdateMeasure(ctx context.Context, input types.Update // ImportMeasure is the resolver for the importMeasure field. func (r *mutationResolver) ImportMeasure(ctx context.Context, input types.ImportMeasureInput) (*types.ImportMeasurePayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionImportMeasure) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionMeasureImport) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) var req probo.ImportMeasureRequest if err := json.NewDecoder(input.File.File).Decode(&req.Measures); err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot unmarshal measure: %w", err)) } measures, err := prb.Measures.Import(ctx, input.OrganizationID, req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot import measure: %w", err)) } @@ -2327,12 +2339,13 @@ func (r *mutationResolver) ImportMeasure(ctx context.Context, input types.Import // DeleteMeasure is the resolver for the deleteMeasure field. func (r *mutationResolver) DeleteMeasure(ctx context.Context, input types.DeleteMeasureInput) (*types.DeleteMeasurePayload, error) { - r.MustBeAuthorized(ctx, input.MeasureID, iam.ActionDeleteMeasure) + r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureDelete) prb := r.ProboService(ctx, input.MeasureID.TenantID()) err := prb.Measures.Delete(ctx, input.MeasureID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete measure: %w", err)) } @@ -2343,12 +2356,13 @@ func (r *mutationResolver) DeleteMeasure(ctx context.Context, input types.Delete // CreateControlMeasureMapping is the resolver for the createControlMeasureMapping field. func (r *mutationResolver) CreateControlMeasureMapping(ctx context.Context, input types.CreateControlMeasureMappingInput) (*types.CreateControlMeasureMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionCreateControlMeasureMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlMeasureMappingCreate) prb := r.ProboService(ctx, input.MeasureID.TenantID()) control, measure, err := prb.Controls.CreateMeasureMapping(ctx, input.ControlID, input.MeasureID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create control measure mapping: %w", err)) } @@ -2360,7 +2374,7 @@ func (r *mutationResolver) CreateControlMeasureMapping(ctx context.Context, inpu // CreateControlDocumentMapping is the resolver for the createControlDocumentMapping field. func (r *mutationResolver) CreateControlDocumentMapping(ctx context.Context, input types.CreateControlDocumentMappingInput) (*types.CreateControlDocumentMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionCreateControlDocumentMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlDocumentMappingCreate) prb := r.ProboService(ctx, input.DocumentID.TenantID()) @@ -2370,6 +2384,7 @@ func (r *mutationResolver) CreateControlDocumentMapping(ctx context.Context, inp return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create control document mapping: %w", err)) } @@ -2381,12 +2396,13 @@ func (r *mutationResolver) CreateControlDocumentMapping(ctx context.Context, inp // DeleteControlMeasureMapping is the resolver for the deleteControlMeasureMapping field. func (r *mutationResolver) DeleteControlMeasureMapping(ctx context.Context, input types.DeleteControlMeasureMappingInput) (*types.DeleteControlMeasureMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionDeleteControlMeasureMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlMeasureMappingDelete) prb := r.ProboService(ctx, input.MeasureID.TenantID()) control, measure, err := prb.Controls.DeleteMeasureMapping(ctx, input.ControlID, input.MeasureID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete control measure mapping: %w", err)) } @@ -2398,12 +2414,13 @@ func (r *mutationResolver) DeleteControlMeasureMapping(ctx context.Context, inpu // DeleteControlDocumentMapping is the resolver for the deleteControlDocumentMapping field. func (r *mutationResolver) DeleteControlDocumentMapping(ctx context.Context, input types.DeleteControlDocumentMappingInput) (*types.DeleteControlDocumentMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionDeleteControlDocumentMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlDocumentMappingDelete) prb := r.ProboService(ctx, input.DocumentID.TenantID()) control, document, err := prb.Controls.DeleteDocumentMapping(ctx, input.ControlID, input.DocumentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete control document mapping: %w", err)) } @@ -2415,7 +2432,7 @@ func (r *mutationResolver) DeleteControlDocumentMapping(ctx context.Context, inp // CreateStateOfApplicabilityControlMapping is the resolver for the createStateOfApplicabilityControlMapping field. func (r *mutationResolver) CreateStateOfApplicabilityControlMapping(ctx context.Context, input types.CreateStateOfApplicabilityControlMappingInput) (*types.CreateStateOfApplicabilityControlMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionCreateStateOfApplicabilityControlMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionStateOfApplicabilityControlMappingCreate) prb := r.ProboService(ctx, input.StateOfApplicabilityID.TenantID()) @@ -2431,7 +2448,7 @@ func (r *mutationResolver) CreateStateOfApplicabilityControlMapping(ctx context. // DeleteStateOfApplicabilityControlMapping is the resolver for the deleteStateOfApplicabilityControlMapping field. func (r *mutationResolver) DeleteStateOfApplicabilityControlMapping(ctx context.Context, input types.DeleteStateOfApplicabilityControlMappingInput) (*types.DeleteStateOfApplicabilityControlMappingPayload, error) { - r.MustBeAuthorized(ctx, input.StateOfApplicabilityID, iam.ActionDeleteStateOfApplicabilityControlMapping) + r.MustAuthorize(ctx, input.StateOfApplicabilityID, probo.ActionStateOfApplicabilityControlMappingDelete) prb := r.ProboService(ctx, input.StateOfApplicabilityID.TenantID()) @@ -2449,12 +2466,13 @@ func (r *mutationResolver) DeleteStateOfApplicabilityControlMapping(ctx context. // CreateControlAuditMapping is the resolver for the createControlAuditMapping field. func (r *mutationResolver) CreateControlAuditMapping(ctx context.Context, input types.CreateControlAuditMappingInput) (*types.CreateControlAuditMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionCreateControlAuditMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlAuditMappingCreate) prb := r.ProboService(ctx, input.AuditID.TenantID()) control, audit, err := prb.Controls.CreateAuditMapping(ctx, input.ControlID, input.AuditID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create control audit mapping: %w", err)) } @@ -2466,12 +2484,13 @@ func (r *mutationResolver) CreateControlAuditMapping(ctx context.Context, input // DeleteControlAuditMapping is the resolver for the deleteControlAuditMapping field. func (r *mutationResolver) DeleteControlAuditMapping(ctx context.Context, input types.DeleteControlAuditMappingInput) (*types.DeleteControlAuditMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionDeleteControlAuditMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlAuditMappingDelete) prb := r.ProboService(ctx, input.AuditID.TenantID()) control, audit, err := prb.Controls.DeleteAuditMapping(ctx, input.ControlID, input.AuditID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete control audit mapping: %w", err)) } @@ -2483,7 +2502,7 @@ func (r *mutationResolver) DeleteControlAuditMapping(ctx context.Context, input // CreateControlObligationMapping is the resolver for the createControlObligationMapping field. func (r *mutationResolver) CreateControlObligationMapping(ctx context.Context, input types.CreateControlObligationMappingInput) (*types.CreateControlObligationMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionCreateControlObligationMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlObligationMappingCreate) prb := r.ProboService(ctx, input.ObligationID.TenantID()) @@ -2500,7 +2519,7 @@ func (r *mutationResolver) CreateControlObligationMapping(ctx context.Context, i // DeleteControlObligationMapping is the resolver for the deleteControlObligationMapping field. func (r *mutationResolver) DeleteControlObligationMapping(ctx context.Context, input types.DeleteControlObligationMappingInput) (*types.DeleteControlObligationMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionDeleteControlObligationMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlObligationMappingDelete) prb := r.ProboService(ctx, input.ObligationID.TenantID()) @@ -2517,12 +2536,13 @@ func (r *mutationResolver) DeleteControlObligationMapping(ctx context.Context, i // CreateControlSnapshotMapping is the resolver for the createControlSnapshotMapping field. func (r *mutationResolver) CreateControlSnapshotMapping(ctx context.Context, input types.CreateControlSnapshotMappingInput) (*types.CreateControlSnapshotMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionCreateControlSnapshotMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlSnapshotMappingCreate) prb := r.ProboService(ctx, input.SnapshotID.TenantID()) control, snapshot, err := prb.Controls.CreateSnapshotMapping(ctx, input.ControlID, input.SnapshotID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create control snapshot mapping: %w", err)) } @@ -2534,12 +2554,13 @@ func (r *mutationResolver) CreateControlSnapshotMapping(ctx context.Context, inp // DeleteControlSnapshotMapping is the resolver for the deleteControlSnapshotMapping field. func (r *mutationResolver) DeleteControlSnapshotMapping(ctx context.Context, input types.DeleteControlSnapshotMappingInput) (*types.DeleteControlSnapshotMappingPayload, error) { - r.MustBeAuthorized(ctx, input.ControlID, iam.ActionDeleteControlSnapshotMapping) + r.MustAuthorize(ctx, input.ControlID, probo.ActionControlSnapshotMappingDelete) prb := r.ProboService(ctx, input.SnapshotID.TenantID()) control, snapshot, err := prb.Controls.DeleteSnapshotMapping(ctx, input.ControlID, input.SnapshotID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete control snapshot mapping: %w", err)) } @@ -2551,24 +2572,28 @@ func (r *mutationResolver) DeleteControlSnapshotMapping(ctx context.Context, inp // CreateTask is the resolver for the createTask field. func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTaskInput) (*types.CreateTaskPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateTask) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionTaskCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) - task, err := prb.Tasks.Create(ctx, probo.CreateTaskRequest{ - MeasureID: input.MeasureID, - OrganizationID: input.OrganizationID, - Name: input.Name, - Description: input.Description, - TimeEstimate: input.TimeEstimate, - AssignedToID: input.AssignedToID, - Deadline: input.Deadline, - }) + task, err := prb.Tasks.Create( + ctx, + probo.CreateTaskRequest{ + MeasureID: input.MeasureID, + OrganizationID: input.OrganizationID, + Name: input.Name, + Description: input.Description, + TimeEstimate: input.TimeEstimate, + AssignedToID: input.AssignedToID, + Deadline: input.Deadline, + }, + ) if err != nil { if errors.Is(err, coredata.ErrResourceAlreadyExists) { return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create task: %w", err)) } @@ -2579,21 +2604,25 @@ func (r *mutationResolver) CreateTask(ctx context.Context, input types.CreateTas // UpdateTask is the resolver for the updateTask field. func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTaskInput) (*types.UpdateTaskPayload, error) { - r.MustBeAuthorized(ctx, input.TaskID, iam.ActionUpdateTask) + r.MustAuthorize(ctx, input.TaskID, probo.ActionTaskUpdate) prb := r.ProboService(ctx, input.TaskID.TenantID()) - task, err := prb.Tasks.Update(ctx, probo.UpdateTaskRequest{ - TaskID: input.TaskID, - Name: input.Name, - Description: gqlutils.UnwrapOmittable(input.Description), - State: input.State, - TimeEstimate: gqlutils.UnwrapOmittable(input.TimeEstimate), - Deadline: gqlutils.UnwrapOmittable(input.Deadline), - AssignedToID: gqlutils.UnwrapOmittable(input.AssignedToID), - MeasureID: gqlutils.UnwrapOmittable(input.MeasureID), - }) + task, err := prb.Tasks.Update( + ctx, + probo.UpdateTaskRequest{ + TaskID: input.TaskID, + Name: input.Name, + Description: gqlutils.UnwrapOmittable(input.Description), + State: input.State, + TimeEstimate: gqlutils.UnwrapOmittable(input.TimeEstimate), + Deadline: gqlutils.UnwrapOmittable(input.Deadline), + AssignedToID: gqlutils.UnwrapOmittable(input.AssignedToID), + MeasureID: gqlutils.UnwrapOmittable(input.MeasureID), + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update task: %w", err)) } @@ -2604,12 +2633,13 @@ func (r *mutationResolver) UpdateTask(ctx context.Context, input types.UpdateTas // DeleteTask is the resolver for the deleteTask field. func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTaskInput) (*types.DeleteTaskPayload, error) { - r.MustBeAuthorized(ctx, input.TaskID, iam.ActionDeleteTask) + r.MustAuthorize(ctx, input.TaskID, probo.ActionTaskDelete) prb := r.ProboService(ctx, input.TaskID.TenantID()) err := prb.Tasks.Delete(ctx, input.TaskID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete task: %w", err)) } @@ -2620,7 +2650,7 @@ func (r *mutationResolver) DeleteTask(ctx context.Context, input types.DeleteTas // CreateRisk is the resolver for the createRisk field. func (r *mutationResolver) CreateRisk(ctx context.Context, input types.CreateRiskInput) (*types.CreateRiskPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateRisk) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionRiskCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -2645,6 +2675,7 @@ func (r *mutationResolver) CreateRisk(ctx context.Context, input types.CreateRis return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create risk: %w", err)) } @@ -2655,7 +2686,7 @@ func (r *mutationResolver) CreateRisk(ctx context.Context, input types.CreateRis // UpdateRisk is the resolver for the updateRisk field. func (r *mutationResolver) UpdateRisk(ctx context.Context, input types.UpdateRiskInput) (*types.UpdateRiskPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateRisk) + r.MustAuthorize(ctx, input.ID, probo.ActionRiskUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -2676,6 +2707,7 @@ func (r *mutationResolver) UpdateRisk(ctx context.Context, input types.UpdateRis }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update risk: %w", err)) } @@ -2686,12 +2718,13 @@ func (r *mutationResolver) UpdateRisk(ctx context.Context, input types.UpdateRis // DeleteRisk is the resolver for the deleteRisk field. func (r *mutationResolver) DeleteRisk(ctx context.Context, input types.DeleteRiskInput) (*types.DeleteRiskPayload, error) { - r.MustBeAuthorized(ctx, input.RiskID, iam.ActionDeleteRisk) + r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskDelete) prb := r.ProboService(ctx, input.RiskID.TenantID()) err := prb.Risks.Delete(ctx, input.RiskID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete risk: %w", err)) } @@ -2702,12 +2735,13 @@ func (r *mutationResolver) DeleteRisk(ctx context.Context, input types.DeleteRis // CreateRiskMeasureMapping is the resolver for the createRiskMeasureMapping field. func (r *mutationResolver) CreateRiskMeasureMapping(ctx context.Context, input types.CreateRiskMeasureMappingInput) (*types.CreateRiskMeasureMappingPayload, error) { - r.MustBeAuthorized(ctx, input.RiskID, iam.ActionCreateRiskMeasureMapping) + r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingCreate) prb := r.ProboService(ctx, input.RiskID.TenantID()) risk, measure, err := prb.Risks.CreateMeasureMapping(ctx, input.RiskID, input.MeasureID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create risk measure mapping: %w", err)) } @@ -2719,12 +2753,13 @@ func (r *mutationResolver) CreateRiskMeasureMapping(ctx context.Context, input t // DeleteRiskMeasureMapping is the resolver for the deleteRiskMeasureMapping field. func (r *mutationResolver) DeleteRiskMeasureMapping(ctx context.Context, input types.DeleteRiskMeasureMappingInput) (*types.DeleteRiskMeasureMappingPayload, error) { - r.MustBeAuthorized(ctx, input.RiskID, iam.ActionDeleteRiskMeasureMapping) + r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskMeasureMappingDelete) prb := r.ProboService(ctx, input.RiskID.TenantID()) risk, measure, err := prb.Risks.DeleteMeasureMapping(ctx, input.RiskID, input.MeasureID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete risk measure mapping: %w", err)) } @@ -2736,12 +2771,13 @@ func (r *mutationResolver) DeleteRiskMeasureMapping(ctx context.Context, input t // CreateRiskDocumentMapping is the resolver for the createRiskDocumentMapping field. func (r *mutationResolver) CreateRiskDocumentMapping(ctx context.Context, input types.CreateRiskDocumentMappingInput) (*types.CreateRiskDocumentMappingPayload, error) { - r.MustBeAuthorized(ctx, input.RiskID, iam.ActionCreateRiskDocumentMapping) + r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingCreate) prb := r.ProboService(ctx, input.RiskID.TenantID()) risk, document, err := prb.Risks.CreateDocumentMapping(ctx, input.RiskID, input.DocumentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create risk document mapping: %w", err)) } @@ -2753,12 +2789,13 @@ func (r *mutationResolver) CreateRiskDocumentMapping(ctx context.Context, input // DeleteRiskDocumentMapping is the resolver for the deleteRiskDocumentMapping field. func (r *mutationResolver) DeleteRiskDocumentMapping(ctx context.Context, input types.DeleteRiskDocumentMappingInput) (*types.DeleteRiskDocumentMappingPayload, error) { - r.MustBeAuthorized(ctx, input.RiskID, iam.ActionDeleteRiskDocumentMapping) + r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskDocumentMappingDelete) prb := r.ProboService(ctx, input.RiskID.TenantID()) risk, document, err := prb.Risks.DeleteDocumentMapping(ctx, input.RiskID, input.DocumentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete risk document mapping: %w", err)) } @@ -2770,12 +2807,13 @@ func (r *mutationResolver) DeleteRiskDocumentMapping(ctx context.Context, input // CreateRiskObligationMapping is the resolver for the createRiskObligationMapping field. func (r *mutationResolver) CreateRiskObligationMapping(ctx context.Context, input types.CreateRiskObligationMappingInput) (*types.CreateRiskObligationMappingPayload, error) { - r.MustBeAuthorized(ctx, input.RiskID, iam.ActionCreateRiskObligationMapping) + r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskObligationMappingCreate) prb := r.ProboService(ctx, input.RiskID.TenantID()) risk, obligation, err := prb.Risks.CreateObligationMapping(ctx, input.RiskID, input.ObligationID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create risk obligation mapping: %w", err)) } @@ -2787,12 +2825,13 @@ func (r *mutationResolver) CreateRiskObligationMapping(ctx context.Context, inpu // DeleteRiskObligationMapping is the resolver for the deleteRiskObligationMapping field. func (r *mutationResolver) DeleteRiskObligationMapping(ctx context.Context, input types.DeleteRiskObligationMappingInput) (*types.DeleteRiskObligationMappingPayload, error) { - r.MustBeAuthorized(ctx, input.RiskID, iam.ActionDeleteRiskObligationMapping) + r.MustAuthorize(ctx, input.RiskID, probo.ActionRiskObligationMappingDelete) prb := r.ProboService(ctx, input.RiskID.TenantID()) risk, obligation, err := prb.Risks.DeleteObligationMapping(ctx, input.RiskID, input.ObligationID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete risk obligation mapping: %w", err)) } @@ -2804,12 +2843,13 @@ func (r *mutationResolver) DeleteRiskObligationMapping(ctx context.Context, inpu // DeleteEvidence is the resolver for the deleteEvidence field. func (r *mutationResolver) DeleteEvidence(ctx context.Context, input types.DeleteEvidenceInput) (*types.DeleteEvidencePayload, error) { - r.MustBeAuthorized(ctx, input.EvidenceID, iam.ActionDeleteEvidence) + r.MustAuthorize(ctx, input.EvidenceID, probo.ActionEvidenceDelete) prb := r.ProboService(ctx, input.EvidenceID.TenantID()) err := prb.Evidences.Delete(ctx, input.EvidenceID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete evidence: %w", err)) } @@ -2820,7 +2860,7 @@ func (r *mutationResolver) DeleteEvidence(ctx context.Context, input types.Delet // UploadMeasureEvidence is the resolver for the uploadMeasureEvidence field. func (r *mutationResolver) UploadMeasureEvidence(ctx context.Context, input types.UploadMeasureEvidenceInput) (*types.UploadMeasureEvidencePayload, error) { - r.MustBeAuthorized(ctx, input.MeasureID, iam.ActionUploadMeasureEvidence) + r.MustAuthorize(ctx, input.MeasureID, probo.ActionMeasureEvidenceUpload) prb := r.ProboService(ctx, input.MeasureID.TenantID()) @@ -2837,6 +2877,7 @@ func (r *mutationResolver) UploadMeasureEvidence(ctx context.Context, input type }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot upload measure evidence: %w", err)) } @@ -2847,7 +2888,7 @@ func (r *mutationResolver) UploadMeasureEvidence(ctx context.Context, input type // UploadVendorComplianceReport is the resolver for the uploadVendorComplianceReport field. func (r *mutationResolver) UploadVendorComplianceReport(ctx context.Context, input types.UploadVendorComplianceReportInput) (*types.UploadVendorComplianceReportPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionUploadVendorComplianceReport) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorComplianceReportUpload) prb := r.ProboService(ctx, input.VendorID.TenantID()) @@ -2862,6 +2903,7 @@ func (r *mutationResolver) UploadVendorComplianceReport(ctx context.Context, inp }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot upload vendor compliance report: %w", err)) } @@ -2872,12 +2914,13 @@ func (r *mutationResolver) UploadVendorComplianceReport(ctx context.Context, inp // DeleteVendorComplianceReport is the resolver for the deleteVendorComplianceReport field. func (r *mutationResolver) DeleteVendorComplianceReport(ctx context.Context, input types.DeleteVendorComplianceReportInput) (*types.DeleteVendorComplianceReportPayload, error) { - r.MustBeAuthorized(ctx, input.ReportID, iam.ActionDeleteVendorComplianceReport) + r.MustAuthorize(ctx, input.ReportID, probo.ActionVendorComplianceReportDelete) prb := r.ProboService(ctx, input.ReportID.TenantID()) err := prb.VendorComplianceReports.Delete(ctx, input.ReportID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete vendor compliance report: %w", err)) } @@ -2888,7 +2931,7 @@ func (r *mutationResolver) DeleteVendorComplianceReport(ctx context.Context, inp // UploadVendorBusinessAssociateAgreement is the resolver for the uploadVendorBusinessAssociateAgreement field. func (r *mutationResolver) UploadVendorBusinessAssociateAgreement(ctx context.Context, input types.UploadVendorBusinessAssociateAgreementInput) (*types.UploadVendorBusinessAssociateAgreementPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionUploadVendorBusinessAssociateAgreement) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorBusinessAssociateAgreementUpload) prb := r.ProboService(ctx, input.VendorID.TenantID()) @@ -2903,6 +2946,7 @@ func (r *mutationResolver) UploadVendorBusinessAssociateAgreement(ctx context.Co }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot upload vendor business associate agreement: %w", err)) } @@ -2913,7 +2957,7 @@ func (r *mutationResolver) UploadVendorBusinessAssociateAgreement(ctx context.Co // UpdateVendorBusinessAssociateAgreement is the resolver for the updateVendorBusinessAssociateAgreement field. func (r *mutationResolver) UpdateVendorBusinessAssociateAgreement(ctx context.Context, input types.UpdateVendorBusinessAssociateAgreementInput) (*types.UpdateVendorBusinessAssociateAgreementPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionUpdateVendorBusinessAssociateAgreement) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorBusinessAssociateAgreementUpdate) prb := r.ProboService(ctx, input.VendorID.TenantID()) @@ -2926,6 +2970,7 @@ func (r *mutationResolver) UpdateVendorBusinessAssociateAgreement(ctx context.Co }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update vendor business associate agreement: %w", err)) } @@ -2936,12 +2981,13 @@ func (r *mutationResolver) UpdateVendorBusinessAssociateAgreement(ctx context.Co // DeleteVendorBusinessAssociateAgreement is the resolver for the deleteVendorBusinessAssociateAgreement field. func (r *mutationResolver) DeleteVendorBusinessAssociateAgreement(ctx context.Context, input types.DeleteVendorBusinessAssociateAgreementInput) (*types.DeleteVendorBusinessAssociateAgreementPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionDeleteVendorBusinessAssociateAgreement) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorBusinessAssociateAgreementDelete) prb := r.ProboService(ctx, input.VendorID.TenantID()) err := prb.VendorBusinessAssociateAgreements.DeleteByVendorID(ctx, input.VendorID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete vendor business associate agreement: %w", err)) } @@ -2952,7 +2998,7 @@ func (r *mutationResolver) DeleteVendorBusinessAssociateAgreement(ctx context.Co // UploadVendorDataPrivacyAgreement is the resolver for the uploadVendorDataPrivacyAgreement field. func (r *mutationResolver) UploadVendorDataPrivacyAgreement(ctx context.Context, input types.UploadVendorDataPrivacyAgreementInput) (*types.UploadVendorDataPrivacyAgreementPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionUploadVendorDataPrivacyAgreement) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorDataPrivacyAgreementUpload) prb := r.ProboService(ctx, input.VendorID.TenantID()) @@ -2967,6 +3013,7 @@ func (r *mutationResolver) UploadVendorDataPrivacyAgreement(ctx context.Context, }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot upload vendor data privacy agreement: %w", err)) } @@ -2977,7 +3024,7 @@ func (r *mutationResolver) UploadVendorDataPrivacyAgreement(ctx context.Context, // UpdateVendorDataPrivacyAgreement is the resolver for the updateVendorDataPrivacyAgreement field. func (r *mutationResolver) UpdateVendorDataPrivacyAgreement(ctx context.Context, input types.UpdateVendorDataPrivacyAgreementInput) (*types.UpdateVendorDataPrivacyAgreementPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionUpdateVendorDataPrivacyAgreement) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorDataPrivacyAgreementUpdate) prb := r.ProboService(ctx, input.VendorID.TenantID()) @@ -2990,6 +3037,7 @@ func (r *mutationResolver) UpdateVendorDataPrivacyAgreement(ctx context.Context, }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update vendor data privacy agreement: %w", err)) } @@ -3000,12 +3048,13 @@ func (r *mutationResolver) UpdateVendorDataPrivacyAgreement(ctx context.Context, // DeleteVendorDataPrivacyAgreement is the resolver for the deleteVendorDataPrivacyAgreement field. func (r *mutationResolver) DeleteVendorDataPrivacyAgreement(ctx context.Context, input types.DeleteVendorDataPrivacyAgreementInput) (*types.DeleteVendorDataPrivacyAgreementPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionDeleteVendorDataPrivacyAgreement) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorDataPrivacyAgreementDelete) prb := r.ProboService(ctx, input.VendorID.TenantID()) err := prb.VendorDataPrivacyAgreements.DeleteByVendorID(ctx, input.VendorID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete vendor data privacy agreement: %w", err)) } @@ -3016,7 +3065,7 @@ func (r *mutationResolver) DeleteVendorDataPrivacyAgreement(ctx context.Context, // CreateDocument is the resolver for the createDocument field. func (r *mutationResolver) CreateDocument(ctx context.Context, input types.CreateDocumentInput) (*types.CreateDocumentPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateDocument) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDocumentCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -3037,6 +3086,7 @@ func (r *mutationResolver) CreateDocument(ctx context.Context, input types.Creat return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create document: %w", err)) } @@ -3048,7 +3098,8 @@ func (r *mutationResolver) CreateDocument(ctx context.Context, input types.Creat // UpdateDocument is the resolver for the updateDocument field. func (r *mutationResolver) UpdateDocument(ctx context.Context, input types.UpdateDocumentInput) (*types.UpdateDocumentPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateDocument) + r.MustAuthorize(ctx, input.ID, probo.ActionDocumentUpdate) + prb := r.ProboService(ctx, input.ID.TenantID()) document, err := prb.Documents.Update( @@ -3064,6 +3115,7 @@ func (r *mutationResolver) UpdateDocument(ctx context.Context, input types.Updat ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update document: %w", err)) } @@ -3074,12 +3126,13 @@ func (r *mutationResolver) UpdateDocument(ctx context.Context, input types.Updat // DeleteDocument is the resolver for the deleteDocument field. func (r *mutationResolver) DeleteDocument(ctx context.Context, input types.DeleteDocumentInput) (*types.DeleteDocumentPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentID, iam.ActionDeleteDocument) + r.MustAuthorize(ctx, input.DocumentID, probo.ActionDocumentDelete) prb := r.ProboService(ctx, input.DocumentID.TenantID()) err := prb.Documents.SoftDelete(ctx, input.DocumentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot soft delete document: %w", err)) } @@ -3090,7 +3143,7 @@ func (r *mutationResolver) DeleteDocument(ctx context.Context, input types.Delet // CreateMeeting is the resolver for the createMeeting field. func (r *mutationResolver) CreateMeeting(ctx context.Context, input types.CreateMeetingInput) (*types.CreateMeetingPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateMeeting) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionMeetingCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -3105,6 +3158,7 @@ func (r *mutationResolver) CreateMeeting(ctx context.Context, input types.Create }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create meeting: %w", err)) } @@ -3115,7 +3169,7 @@ func (r *mutationResolver) CreateMeeting(ctx context.Context, input types.Create // UpdateMeeting is the resolver for the updateMeeting field. func (r *mutationResolver) UpdateMeeting(ctx context.Context, input types.UpdateMeetingInput) (*types.UpdateMeetingPayload, error) { - r.MustBeAuthorized(ctx, input.MeetingID, iam.ActionUpdateMeeting) + r.MustAuthorize(ctx, input.MeetingID, probo.ActionMeetingUpdate) prb := r.ProboService(ctx, input.MeetingID.TenantID()) @@ -3135,6 +3189,7 @@ func (r *mutationResolver) UpdateMeeting(ctx context.Context, input types.Update }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update meeting: %w", err)) } @@ -3145,12 +3200,13 @@ func (r *mutationResolver) UpdateMeeting(ctx context.Context, input types.Update // DeleteMeeting is the resolver for the deleteMeeting field. func (r *mutationResolver) DeleteMeeting(ctx context.Context, input types.DeleteMeetingInput) (*types.DeleteMeetingPayload, error) { - r.MustBeAuthorized(ctx, input.MeetingID, iam.ActionDeleteMeeting) + r.MustAuthorize(ctx, input.MeetingID, probo.ActionMeetingDelete) prb := r.ProboService(ctx, input.MeetingID.TenantID()) err := prb.Meetings.Delete(ctx, input.MeetingID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete meeting: %w", err)) } @@ -3161,7 +3217,7 @@ func (r *mutationResolver) DeleteMeeting(ctx context.Context, input types.Delete // CreateStateOfApplicability is the resolver for the createStateOfApplicability field. func (r *mutationResolver) CreateStateOfApplicability(ctx context.Context, input types.CreateStateOfApplicabilityInput) (*types.CreateStateOfApplicabilityPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateStateOfApplicability) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionStateOfApplicabilityCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -3187,7 +3243,7 @@ func (r *mutationResolver) CreateStateOfApplicability(ctx context.Context, input // UpdateStateOfApplicability is the resolver for the updateStateOfApplicability field. func (r *mutationResolver) UpdateStateOfApplicability(ctx context.Context, input types.UpdateStateOfApplicabilityInput) (*types.UpdateStateOfApplicabilityPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateStateOfApplicability) + r.MustAuthorize(ctx, input.ID, probo.ActionStateOfApplicabilityUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -3218,7 +3274,7 @@ func (r *mutationResolver) UpdateStateOfApplicability(ctx context.Context, input // DeleteStateOfApplicability is the resolver for the deleteStateOfApplicability field. func (r *mutationResolver) DeleteStateOfApplicability(ctx context.Context, input types.DeleteStateOfApplicabilityInput) (*types.DeleteStateOfApplicabilityPayload, error) { - r.MustBeAuthorized(ctx, input.StateOfApplicabilityID, iam.ActionDeleteStateOfApplicability) + r.MustAuthorize(ctx, input.StateOfApplicabilityID, probo.ActionStateOfApplicabilityDelete) prb := r.ProboService(ctx, input.StateOfApplicabilityID.TenantID()) @@ -3234,7 +3290,7 @@ func (r *mutationResolver) DeleteStateOfApplicability(ctx context.Context, input // ExportStateOfApplicabilityPDF is the resolver for the exportStateOfApplicabilityPDF field. func (r *mutationResolver) ExportStateOfApplicabilityPDF(ctx context.Context, input types.ExportStateOfApplicabilityPDFInput) (*types.ExportStateOfApplicabilityPDFPayload, error) { - r.MustBeAuthorized(ctx, input.StateOfApplicabilityID, iam.ActionUpdateStateOfApplicability) + r.MustAuthorize(ctx, input.StateOfApplicabilityID, probo.ActionStateOfApplicabilityExport) prb := r.ProboService(ctx, input.StateOfApplicabilityID.TenantID()) @@ -3253,7 +3309,7 @@ func (r *mutationResolver) ExportStateOfApplicabilityPDF(ctx context.Context, in // PublishDocumentVersion is the resolver for the publishDocumentVersion field. func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input types.PublishDocumentVersionInput) (*types.PublishDocumentVersionPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentID, iam.ActionPublishDocumentVersion) + r.MustAuthorize(ctx, input.DocumentID, probo.ActionDocumentVersionPublish) prb := r.ProboService(ctx, input.DocumentID.TenantID()) @@ -3265,6 +3321,8 @@ func (r *mutationResolver) PublishDocumentVersion(ctx context.Context, input typ if errors.As(err, &errNoChanges) { return nil, gqlutils.Invalid(errNoChanges, nil) } + + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot publish document version: %w", err)) } @@ -3283,7 +3341,9 @@ func (r *mutationResolver) BulkPublishDocumentVersions(ctx context.Context, inpu }, nil } - r.MustBeAuthorized(ctx, input.DocumentIds[0], iam.ActionBulkPublishDocumentVersions) + for _, documentID := range input.DocumentIds { + r.MustAuthorize(ctx, documentID, probo.ActionDocumentVersionPublish) + } prb := r.ProboService(ctx, input.DocumentIds[0].TenantID()) @@ -3302,6 +3362,8 @@ func (r *mutationResolver) BulkPublishDocumentVersions(ctx context.Context, inpu if errors.As(err, &errNoChanges) { return nil, gqlutils.Invalid(errNoChanges, nil) } + + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot bulk publish document versions: %w", err)) } @@ -3319,7 +3381,9 @@ func (r *mutationResolver) BulkDeleteDocuments(ctx context.Context, input types. }, nil } - r.MustBeAuthorized(ctx, input.DocumentIds[0], iam.ActionBulkDeleteDocuments) + for _, documentID := range input.DocumentIds { + r.MustAuthorize(ctx, documentID, probo.ActionDocumentDelete) + } prb := r.ProboService(ctx, input.DocumentIds[0].TenantID()) @@ -3339,7 +3403,10 @@ func (r *mutationResolver) BulkExportDocuments(ctx context.Context, input types. panic(fmt.Errorf("no document ids provided")) } - r.MustBeAuthorized(ctx, input.DocumentIds[0], iam.ActionBulkExportDocuments) + // TODO have a way to batch authorize for resources + for _, documentID := range input.DocumentIds { + r.MustAuthorize(ctx, documentID, probo.ActionDocumentVersionExport) + } prb := r.ProboService(ctx, input.DocumentIds[0].TenantID()) @@ -3363,12 +3430,13 @@ func (r *mutationResolver) BulkExportDocuments(ctx context.Context, input types. // GenerateDocumentChangelog is the resolver for the generateDocumentChangelog field. func (r *mutationResolver) GenerateDocumentChangelog(ctx context.Context, input types.GenerateDocumentChangelogInput) (*types.GenerateDocumentChangelogPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentID, iam.ActionGenerateDocumentChangelog) + r.MustAuthorize(ctx, input.DocumentID, probo.ActionDocumentChangelogGenerate) prb := r.ProboService(ctx, input.DocumentID.TenantID()) changelog, err := prb.Documents.GenerateChangelog(ctx, input.DocumentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot generate document changelog: %w", err)) } @@ -3379,12 +3447,13 @@ func (r *mutationResolver) GenerateDocumentChangelog(ctx context.Context, input // CreateDraftDocumentVersion is the resolver for the createDraftDocumentVersion field. func (r *mutationResolver) CreateDraftDocumentVersion(ctx context.Context, input types.CreateDraftDocumentVersionInput) (*types.CreateDraftDocumentVersionPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentID, iam.ActionCreateDraftDocumentVersion) + r.MustAuthorize(ctx, input.DocumentID, probo.ActionDocumentDraftVersionCreate) prb := r.ProboService(ctx, input.DocumentID.TenantID()) documentVersion, err := prb.Documents.CreateDraft(ctx, input.DocumentID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create draft document version: %w", err)) } @@ -3395,12 +3464,13 @@ func (r *mutationResolver) CreateDraftDocumentVersion(ctx context.Context, input // DeleteDraftDocumentVersion is the resolver for the deleteDraftDocumentVersion field. func (r *mutationResolver) DeleteDraftDocumentVersion(ctx context.Context, input types.DeleteDraftDocumentVersionInput) (*types.DeleteDraftDocumentVersionPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentVersionID, iam.ActionDeleteDraftDocumentVersion) + r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionDeleteDraft) prb := r.ProboService(ctx, input.DocumentVersionID.TenantID()) err := prb.Documents.DeleteDraft(ctx, input.DocumentVersionID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete draft document version: %w", err)) } @@ -3411,15 +3481,19 @@ func (r *mutationResolver) DeleteDraftDocumentVersion(ctx context.Context, input // UpdateDocumentVersion is the resolver for the updateDocumentVersion field. func (r *mutationResolver) UpdateDocumentVersion(ctx context.Context, input types.UpdateDocumentVersionInput) (*types.UpdateDocumentVersionPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentVersionID, iam.ActionUpdateDocumentVersion) + r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionUpdate) prb := r.ProboService(ctx, input.DocumentVersionID.TenantID()) - documentVersion, err := prb.Documents.UpdateVersion(ctx, probo.UpdateDocumentVersionRequest{ - ID: input.DocumentVersionID, - Content: input.Content, - }) + documentVersion, err := prb.Documents.UpdateVersion( + ctx, + probo.UpdateDocumentVersionRequest{ + ID: input.DocumentVersionID, + Content: input.Content, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update document version: %w", err)) } @@ -3430,7 +3504,7 @@ func (r *mutationResolver) UpdateDocumentVersion(ctx context.Context, input type // RequestSignature is the resolver for the requestSignature field. func (r *mutationResolver) RequestSignature(ctx context.Context, input types.RequestSignatureInput) (*types.RequestSignaturePayload, error) { - r.MustBeAuthorized(ctx, input.DocumentVersionID, iam.ActionRequestSignature) + r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSignatureRequest) prb := r.ProboService(ctx, input.DocumentVersionID.TenantID()) @@ -3442,6 +3516,7 @@ func (r *mutationResolver) RequestSignature(ctx context.Context, input types.Req }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot request signature: %w", err)) } @@ -3458,7 +3533,9 @@ func (r *mutationResolver) BulkRequestSignatures(ctx context.Context, input type }, nil } - r.MustBeAuthorized(ctx, input.DocumentIds[0], iam.ActionBulkRequestSignatures) + for _, documentID := range input.DocumentIds { + r.MustAuthorize(ctx, documentID, probo.ActionDocumentVersionSignatureRequest) + } prb := r.ProboService(ctx, input.DocumentIds[0].TenantID()) @@ -3470,6 +3547,7 @@ func (r *mutationResolver) BulkRequestSignatures(ctx context.Context, input type }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot bulk request signatures: %w", err)) } @@ -3480,12 +3558,13 @@ func (r *mutationResolver) BulkRequestSignatures(ctx context.Context, input type // SendSigningNotifications is the resolver for the sendSigningNotifications field. func (r *mutationResolver) SendSigningNotifications(ctx context.Context, input types.SendSigningNotificationsInput) (*types.SendSigningNotificationsPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionSendSigningNotifications) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDocumentSendSigningNotifications) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) err := prb.Documents.SendSigningNotifications(ctx, input.OrganizationID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot send signing notifications: %w", err)) } @@ -3496,12 +3575,13 @@ func (r *mutationResolver) SendSigningNotifications(ctx context.Context, input t // CancelSignatureRequest is the resolver for the cancelSignatureRequest field. func (r *mutationResolver) CancelSignatureRequest(ctx context.Context, input types.CancelSignatureRequestInput) (*types.CancelSignatureRequestPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentVersionSignatureID, iam.ActionCancelSignatureRequest) + r.MustAuthorize(ctx, input.DocumentVersionSignatureID, probo.ActionDocumentVersionCancelSignature) prb := r.ProboService(ctx, input.DocumentVersionSignatureID.TenantID()) err := prb.Documents.CancelSignatureRequest(ctx, input.DocumentVersionSignatureID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot cancel signature request: %w", err)) } @@ -3512,7 +3592,7 @@ func (r *mutationResolver) CancelSignatureRequest(ctx context.Context, input typ // SignDocument is the resolver for the signDocument field. func (r *mutationResolver) SignDocument(ctx context.Context, input types.SignDocumentInput) (*types.SignDocumentPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentVersionID, iam.ActionSignDocument) + r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionSign) identity := connect_v1.IdentityFromContext(ctx) prb := r.ProboService(ctx, input.DocumentVersionID.TenantID()) @@ -3523,6 +3603,7 @@ func (r *mutationResolver) SignDocument(ctx context.Context, input types.SignDoc return nil, gqlutils.Conflict(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot sign document: %w", err)) } @@ -3533,7 +3614,7 @@ func (r *mutationResolver) SignDocument(ctx context.Context, input types.SignDoc // ExportDocumentVersionPDF is the resolver for the exportDocumentVersionPDF field. func (r *mutationResolver) ExportDocumentVersionPDF(ctx context.Context, input types.ExportDocumentVersionPDFInput) (*types.ExportDocumentVersionPDFPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentVersionID, iam.ActionExportDocumentVersionPDF) + r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionExportPDF) prb := r.ProboService(ctx, input.DocumentVersionID.TenantID()) @@ -3545,6 +3626,7 @@ func (r *mutationResolver) ExportDocumentVersionPDF(ctx context.Context, input t pdf, err := prb.Documents.ExportPDF(ctx, input.DocumentVersionID, options) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot export document version PDF: %w", err)) } @@ -3555,12 +3637,13 @@ func (r *mutationResolver) ExportDocumentVersionPDF(ctx context.Context, input t // ExportSignableVersionDocumentPDF is the resolver for the exportSignableVersionDocumentPDF field. func (r *mutationResolver) ExportSignableVersionDocumentPDF(ctx context.Context, input types.ExportSignableDocumentVersionPDFInput) (*types.ExportSignableDocumentVersionPDFPayload, error) { - r.MustBeAuthorized(ctx, input.DocumentVersionID, iam.ActionExportSignableVersionDocumentPDF) + r.MustAuthorize(ctx, input.DocumentVersionID, probo.ActionDocumentVersionExportSignable) prb := r.ProboService(ctx, input.DocumentVersionID.TenantID()) documentVersion, err := prb.Documents.GetVersion(ctx, input.DocumentVersionID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get document version: %w", err)) } @@ -3573,6 +3656,7 @@ func (r *mutationResolver) ExportSignableVersionDocumentPDF(ctx context.Context, return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get signable document: %w", err)) } @@ -3584,6 +3668,7 @@ func (r *mutationResolver) ExportSignableVersionDocumentPDF(ctx context.Context, pdf, err := prb.Documents.ExportPDF(ctx, input.DocumentVersionID, options) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot export signable document PDF: %w", err)) } @@ -3594,7 +3679,7 @@ func (r *mutationResolver) ExportSignableVersionDocumentPDF(ctx context.Context, // ExportProcessingActivitiesPDF is the resolver for the exportProcessingActivitiesPDF field. func (r *mutationResolver) ExportProcessingActivitiesPDF(ctx context.Context, input types.ExportProcessingActivitiesPDFInput) (*types.ExportProcessingActivitiesPDFPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionExportProcessingActivitiesPDF) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionProcessingActivityExport) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -3620,7 +3705,7 @@ func (r *mutationResolver) ExportProcessingActivitiesPDF(ctx context.Context, in // ExportDataProtectionImpactAssessmentsPDF is the resolver for the exportDataProtectionImpactAssessmentsPDF field. func (r *mutationResolver) ExportDataProtectionImpactAssessmentsPDF(ctx context.Context, input types.ExportDataProtectionImpactAssessmentsPDFInput) (*types.ExportDataProtectionImpactAssessmentsPDFPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionExportDataProtectionImpactAssessmentsPDF) + r.MustAuthorize(ctx, input.OrganizationID, iam.ActionExportDataProtectionImpactAssessmentsPDF) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -3646,7 +3731,7 @@ func (r *mutationResolver) ExportDataProtectionImpactAssessmentsPDF(ctx context. // ExportTransferImpactAssessmentsPDF is the resolver for the exportTransferImpactAssessmentsPDF field. func (r *mutationResolver) ExportTransferImpactAssessmentsPDF(ctx context.Context, input types.ExportTransferImpactAssessmentsPDFInput) (*types.ExportTransferImpactAssessmentsPDFPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionExportTransferImpactAssessmentsPDF) + r.MustAuthorize(ctx, input.OrganizationID, iam.ActionExportTransferImpactAssessmentsPDF) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -3672,7 +3757,7 @@ func (r *mutationResolver) ExportTransferImpactAssessmentsPDF(ctx context.Contex // CreateVendorRiskAssessment is the resolver for the createVendorRiskAssessment field. func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input types.CreateVendorRiskAssessmentInput) (*types.CreateVendorRiskAssessmentPayload, error) { - r.MustBeAuthorized(ctx, input.VendorID, iam.ActionCreateVendorRiskAssessment) + r.MustAuthorize(ctx, input.VendorID, probo.ActionVendorRiskAssessmentCreate) prb := r.ProboService(ctx, input.VendorID.TenantID()) @@ -3687,6 +3772,7 @@ func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input }, ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create vendor risk assessment: %w", err)) } @@ -3697,15 +3783,19 @@ func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input // AssessVendor is the resolver for the assessVendor field. func (r *mutationResolver) AssessVendor(ctx context.Context, input types.AssessVendorInput) (*types.AssessVendorPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionAssessVendor) + r.MustAuthorize(ctx, input.ID, probo.ActionVendorAssess) prb := r.ProboService(ctx, input.ID.TenantID()) - vendor, err := prb.Vendors.Assess(ctx, probo.AssessVendorRequest{ - ID: input.ID, - WebsiteURL: input.WebsiteURL, - }) + vendor, err := prb.Vendors.Assess( + ctx, + probo.AssessVendorRequest{ + ID: input.ID, + WebsiteURL: input.WebsiteURL, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot assess vendor: %w", err)) } @@ -3716,21 +3806,25 @@ func (r *mutationResolver) AssessVendor(ctx context.Context, input types.AssessV // CreateAsset is the resolver for the createAsset field. func (r *mutationResolver) CreateAsset(ctx context.Context, input types.CreateAssetInput) (*types.CreateAssetPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateAsset) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAssetCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) - asset, err := prb.Assets.Create(ctx, probo.CreateAssetRequest{ - OrganizationID: input.OrganizationID, - Name: input.Name, - Amount: input.Amount, - OwnerID: input.OwnerID, - AssetType: input.AssetType, - DataTypesStored: input.DataTypesStored, - VendorIDs: input.VendorIds, - }) + asset, err := prb.Assets.Create( + ctx, + probo.CreateAssetRequest{ + OrganizationID: input.OrganizationID, + Name: input.Name, + Amount: input.Amount, + OwnerID: input.OwnerID, + AssetType: input.AssetType, + DataTypesStored: input.DataTypesStored, + VendorIDs: input.VendorIds, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create asset: %w", err)) } @@ -3741,20 +3835,24 @@ func (r *mutationResolver) CreateAsset(ctx context.Context, input types.CreateAs // UpdateAsset is the resolver for the updateAsset field. func (r *mutationResolver) UpdateAsset(ctx context.Context, input types.UpdateAssetInput) (*types.UpdateAssetPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateAsset) + r.MustAuthorize(ctx, input.ID, probo.ActionAssetUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) - asset, err := prb.Assets.Update(ctx, probo.UpdateAssetRequest{ - ID: input.ID, - Name: input.Name, - Amount: input.Amount, - OwnerID: input.OwnerID, - AssetType: input.AssetType, - DataTypesStored: input.DataTypesStored, - VendorIDs: input.VendorIds, - }) + asset, err := prb.Assets.Update( + ctx, + probo.UpdateAssetRequest{ + ID: input.ID, + Name: input.Name, + Amount: input.Amount, + OwnerID: input.OwnerID, + AssetType: input.AssetType, + DataTypesStored: input.DataTypesStored, + VendorIDs: input.VendorIds, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update asset: %w", err)) } @@ -3765,12 +3863,13 @@ func (r *mutationResolver) UpdateAsset(ctx context.Context, input types.UpdateAs // DeleteAsset is the resolver for the deleteAsset field. func (r *mutationResolver) DeleteAsset(ctx context.Context, input types.DeleteAssetInput) (*types.DeleteAssetPayload, error) { - r.MustBeAuthorized(ctx, input.AssetID, iam.ActionDeleteAsset) + r.MustAuthorize(ctx, input.AssetID, probo.ActionAssetDelete) prb := r.ProboService(ctx, input.AssetID.TenantID()) err := prb.Assets.Delete(ctx, input.AssetID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete asset: %w", err)) } @@ -3781,19 +3880,23 @@ func (r *mutationResolver) DeleteAsset(ctx context.Context, input types.DeleteAs // CreateDatum is the resolver for the createDatum field. func (r *mutationResolver) CreateDatum(ctx context.Context, input types.CreateDatumInput) (*types.CreateDatumPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateDatum) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionDatumCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) - data, err := prb.Data.Create(ctx, probo.CreateDatumRequest{ - OrganizationID: input.OrganizationID, - Name: input.Name, - DataClassification: input.DataClassification, - OwnerID: input.OwnerID, - VendorIDs: input.VendorIds, - }) + data, err := prb.Data.Create( + ctx, + probo.CreateDatumRequest{ + OrganizationID: input.OrganizationID, + Name: input.Name, + DataClassification: input.DataClassification, + OwnerID: input.OwnerID, + VendorIDs: input.VendorIds, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create datum: %w", err)) } @@ -3804,19 +3907,23 @@ func (r *mutationResolver) CreateDatum(ctx context.Context, input types.CreateDa // UpdateDatum is the resolver for the updateDatum field. func (r *mutationResolver) UpdateDatum(ctx context.Context, input types.UpdateDatumInput) (*types.UpdateDatumPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateDatum) + r.MustAuthorize(ctx, input.ID, probo.ActionDatumUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) - datum, err := prb.Data.Update(ctx, probo.UpdateDatumRequest{ - ID: input.ID, - Name: input.Name, - DataClassification: input.DataClassification, - OwnerID: input.OwnerID, - VendorIDs: input.VendorIds, - }) + datum, err := prb.Data.Update( + ctx, + probo.UpdateDatumRequest{ + ID: input.ID, + Name: input.Name, + DataClassification: input.DataClassification, + OwnerID: input.OwnerID, + VendorIDs: input.VendorIds, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update datum: %w", err)) } @@ -3827,11 +3934,12 @@ func (r *mutationResolver) UpdateDatum(ctx context.Context, input types.UpdateDa // DeleteDatum is the resolver for the deleteDatum field. func (r *mutationResolver) DeleteDatum(ctx context.Context, input types.DeleteDatumInput) (*types.DeleteDatumPayload, error) { - r.MustBeAuthorized(ctx, input.DatumID, iam.ActionDeleteDatum) + r.MustAuthorize(ctx, input.DatumID, probo.ActionDatumDelete) prb := r.ProboService(ctx, input.DatumID.TenantID()) if err := prb.Data.Delete(ctx, input.DatumID); err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete datum: %w", err)) } @@ -3842,7 +3950,7 @@ func (r *mutationResolver) DeleteDatum(ctx context.Context, input types.DeleteDa // CreateAudit is the resolver for the createAudit field. func (r *mutationResolver) CreateAudit(ctx context.Context, input types.CreateAuditInput) (*types.CreateAuditPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateAudit) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionAuditCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -3858,6 +3966,7 @@ func (r *mutationResolver) CreateAudit(ctx context.Context, input types.CreateAu audit, err := prb.Audits.Create(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create audit: %w", err)) } @@ -3868,7 +3977,7 @@ func (r *mutationResolver) CreateAudit(ctx context.Context, input types.CreateAu // UpdateAudit is the resolver for the updateAudit field. func (r *mutationResolver) UpdateAudit(ctx context.Context, input types.UpdateAuditInput) (*types.UpdateAuditPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateAudit) + r.MustAuthorize(ctx, input.ID, probo.ActionAuditUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -3883,6 +3992,7 @@ func (r *mutationResolver) UpdateAudit(ctx context.Context, input types.UpdateAu audit, err := prb.Audits.Update(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update audit: %w", err)) } @@ -3893,12 +4003,13 @@ func (r *mutationResolver) UpdateAudit(ctx context.Context, input types.UpdateAu // DeleteAudit is the resolver for the deleteAudit field. func (r *mutationResolver) DeleteAudit(ctx context.Context, input types.DeleteAuditInput) (*types.DeleteAuditPayload, error) { - r.MustBeAuthorized(ctx, input.AuditID, iam.ActionDeleteAudit) + r.MustAuthorize(ctx, input.AuditID, probo.ActionAuditDelete) prb := r.ProboService(ctx, input.AuditID.TenantID()) err := prb.Audits.Delete(ctx, input.AuditID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete audit: %w", err)) } @@ -3909,7 +4020,7 @@ func (r *mutationResolver) DeleteAudit(ctx context.Context, input types.DeleteAu // UploadAuditReport is the resolver for the uploadAuditReport field. func (r *mutationResolver) UploadAuditReport(ctx context.Context, input types.UploadAuditReportInput) (*types.UploadAuditReportPayload, error) { - r.MustBeAuthorized(ctx, input.AuditID, iam.ActionUploadAuditReport) + r.MustAuthorize(ctx, input.AuditID, probo.ActionAuditReportUpload) prb := r.ProboService(ctx, input.AuditID.TenantID()) @@ -3925,6 +4036,7 @@ func (r *mutationResolver) UploadAuditReport(ctx context.Context, input types.Up audit, err := prb.Audits.UploadReport(ctx, req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot upload audit report: %w", err)) } @@ -3935,12 +4047,13 @@ func (r *mutationResolver) UploadAuditReport(ctx context.Context, input types.Up // DeleteAuditReport is the resolver for the deleteAuditReport field. func (r *mutationResolver) DeleteAuditReport(ctx context.Context, input types.DeleteAuditReportInput) (*types.DeleteAuditReportPayload, error) { - r.MustBeAuthorized(ctx, input.AuditID, iam.ActionDeleteAuditReport) + r.MustAuthorize(ctx, input.AuditID, probo.ActionAuditReportDelete) prb := r.ProboService(ctx, input.AuditID.TenantID()) audit, err := prb.Audits.DeleteReport(ctx, input.AuditID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete audit report: %w", err)) } @@ -3951,7 +4064,7 @@ func (r *mutationResolver) DeleteAuditReport(ctx context.Context, input types.De // CreateNonconformity is the resolver for the createNonconformity field. func (r *mutationResolver) CreateNonconformity(ctx context.Context, input types.CreateNonconformityInput) (*types.CreateNonconformityPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateNonconformity) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionNonconformityCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -3971,6 +4084,7 @@ func (r *mutationResolver) CreateNonconformity(ctx context.Context, input types. nonconformity, err := prb.Nonconformities.Create(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create nonconformity: %w", err)) } @@ -3981,7 +4095,7 @@ func (r *mutationResolver) CreateNonconformity(ctx context.Context, input types. // UpdateNonconformity is the resolver for the updateNonconformity field. func (r *mutationResolver) UpdateNonconformity(ctx context.Context, input types.UpdateNonconformityInput) (*types.UpdateNonconformityPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateNonconformity) + r.MustAuthorize(ctx, input.ID, probo.ActionNonconformityUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -4001,6 +4115,7 @@ func (r *mutationResolver) UpdateNonconformity(ctx context.Context, input types. nonconformity, err := prb.Nonconformities.Update(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update nonconformity: %w", err)) } @@ -4011,12 +4126,13 @@ func (r *mutationResolver) UpdateNonconformity(ctx context.Context, input types. // DeleteNonconformity is the resolver for the deleteNonconformity field. func (r *mutationResolver) DeleteNonconformity(ctx context.Context, input types.DeleteNonconformityInput) (*types.DeleteNonconformityPayload, error) { - r.MustBeAuthorized(ctx, input.NonconformityID, iam.ActionDeleteNonconformity) + r.MustAuthorize(ctx, input.NonconformityID, probo.ActionNonconformityDelete) prb := r.ProboService(ctx, input.NonconformityID.TenantID()) err := prb.Nonconformities.Delete(ctx, input.NonconformityID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete nonconformity: %w", err)) } @@ -4027,7 +4143,7 @@ func (r *mutationResolver) DeleteNonconformity(ctx context.Context, input types. // CreateObligation is the resolver for the createObligation field. func (r *mutationResolver) CreateObligation(ctx context.Context, input types.CreateObligationInput) (*types.CreateObligationPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateObligation) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionObligationCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -4047,6 +4163,7 @@ func (r *mutationResolver) CreateObligation(ctx context.Context, input types.Cre obligation, err := prb.Obligations.Create(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create obligation: %w", err)) } @@ -4057,7 +4174,7 @@ func (r *mutationResolver) CreateObligation(ctx context.Context, input types.Cre // UpdateObligation is the resolver for the updateObligation field. func (r *mutationResolver) UpdateObligation(ctx context.Context, input types.UpdateObligationInput) (*types.UpdateObligationPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateObligation) + r.MustAuthorize(ctx, input.ID, probo.ActionObligationUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -4077,6 +4194,7 @@ func (r *mutationResolver) UpdateObligation(ctx context.Context, input types.Upd obligation, err := prb.Obligations.Update(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update obligation: %w", err)) } @@ -4087,12 +4205,13 @@ func (r *mutationResolver) UpdateObligation(ctx context.Context, input types.Upd // DeleteObligation is the resolver for the deleteObligation field. func (r *mutationResolver) DeleteObligation(ctx context.Context, input types.DeleteObligationInput) (*types.DeleteObligationPayload, error) { - r.MustBeAuthorized(ctx, input.ObligationID, iam.ActionDeleteObligation) + r.MustAuthorize(ctx, input.ObligationID, probo.ActionObligationDelete) prb := r.ProboService(ctx, input.ObligationID.TenantID()) err := prb.Obligations.Delete(ctx, input.ObligationID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete obligation: %w", err)) } @@ -4103,7 +4222,7 @@ func (r *mutationResolver) DeleteObligation(ctx context.Context, input types.Del // CreateContinualImprovement is the resolver for the createContinualImprovement field. func (r *mutationResolver) CreateContinualImprovement(ctx context.Context, input types.CreateContinualImprovementInput) (*types.CreateContinualImprovementPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateContinualImprovement) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionContinualImprovementCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -4120,6 +4239,7 @@ func (r *mutationResolver) CreateContinualImprovement(ctx context.Context, input continualImprovement, err := prb.ContinualImprovements.Create(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create continual improvement: %w", err)) } @@ -4130,7 +4250,7 @@ func (r *mutationResolver) CreateContinualImprovement(ctx context.Context, input // UpdateContinualImprovement is the resolver for the updateContinualImprovement field. func (r *mutationResolver) UpdateContinualImprovement(ctx context.Context, input types.UpdateContinualImprovementInput) (*types.UpdateContinualImprovementPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateContinualImprovement) + r.MustAuthorize(ctx, input.ID, probo.ActionContinualImprovementUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -4147,6 +4267,7 @@ func (r *mutationResolver) UpdateContinualImprovement(ctx context.Context, input continualImprovement, err := prb.ContinualImprovements.Update(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update continual improvement: %w", err)) } @@ -4157,12 +4278,13 @@ func (r *mutationResolver) UpdateContinualImprovement(ctx context.Context, input // DeleteContinualImprovement is the resolver for the deleteContinualImprovement field. func (r *mutationResolver) DeleteContinualImprovement(ctx context.Context, input types.DeleteContinualImprovementInput) (*types.DeleteContinualImprovementPayload, error) { - r.MustBeAuthorized(ctx, input.ContinualImprovementID, iam.ActionDeleteContinualImprovement) + r.MustAuthorize(ctx, input.ContinualImprovementID, probo.ActionContinualImprovementDelete) prb := r.ProboService(ctx, input.ContinualImprovementID.TenantID()) err := prb.ContinualImprovements.Delete(ctx, input.ContinualImprovementID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete continual improvement: %w", err)) } @@ -4173,7 +4295,7 @@ func (r *mutationResolver) DeleteContinualImprovement(ctx context.Context, input // CreateRightsRequest is the resolver for the createRightsRequest field. func (r *mutationResolver) CreateRightsRequest(ctx context.Context, input types.CreateRightsRequestInput) (*types.CreateRightsRequestPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateRightsRequest) + r.MustAuthorize(ctx, input.OrganizationID, iam.ActionCreateRightsRequest) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -4200,7 +4322,7 @@ func (r *mutationResolver) CreateRightsRequest(ctx context.Context, input types. // UpdateRightsRequest is the resolver for the updateRightsRequest field. func (r *mutationResolver) UpdateRightsRequest(ctx context.Context, input types.UpdateRightsRequestInput) (*types.UpdateRightsRequestPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateRightsRequest) + r.MustAuthorize(ctx, input.ID, iam.ActionUpdateRightsRequest) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -4227,7 +4349,7 @@ func (r *mutationResolver) UpdateRightsRequest(ctx context.Context, input types. // DeleteRightsRequest is the resolver for the deleteRightsRequest field. func (r *mutationResolver) DeleteRightsRequest(ctx context.Context, input types.DeleteRightsRequestInput) (*types.DeleteRightsRequestPayload, error) { - r.MustBeAuthorized(ctx, input.RightsRequestID, iam.ActionDeleteRightsRequest) + r.MustAuthorize(ctx, input.RightsRequestID, iam.ActionDeleteRightsRequest) prb := r.ProboService(ctx, input.RightsRequestID.TenantID()) @@ -4243,7 +4365,7 @@ func (r *mutationResolver) DeleteRightsRequest(ctx context.Context, input types. // CreateProcessingActivity is the resolver for the createProcessingActivity field. func (r *mutationResolver) CreateProcessingActivity(ctx context.Context, input types.CreateProcessingActivityInput) (*types.CreateProcessingActivityPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateProcessingActivity) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionProcessingActivityCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) @@ -4272,6 +4394,7 @@ func (r *mutationResolver) CreateProcessingActivity(ctx context.Context, input t activity, err := prb.ProcessingActivities.Create(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create processing activity: %w", err)) } @@ -4282,7 +4405,7 @@ func (r *mutationResolver) CreateProcessingActivity(ctx context.Context, input t // UpdateProcessingActivity is the resolver for the updateProcessingActivity field. func (r *mutationResolver) UpdateProcessingActivity(ctx context.Context, input types.UpdateProcessingActivityInput) (*types.UpdateProcessingActivityPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateProcessingActivity) + r.MustAuthorize(ctx, input.ID, probo.ActionProcessingActivityUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -4311,6 +4434,7 @@ func (r *mutationResolver) UpdateProcessingActivity(ctx context.Context, input t activity, err := prb.ProcessingActivities.Update(ctx, &req) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot update processing activity: %w", err)) } @@ -4321,12 +4445,13 @@ func (r *mutationResolver) UpdateProcessingActivity(ctx context.Context, input t // DeleteProcessingActivity is the resolver for the deleteProcessingActivity field. func (r *mutationResolver) DeleteProcessingActivity(ctx context.Context, input types.DeleteProcessingActivityInput) (*types.DeleteProcessingActivityPayload, error) { - r.MustBeAuthorized(ctx, input.ProcessingActivityID, iam.ActionDeleteProcessingActivity) + r.MustAuthorize(ctx, input.ProcessingActivityID, probo.ActionProcessingActivityDelete) prb := r.ProboService(ctx, input.ProcessingActivityID.TenantID()) err := prb.ProcessingActivities.Delete(ctx, input.ProcessingActivityID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete processing activity: %w", err)) } @@ -4337,7 +4462,7 @@ func (r *mutationResolver) DeleteProcessingActivity(ctx context.Context, input t // CreateDataProtectionImpactAssessment is the resolver for the createDataProtectionImpactAssessment field. func (r *mutationResolver) CreateDataProtectionImpactAssessment(ctx context.Context, input types.CreateDataProtectionImpactAssessmentInput) (*types.CreateDataProtectionImpactAssessmentPayload, error) { - r.MustBeAuthorized(ctx, input.ProcessingActivityID, iam.ActionCreateDataProtectionImpactAssessment) + r.MustAuthorize(ctx, input.ProcessingActivityID, probo.ActionDataProtectionImpactAssessmentCreate) prb := r.ProboService(ctx, input.ProcessingActivityID.TenantID()) @@ -4362,7 +4487,7 @@ func (r *mutationResolver) CreateDataProtectionImpactAssessment(ctx context.Cont // UpdateDataProtectionImpactAssessment is the resolver for the updateDataProtectionImpactAssessment field. func (r *mutationResolver) UpdateDataProtectionImpactAssessment(ctx context.Context, input types.UpdateDataProtectionImpactAssessmentInput) (*types.UpdateDataProtectionImpactAssessmentPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateDataProtectionImpactAssessment) + r.MustAuthorize(ctx, input.ID, probo.ActionDataProtectionImpactAssessmentUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -4387,7 +4512,7 @@ func (r *mutationResolver) UpdateDataProtectionImpactAssessment(ctx context.Cont // DeleteDataProtectionImpactAssessment is the resolver for the deleteDataProtectionImpactAssessment field. func (r *mutationResolver) DeleteDataProtectionImpactAssessment(ctx context.Context, input types.DeleteDataProtectionImpactAssessmentInput) (*types.DeleteDataProtectionImpactAssessmentPayload, error) { - r.MustBeAuthorized(ctx, input.DataProtectionImpactAssessmentID, iam.ActionDeleteDataProtectionImpactAssessment) + r.MustAuthorize(ctx, input.DataProtectionImpactAssessmentID, probo.ActionDataProtectionImpactAssessmentDelete) prb := r.ProboService(ctx, input.DataProtectionImpactAssessmentID.TenantID()) @@ -4403,7 +4528,7 @@ func (r *mutationResolver) DeleteDataProtectionImpactAssessment(ctx context.Cont // CreateTransferImpactAssessment is the resolver for the createTransferImpactAssessment field. func (r *mutationResolver) CreateTransferImpactAssessment(ctx context.Context, input types.CreateTransferImpactAssessmentInput) (*types.CreateTransferImpactAssessmentPayload, error) { - r.MustBeAuthorized(ctx, input.ProcessingActivityID, iam.ActionCreateTransferImpactAssessment) + r.MustAuthorize(ctx, input.ProcessingActivityID, probo.ActionTransferImpactAssessmentCreate) prb := r.ProboService(ctx, input.ProcessingActivityID.TenantID()) @@ -4428,7 +4553,7 @@ func (r *mutationResolver) CreateTransferImpactAssessment(ctx context.Context, i // UpdateTransferImpactAssessment is the resolver for the updateTransferImpactAssessment field. func (r *mutationResolver) UpdateTransferImpactAssessment(ctx context.Context, input types.UpdateTransferImpactAssessmentInput) (*types.UpdateTransferImpactAssessmentPayload, error) { - r.MustBeAuthorized(ctx, input.ID, iam.ActionUpdateTransferImpactAssessment) + r.MustAuthorize(ctx, input.ID, probo.ActionTransferImpactAssessmentUpdate) prb := r.ProboService(ctx, input.ID.TenantID()) @@ -4453,7 +4578,7 @@ func (r *mutationResolver) UpdateTransferImpactAssessment(ctx context.Context, i // DeleteTransferImpactAssessment is the resolver for the deleteTransferImpactAssessment field. func (r *mutationResolver) DeleteTransferImpactAssessment(ctx context.Context, input types.DeleteTransferImpactAssessmentInput) (*types.DeleteTransferImpactAssessmentPayload, error) { - r.MustBeAuthorized(ctx, input.TransferImpactAssessmentID, iam.ActionDeleteTransferImpactAssessment) + r.MustAuthorize(ctx, input.TransferImpactAssessmentID, probo.ActionTransferImpactAssessmentDelete) prb := r.ProboService(ctx, input.TransferImpactAssessmentID.TenantID()) @@ -4469,17 +4594,21 @@ func (r *mutationResolver) DeleteTransferImpactAssessment(ctx context.Context, i // CreateSnapshot is the resolver for the createSnapshot field. func (r *mutationResolver) CreateSnapshot(ctx context.Context, input types.CreateSnapshotInput) (*types.CreateSnapshotPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateSnapshot) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionSnapshotCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) - snapshot, err := prb.Snapshots.Create(ctx, &probo.CreateSnapshotRequest{ - OrganizationID: input.OrganizationID, - Name: input.Name, - Description: input.Description, - Type: input.Type, - }) + snapshot, err := prb.Snapshots.Create( + ctx, + &probo.CreateSnapshotRequest{ + OrganizationID: input.OrganizationID, + Name: input.Name, + Description: input.Description, + Type: input.Type, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create snapshot: %w", err)) } @@ -4490,12 +4619,13 @@ func (r *mutationResolver) CreateSnapshot(ctx context.Context, input types.Creat // DeleteSnapshot is the resolver for the deleteSnapshot field. func (r *mutationResolver) DeleteSnapshot(ctx context.Context, input types.DeleteSnapshotInput) (*types.DeleteSnapshotPayload, error) { - r.MustBeAuthorized(ctx, input.SnapshotID, iam.ActionDeleteSnapshot) + r.MustAuthorize(ctx, input.SnapshotID, probo.ActionSnapshotDelete) prb := r.ProboService(ctx, input.SnapshotID.TenantID()) err := prb.Snapshots.Delete(ctx, input.SnapshotID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete snapshot: %w", err)) } @@ -4506,15 +4636,19 @@ func (r *mutationResolver) DeleteSnapshot(ctx context.Context, input types.Delet // CreateCustomDomain is the resolver for the createCustomDomain field. func (r *mutationResolver) CreateCustomDomain(ctx context.Context, input types.CreateCustomDomainInput) (*types.CreateCustomDomainPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionCreateCustomDomain) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionCustomDomainCreate) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) - domain, err := prb.CustomDomains.CreateCustomDomain(ctx, probo.CreateCustomDomainRequest{ - OrganizationID: input.OrganizationID, - Domain: input.Domain, - }) + domain, err := prb.CustomDomains.CreateCustomDomain( + ctx, + probo.CreateCustomDomainRequest{ + OrganizationID: input.OrganizationID, + Domain: input.Domain, + }, + ) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot create custom domain: %w", err)) } @@ -4525,10 +4659,11 @@ func (r *mutationResolver) CreateCustomDomain(ctx context.Context, input types.C // DeleteCustomDomain is the resolver for the deleteCustomDomain field. func (r *mutationResolver) DeleteCustomDomain(ctx context.Context, input types.DeleteCustomDomainInput) (*types.DeleteCustomDomainPayload, error) { - r.MustBeAuthorized(ctx, input.OrganizationID, iam.ActionDeleteCustomDomain) + r.MustAuthorize(ctx, input.OrganizationID, probo.ActionCustomDomainDelete) prb := r.ProboService(ctx, input.OrganizationID.TenantID()) + // TODO Drop this wierd logic // Get the current custom domain ID before deleting domain, err := prb.CustomDomains.GetOrganizationCustomDomain(ctx, input.OrganizationID) if err != nil { @@ -4542,6 +4677,7 @@ func (r *mutationResolver) DeleteCustomDomain(ctx context.Context, input types.D deletedDomainID := domain.ID if err := prb.CustomDomains.DeleteCustomDomain(ctx, input.OrganizationID); err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot delete custom domain: %w", err)) } @@ -4552,21 +4688,17 @@ func (r *mutationResolver) DeleteCustomDomain(ctx context.Context, input types.D // Organization is the resolver for the organization field. func (r *nonconformityResolver) Organization(ctx context.Context, obj *types.Nonconformity) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - nonconformity, err := prb.Nonconformities.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get nonconformity: %w", err)) - } - - organization, err := prb.Organizations.Get(ctx, nonconformity.OrganizationID) + organization, err := prb.Organizations.Get(ctx, obj.Organization.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get nonconformity organization: %w", err)) } @@ -4575,25 +4707,21 @@ func (r *nonconformityResolver) Organization(ctx context.Context, obj *types.Non // Audit is the resolver for the audit field. func (r *nonconformityResolver) Audit(ctx context.Context, obj *types.Nonconformity) (*types.Audit, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionAudit) + r.MustAuthorize(ctx, obj.ID, probo.ActionAuditGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - nonconformity, err := prb.Nonconformities.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get nonconformity: %w", err)) - } - - if nonconformity.AuditID == nil { + if obj.Audit == nil { return nil, nil } - audit, err := prb.Audits.Get(ctx, *nonconformity.AuditID) + audit, err := prb.Audits.Get(ctx, obj.Audit.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get nonconformity audit: %w", err)) } @@ -4602,21 +4730,17 @@ func (r *nonconformityResolver) Audit(ctx context.Context, obj *types.Nonconform // Owner is the resolver for the owner field. func (r *nonconformityResolver) Owner(ctx context.Context, obj *types.Nonconformity) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOwner) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - nonconformity, err := prb.Nonconformities.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get nonconformity: %w", err)) - } - - people, err := prb.Peoples.Get(ctx, nonconformity.OwnerID) + people, err := prb.Peoples.Get(ctx, obj.Owner.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get nonconformity owner: %w", err)) } @@ -4625,7 +4749,7 @@ func (r *nonconformityResolver) Owner(ctx context.Context, obj *types.Nonconform // TotalCount is the resolver for the totalCount field. func (r *nonconformityConnectionResolver) TotalCount(ctx context.Context, obj *types.NonconformityConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionNonconformityList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) switch obj.Resolver.(type) { @@ -4637,31 +4761,29 @@ func (r *nonconformityConnectionResolver) TotalCount(ctx context.Context, obj *t count, err := prb.Nonconformities.CountForOrganizationID(ctx, obj.ParentID, nonconformityFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count nonconformities: %w", err)) } return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // Organization is the resolver for the organization field. func (r *obligationResolver) Organization(ctx context.Context, obj *types.Obligation) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - obligation, err := prb.Obligations.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get obligation: %w", err)) - } - - organization, err := prb.Organizations.Get(ctx, obligation.OrganizationID) + organization, err := prb.Organizations.Get(ctx, obj.Organization.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get obligation organization: %w", err)) } @@ -4670,21 +4792,17 @@ func (r *obligationResolver) Organization(ctx context.Context, obj *types.Obliga // Owner is the resolver for the owner field. func (r *obligationResolver) Owner(ctx context.Context, obj *types.Obligation) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOwner) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - obligation, err := prb.Obligations.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get obligation: %w", err)) - } - - people, err := prb.Peoples.Get(ctx, obligation.OwnerID) + people, err := prb.Peoples.Get(ctx, obj.Owner.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get obligation owner: %w", err)) } @@ -4693,7 +4811,7 @@ func (r *obligationResolver) Owner(ctx context.Context, obj *types.Obligation) ( // TotalCount is the resolver for the totalCount field. func (r *obligationConnectionResolver) TotalCount(ctx context.Context, obj *types.ObligationConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionObligationList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -4706,6 +4824,7 @@ func (r *obligationConnectionResolver) TotalCount(ctx context.Context, obj *type count, err := prb.Obligations.CountForOrganizationID(ctx, obj.ParentID, obligationFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count obligations: %w", err)) } return count, nil @@ -4717,38 +4836,55 @@ func (r *obligationConnectionResolver) TotalCount(ctx context.Context, obj *type count, err := prb.Obligations.CountForRiskID(ctx, obj.ParentID, obligationFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count risk obligations: %w", err)) } return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // LogoURL is the resolver for the logoUrl field. func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organization) (*string, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetLogoUrl) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGetLogoUrl) prb := r.ProboService(ctx, obj.ID.TenantID()) - return prb.Organizations.GenerateLogoURL(ctx, obj.ID, 1*time.Hour) + logoURL, err := prb.Organizations.GenerateLogoURL(ctx, obj.ID, 1*time.Hour) + if err != nil { + // TODO no panic use gqlutils.InternalError + panic(fmt.Errorf("cannot generate logo url: %w", err)) + } + + return logoURL, nil } // HorizontalLogoURL is the resolver for the horizontalLogoUrl field. func (r *organizationResolver) HorizontalLogoURL(ctx context.Context, obj *types.Organization) (*string, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetHorizontalLogoUrl) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGetHorizontalLogoUrl) prb := r.ProboService(ctx, obj.ID.TenantID()) - return prb.Organizations.GenerateHorizontalLogoURL(ctx, obj.ID, 1*time.Hour) + horizontalLogoURL, err := prb.Organizations.GenerateHorizontalLogoURL(ctx, obj.ID, 1*time.Hour) + if err != nil { + // TODO no panic use gqlutils.InternalError + panic(fmt.Errorf("cannot generate horizontal logo url: %w", err)) + } + + return horizontalLogoURL, nil } // Context is the resolver for the context field. func (r *organizationResolver) Context(ctx context.Context, obj *types.Organization) (*types.OrganizationContext, error) { + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationContextGet) + prb := r.ProboService(ctx, obj.ID.TenantID()) orgContext, err := prb.Organizations.GetContextSummary(ctx, obj.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot load organization context: %w", err)) } @@ -4757,11 +4893,10 @@ func (r *organizationResolver) Context(ctx context.Context, obj *types.Organizat // SlackConnections is the resolver for the slackConnections field. func (r *organizationResolver) SlackConnections(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.SlackConnectionConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListSlackConnections) + r.MustAuthorize(ctx, obj.ID, probo.ActionSlackConnectionList) prb := r.ProboService(ctx, obj.ID.TenantID()) - // Filter for Slack connectors only slackProvider := coredata.ConnectorProviderSlack filter := coredata.NewConnectorProviderFilter(&slackProvider) @@ -4774,6 +4909,7 @@ func (r *organizationResolver) SlackConnections(ctx context.Context, obj *types. page, err := prb.Connectors.ListForOrganizationID(ctx, obj.ID, cursor, filter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization slack connections: %w", err)) } @@ -4782,7 +4918,7 @@ func (r *organizationResolver) SlackConnections(ctx context.Context, obj *types. // Frameworks is the resolver for the frameworks field. func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.FrameworkOrderBy) (*types.FrameworkConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListFrameworks) + r.MustAuthorize(ctx, obj.ID, probo.ActionFrameworkList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -4801,6 +4937,7 @@ func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organi page, err := prb.Frameworks.ListForOrganizationID(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization frameworks: %w", err)) } @@ -4809,7 +4946,7 @@ func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organi // Controls is the resolver for the controls field. func (r *organizationResolver) Controls(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListControls) + r.MustAuthorize(ctx, obj.ID, probo.ActionControlList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -4833,6 +4970,7 @@ func (r *organizationResolver) Controls(ctx context.Context, obj *types.Organiza page, err := prb.Controls.ListForOrganizationID(ctx, obj.ID, cursor, controlFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list controls: %w", err)) } @@ -4841,7 +4979,7 @@ func (r *organizationResolver) Controls(ctx context.Context, obj *types.Organiza // Vendors is the resolver for the vendors field. func (r *organizationResolver) Vendors(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy, filter *types.VendorFilter) (*types.VendorConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListVendors) + r.MustAuthorize(ctx, obj.ID, probo.ActionVendorList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -4865,6 +5003,7 @@ func (r *organizationResolver) Vendors(ctx context.Context, obj *types.Organizat page, err := prb.Vendors.ListForOrganizationID(ctx, obj.ID, cursor, vendorFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization vendors: %w", err)) } @@ -4873,7 +5012,7 @@ func (r *organizationResolver) Vendors(ctx context.Context, obj *types.Organizat // Peoples is the resolver for the peoples field. func (r *organizationResolver) Peoples(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.PeopleOrderBy, filter *types.PeopleFilter) (*types.PeopleConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionPeoples) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -4897,6 +5036,7 @@ func (r *organizationResolver) Peoples(ctx context.Context, obj *types.Organizat page, err := prb.Peoples.ListForOrganizationID(ctx, obj.ID, cursor, peopleFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization peoples: %w", err)) } @@ -4905,7 +5045,7 @@ func (r *organizationResolver) Peoples(ctx context.Context, obj *types.Organizat // Documents is the resolver for the documents field. func (r *organizationResolver) Documents(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListDocuments) + r.MustAuthorize(ctx, obj.ID, probo.ActionDocumentList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -4929,6 +5069,7 @@ func (r *organizationResolver) Documents(ctx context.Context, obj *types.Organiz page, err := prb.Documents.ListByOrganizationID(ctx, obj.ID, cursor, documentFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization documents: %w", err)) } @@ -4937,7 +5078,7 @@ func (r *organizationResolver) Documents(ctx context.Context, obj *types.Organiz // Meetings is the resolver for the meetings field. func (r *organizationResolver) Meetings(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeetingOrderBy) (*types.MeetingConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListMeetings) + r.MustAuthorize(ctx, obj.ID, probo.ActionMeetingList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -4956,6 +5097,7 @@ func (r *organizationResolver) Meetings(ctx context.Context, obj *types.Organiza page, err := prb.Meetings.ListForOrganizationID(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization meetings: %w", err)) } @@ -4964,7 +5106,7 @@ func (r *organizationResolver) Meetings(ctx context.Context, obj *types.Organiza // StatesOfApplicability is the resolver for the statesOfApplicability field. func (r *organizationResolver) StatesOfApplicability(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.StateOfApplicabilityOrderBy, filter *types.StateOfApplicabilityFilter) (*types.StateOfApplicabilityConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListStatesOfApplicability) + r.MustAuthorize(ctx, obj.ID, probo.ActionStateOfApplicabilityList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -4996,7 +5138,7 @@ func (r *organizationResolver) StatesOfApplicability(ctx context.Context, obj *t // Measures is the resolver for the measures field. func (r *organizationResolver) Measures(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListMeasures) + r.MustAuthorize(ctx, obj.ID, probo.ActionMeasureList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5020,6 +5162,7 @@ func (r *organizationResolver) Measures(ctx context.Context, obj *types.Organiza page, err := prb.Measures.ListForOrganizationID(ctx, obj.ID, cursor, measureFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization measures: %w", err)) } @@ -5028,7 +5171,7 @@ func (r *organizationResolver) Measures(ctx context.Context, obj *types.Organiza // Risks is the resolver for the risks field. func (r *organizationResolver) Risks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RiskOrderBy, filter *types.RiskFilter) (*types.RiskConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListRisks) + r.MustAuthorize(ctx, obj.ID, probo.ActionRiskList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5052,6 +5195,7 @@ func (r *organizationResolver) Risks(ctx context.Context, obj *types.Organizatio page, err := prb.Risks.ListForOrganizationID(ctx, obj.ID, cursor, riskFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization risks: %w", err)) } @@ -5060,7 +5204,7 @@ func (r *organizationResolver) Risks(ctx context.Context, obj *types.Organizatio // Tasks is the resolver for the tasks field. func (r *organizationResolver) Tasks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TaskOrderBy) (*types.TaskConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListTasks) + r.MustAuthorize(ctx, obj.ID, probo.ActionTaskList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5079,6 +5223,7 @@ func (r *organizationResolver) Tasks(ctx context.Context, obj *types.Organizatio page, err := prb.Tasks.ListForOrganizationID(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization tasks: %w", err)) } @@ -5087,7 +5232,7 @@ func (r *organizationResolver) Tasks(ctx context.Context, obj *types.Organizatio // Assets is the resolver for the assets field. func (r *organizationResolver) Assets(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AssetOrderBy, filter *types.AssetFilter) (*types.AssetConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListAssets) + r.MustAuthorize(ctx, obj.ID, probo.ActionAssetList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5111,6 +5256,7 @@ func (r *organizationResolver) Assets(ctx context.Context, obj *types.Organizati page, err := prb.Assets.ListForOrganizationID(ctx, obj.ID, cursor, assetFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization assets: %w", err)) } @@ -5119,7 +5265,7 @@ func (r *organizationResolver) Assets(ctx context.Context, obj *types.Organizati // Assets is the resolver for the assets field. func (r *organizationResolver) Data(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DatumOrderBy, filter *types.DatumFilter) (*types.DatumConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListAssets) + r.MustAuthorize(ctx, obj.ID, probo.ActionDatumList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5143,6 +5289,7 @@ func (r *organizationResolver) Data(ctx context.Context, obj *types.Organization page, err := prb.Data.ListForOrganizationID(ctx, obj.ID, cursor, datumFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization data: %w", err)) } @@ -5151,7 +5298,7 @@ func (r *organizationResolver) Data(ctx context.Context, obj *types.Organization // Audits is the resolver for the audits field. func (r *organizationResolver) Audits(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.AuditOrderBy) (*types.AuditConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListAudits) + r.MustAuthorize(ctx, obj.ID, probo.ActionAuditList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5170,6 +5317,7 @@ func (r *organizationResolver) Audits(ctx context.Context, obj *types.Organizati page, err := prb.Audits.ListForOrganizationID(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization audits: %w", err)) } @@ -5178,7 +5326,7 @@ func (r *organizationResolver) Audits(ctx context.Context, obj *types.Organizati // Nonconformities is the resolver for the nonconformities field. func (r *organizationResolver) Nonconformities(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.NonconformityOrderBy, filter *types.NonconformityFilter) (*types.NonconformityConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListNonconformities) + r.MustAuthorize(ctx, obj.ID, probo.ActionNonconformityList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5203,6 +5351,7 @@ func (r *organizationResolver) Nonconformities(ctx context.Context, obj *types.O page, err := prb.Nonconformities.ListForOrganizationID(ctx, obj.ID, cursor, nonconformityFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization nonconformities: %w", err)) } @@ -5211,7 +5360,7 @@ func (r *organizationResolver) Nonconformities(ctx context.Context, obj *types.O // Obligations is the resolver for the obligations field. func (r *organizationResolver) Obligations(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) (*types.ObligationConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListObligations) + r.MustAuthorize(ctx, obj.ID, probo.ActionObligationList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5236,6 +5385,7 @@ func (r *organizationResolver) Obligations(ctx context.Context, obj *types.Organ page, err := prb.Obligations.ListForOrganizationID(ctx, obj.ID, cursor, obligationFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization obligations: %w", err)) } @@ -5244,7 +5394,7 @@ func (r *organizationResolver) Obligations(ctx context.Context, obj *types.Organ // ContinualImprovements is the resolver for the continualImprovements field. func (r *organizationResolver) ContinualImprovements(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ContinualImprovementOrderBy, filter *types.ContinualImprovementFilter) (*types.ContinualImprovementConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListContinualImprovements) + r.MustAuthorize(ctx, obj.ID, probo.ActionContinualImprovementList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5269,6 +5419,7 @@ func (r *organizationResolver) ContinualImprovements(ctx context.Context, obj *t page, err := prb.ContinualImprovements.ListForOrganizationID(ctx, obj.ID, cursor, continualImprovementFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization continual improvements: %w", err)) } @@ -5277,7 +5428,7 @@ func (r *organizationResolver) ContinualImprovements(ctx context.Context, obj *t // RightsRequests is the resolver for the rightsRequests field. func (r *organizationResolver) RightsRequests(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.RightsRequestOrderBy) (*types.RightsRequestConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListRightsRequests) + r.MustAuthorize(ctx, obj.ID, iam.ActionListRightsRequests) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5305,7 +5456,7 @@ func (r *organizationResolver) RightsRequests(ctx context.Context, obj *types.Or // ProcessingActivities is the resolver for the processingActivities field. func (r *organizationResolver) ProcessingActivities(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ProcessingActivityOrderBy, filter *types.ProcessingActivityFilter) (*types.ProcessingActivityConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListProcessingActivities) + r.MustAuthorize(ctx, obj.ID, probo.ActionProcessingActivityList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5330,6 +5481,7 @@ func (r *organizationResolver) ProcessingActivities(ctx context.Context, obj *ty page, err := prb.ProcessingActivities.ListForOrganizationID(ctx, obj.ID, cursor, processingActivityFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization processing activities: %w", err)) } @@ -5338,7 +5490,7 @@ func (r *organizationResolver) ProcessingActivities(ctx context.Context, obj *ty // DataProtectionImpactAssessments is the resolver for the dataProtectionImpactAssessments field. func (r *organizationResolver) DataProtectionImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DataProtectionImpactAssessmentOrderBy, filter *types.DataProtectionImpactAssessmentFilter) (*types.DataProtectionImpactAssessmentConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListProcessingActivities) + r.MustAuthorize(ctx, obj.ID, probo.ActionDataProtectionImpactAssessmentList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5371,7 +5523,7 @@ func (r *organizationResolver) DataProtectionImpactAssessments(ctx context.Conte // TransferImpactAssessments is the resolver for the transferImpactAssessments field. func (r *organizationResolver) TransferImpactAssessments(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.TransferImpactAssessmentOrderBy, filter *types.TransferImpactAssessmentFilter) (*types.TransferImpactAssessmentConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListProcessingActivities) + r.MustAuthorize(ctx, obj.ID, probo.ActionTransferImpactAssessmentList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5404,7 +5556,7 @@ func (r *organizationResolver) TransferImpactAssessments(ctx context.Context, ob // Snapshots is the resolver for the snapshots field. func (r *organizationResolver) Snapshots(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.SnapshotOrderBy) (*types.SnapshotConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListSnapshots) + r.MustAuthorize(ctx, obj.ID, probo.ActionSnapshotList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5423,6 +5575,7 @@ func (r *organizationResolver) Snapshots(ctx context.Context, obj *types.Organiz page, err := prb.Snapshots.ListForOrganizationID(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization snapshots: %w", err)) } @@ -5431,7 +5584,7 @@ func (r *organizationResolver) Snapshots(ctx context.Context, obj *types.Organiz // TrustCenterFiles is the resolver for the trustCenterFiles field. func (r *organizationResolver) TrustCenterFiles(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterFileOrderField]) (*types.TrustCenterFileConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListTrustCenterFiles) + r.MustAuthorize(ctx, obj.ID, probo.ActionTrustCenterFileList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5450,6 +5603,7 @@ func (r *organizationResolver) TrustCenterFiles(ctx context.Context, obj *types. pageResult, err := prb.TrustCenterFiles.ListForOrganizationID(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list organization trust center files: %w", err)) } @@ -5458,13 +5612,14 @@ func (r *organizationResolver) TrustCenterFiles(ctx context.Context, obj *types. // TrustCenter is the resolver for the trustCenter field. func (r *organizationResolver) TrustCenter(ctx context.Context, obj *types.Organization) (*types.TrustCenter, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetTrustCenter) + r.MustAuthorize(ctx, obj.ID, probo.ActionTrustCenterGet) prb := r.ProboService(ctx, obj.ID.TenantID()) trustCenter, file, err := prb.TrustCenters.GetByOrganizationID(ctx, obj.ID) if err != nil { - return nil, fmt.Errorf("cannot get trust center: %w", err) + // TODO no panic use gqlutils.InternalError + panic(fmt.Errorf("cannot get trust center: %w", err)) } return types.NewTrustCenter(trustCenter, file), nil @@ -5472,12 +5627,13 @@ func (r *organizationResolver) TrustCenter(ctx context.Context, obj *types.Organ // CustomDomain is the resolver for the customDomain field. func (r *organizationResolver) CustomDomain(ctx context.Context, obj *types.Organization) (*types.CustomDomain, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetCustomDomain) + r.MustAuthorize(ctx, obj.ID, probo.ActionCustomDomainGet) prb := r.ProboService(ctx, obj.ID.TenantID()) domain, err := prb.CustomDomains.GetOrganizationCustomDomain(ctx, obj.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get custom domain: %w", err)) } @@ -5490,7 +5646,7 @@ func (r *organizationResolver) CustomDomain(ctx context.Context, obj *types.Orga // TotalCount is the resolver for the totalCount field. func (r *peopleConnectionResolver) TotalCount(ctx context.Context, obj *types.PeopleConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionPeopleList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -5498,31 +5654,30 @@ func (r *peopleConnectionResolver) TotalCount(ctx context.Context, obj *types.Pe case *organizationResolver: count, err := prb.Peoples.CountForOrganizationID(ctx, obj.ParentID, obj.Filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count peoples: %w", err)) } + return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // Organization is the resolver for the organization field. func (r *processingActivityResolver) Organization(ctx context.Context, obj *types.ProcessingActivity) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - processingActivity, err := prb.ProcessingActivities.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get processing activity: %w", err)) - } - - organization, err := prb.Organizations.Get(ctx, processingActivity.OrganizationID) + organization, err := prb.Organizations.Get(ctx, obj.Organization.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get organization: %w", err)) } @@ -5531,7 +5686,7 @@ func (r *processingActivityResolver) Organization(ctx context.Context, obj *type // DataProtectionOfficer is the resolver for the dataProtectionOfficer field. func (r *processingActivityResolver) DataProtectionOfficer(ctx context.Context, obj *types.ProcessingActivity) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetDataProtectionOfficer) + r.MustAuthorize(ctx, obj.ID, probo.ActionDataProtectionOfficerList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5554,7 +5709,7 @@ func (r *processingActivityResolver) DataProtectionOfficer(ctx context.Context, // Vendors is the resolver for the vendors field. func (r *processingActivityResolver) Vendors(ctx context.Context, obj *types.ProcessingActivity, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.VendorOrderBy) (*types.VendorConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListVendors) + r.MustAuthorize(ctx, obj.ID, probo.ActionVendorList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5573,6 +5728,7 @@ func (r *processingActivityResolver) Vendors(ctx context.Context, obj *types.Pro page, err := prb.Vendors.ListForProcessingActivityID(ctx, obj.ID, cursor) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list processing activity vendors: %w", err)) } @@ -5581,7 +5737,7 @@ func (r *processingActivityResolver) Vendors(ctx context.Context, obj *types.Pro // DataProtectionImpactAssessment is the resolver for the dataProtectionImpactAssessment field. func (r *processingActivityResolver) DataProtectionImpactAssessment(ctx context.Context, obj *types.ProcessingActivity) (*types.DataProtectionImpactAssessment, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetDataProtectionImpactAssessment) + r.MustAuthorize(ctx, obj.ID, probo.ActionDataProtectionImpactAssessmentList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5599,7 +5755,7 @@ func (r *processingActivityResolver) DataProtectionImpactAssessment(ctx context. // TransferImpactAssessment is the resolver for the transferImpactAssessment field. func (r *processingActivityResolver) TransferImpactAssessment(ctx context.Context, obj *types.ProcessingActivity) (*types.TransferImpactAssessment, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetTransferImpactAssessment) + r.MustAuthorize(ctx, obj.ID, probo.ActionTransferImpactAssessmentList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5617,7 +5773,7 @@ func (r *processingActivityResolver) TransferImpactAssessment(ctx context.Contex // TotalCount is the resolver for the totalCount field. func (r *processingActivityConnectionResolver) TotalCount(ctx context.Context, obj *types.ProcessingActivityConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionProcessingActivityList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -5630,17 +5786,20 @@ func (r *processingActivityConnectionResolver) TotalCount(ctx context.Context, o count, err := prb.ProcessingActivities.CountForOrganizationID(ctx, obj.ParentID, processingActivityFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count organization processing activities: %w", err)) } return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } // Node is the resolver for the node field. func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error) { - r.MustBeAuthorized(ctx, id, iam.ActionGet) + // TODO use right action + //r.MustAuthorize(ctx, id, probo.ActionGet) prb := r.ProboService(ctx, id.TenantID()) @@ -5938,12 +6097,13 @@ func (r *queryResolver) Viewer(ctx context.Context) (*types.Viewer, error) { // DownloadURL is the resolver for the downloadUrl field. func (r *reportResolver) DownloadURL(ctx context.Context, obj *types.Report) (*string, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionDownloadUrl) + r.MustAuthorize(ctx, obj.ID, probo.ActionReportDownloadUrlGet) prb := r.ProboService(ctx, obj.ID.TenantID()) url, err := prb.Reports.GenerateDownloadURL(ctx, obj.ID, 15*time.Minute) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot generate download URL: %w", err)) } @@ -5952,23 +6112,22 @@ func (r *reportResolver) DownloadURL(ctx context.Context, obj *types.Report) (*s // Audit is the resolver for the audit field. func (r *reportResolver) Audit(ctx context.Context, obj *types.Report) (*types.Audit, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetAudit) + r.MustAuthorize(ctx, obj.ID, probo.ActionAuditGet) prb := r.ProboService(ctx, obj.ID.TenantID()) audit, err := prb.Audits.GetByReportID(ctx, obj.ID) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot load audit for report: %w", err)) } - r.MustBeAuthorized(ctx, audit.OrganizationID, iam.ActionAudit) - return types.NewAudit(audit), nil } // Organization is the resolver for the organization field. func (r *rightsRequestResolver) Organization(ctx context.Context, obj *types.RightsRequest) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, iam.ActionGetOrganization) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -5990,7 +6149,7 @@ func (r *rightsRequestResolver) Organization(ctx context.Context, obj *types.Rig // TotalCount is the resolver for the totalCount field. func (r *rightsRequestConnectionResolver) TotalCount(ctx context.Context, obj *types.RightsRequestConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionRightsRequesList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -6009,29 +6168,21 @@ func (r *rightsRequestConnectionResolver) TotalCount(ctx context.Context, obj *t // Owner is the resolver for the owner field. func (r *riskResolver) Owner(ctx context.Context, obj *types.Risk) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOwner) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - risk, err := prb.Risks.Get(ctx, obj.ID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, gqlutils.NotFound(err) - } - - panic(fmt.Errorf("cannot get risk: %w", err)) - } - - if risk.OwnerID == nil { + if obj.Owner == nil { return nil, nil } - owner, err := prb.Peoples.Get(ctx, *risk.OwnerID) + owner, err := prb.Peoples.Get(ctx, obj.Owner.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get owner: %w", err)) } @@ -6040,21 +6191,17 @@ func (r *riskResolver) Owner(ctx context.Context, obj *types.Risk) (*types.Peopl // Organization is the resolver for the organization field. func (r *riskResolver) Organization(ctx context.Context, obj *types.Risk) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) - risk, err := prb.Risks.Get(ctx, obj.ID) - if err != nil { - panic(fmt.Errorf("cannot get risk: %w", err)) - } - - organization, err := prb.Organizations.Get(ctx, risk.OrganizationID) + organization, err := prb.Organizations.Get(ctx, obj.Organization.ID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return nil, gqlutils.NotFound(err) } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot get organization: %w", err)) } @@ -6063,7 +6210,7 @@ func (r *riskResolver) Organization(ctx context.Context, obj *types.Risk) (*type // Measures is the resolver for the measures field. func (r *riskResolver) Measures(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MeasureOrderBy, filter *types.MeasureFilter) (*types.MeasureConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListMeasures) + r.MustAuthorize(ctx, obj.ID, probo.ActionMeasureList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6087,6 +6234,7 @@ func (r *riskResolver) Measures(ctx context.Context, obj *types.Risk, first *int page, err := prb.Measures.ListForRiskID(ctx, obj.ID, cursor, measureFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list risk measures: %w", err)) } @@ -6095,7 +6243,7 @@ func (r *riskResolver) Measures(ctx context.Context, obj *types.Risk, first *int // Documents is the resolver for the documents field. func (r *riskResolver) Documents(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.DocumentOrderBy, filter *types.DocumentFilter) (*types.DocumentConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListDocuments) + r.MustAuthorize(ctx, obj.ID, probo.ActionDocumentList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6119,6 +6267,7 @@ func (r *riskResolver) Documents(ctx context.Context, obj *types.Risk, first *in page, err := prb.Documents.ListForRiskID(ctx, obj.ID, cursor, documentFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list risk documents: %w", err)) } @@ -6127,7 +6276,7 @@ func (r *riskResolver) Documents(ctx context.Context, obj *types.Risk, first *in // Controls is the resolver for the controls field. func (r *riskResolver) Controls(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListControls) + r.MustAuthorize(ctx, obj.ID, probo.ActionControlList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6150,6 +6299,7 @@ func (r *riskResolver) Controls(ctx context.Context, obj *types.Risk, first *int page, err := prb.Controls.ListForRiskID(ctx, obj.ID, cursor, filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list risk controls: %w", err)) } @@ -6158,7 +6308,7 @@ func (r *riskResolver) Controls(ctx context.Context, obj *types.Risk, first *int // Obligations is the resolver for the obligations field. func (r *riskResolver) Obligations(ctx context.Context, obj *types.Risk, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ObligationOrderBy, filter *types.ObligationFilter) (*types.ObligationConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListObligations) + r.MustAuthorize(ctx, obj.ID, probo.ActionObligationList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6182,6 +6332,7 @@ func (r *riskResolver) Obligations(ctx context.Context, obj *types.Risk, first * page, err := prb.Obligations.ListForRiskID(ctx, obj.ID, cursor, obligationFilter) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot list risk obligations: %w", err)) } @@ -6190,7 +6341,7 @@ func (r *riskResolver) Obligations(ctx context.Context, obj *types.Risk, first * // TotalCount is the resolver for the totalCount field. func (r *riskConnectionResolver) TotalCount(ctx context.Context, obj *types.RiskConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionRiskList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -6198,17 +6349,20 @@ func (r *riskConnectionResolver) TotalCount(ctx context.Context, obj *types.Risk case *measureResolver: count, err := prb.Risks.CountForMeasureID(ctx, obj.ParentID, obj.Filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count risks: %w", err)) } return count, nil case *organizationResolver: count, err := prb.Risks.CountForOrganizationID(ctx, obj.ParentID, obj.Filters) if err != nil { + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("cannot count risks: %w", err)) } return count, nil } + // TODO no panic use gqlutils.InternalError panic(fmt.Errorf("unsupported resolver: %T", obj.Resolver)) } @@ -6239,7 +6393,7 @@ func (r *snapshotConnectionResolver) TotalCount(ctx context.Context, obj *types. // Organization is the resolver for the organization field. func (r *stateOfApplicabilityResolver) Organization(ctx context.Context, obj *types.StateOfApplicability) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6256,7 +6410,7 @@ func (r *stateOfApplicabilityResolver) Organization(ctx context.Context, obj *ty // Owner is the resolver for the owner field. func (r *stateOfApplicabilityResolver) Owner(ctx context.Context, obj *types.StateOfApplicability) (*types.People, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOwner) + r.MustAuthorize(ctx, obj.ID, probo.ActionPeopleGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6273,7 +6427,7 @@ func (r *stateOfApplicabilityResolver) Owner(ctx context.Context, obj *types.Sta // Controls is the resolver for the controls field. func (r *stateOfApplicabilityResolver) Controls(ctx context.Context, obj *types.StateOfApplicability, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.ControlOrderBy, filter *types.ControlFilter) (*types.ControlConnection, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListControls) + r.MustAuthorize(ctx, obj.ID, probo.ActionControlList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6305,7 +6459,7 @@ func (r *stateOfApplicabilityResolver) Controls(ctx context.Context, obj *types. // AvailableControls is the resolver for the availableControls field. func (r *stateOfApplicabilityResolver) AvailableControls(ctx context.Context, obj *types.StateOfApplicability) ([]*types.AvailableStateOfApplicabilityControl, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionListControls) + r.MustAuthorize(ctx, obj.ID, probo.ActionControlList) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6354,7 +6508,7 @@ func (r *stateOfApplicabilityConnectionResolver) TotalCount(ctx context.Context, // StateOfApplicability is the resolver for the stateOfApplicability field. func (r *stateOfApplicabilityControlResolver) StateOfApplicability(ctx context.Context, obj *types.StateOfApplicabilityControl) (*types.StateOfApplicability, error) { - r.MustBeAuthorized(ctx, obj.StateOfApplicabilityID, iam.ActionGet) + r.MustAuthorize(ctx, obj.StateOfApplicabilityID, probo.ActionStateOfApplicabilityGet) prb := r.ProboService(ctx, obj.StateOfApplicabilityID.TenantID()) @@ -6378,7 +6532,7 @@ func (r *taskResolver) Organization(ctx context.Context, obj *types.Task) (*type // Measure is the resolver for the measure field. func (r *taskResolver) Measure(ctx context.Context, obj *types.Task) (*types.Measure, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetMeasure) + r.MustAuthorize(ctx, obj.ID, probo.ActionMeasureGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6409,7 +6563,7 @@ func (r *taskConnectionResolver) TotalCount(ctx context.Context, obj *types.Task // ProcessingActivity is the resolver for the processingActivity field. func (r *transferImpactAssessmentResolver) ProcessingActivity(ctx context.Context, obj *types.TransferImpactAssessment) (*types.ProcessingActivity, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGet) + r.MustAuthorize(ctx, obj.ID, probo.ActionProcessingActivityGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6428,7 +6582,7 @@ func (r *transferImpactAssessmentResolver) ProcessingActivity(ctx context.Contex // Organization is the resolver for the organization field. func (r *transferImpactAssessmentResolver) Organization(ctx context.Context, obj *types.TransferImpactAssessment) (*types.Organization, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetOrganization) + r.MustAuthorize(ctx, obj.ID, probo.ActionOrganizationGet) prb := r.ProboService(ctx, obj.ID.TenantID()) @@ -6450,7 +6604,7 @@ func (r *transferImpactAssessmentResolver) Organization(ctx context.Context, obj // TotalCount is the resolver for the totalCount field. func (r *transferImpactAssessmentConnectionResolver) TotalCount(ctx context.Context, obj *types.TransferImpactAssessmentConnection) (int, error) { - r.MustBeAuthorized(ctx, obj.ParentID, iam.ActionTotalCount) + r.MustAuthorize(ctx, obj.ParentID, probo.ActionTransferImpactAssessmentList) prb := r.ProboService(ctx, obj.ParentID.TenantID()) @@ -6633,7 +6787,7 @@ func (r *vendorDataPrivacyAgreementResolver) FileURL(ctx context.Context, obj *t // Vendor is the resolver for the vendor field. func (r *vendorRiskAssessmentResolver) Vendor(ctx context.Context, obj *types.VendorRiskAssessment) (*types.Vendor, error) { - r.MustBeAuthorized(ctx, obj.ID, iam.ActionGetVendor) + r.MustAuthorize(ctx, obj.ID, probo.ActionVendorGet) prb := r.ProboService(ctx, obj.ID.TenantID()) diff --git a/pkg/server/api/mcp/v1/resolver.go b/pkg/server/api/mcp/v1/resolver.go index c4f1929bf..1f9c30c52 100644 --- a/pkg/server/api/mcp/v1/resolver.go +++ b/pkg/server/api/mcp/v1/resolver.go @@ -30,7 +30,34 @@ func (r *Resolver) MustBeAuthorized(ctx context.Context, entityID gid.GID, actio credentialID = &apiKey.ID } - err := r.iamSvc.LegacyAccessManagementService.Authorize(ctx, user.ID, credentialID, entityID, action) + // When API key is used, fall back to legacy system for intersection semantics. + // The legacy system handles API key role checking properly. + // TODO: Migrate API key authorization to new system. + if credentialID != nil { + err := r.iamSvc.LegacyAccessManagementService.Authorize(ctx, user.ID, credentialID, entityID, action) + if err != nil { + panic(err) + } + return + } + + // Map legacy action to new namespaced action + newAction, ok := probo.MapLegacyAction(entityID.EntityType(), action) + if !ok { + // Fall back to legacy system for unmapped actions + err := r.iamSvc.LegacyAccessManagementService.Authorize(ctx, user.ID, credentialID, entityID, action) + if err != nil { + panic(err) + } + return + } + + // Use new authorizer with mapped action + err := r.iamSvc.Authorizer.Authorize(ctx, iam.AuthorizeParams{ + Principal: user.ID, + Resource: entityID, + Action: newAction, + }) if err != nil { panic(err) }