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 <bryan@probo.com>
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -149,8 +149,6 @@ var OAuth2ScopeMappings = map[coredata.OAuth2Scope][]string{
|
||||
ActionComplianceExternalURLDelete,
|
||||
ActionCustomDomainCreate,
|
||||
ActionCustomDomainDelete,
|
||||
ActionTrustCenterAliasSet,
|
||||
ActionTrustCenterAliasRemove,
|
||||
},
|
||||
ScopeV1ConnectorRead: {
|
||||
ActionConnectorList,
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
// Copyright (c) 2025-2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package 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}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
23
pkg/resourcealias/actions.go
Normal file
23
pkg/resourcealias/actions.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2025-2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package resourcealias
|
||||
|
||||
// Resource alias service actions.
|
||||
// Format: resourcealias:alias:<action>
|
||||
const (
|
||||
ActionAliasGet = "resourcealias:alias:get"
|
||||
ActionAliasSet = "resourcealias:alias:set"
|
||||
ActionAliasRemove = "resourcealias:alias:remove"
|
||||
)
|
||||
33
pkg/resourcealias/oauth2_scopes.go
Normal file
33
pkg/resourcealias/oauth2_scopes.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2025-2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package 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,
|
||||
},
|
||||
}
|
||||
55
pkg/resourcealias/policies.go
Normal file
55
pkg/resourcealias/policies.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2025-2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package 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)
|
||||
}
|
||||
185
pkg/resourcealias/service.go
Normal file
185
pkg/resourcealias/service.go
Normal file
@@ -0,0 +1,185 @@
|
||||
// Copyright (c) 2025-2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package 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
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright (c) 2025-2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package 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
|
||||
}
|
||||
Reference in New Issue
Block a user