From 9b0a5745a07e42b68adb73ee854ab50f747c2cc5 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Mon, 22 Jun 2026 10:58:49 +0200 Subject: [PATCH] Add resourcealias application service Introduce a standalone resourcealias package with its own service, IAM policies, and OAuth2 scopes so alias management no longer lives inside the trust center services. Remove the trust-center-specific alias services from probo and trust, and wire the new service into probod, the server, and the API layer. Signed-off-by: Bryan Frimin --- pkg/probo/actions.go | 4 - pkg/probo/oauth2_scopes.go | 2 - pkg/probo/service.go | 2 - pkg/probo/trust_center_alias_service.go | 211 ------------------------ pkg/probod/probod.go | 10 ++ pkg/resourcealias/actions.go | 23 +++ pkg/resourcealias/oauth2_scopes.go | 33 ++++ pkg/resourcealias/policies.go | 55 ++++++ pkg/resourcealias/service.go | 185 +++++++++++++++++++++ pkg/server/api/api.go | 5 + pkg/server/server.go | 3 + pkg/trust/compliance_page_service.go | 4 +- pkg/trust/service.go | 6 +- pkg/trust/trust_center_alias_service.go | 115 ------------- 14 files changed, 320 insertions(+), 338 deletions(-) delete mode 100644 pkg/probo/trust_center_alias_service.go create mode 100644 pkg/resourcealias/actions.go create mode 100644 pkg/resourcealias/oauth2_scopes.go create mode 100644 pkg/resourcealias/policies.go create mode 100644 pkg/resourcealias/service.go delete mode 100644 pkg/trust/trust_center_alias_service.go diff --git a/pkg/probo/actions.go b/pkg/probo/actions.go index c5615c8bf..7079b5953 100644 --- a/pkg/probo/actions.go +++ b/pkg/probo/actions.go @@ -75,10 +75,6 @@ const ( ActionComplianceExternalURLUpdate = "core:compliance-external-url:update" ActionComplianceExternalURLDelete = "core:compliance-external-url:delete" - // TrustCenterAlias actions - ActionTrustCenterAliasSet = "core:trust-center-alias:set" - ActionTrustCenterAliasRemove = "core:trust-center-alias:remove" - // TrustCenterFile actions ActionTrustCenterFileGet = "core:trust-center-file:get" ActionTrustCenterFileList = "core:trust-center-file:list" diff --git a/pkg/probo/oauth2_scopes.go b/pkg/probo/oauth2_scopes.go index 44ba7c6b2..ea32a783d 100644 --- a/pkg/probo/oauth2_scopes.go +++ b/pkg/probo/oauth2_scopes.go @@ -149,8 +149,6 @@ var OAuth2ScopeMappings = map[coredata.OAuth2Scope][]string{ ActionComplianceExternalURLDelete, ActionCustomDomainCreate, ActionCustomDomainDelete, - ActionTrustCenterAliasSet, - ActionTrustCenterAliasRemove, }, ScopeV1ConnectorRead: { ActionConnectorList, diff --git a/pkg/probo/service.go b/pkg/probo/service.go index fe4a06cc1..8a82f3a7d 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -107,7 +107,6 @@ type ( TrustCenters *TrustCenterService TrustCenterAccesses *TrustCenterAccessService TrustCenterReferences *TrustCenterReferenceService - TrustCenterAliases *TrustCenterAliasService TrustCenterFiles *TrustCenterFileService ComplianceFrameworks *ComplianceFrameworkService ComplianceExternalURLs *ComplianceExternalURLService @@ -229,7 +228,6 @@ func NewService( svc.TrustCenters = &TrustCenterService{svc: svc} svc.TrustCenterAccesses = &TrustCenterAccessService{svc: svc} svc.TrustCenterReferences = &TrustCenterReferenceService{svc: svc} - svc.TrustCenterAliases = &TrustCenterAliasService{svc: svc} svc.ComplianceFrameworks = &ComplianceFrameworkService{svc: svc} svc.ComplianceExternalURLs = &ComplianceExternalURLService{svc: svc} svc.TrustCenterFiles = &TrustCenterFileService{ diff --git a/pkg/probo/trust_center_alias_service.go b/pkg/probo/trust_center_alias_service.go deleted file mode 100644 index f8e72d633..000000000 --- a/pkg/probo/trust_center_alias_service.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) 2025-2026 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 ( - "context" - "errors" - "fmt" - - "go.gearno.de/kit/pg" - "go.probo.inc/probo/pkg/coredata" - "go.probo.inc/probo/pkg/gid" - "go.probo.inc/probo/pkg/validator" -) - -type ( - TrustCenterAliasService struct { - svc *Service - } - - CreateTrustCenterAliasRequest struct { - ResourceID gid.GID - Alias string - } - - ErrTrustCenterAliasResourceInvalid struct { - ResourceID gid.GID - } - - ErrTrustCenterAliasAuditReportMissing struct { - AuditID gid.GID - } -) - -func (e ErrTrustCenterAliasResourceInvalid) Error() string { - return fmt.Sprintf("resource %q cannot have a trust center alias", e.ResourceID) -} - -func (e ErrTrustCenterAliasAuditReportMissing) Error() string { - return fmt.Sprintf("audit %q has no report file", e.AuditID) -} - -func (req *CreateTrustCenterAliasRequest) Validate() error { - v := validator.New() - - v.Check(req.ResourceID, "resource_id", validator.Required(), validator.GID()) - v.Check(req.Alias, "alias", validator.Required(), validator.Slug(NameMaxLength)) - - return v.Error() -} - -func (s TrustCenterAliasService) ResolveAlias( - ctx context.Context, - scope coredata.Scoper, - organizationID gid.GID, - alias string, -) (gid.GID, error) { - record := &coredata.TrustCenterAlias{} - - err := s.svc.pg.WithConn( - ctx, - func(ctx context.Context, conn pg.Querier) error { - if err := record.LoadByAlias(ctx, conn, scope, organizationID, alias); err != nil { - return fmt.Errorf("cannot load trust center alias: %w", err) - } - - return nil - }, - ) - if err != nil { - return gid.Nil, err - } - - return record.ResourceID, nil -} - -func (s TrustCenterAliasService) Create( - ctx context.Context, - scope coredata.Scoper, - req CreateTrustCenterAliasRequest, -) (*coredata.TrustCenterAlias, error) { - if err := req.Validate(); err != nil { - return nil, err - } - - aliasResourceID, err := s.aliasResourceID(ctx, scope, req.ResourceID) - if err != nil { - return nil, err - } - - alias := &coredata.TrustCenterAlias{} - - err = s.svc.pg.WithConn( - ctx, - func(ctx context.Context, conn pg.Querier) error { - if err := alias.Upsert(ctx, conn, scope, aliasResourceID, req.Alias); err != nil { - return fmt.Errorf("cannot create trust center alias: %w", err) - } - - return nil - }, - ) - if err != nil { - return nil, err - } - - return alias, nil -} - -func (s TrustCenterAliasService) Remove( - ctx context.Context, - scope coredata.Scoper, - resourceID gid.GID, -) (gid.GID, error) { - aliasResourceID, err := s.aliasResourceID(ctx, scope, resourceID) - if err != nil { - return gid.Nil, err - } - - err = s.svc.pg.WithConn( - ctx, - func(ctx context.Context, conn pg.Querier) error { - alias := &coredata.TrustCenterAlias{ResourceID: aliasResourceID} - if err := alias.Delete(ctx, conn, scope); err != nil { - return fmt.Errorf("cannot remove trust center alias: %w", err) - } - - return nil - }, - ) - if err != nil { - return gid.Nil, err - } - - return aliasResourceID, nil -} - -func (s TrustCenterAliasService) GetByResourceID( - ctx context.Context, - scope coredata.Scoper, - resourceID gid.GID, -) (*string, error) { - aliasResourceID, err := s.aliasResourceID(ctx, scope, resourceID) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, nil - } - - return nil, err - } - - alias := &coredata.TrustCenterAlias{} - - err = s.svc.pg.WithConn( - ctx, - func(ctx context.Context, conn pg.Querier) error { - if err := alias.LoadByResourceID(ctx, conn, scope, aliasResourceID); err != nil { - return fmt.Errorf("cannot load trust center alias: %w", err) - } - - return nil - }, - ) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, nil - } - - return nil, err - } - - return &alias.Alias, nil -} - -func (s TrustCenterAliasService) aliasResourceID( - ctx context.Context, - scope coredata.Scoper, - resourceID gid.GID, -) (gid.GID, error) { - switch resourceID.EntityType() { - case coredata.DocumentEntityType, coredata.TrustCenterFileEntityType: - return resourceID, nil - - case coredata.AuditEntityType: - audit, err := s.svc.Audits.Get(ctx, scope, resourceID) - if err != nil { - return gid.Nil, err - } - - if audit.ReportFileID == nil { - return gid.Nil, &ErrTrustCenterAliasAuditReportMissing{AuditID: audit.ID} - } - - return *audit.ReportFileID, nil - - default: - return gid.Nil, &ErrTrustCenterAliasResourceInvalid{ResourceID: resourceID} - } -} diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index 1aa95a3b5..758675c90 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -66,6 +66,7 @@ import ( "go.probo.inc/probo/pkg/mailer" "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/securecookie" "go.probo.inc/probo/pkg/server" @@ -583,6 +584,8 @@ func (impl *Implm) Run( return fmt.Errorf("cannot create probo service: %w", err) } + resourceAliasService := resourcealias.NewService(pgClient) + trustService := trust.NewService( pgClient, s3Client, @@ -595,6 +598,7 @@ func (impl *Implm) Run( fileManagerService, l, slackService, + resourceAliasService, ) accessReviewService := accessreview.NewService( @@ -609,6 +613,11 @@ func (impl *Implm) Run( iamService.Authorizer.RegisterPolicySet(agentrun.PolicySet()) iamService.Authorizer.RegisterPolicySet(accessreview.PolicySet()) + iamService.Authorizer.RegisterPolicySet(resourcealias.PolicySet()) + iamService.OAuth2ScopeRegistry.Register(agentrun.OAuth2ScopeMappings) + iamService.OAuth2ScopeRegistry.Register(accessreview.OAuth2ScopeMappings) + iamService.OAuth2ScopeRegistry.Register(iam.IAMOAuth2ScopeMappings) + iamService.OAuth2ScopeRegistry.Register(resourcealias.OAuth2ScopeMappings) thirdPartyService := thirdparty.NewService(pgClient, fileManagerService, thirdPartyVetter) riskManagementService := riskmanagement.NewService(pgClient) @@ -618,6 +627,7 @@ func (impl *Implm) Run( AllowedOrigins: impl.cfg.Api.Cors.AllowedOrigins, ExtraHeaderFields: impl.cfg.Api.ExtraHeaderFields, Probo: proboService, + ResourceAlias: resourceAliasService, File: fileManagerService, IAM: iamService, Trust: trustService, diff --git a/pkg/resourcealias/actions.go b/pkg/resourcealias/actions.go new file mode 100644 index 000000000..8220a9d0e --- /dev/null +++ b/pkg/resourcealias/actions.go @@ -0,0 +1,23 @@ +// Copyright (c) 2025-2026 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 resourcealias + +// Resource alias service actions. +// Format: resourcealias:alias: +const ( + ActionAliasGet = "resourcealias:alias:get" + ActionAliasSet = "resourcealias:alias:set" + ActionAliasRemove = "resourcealias:alias:remove" +) diff --git a/pkg/resourcealias/oauth2_scopes.go b/pkg/resourcealias/oauth2_scopes.go new file mode 100644 index 000000000..ec33932b4 --- /dev/null +++ b/pkg/resourcealias/oauth2_scopes.go @@ -0,0 +1,33 @@ +// Copyright (c) 2025-2026 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 resourcealias + +import "go.probo.inc/probo/pkg/coredata" + +const ( + ScopeV1ResourceAliasRead coredata.OAuth2Scope = "v1:resource-alias:read" + ScopeV1ResourceAlias coredata.OAuth2Scope = "v1:resource-alias" +) + +// OAuth2ScopeMappings maps OAuth2 scopes to resource-alias actions. +var OAuth2ScopeMappings = map[coredata.OAuth2Scope][]string{ + ScopeV1ResourceAliasRead: { + ActionAliasGet, + }, + ScopeV1ResourceAlias: { + ActionAliasSet, + ActionAliasRemove, + }, +} diff --git a/pkg/resourcealias/policies.go b/pkg/resourcealias/policies.go new file mode 100644 index 000000000..cabece1e4 --- /dev/null +++ b/pkg/resourcealias/policies.go @@ -0,0 +1,55 @@ +// Copyright (c) 2025-2026 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 resourcealias + +import ( + "go.probo.inc/probo/pkg/iam" + "go.probo.inc/probo/pkg/iam/policy" +) + +var organizationCondition = policy.Equals("principal.organization_id", "resource.organization_id") + +// FullAccessPolicy grants complete resource-alias access to organization owners +// and admins. +var FullAccessPolicy = policy.NewPolicy( + "resourcealias:full-access", + "Resource Alias Full Access", + policy.Allow( + ActionAliasGet, + ActionAliasSet, + ActionAliasRemove, + ).WithSID("resource-alias-full-access").When(organizationCondition), +).WithDescription("Full resource-alias access including set and remove") + +// ReadAccessPolicy grants read-only resource-alias access to viewers and auditors. +var ReadAccessPolicy = policy.NewPolicy( + "resourcealias:read-access", + "Resource Alias Read Access", + policy.Allow( + ActionAliasGet, + ).WithSID("resource-alias-read-access").When(organizationCondition), +).WithDescription("Read-only resource-alias access") + +// PolicySet returns the PolicySet for the resource-alias service. It is owned by +// this package and registered into the authorizer at composition time so the +// resource-alias authorization rules live alongside the resource-alias domain +// logic instead of in the core probo policy set. +func PolicySet() *iam.PolicySet { + return iam.NewPolicySet(). + AddRolePolicy("OWNER", FullAccessPolicy). + AddRolePolicy("ADMIN", FullAccessPolicy). + AddRolePolicy("VIEWER", ReadAccessPolicy). + AddRolePolicy("AUDITOR", ReadAccessPolicy) +} diff --git a/pkg/resourcealias/service.go b/pkg/resourcealias/service.go new file mode 100644 index 000000000..c98d5cc36 --- /dev/null +++ b/pkg/resourcealias/service.go @@ -0,0 +1,185 @@ +// Copyright (c) 2025-2026 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 resourcealias + +import ( + "context" + "errors" + "fmt" + + "go.gearno.de/kit/pg" + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/gid" + "go.probo.inc/probo/pkg/validator" +) + +const aliasMaxLength = 100 + +type ( + Service struct { + pg *pg.Client + } + + CreateRequest struct { + ResourceID gid.GID + Alias string + } +) + +func NewService(pgClient *pg.Client) *Service { + return &Service{ + pg: pgClient, + } +} + +func (req *CreateRequest) Validate() error { + v := validator.New() + + v.Check(req.ResourceID, "resource_id", validator.Required(), validator.GID()) + v.Check(req.Alias, "alias", validator.Required(), validator.Slug(aliasMaxLength)) + + return v.Error() +} + +func (s *Service) ResolveAlias( + ctx context.Context, + scope coredata.Scoper, + alias string, +) (gid.GID, error) { + record := &coredata.ResourceAlias{} + + err := s.pg.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + if err := record.LoadByAlias(ctx, conn, scope, alias); err != nil { + return fmt.Errorf("cannot load resource alias: %w", err) + } + + return nil + }, + ) + if err != nil { + return gid.Nil, err + } + + return record.ResourceID, nil +} + +func (s *Service) Create( + ctx context.Context, + scope coredata.Scoper, + req CreateRequest, +) (*coredata.ResourceAlias, error) { + if err := req.Validate(); err != nil { + return nil, err + } + + alias := &coredata.ResourceAlias{} + + err := s.pg.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + if err := alias.Upsert(ctx, conn, scope, req.ResourceID, req.Alias); err != nil { + return fmt.Errorf("cannot create resource alias: %w", err) + } + + return nil + }, + ) + if err != nil { + return nil, err + } + + return alias, nil +} + +func (s *Service) Remove( + ctx context.Context, + scope coredata.Scoper, + resourceID gid.GID, +) error { + return s.pg.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + alias := &coredata.ResourceAlias{ResourceID: resourceID} + if err := alias.Delete(ctx, conn, scope); err != nil { + return fmt.Errorf("cannot remove resource alias: %w", err) + } + + return nil + }, + ) +} + +func (s *Service) GetByResourceID( + ctx context.Context, + scope coredata.Scoper, + resourceID gid.GID, +) (*string, error) { + record := &coredata.ResourceAlias{} + + err := s.pg.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + if err := record.LoadByResourceID(ctx, conn, scope, resourceID); err != nil { + return fmt.Errorf("cannot load resource alias: %w", err) + } + + return nil + }, + ) + if err != nil { + if errors.Is(err, coredata.ErrResourceNotFound) { + return nil, nil + } + + return nil, err + } + + return &record.Alias, nil +} + +func (s *Service) LoadByResourceIDs( + ctx context.Context, + scope coredata.Scoper, + resourceIDs []gid.GID, +) (map[gid.GID]string, error) { + if len(resourceIDs) == 0 { + return map[gid.GID]string{}, nil + } + + var aliases coredata.ResourceAliases + + err := s.pg.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + if err := aliases.LoadByResourceIDs(ctx, conn, scope, resourceIDs); err != nil { + return fmt.Errorf("cannot load resource aliases: %w", err) + } + + return nil + }, + ) + if err != nil { + return nil, err + } + + result := make(map[gid.GID]string, len(aliases)) + for _, alias := range aliases { + result[alias.ResourceID] = alias.Alias + } + + return result, nil +} diff --git a/pkg/server/api/api.go b/pkg/server/api/api.go index d25f1e9f6..2cde6be83 100644 --- a/pkg/server/api/api.go +++ b/pkg/server/api/api.go @@ -37,6 +37,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/securecookie" connect_v1 "go.probo.inc/probo/pkg/server/api/connect/v1" @@ -56,6 +57,7 @@ type ( BaseURL *baseurl.BaseURL AllowedOrigins []string Probo *probo.Service + ResourceAlias *resourcealias.Service File *filemanager.Service IAM *iam.Service Trust *trust.Service @@ -179,6 +181,7 @@ func NewServer(cfg Config) (*Server, error) { cfg.Logger.Named("trust.v1"), cfg.IAM, cfg.Trust, + cfg.ResourceAlias, cfg.File, cfg.ESign, cfg.Mailman, @@ -189,6 +192,7 @@ func NewServer(cfg Config) (*Server, error) { consoleHandler: console_v1.NewMux( cfg.Logger.Named("console.v1"), cfg.Probo, + cfg.ResourceAlias, cfg.IAM, cfg.ESign, cfg.AccessReview, @@ -221,6 +225,7 @@ func NewServer(cfg Config) (*Server, error) { mcpHandler: mcp_v1.NewMux( cfg.Logger.Named("mcp.v1"), cfg.Probo, + cfg.ResourceAlias, cfg.ThirdParty, cfg.IAM, cfg.AccessReview, diff --git a/pkg/server/server.go b/pkg/server/server.go index 1cf2f25bd..f879360f8 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -37,6 +37,7 @@ import ( "go.probo.inc/probo/pkg/iam/oauth2" "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/securecookie" "go.probo.inc/probo/pkg/server/api" @@ -55,6 +56,7 @@ type Config struct { AllowedOrigins []string ExtraHeaderFields map[string]string Probo *probo.Service + ResourceAlias *resourcealias.Service File *filemanager.Service IAM *iam.Service Trust *trust.Service @@ -94,6 +96,7 @@ func NewServer(cfg Config) (*Server, error) { BaseURL: cfg.BaseURL, AllowedOrigins: cfg.AllowedOrigins, Probo: cfg.Probo, + ResourceAlias: cfg.ResourceAlias, File: cfg.File, IAM: cfg.IAM, Trust: cfg.Trust, diff --git a/pkg/trust/compliance_page_service.go b/pkg/trust/compliance_page_service.go index 267ff7145..65d425378 100644 --- a/pkg/trust/compliance_page_service.go +++ b/pkg/trust/compliance_page_service.go @@ -364,9 +364,9 @@ func (s *Service) fetchDocumentIDs(ctx context.Context, scope coredata.Scoper, o cursorKey = &ck } - aliases, err := s.TrustCenterAliases.LoadByResourceIDs(ctx, scope, resourceIDs) + aliases, err := s.resourceAlias.LoadByResourceIDs(ctx, scope, resourceIDs) if err != nil { - return nil, fmt.Errorf("cannot load trust center aliases: %w", err) + return nil, fmt.Errorf("cannot load resource aliases: %w", err) } paths := make([]string, 0, len(resourceIDs)) diff --git a/pkg/trust/service.go b/pkg/trust/service.go index b8fa1371b..e6f3341dd 100644 --- a/pkg/trust/service.go +++ b/pkg/trust/service.go @@ -31,6 +31,7 @@ import ( "go.probo.inc/probo/pkg/html2pdf" "go.probo.inc/probo/pkg/iam" "go.probo.inc/probo/pkg/probo" + "go.probo.inc/probo/pkg/resourcealias" "go.probo.inc/probo/pkg/slack" ) @@ -62,7 +63,7 @@ type ( Reports *ReportService Organizations *OrganizationService ComplianceExternalURLs *ComplianceExternalURLService - TrustCenterAliases *TrustCenterAliasService + resourceAlias *resourcealias.Service } ) @@ -78,6 +79,7 @@ func NewService( fileManagerService *filemanager.Service, logger *log.Logger, slack *slack.Service, + resourceAliasSvc *resourcealias.Service, ) *Service { svc := &Service{ pg: pgClient, @@ -91,6 +93,7 @@ func NewService( fileManager: fileManagerService, logger: logger, slack: slack, + resourceAlias: resourceAliasSvc, } svc.TrustCenters = &TrustCenterService{svc: svc} svc.Documents = &DocumentService{svc: svc, html2pdfConverter: html2pdfConverter} @@ -104,7 +107,6 @@ func NewService( svc.Reports = &ReportService{svc: svc} svc.Organizations = &OrganizationService{svc: svc} svc.ComplianceExternalURLs = &ComplianceExternalURLService{svc: svc} - svc.TrustCenterAliases = &TrustCenterAliasService{svc: svc} return svc } diff --git a/pkg/trust/trust_center_alias_service.go b/pkg/trust/trust_center_alias_service.go deleted file mode 100644 index 2b64b95eb..000000000 --- a/pkg/trust/trust_center_alias_service.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2025-2026 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 trust - -import ( - "context" - "errors" - "fmt" - - "go.gearno.de/kit/pg" - "go.probo.inc/probo/pkg/coredata" - "go.probo.inc/probo/pkg/gid" -) - -type TrustCenterAliasService struct { - svc *Service -} - -func (s TrustCenterAliasService) ResolveAlias( - ctx context.Context, - scope coredata.Scoper, - organizationID gid.GID, - alias string, -) (gid.GID, error) { - record := &coredata.TrustCenterAlias{} - - err := s.svc.pg.WithConn( - ctx, - func(ctx context.Context, conn pg.Querier) error { - if err := record.LoadByAlias(ctx, conn, scope, organizationID, alias); err != nil { - return fmt.Errorf("cannot load trust center alias: %w", err) - } - - return nil - }, - ) - if err != nil { - return gid.Nil, err - } - - return record.ResourceID, nil -} - -func (s TrustCenterAliasService) GetByStorageResourceID( - ctx context.Context, - scope coredata.Scoper, - storageResourceID gid.GID, -) (*string, error) { - record := &coredata.TrustCenterAlias{} - - err := s.svc.pg.WithConn( - ctx, - func(ctx context.Context, conn pg.Querier) error { - if err := record.LoadByResourceID(ctx, conn, scope, storageResourceID); err != nil { - return fmt.Errorf("cannot load trust center alias: %w", err) - } - - return nil - }, - ) - if err != nil { - if errors.Is(err, coredata.ErrResourceNotFound) { - return nil, nil - } - - return nil, err - } - - return &record.Alias, nil -} - -func (s TrustCenterAliasService) LoadByResourceIDs( - ctx context.Context, - scope coredata.Scoper, - resourceIDs []gid.GID, -) (map[gid.GID]string, error) { - if len(resourceIDs) == 0 { - return map[gid.GID]string{}, nil - } - - var aliases coredata.TrustCenterAliases - - err := s.svc.pg.WithConn( - ctx, - func(ctx context.Context, conn pg.Querier) error { - if err := aliases.LoadByResourceIDs(ctx, conn, scope, resourceIDs); err != nil { - return fmt.Errorf("cannot load trust center aliases: %w", err) - } - - return nil - }, - ) - if err != nil { - return nil, err - } - - result := make(map[gid.GID]string, len(aliases)) - for _, alias := range aliases { - result[alias.ResourceID] = alias.Alias - } - - return result, nil -}