Add organization deletion

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-08-07 17:08:04 +02:00
parent c9ab0678be
commit ab97fc8cf8
16 changed files with 958 additions and 232 deletions

View File

@@ -250,6 +250,25 @@ DELETE FROM documents WHERE %s AND id = @document_id
return err
}
func (p Document) DeleteByOrganizationID(
ctx context.Context,
conn pg.Conn,
scope Scoper,
organizationID gid.GID,
) error {
q := `
DELETE FROM documents WHERE %s AND organization_id = @organization_id
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{"organization_id": organizationID}
maps.Copy(args, scope.SQLArguments())
_, err := conn.Exec(ctx, q, args)
return err
}
func (p *Document) Update(
ctx context.Context,
conn pg.Conn,

View File

@@ -0,0 +1,45 @@
ALTER TABLE frameworks DROP CONSTRAINT IF EXISTS frameworks_organization_id_fkey;
ALTER TABLE frameworks ADD CONSTRAINT frameworks_organization_id_fkey
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE peoples DROP CONSTRAINT IF EXISTS peoples_organization_id_fkey;
ALTER TABLE peoples ADD CONSTRAINT peoples_organization_id_fkey
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE vendors DROP CONSTRAINT IF EXISTS vendors_organization_id_fkey;
ALTER TABLE vendors ADD CONSTRAINT vendors_organization_id_fkey
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE documents DROP CONSTRAINT IF EXISTS policies_organization_id_fkey;
ALTER TABLE documents DROP CONSTRAINT IF EXISTS documents_organization_id_fkey;
ALTER TABLE documents ADD CONSTRAINT documents_organization_id_fkey
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE risks DROP CONSTRAINT IF EXISTS risks_organization_id_fkey;
ALTER TABLE risks ADD CONSTRAINT risks_organization_id_fkey
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE connectors DROP CONSTRAINT IF EXISTS connectors_organization_id_fkey;
ALTER TABLE connectors ADD CONSTRAINT connectors_organization_id_fkey
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE data DROP CONSTRAINT IF EXISTS data_organization_id_fkey;
ALTER TABLE data ADD CONSTRAINT data_organization_id_fkey
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE users_organizations ADD CONSTRAINT users_organizations_organization_id_fkey
FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
ALTER TABLE controls DROP CONSTRAINT IF EXISTS controls_framework_id_fkey;
ALTER TABLE controls ADD CONSTRAINT controls_framework_id_fkey
FOREIGN KEY (framework_id) REFERENCES frameworks(id) ON DELETE CASCADE;
ALTER TABLE document_versions DROP CONSTRAINT IF EXISTS document_versions_document_id_fkey;
ALTER TABLE document_versions ADD CONSTRAINT document_versions_document_id_fkey
FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE;
ALTER TABLE document_versions DROP CONSTRAINT IF EXISTS document_versions_published_by_fkey;
ALTER TABLE document_versions ADD CONSTRAINT document_versions_published_by_fkey
FOREIGN KEY (published_by) REFERENCES peoples(id)
ON DELETE SET NULL
ON UPDATE CASCADE;

View File

@@ -156,3 +156,28 @@ WHERE
return nil
}
func (o *Organization) Delete(
ctx context.Context,
conn pg.Conn,
scope Scoper,
) error {
q := `
DELETE FROM organizations
WHERE
%s
AND id = @id
`
q = fmt.Sprintf(q, scope.SQLFragment())
args := pgx.StrictNamedArgs{"id": o.ID}
maps.Copy(args, scope.SQLArguments())
_, err := conn.Exec(ctx, q, args)
if err != nil {
return fmt.Errorf("cannot delete organization: %w", err)
}
return nil
}

View File

@@ -281,6 +281,51 @@ func (s OrganizationService) GenerateLogoURL(
return &presignedReq.URL, nil
}
func (s OrganizationService) Delete(
ctx context.Context,
organizationID gid.GID,
) error {
organization := &coredata.Organization{}
err := s.svc.pg.WithTx(
ctx,
func(tx pg.Conn) error {
if err := organization.LoadByID(ctx, tx, s.svc.scope, organizationID); err != nil {
return fmt.Errorf("cannot load organization: %w", err)
}
// Delete documents first because versions and signatures have a delete restriction on people
// that must be resolved before deleting the organization
document := &coredata.Document{}
if err := document.DeleteByOrganizationID(ctx, tx, s.svc.scope, organizationID); err != nil {
return fmt.Errorf("cannot delete documents: %w", err)
}
if err := organization.Delete(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot delete organization: %w", err)
}
return nil
},
)
if err != nil {
return err
}
if organization.LogoObjectKey != "" {
_, err := s.svc.s3.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(organization.LogoObjectKey),
})
if err != nil {
return fmt.Errorf("organization deleted but failed to delete logo from S3: %w", err)
}
}
return nil
}
func (s OrganizationService) createProboVendor(ctx context.Context, tx pg.Conn, organization *coredata.Organization, now time.Time) error {
proboData := &coredata.Vendor{
ID: gid.New(s.svc.scope.GetTenantID(), coredata.VendorEntityType),

View File

@@ -1478,6 +1478,9 @@ type Mutation {
updateOrganization(
input: UpdateOrganizationInput!
): UpdateOrganizationPayload!
deleteOrganization(
input: DeleteOrganizationInput!
): DeleteOrganizationPayload!
updateTrustCenter(
input: UpdateTrustCenterInput!
@@ -1658,6 +1661,10 @@ input UpdateOrganizationInput {
logo: Upload
}
input DeleteOrganizationInput {
organizationId: ID!
}
input UpdateTrustCenterInput {
trustCenterId: ID!
active: Boolean
@@ -2035,6 +2042,10 @@ type UpdateOrganizationPayload {
organization: Organization!
}
type DeleteOrganizationPayload {
deletedOrganizationId: ID!
}
type UpdateTrustCenterPayload {
trustCenter: TrustCenter!
}

View File

@@ -355,6 +355,10 @@ type ComplexityRoot struct {
DeletedMeasureID func(childComplexity int) int
}
DeleteOrganizationPayload struct {
DeletedOrganizationID func(childComplexity int) int
}
DeletePeoplePayload struct {
DeletedPeopleID func(childComplexity int) int
}
@@ -601,6 +605,7 @@ type ComplexityRoot struct {
DeleteEvidence func(childComplexity int, input types.DeleteEvidenceInput) int
DeleteFramework func(childComplexity int, input types.DeleteFrameworkInput) int
DeleteMeasure func(childComplexity int, input types.DeleteMeasureInput) int
DeleteOrganization func(childComplexity int, input types.DeleteOrganizationInput) int
DeletePeople func(childComplexity int, input types.DeletePeopleInput) int
DeleteRisk func(childComplexity int, input types.DeleteRiskInput) int
DeleteRiskDocumentMapping func(childComplexity int, input types.DeleteRiskDocumentMappingInput) int
@@ -1119,6 +1124,7 @@ type MeasureConnectionResolver interface {
type MutationResolver interface {
CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error)
UpdateOrganization(ctx context.Context, input types.UpdateOrganizationInput) (*types.UpdateOrganizationPayload, error)
DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error)
UpdateTrustCenter(ctx context.Context, input types.UpdateTrustCenterInput) (*types.UpdateTrustCenterPayload, error)
CreateTrustCenterAccess(ctx context.Context, input types.CreateTrustCenterAccessInput) (*types.CreateTrustCenterAccessPayload, error)
DeleteTrustCenterAccess(ctx context.Context, input types.DeleteTrustCenterAccessInput) (*types.DeleteTrustCenterAccessPayload, error)
@@ -2115,6 +2121,13 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.DeleteMeasurePayload.DeletedMeasureID(childComplexity), true
case "DeleteOrganizationPayload.deletedOrganizationId":
if e.complexity.DeleteOrganizationPayload.DeletedOrganizationID == nil {
break
}
return e.complexity.DeleteOrganizationPayload.DeletedOrganizationID(childComplexity), true
case "DeletePeoplePayload.deletedPeopleId":
if e.complexity.DeletePeoplePayload.DeletedPeopleID == nil {
break
@@ -3357,6 +3370,18 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
return e.complexity.Mutation.DeleteMeasure(childComplexity, args["input"].(types.DeleteMeasureInput)), true
case "Mutation.deleteOrganization":
if e.complexity.Mutation.DeleteOrganization == nil {
break
}
args, err := ec.field_Mutation_deleteOrganization_args(ctx, rawArgs)
if err != nil {
return 0, false
}
return e.complexity.Mutation.DeleteOrganization(childComplexity, args["input"].(types.DeleteOrganizationInput)), true
case "Mutation.deletePeople":
if e.complexity.Mutation.DeletePeople == nil {
break
@@ -5473,6 +5498,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
ec.unmarshalInputDeleteEvidenceInput,
ec.unmarshalInputDeleteFrameworkInput,
ec.unmarshalInputDeleteMeasureInput,
ec.unmarshalInputDeleteOrganizationInput,
ec.unmarshalInputDeletePeopleInput,
ec.unmarshalInputDeleteRiskDocumentMappingInput,
ec.unmarshalInputDeleteRiskInput,
@@ -7110,6 +7136,9 @@ type Mutation {
updateOrganization(
input: UpdateOrganizationInput!
): UpdateOrganizationPayload!
deleteOrganization(
input: DeleteOrganizationInput!
): DeleteOrganizationPayload!
updateTrustCenter(
input: UpdateTrustCenterInput!
@@ -7290,6 +7319,10 @@ input UpdateOrganizationInput {
logo: Upload
}
input DeleteOrganizationInput {
organizationId: ID!
}
input UpdateTrustCenterInput {
trustCenterId: ID!
active: Boolean
@@ -7667,6 +7700,10 @@ type UpdateOrganizationPayload {
organization: Organization!
}
type DeleteOrganizationPayload {
deletedOrganizationId: ID!
}
type UpdateTrustCenterPayload {
trustCenter: TrustCenter!
}
@@ -10370,6 +10407,29 @@ func (ec *executionContext) field_Mutation_deleteMeasure_argsInput(
return zeroVal, nil
}
func (ec *executionContext) field_Mutation_deleteOrganization_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
arg0, err := ec.field_Mutation_deleteOrganization_argsInput(ctx, rawArgs)
if err != nil {
return nil, err
}
args["input"] = arg0
return args, nil
}
func (ec *executionContext) field_Mutation_deleteOrganization_argsInput(
ctx context.Context,
rawArgs map[string]any,
) (types.DeleteOrganizationInput, error) {
ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input"))
if tmp, ok := rawArgs["input"]; ok {
return ec.unmarshalNDeleteOrganizationInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationInput(ctx, tmp)
}
var zeroVal types.DeleteOrganizationInput
return zeroVal, nil
}
func (ec *executionContext) field_Mutation_deletePeople_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
var err error
args := map[string]any{}
@@ -19457,6 +19517,50 @@ func (ec *executionContext) fieldContext_DeleteMeasurePayload_deletedMeasureId(_
return fc, nil
}
func (ec *executionContext) _DeleteOrganizationPayload_deletedOrganizationId(ctx context.Context, field graphql.CollectedField, obj *types.DeleteOrganizationPayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_DeleteOrganizationPayload_deletedOrganizationId(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return obj.DeletedOrganizationID, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(gid.GID)
fc.Result = res
return ec.marshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_DeleteOrganizationPayload_deletedOrganizationId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "DeleteOrganizationPayload",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type ID does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _DeletePeoplePayload_deletedPeopleId(ctx context.Context, field graphql.CollectedField, obj *types.DeletePeoplePayload) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_DeletePeoplePayload_deletedPeopleId(ctx, field)
if err != nil {
@@ -25092,6 +25196,65 @@ func (ec *executionContext) fieldContext_Mutation_updateOrganization(ctx context
return fc, nil
}
func (ec *executionContext) _Mutation_deleteOrganization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_deleteOrganization(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Mutation().DeleteOrganization(rctx, fc.Args["input"].(types.DeleteOrganizationInput))
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(*types.DeleteOrganizationPayload)
fc.Result = res
return ec.marshalNDeleteOrganizationPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationPayload(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Mutation_deleteOrganization(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Mutation",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
switch field.Name {
case "deletedOrganizationId":
return ec.fieldContext_DeleteOrganizationPayload_deletedOrganizationId(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type DeleteOrganizationPayload", field.Name)
},
}
defer func() {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.field_Mutation_deleteOrganization_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return fc, err
}
return fc, nil
}
func (ec *executionContext) _Mutation_updateTrustCenter(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Mutation_updateTrustCenter(ctx, field)
if err != nil {
@@ -44360,6 +44523,33 @@ func (ec *executionContext) unmarshalInputDeleteMeasureInput(ctx context.Context
return it, nil
}
func (ec *executionContext) unmarshalInputDeleteOrganizationInput(ctx context.Context, obj any) (types.DeleteOrganizationInput, error) {
var it types.DeleteOrganizationInput
asMap := map[string]any{}
for k, v := range obj.(map[string]any) {
asMap[k] = v
}
fieldsInOrder := [...]string{"organizationId"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
case "organizationId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationId"))
data, err := ec.unmarshalNID2githubᚗcomᚋgetproboᚋproboᚋpkgᚋgidᚐGID(ctx, v)
if err != nil {
return it, err
}
it.OrganizationID = data
}
}
return it, nil
}
func (ec *executionContext) unmarshalInputDeletePeopleInput(ctx context.Context, obj any) (types.DeletePeopleInput, error) {
var it types.DeletePeopleInput
asMap := map[string]any{}
@@ -49842,6 +50032,45 @@ func (ec *executionContext) _DeleteMeasurePayload(ctx context.Context, sel ast.S
return out
}
var deleteOrganizationPayloadImplementors = []string{"DeleteOrganizationPayload"}
func (ec *executionContext) _DeleteOrganizationPayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeleteOrganizationPayload) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, deleteOrganizationPayloadImplementors)
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("DeleteOrganizationPayload")
case "deletedOrganizationId":
out.Values[i] = ec._DeleteOrganizationPayload_deletedOrganizationId(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 deletePeoplePayloadImplementors = []string{"DeletePeoplePayload"}
func (ec *executionContext) _DeletePeoplePayload(ctx context.Context, sel ast.SelectionSet, obj *types.DeletePeoplePayload) graphql.Marshaler {
@@ -52270,6 +52499,13 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "deleteOrganization":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_deleteOrganization(ctx, field)
})
if out.Values[i] == graphql.Null {
out.Invalids++
}
case "updateTrustCenter":
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._Mutation_updateTrustCenter(ctx, field)
@@ -58964,6 +59200,25 @@ func (ec *executionContext) marshalNDeleteMeasurePayload2ᚖgithubᚗcomᚋgetpr
return ec._DeleteMeasurePayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNDeleteOrganizationInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationInput(ctx context.Context, v any) (types.DeleteOrganizationInput, error) {
res, err := ec.unmarshalInputDeleteOrganizationInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) marshalNDeleteOrganizationPayload2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationPayload(ctx context.Context, sel ast.SelectionSet, v types.DeleteOrganizationPayload) graphql.Marshaler {
return ec._DeleteOrganizationPayload(ctx, sel, &v)
}
func (ec *executionContext) marshalNDeleteOrganizationPayload2ᚖgithubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeleteOrganizationPayload(ctx context.Context, sel ast.SelectionSet, v *types.DeleteOrganizationPayload) graphql.Marshaler {
if v == nil {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
return graphql.Null
}
return ec._DeleteOrganizationPayload(ctx, sel, v)
}
func (ec *executionContext) unmarshalNDeletePeopleInput2githubᚗcomᚋgetproboᚋproboᚋpkgᚋserverᚋapiᚋconsoleᚋv1ᚋtypesᚐDeletePeopleInput(ctx context.Context, v any) (types.DeletePeopleInput, error) {
res, err := ec.unmarshalInputDeletePeopleInput(ctx, v)
return res, graphql.ErrorOnPath(ctx, err)

View File

@@ -527,6 +527,14 @@ type DeleteMeasurePayload struct {
DeletedMeasureID gid.GID `json:"deletedMeasureId"`
}
type DeleteOrganizationInput struct {
OrganizationID gid.GID `json:"organizationId"`
}
type DeleteOrganizationPayload struct {
DeletedOrganizationID gid.GID `json:"deletedOrganizationId"`
}
type DeletePeopleInput struct {
PeopleID gid.GID `json:"peopleId"`
}

View File

@@ -980,6 +980,20 @@ func (r *mutationResolver) UpdateOrganization(ctx context.Context, input types.U
}, nil
}
// DeleteOrganization is the resolver for the deleteOrganization field.
func (r *mutationResolver) DeleteOrganization(ctx context.Context, input types.DeleteOrganizationInput) (*types.DeleteOrganizationPayload, error) {
prb := r.ProboService(ctx, input.OrganizationID.TenantID())
err := prb.Organizations.Delete(ctx, input.OrganizationID)
if err != nil {
return nil, fmt.Errorf("cannot delete organization: %w", err)
}
return &types.DeleteOrganizationPayload{
DeletedOrganizationID: input.OrganizationID,
}, nil
}
// UpdateTrustCenter is the resolver for the updateTrustCenter field.
func (r *mutationResolver) UpdateTrustCenter(ctx context.Context, input types.UpdateTrustCenterInput) (*types.UpdateTrustCenterPayload, error) {
prb := r.ProboService(ctx, input.TrustCenterID.TenantID())