Replace trust center alias with resource alias in console API

Drop the setTrustCenterAlias and removeTrustCenterAlias mutations and
the alias field on Audit in favor of generic setResourceAlias and
removeResourceAlias mutations backed by the resourcealias service.

Signed-off-by: Bryan Frimin <bryan@probo.com>
This commit is contained in:
Bryan Frimin
2026-06-22 10:59:04 +02:00
parent 9b0a5745a0
commit 231f7d153e
11 changed files with 123 additions and 157 deletions

View File

@@ -173,22 +173,6 @@ func (r *auditResolver) Findings(ctx context.Context, obj *types.Audit, first *i
return types.NewFindingConnection(p, r, obj.ID, filter), nil
}
// Alias is the resolver for the alias field.
func (r *auditResolver) Alias(ctx context.Context, obj *types.Audit) (*string, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionAuditGet)
if err != nil {
return nil, err
}
alias, err := r.probo.TrustCenterAliases.GetByResourceID(ctx, scope, obj.ID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot get audit alias", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return alias, nil
}
// Permission is the resolver for the permission field.
func (r *auditResolver) Permission(ctx context.Context, obj *types.Audit, action string) (bool, error) {
return r.Resolver.Permission(ctx, obj, action)

View File

@@ -19,6 +19,7 @@ import (
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/page"
"go.probo.inc/probo/pkg/probo"
"go.probo.inc/probo/pkg/resourcealias"
"go.probo.inc/probo/pkg/server/api/authn"
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
@@ -29,12 +30,12 @@ import (
// Alias is the resolver for the alias field.
func (r *documentResolver) Alias(ctx context.Context, obj *types.Document) (*string, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
scope, err := r.authorize(ctx, obj.ID, resourcealias.ActionAliasGet)
if err != nil {
return nil, err
}
return r.probo.TrustCenterAliases.GetByResourceID(ctx, scope, obj.ID)
return r.resourceAlias.GetByResourceID(ctx, scope, obj.ID)
}
// Organization is the resolver for the organization field.

View File

@@ -41,6 +41,6 @@ models:
EmailAddr:
model:
- "go.probo.inc/probo/pkg/server/gqlutils/types/mail.AddrScalar"
TrustCenterAlias:
ResourceAlias:
model:
- "go.probo.inc/probo/pkg/server/api/console/v1/types.TrustCenterAlias"
- "go.probo.inc/probo/pkg/server/api/console/v1/types.ResourceAlias"

View File

@@ -173,7 +173,6 @@ type Audit implements Node {
): FindingConnection @goField(forceResolver: true)
trustCenterVisibility: TrustCenterVisibility!
alias: String @goField(forceResolver: true)
createdAt: Datetime!
updatedAt: Datetime!

View File

@@ -0,0 +1,30 @@
type ResourceAlias {
resourceId: ID!
alias: String!
}
input SetResourceAliasInput {
resourceId: ID!
alias: String!
}
input RemoveResourceAliasInput {
resourceId: ID!
}
type SetResourceAliasPayload {
resourceAlias: ResourceAlias!
}
type RemoveResourceAliasPayload {
deletedResourceId: ID!
}
extend type Mutation {
setResourceAlias(
input: SetResourceAliasInput!
): SetResourceAliasPayload!
removeResourceAlias(
input: RemoveResourceAliasInput!
): RemoveResourceAliasPayload!
}

View File

@@ -550,12 +550,6 @@ extend type Mutation {
deleteCustomDomain(
input: DeleteCustomDomainInput!
): DeleteCustomDomainPayload!
setTrustCenterAlias(
input: SetTrustCenterAliasInput!
): SetTrustCenterAliasPayload!
removeTrustCenterAlias(
input: RemoveTrustCenterAliasInput!
): RemoveTrustCenterAliasPayload!
}
input UpdateTrustCenterInput {
@@ -765,26 +759,3 @@ type CreateCustomDomainPayload {
type DeleteCustomDomainPayload {
deletedCustomDomainId: ID!
}
input SetTrustCenterAliasInput {
resourceId: ID!
alias: String!
}
input RemoveTrustCenterAliasInput {
resourceId: ID!
}
type TrustCenterAlias {
resourceId: ID!
alias: String!
organization: Organization! @goField(forceResolver: true)
}
type SetTrustCenterAliasPayload {
alias: TrustCenterAlias!
}
type RemoveTrustCenterAliasPayload {
deletedResourceId: ID!
}

View File

@@ -29,6 +29,7 @@ import (
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/mailman"
"go.probo.inc/probo/pkg/probo"
"go.probo.inc/probo/pkg/resourcealias"
"go.probo.inc/probo/pkg/riskmanagement"
"go.probo.inc/probo/pkg/server/api/authz"
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
@@ -40,6 +41,7 @@ import (
func NewGraphQLHandler(
iamSvc *iam.Service,
proboSvc *probo.Service,
resourceAliasSvc *resourcealias.Service,
esignSvc *esign.Service,
accessReviewSvc *accessreview.Service,
agentRunSvc *agentrun.Service,
@@ -59,6 +61,7 @@ func NewGraphQLHandler(
authorize: dataloader.NewAuthorizeFunc(logger),
batchAuthorize: authz.NewBatchAuthorizeFunc(iamSvc, logger),
probo: proboSvc,
resourceAlias: resourceAliasSvc,
iam: iamSvc,
esign: esignSvc,
accessReview: accessReviewSvc,

View File

@@ -39,6 +39,7 @@ import (
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/mailman"
"go.probo.inc/probo/pkg/probo"
"go.probo.inc/probo/pkg/resourcealias"
"go.probo.inc/probo/pkg/riskmanagement"
"go.probo.inc/probo/pkg/saferedirect"
"go.probo.inc/probo/pkg/securecookie"
@@ -54,6 +55,7 @@ type (
authorize authz.AuthorizeFunc
batchAuthorize authz.BatchAuthorizeFunc
probo *probo.Service
resourceAlias *resourcealias.Service
iam *iam.Service
esign *esign.Service
accessReview *accessreview.Service
@@ -74,6 +76,7 @@ type (
func NewMux(
logger *log.Logger,
proboSvc *probo.Service,
resourceAliasSvc *resourcealias.Service,
iamSvc *iam.Service,
esignSvc *esign.Service,
accessReviewSvc *accessreview.Service,
@@ -97,6 +100,7 @@ func NewMux(
graphqlHandler := NewGraphQLHandler(
iamSvc,
proboSvc,
resourceAliasSvc,
esignSvc,
accessReviewSvc,
agentRunSvc,

View File

@@ -0,0 +1,71 @@
package console_v1
// This file will be automatically regenerated based on the schema, any resolver
// implementations
// will be copied through when generating and any unknown code will be moved to the end.
// Code generated by github.com/99designs/gqlgen version v0.17.90
import (
"context"
"errors"
"go.gearno.de/kit/log"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/resourcealias"
"go.probo.inc/probo/pkg/server/api/console/v1/types"
"go.probo.inc/probo/pkg/server/gqlutils"
"go.probo.inc/probo/pkg/validator"
)
// SetResourceAlias is the resolver for the setResourceAlias field.
func (r *mutationResolver) SetResourceAlias(ctx context.Context, input types.SetResourceAliasInput) (*types.SetResourceAliasPayload, error) {
scope, err := r.authorize(ctx, input.ResourceID, resourcealias.ActionAliasSet)
if err != nil {
return nil, err
}
alias, err := r.resourceAlias.Create(
ctx,
scope,
resourcealias.CreateRequest{
ResourceID: input.ResourceID,
Alias: input.Alias,
},
)
if err != nil {
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
return nil, gqlutils.Conflict(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
r.logger.ErrorCtx(ctx, "cannot set resource alias", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.SetResourceAliasPayload{
ResourceAlias: types.NewResourceAlias(input.ResourceID, alias),
}, nil
}
// RemoveResourceAlias is the resolver for the removeResourceAlias field.
func (r *mutationResolver) RemoveResourceAlias(ctx context.Context, input types.RemoveResourceAliasInput) (*types.RemoveResourceAliasPayload, error) {
scope, err := r.authorize(ctx, input.ResourceID, resourcealias.ActionAliasRemove)
if err != nil {
return nil, err
}
err = r.resourceAlias.Remove(ctx, scope, input.ResourceID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot remove resource alias", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.RemoveResourceAliasPayload{
DeletedResourceID: input.ResourceID,
}, nil
}

View File

@@ -16,6 +16,7 @@ import (
"go.probo.inc/probo/pkg/iam"
"go.probo.inc/probo/pkg/page"
"go.probo.inc/probo/pkg/probo"
"go.probo.inc/probo/pkg/resourcealias"
"go.probo.inc/probo/pkg/server/api/console/v1/dataloader"
"go.probo.inc/probo/pkg/server/api/console/v1/schema"
"go.probo.inc/probo/pkg/server/api/console/v1/types"
@@ -688,75 +689,6 @@ func (r *mutationResolver) DeleteCustomDomain(ctx context.Context, input types.D
}, nil
}
// SetTrustCenterAlias is the resolver for the setTrustCenterAlias field.
func (r *mutationResolver) SetTrustCenterAlias(ctx context.Context, input types.SetTrustCenterAliasInput) (*types.SetTrustCenterAliasPayload, error) {
scope, err := r.authorize(ctx, input.ResourceID, probo.ActionTrustCenterAliasSet)
if err != nil {
return nil, err
}
alias, err := r.probo.TrustCenterAliases.Create(
ctx,
scope,
probo.CreateTrustCenterAliasRequest{
ResourceID: input.ResourceID,
Alias: input.Alias,
},
)
if err != nil {
if errors.Is(err, coredata.ErrResourceAlreadyExists) {
return nil, gqlutils.Conflict(ctx, err)
}
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
}
if _, ok := errors.AsType[*probo.ErrTrustCenterAliasAuditReportMissing](err); ok {
return nil, gqlutils.Invalid(ctx, err)
}
if _, ok := errors.AsType[*probo.ErrTrustCenterAliasResourceInvalid](err); ok {
return nil, gqlutils.Invalid(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot set trust center alias", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.SetTrustCenterAliasPayload{
Alias: types.NewTrustCenterAlias(input.ResourceID, alias),
}, nil
}
// RemoveTrustCenterAlias is the resolver for the removeTrustCenterAlias field.
func (r *mutationResolver) RemoveTrustCenterAlias(ctx context.Context, input types.RemoveTrustCenterAliasInput) (*types.RemoveTrustCenterAliasPayload, error) {
scope, err := r.authorize(ctx, input.ResourceID, probo.ActionTrustCenterAliasRemove)
if err != nil {
return nil, err
}
_, err = r.probo.TrustCenterAliases.Remove(ctx, scope, input.ResourceID)
if err != nil {
if _, ok := errors.AsType[*probo.ErrTrustCenterAliasAuditReportMissing](err); ok {
return nil, gqlutils.Invalid(ctx, err)
}
if _, ok := errors.AsType[*probo.ErrTrustCenterAliasResourceInvalid](err); ok {
return nil, gqlutils.Invalid(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot remove trust center alias", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.RemoveTrustCenterAliasPayload{
DeletedResourceID: input.ResourceID,
}, nil
}
// Logo is the resolver for the logo field.
func (r *trustCenterResolver) Logo(ctx context.Context, obj *types.TrustCenter) (*types.File, error) {
if _, err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterGet); err != nil {
@@ -1085,27 +1017,6 @@ func (r *trustCenterAccessResolver) Permission(ctx context.Context, obj *types.T
return r.Resolver.Permission(ctx, obj, action)
}
// Organization is the resolver for the organization field.
func (r *trustCenterAliasResolver) Organization(ctx context.Context, obj *types.TrustCenterAlias) (*types.Organization, error) {
scope, err := r.authorize(ctx, obj.OrganizationID, probo.ActionOrganizationGet)
if err != nil {
return nil, err
}
organization, err := r.probo.Organizations.Get(ctx, scope, obj.OrganizationID)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot get organization", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewOrganization(organization), nil
}
// Document is the resolver for the document field.
func (r *trustCenterDocumentAccessResolver) Document(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Document, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionDocumentGet)
@@ -1229,12 +1140,12 @@ func (r *trustCenterFileResolver) File(ctx context.Context, obj *types.TrustCent
// Alias is the resolver for the alias field.
func (r *trustCenterFileResolver) Alias(ctx context.Context, obj *types.TrustCenterFile) (*string, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionTrustCenterFileGet)
scope, err := r.authorize(ctx, obj.ID, resourcealias.ActionAliasGet)
if err != nil {
return nil, err
}
return r.probo.TrustCenterAliases.GetByResourceID(ctx, scope, obj.ID)
return r.resourceAlias.GetByResourceID(ctx, scope, obj.ID)
}
// Organization is the resolver for the organization field.
@@ -1336,11 +1247,6 @@ func (r *Resolver) TrustCenterAccess() schema.TrustCenterAccessResolver {
return &trustCenterAccessResolver{r}
}
// TrustCenterAlias returns schema.TrustCenterAliasResolver implementation.
func (r *Resolver) TrustCenterAlias() schema.TrustCenterAliasResolver {
return &trustCenterAliasResolver{r}
}
// TrustCenterDocumentAccess returns schema.TrustCenterDocumentAccessResolver implementation.
func (r *Resolver) TrustCenterDocumentAccess() schema.TrustCenterDocumentAccessResolver {
return &trustCenterDocumentAccessResolver{r}
@@ -1376,7 +1282,6 @@ type complianceFrameworkResolver struct{ *Resolver }
type customDomainResolver struct{ *Resolver }
type trustCenterResolver struct{ *Resolver }
type trustCenterAccessResolver struct{ *Resolver }
type trustCenterAliasResolver struct{ *Resolver }
type trustCenterDocumentAccessResolver struct{ *Resolver }
type trustCenterDocumentAccessConnectionResolver struct{ *Resolver }
type trustCenterFileResolver struct{ *Resolver }

View File

@@ -19,16 +19,14 @@ import (
"go.probo.inc/probo/pkg/gid"
)
type TrustCenterAlias struct {
ResourceID gid.GID `json:"resourceId"`
Alias string `json:"alias"`
OrganizationID gid.GID `json:"-"`
type ResourceAlias struct {
ResourceID gid.GID `json:"resourceId"`
Alias string `json:"alias"`
}
func NewTrustCenterAlias(resourceID gid.GID, alias *coredata.TrustCenterAlias) *TrustCenterAlias {
return &TrustCenterAlias{
ResourceID: resourceID,
Alias: alias.Alias,
OrganizationID: alias.OrganizationID,
func NewResourceAlias(resourceID gid.GID, alias *coredata.ResourceAlias) *ResourceAlias {
return &ResourceAlias{
ResourceID: resourceID,
Alias: alias.Alias,
}
}