From 7e0d187dcf9f41dca53c0ee53a5902489828e3ce Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Fri, 17 Jul 2026 16:19:39 +0200 Subject: [PATCH] Flatten compliance portal package layout Remove the root complianceportal package and the resolver facade that existed only to break an IAM import cycle. Admin policies, domain URL helpers, and actions live under management; visitor OAuth metadata, brand URLs, and public read paths live under visitor. Drop the duplicate trust API magic-link mutations now that Connect handles portal auth, and stop IAM from owning compliance page email branding. Signed-off-by: Bryan Frimin --- e2e/trust/trust_center_slug_test.go | 66 ++++++ pkg/complianceportal/domain_resolver.go | 51 ----- .../management/access_service.go | 18 +- .../{ => management}/actions.go | 2 +- .../management/custom_link_service.go | 12 +- .../resolver.go => management/domain.go} | 53 ++--- .../management/domain_service.go | 171 +++++----------- .../{ => management}/errors.go | 2 +- .../management/file_service.go | 24 +-- .../management/framework_service.go | 12 +- .../{ => management}/oauth2_scopes.go | 2 +- .../{ => management}/policies.go | 2 +- .../management/portal_service.go | 193 +++++++++--------- .../management/reference_service.go | 50 ++--- pkg/complianceportal/management/service.go | 4 +- pkg/complianceportal/{ => visitor}/brand.go | 2 +- pkg/complianceportal/{ => visitor}/cimd.go | 2 +- .../{ => visitor}/cimd_test.go | 8 +- .../visitor/compliance_framework_service.go | 4 +- .../visitor/compliance_page_service.go | 48 ++--- .../visitor/custom_link_service.go | 4 +- .../visitor/document_service.go | 2 +- pkg/complianceportal/visitor/errors.go | 26 +-- .../visitor/portal_access_service.go | 70 +++---- .../visitor/portal_file_service.go | 12 +- .../visitor/portal_reference_service.go | 10 +- .../visitor/portal_service.go | 62 +++--- pkg/complianceportal/visitor/service.go | 77 +++---- .../visitor/third_party_service.go | 12 +- pkg/coredata/migrations/20260717T121103Z.sql | 21 ++ pkg/iam/auth_service.go | 30 +-- pkg/iam/compliance_page_service.go | 163 --------------- pkg/iam/organization_service.go | 2 +- pkg/iam/service.go | 24 +-- pkg/mailman/compliance_mailing_list.go | 4 +- pkg/mailman/service.go | 35 ++-- pkg/probod/probod.go | 37 ++-- pkg/server/api/api.go | 4 + pkg/server/api/complianceportal/oauth.go | 16 +- .../api/complianceportal/v1/auth_resolvers.go | 136 ------------ .../api/complianceportal/v1/base_resolvers.go | 2 +- .../complianceportal/v1/graphql/auth.graphql | 21 -- pkg/server/api/complianceportal/v1/mux.go | 3 +- .../v1/oauth_client_metadata_handler.go | 4 +- .../v1/trust_center_resolvers.go | 10 +- pkg/server/api/console/v1/base_resolvers.go | 6 +- pkg/server/api/console/v1/graphql_handler.go | 3 + .../api/console/v1/mailing_list_resolvers.go | 24 +-- .../api/console/v1/organization_resolvers.go | 6 +- pkg/server/api/console/v1/resolver.go | 16 +- .../api/console/v1/trust_center_resolvers.go | 87 ++++---- pkg/server/api/mcp/v1/resolver.go | 2 + pkg/server/api/mcp/v1/schema.resolvers.go | 47 +++-- pkg/server/api/mcp/v1/v1_handler.go | 3 + pkg/server/server.go | 3 + pkg/slug/slug.go | 13 ++ pkg/slug/slug_test.go | 75 +++++-- 57 files changed, 737 insertions(+), 1061 deletions(-) create mode 100644 e2e/trust/trust_center_slug_test.go delete mode 100644 pkg/complianceportal/domain_resolver.go rename pkg/complianceportal/{ => management}/actions.go (99%) rename pkg/complianceportal/{resolver/resolver.go => management/domain.go} (58%) rename pkg/complianceportal/{ => management}/errors.go (98%) rename pkg/complianceportal/{ => management}/oauth2_scopes.go (99%) rename pkg/complianceportal/{ => management}/policies.go (99%) rename pkg/complianceportal/{ => visitor}/brand.go (98%) rename pkg/complianceportal/{ => visitor}/cimd.go (99%) rename pkg/complianceportal/{ => visitor}/cimd_test.go (95%) create mode 100644 pkg/coredata/migrations/20260717T121103Z.sql delete mode 100644 pkg/iam/compliance_page_service.go diff --git a/e2e/trust/trust_center_slug_test.go b/e2e/trust/trust_center_slug_test.go new file mode 100644 index 000000000..3efc8152c --- /dev/null +++ b/e2e/trust/trust_center_slug_test.go @@ -0,0 +1,66 @@ +// Copyright (c) 2026 Probo Inc . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package trust_test + +import ( + "regexp" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.probo.inc/probo/e2e/internal/testutil" +) + +func TestTrustCenter_SlugHasEntropySuffix(t *testing.T) { + t.Parallel() + + owner := testutil.NewClient(t, testutil.RoleOwner) + organizationID := owner.GetOrganizationID().String() + + const query = ` + query($organizationId: ID!) { + node(id: $organizationId) { + ... on Organization { + trustCenter { + slug + } + } + } + } + ` + + var result struct { + Node struct { + TrustCenter struct { + Slug string `json:"slug"` + } `json:"trustCenter"` + } `json:"node"` + } + + err := owner.Execute(query, map[string]any{ + "organizationId": organizationID, + }, &result) + require.NoError(t, err) + require.NotEmpty(t, result.Node.TrustCenter.Slug) + + slugWithEntropy := regexp.MustCompile(`^[a-z0-9-]+-[0-9a-f]{8}$`) + assert.Regexp(t, slugWithEntropy, result.Node.TrustCenter.Slug) +} diff --git a/pkg/complianceportal/domain_resolver.go b/pkg/complianceportal/domain_resolver.go deleted file mode 100644 index 23e5d4396..000000000 --- a/pkg/complianceportal/domain_resolver.go +++ /dev/null @@ -1,51 +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 complianceportal - -import ( - "context" - - "go.gearno.de/kit/pg" - "go.probo.inc/probo/pkg/complianceportal/resolver" - "go.probo.inc/probo/pkg/coredata" -) - -// EffectiveDomainForTrustCenter returns the domain a compliance page is served -// under: the custom domain when it has an active certificate, otherwise the -// default subdomain when its certificate is active. It returns nil when no -// serving domain is available yet. -// -// It is the single certificate-status-aware domain resolver shared by the -// management and visitor sub-packages. -func EffectiveDomainForTrustCenter( - ctx context.Context, - conn pg.Querier, - scope coredata.Scoper, - trustCenter *coredata.TrustCenter, -) (*coredata.CustomDomain, error) { - return resolver.EffectiveDomainForTrustCenter(ctx, conn, scope, trustCenter) -} - -// PublicURLForTrustCenter returns the canonical public URL of a compliance -// page on its dedicated domain. -func PublicURLForTrustCenter( - ctx context.Context, - conn pg.Querier, - scope coredata.Scoper, - trustCenter *coredata.TrustCenter, - baseDomain string, -) (string, error) { - return resolver.PublicURLForTrustCenter(ctx, conn, scope, trustCenter, baseDomain) -} diff --git a/pkg/complianceportal/management/access_service.go b/pkg/complianceportal/management/access_service.go index ce769d96b..039a85745 100644 --- a/pkg/complianceportal/management/access_service.go +++ b/pkg/complianceportal/management/access_service.go @@ -83,7 +83,7 @@ func (utcar *UpdateAccessRequest) Validate() error { func (s *Service) ListAccesses( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, cursor *page.Cursor[coredata.TrustCenterAccessOrderField], ) (*page.Page[*coredata.TrustCenterAccess, coredata.TrustCenterAccessOrderField], error) { var accesses coredata.TrustCenterAccesses @@ -91,7 +91,7 @@ func (s *Service) ListAccesses( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - return accesses.LoadByTrustCenterID(ctx, conn, scope, trustCenterID, cursor) + return accesses.LoadByTrustCenterID(ctx, conn, scope, compliancePageID, cursor) }, ) if err != nil { @@ -244,7 +244,7 @@ func (s *Service) UpdateAccess( access = &coredata.TrustCenterAccess{} if err := access.LoadByID(ctx, tx, scope, req.ID); err != nil { - return fmt.Errorf("cannot load trust center access: %w", err) + return fmt.Errorf("cannot load compliance page access: %w", err) } var tcdas coredata.TrustCenterDocumentAccesses @@ -310,11 +310,11 @@ func (s *Service) UpdateAccess( trustCenterFiles := &coredata.TrustCenterFiles{} if err := trustCenterFiles.LoadByIDs(ctx, tx, scope, trustCenterFileIDs); err != nil { - return fmt.Errorf("cannot load trust center files: %w", err) + return fmt.Errorf("cannot load compliance page files: %w", err) } if err := tcdas.MergeTrustCenterFileAccesses(ctx, tx, scope, access.OrganizationID, access.ID, fileData); err != nil { - return fmt.Errorf("cannot merge trust center file accesses: %w", err) + return fmt.Errorf("cannot merge compliance page file accesses: %w", err) } } @@ -358,11 +358,11 @@ func (s *Service) DeleteAccess( access := &coredata.TrustCenterAccess{} if err := access.LoadByID(ctx, tx, scope, trustCenterAccessID); err != nil { - return fmt.Errorf("cannot load trust center access: %w", err) + return fmt.Errorf("cannot load compliance page access: %w", err) } if err := access.Delete(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot delete trust center access: %w", err) + return fmt.Errorf("cannot delete compliance page access: %w", err) } return nil @@ -387,7 +387,7 @@ func (s *Service) sendAccessEmail( access.UpdatedAt = now if err := access.Update(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot update trust center access with expiration: %w", err) + return fmt.Errorf("cannot update compliance page access with expiration: %w", err) } profile := &coredata.MembershipProfile{} @@ -410,7 +410,7 @@ func (s *Service) sendAccessEmail( subject, textBody, htmlBody, err := emailPresenter.RenderTrustCenterAccess(ctx, organization.Name) if err != nil { - return fmt.Errorf("cannot render trust center access email: %w", err) + return fmt.Errorf("cannot render compliance page access email: %w", err) } accessEmail := coredata.NewEmail( diff --git a/pkg/complianceportal/actions.go b/pkg/complianceportal/management/actions.go similarity index 99% rename from pkg/complianceportal/actions.go rename to pkg/complianceportal/management/actions.go index 1def1d104..7ab4394d8 100644 --- a/pkg/complianceportal/actions.go +++ b/pkg/complianceportal/management/actions.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package complianceportal +package management const ( // Custom domain actions. diff --git a/pkg/complianceportal/management/custom_link_service.go b/pkg/complianceportal/management/custom_link_service.go index e7046d97d..8f0bf70ca 100644 --- a/pkg/complianceportal/management/custom_link_service.go +++ b/pkg/complianceportal/management/custom_link_service.go @@ -78,7 +78,7 @@ func (r *DeleteCustomLinkRequest) Validate() error { func (s *Service) ListCustomLinks( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, cursor *page.Cursor[coredata.ComplianceCustomLinkOrderField], ) (*page.Page[*coredata.ComplianceCustomLink, coredata.ComplianceCustomLinkOrderField], error) { var items coredata.ComplianceCustomLinks @@ -86,7 +86,7 @@ func (s *Service) ListCustomLinks( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - if err := items.LoadByTrustCenterID(ctx, conn, scope, trustCenterID, cursor); err != nil { + if err := items.LoadByTrustCenterID(ctx, conn, scope, compliancePageID, cursor); err != nil { return fmt.Errorf("cannot load custom links: %w", err) } @@ -117,14 +117,14 @@ func (s *Service) CreateCustomLink( err := s.pg.WithTx( ctx, func(ctx context.Context, tx pg.Tx) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, tx, scope, req.TrustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, tx, scope, req.TrustCenterID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } item = &coredata.ComplianceCustomLink{ ID: id, - OrganizationID: trustCenter.OrganizationID, + OrganizationID: compliancePage.OrganizationID, TrustCenterID: req.TrustCenterID, Name: req.Name, URL: req.URL, diff --git a/pkg/complianceportal/resolver/resolver.go b/pkg/complianceportal/management/domain.go similarity index 58% rename from pkg/complianceportal/resolver/resolver.go rename to pkg/complianceportal/management/domain.go index 67b84c4bd..692d065ed 100644 --- a/pkg/complianceportal/resolver/resolver.go +++ b/pkg/complianceportal/management/domain.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package resolver +package management import ( "context" @@ -23,29 +23,25 @@ import ( "go.probo.inc/probo/pkg/gid" ) -// EffectiveDomainForTrustCenter returns the domain a compliance page is served -// under: the custom domain when it has an active certificate, otherwise the -// default subdomain when its certificate is active. It returns nil when no -// serving domain is available yet. -func EffectiveDomainForTrustCenter( +func (s *Service) EffectiveDomainForCompliancePage( ctx context.Context, conn pg.Querier, scope coredata.Scoper, - trustCenter *coredata.TrustCenter, + compliancePage *coredata.TrustCenter, ) (*coredata.CustomDomain, error) { - byID, active, err := loadDomains(ctx, conn, scope, trustCenter) + byID, active, err := loadDomains(ctx, conn, scope, compliancePage) if err != nil { return nil, err } - if trustCenter.CustomDomainID != nil { - if d := byID[*trustCenter.CustomDomainID]; d != nil && active[d.ID] { + if compliancePage.CustomDomainID != nil { + if d := byID[*compliancePage.CustomDomainID]; d != nil && active[d.ID] { return d, nil } } - if trustCenter.DefaultDomainID != nil { - if d := byID[*trustCenter.DefaultDomainID]; d != nil && active[d.ID] { + if compliancePage.DefaultDomainID != nil { + if d := byID[*compliancePage.DefaultDomainID]; d != nil && active[d.ID] { return d, nil } } @@ -53,20 +49,13 @@ func EffectiveDomainForTrustCenter( return nil, nil } -// PublicURLForTrustCenter returns the canonical public URL of a compliance -// page. Compliance pages are always served on a dedicated domain: the custom -// domain when its certificate is active, otherwise the default probopage -// subdomain (even while its certificate provisions), and finally the default -// subdomain hostname derived from the page slug when no domain row is loaded -// yet. -func PublicURLForTrustCenter( +func (s *Service) PublicURLForCompliancePage( ctx context.Context, conn pg.Querier, scope coredata.Scoper, - trustCenter *coredata.TrustCenter, - baseDomain string, + compliancePage *coredata.TrustCenter, ) (string, error) { - byID, active, err := loadDomains(ctx, conn, scope, trustCenter) + byID, active, err := loadDomains(ctx, conn, scope, compliancePage) if err != nil { return "", err } @@ -74,14 +63,14 @@ func PublicURLForTrustCenter( var host string switch { - case trustCenter.CustomDomainID != nil && byID[*trustCenter.CustomDomainID] != nil && active[*trustCenter.CustomDomainID]: - host = byID[*trustCenter.CustomDomainID].Domain - case trustCenter.DefaultDomainID != nil && byID[*trustCenter.DefaultDomainID] != nil: - host = byID[*trustCenter.DefaultDomainID].Domain + case compliancePage.CustomDomainID != nil && byID[*compliancePage.CustomDomainID] != nil && active[*compliancePage.CustomDomainID]: + host = byID[*compliancePage.CustomDomainID].Domain + case compliancePage.DefaultDomainID != nil && byID[*compliancePage.DefaultDomainID] != nil: + host = byID[*compliancePage.DefaultDomainID].Domain } if host == "" { - host = trustCenter.Slug + "." + baseDomain + host = compliancePage.Slug + "." + s.baseDomain } return "https://" + host, nil @@ -91,15 +80,15 @@ func loadDomains( ctx context.Context, conn pg.Querier, scope coredata.Scoper, - trustCenter *coredata.TrustCenter, + compliancePage *coredata.TrustCenter, ) (map[gid.GID]*coredata.CustomDomain, map[gid.GID]bool, error) { var ids []gid.GID - if trustCenter.CustomDomainID != nil { - ids = append(ids, *trustCenter.CustomDomainID) + if compliancePage.CustomDomainID != nil { + ids = append(ids, *compliancePage.CustomDomainID) } - if trustCenter.DefaultDomainID != nil { - ids = append(ids, *trustCenter.DefaultDomainID) + if compliancePage.DefaultDomainID != nil { + ids = append(ids, *compliancePage.DefaultDomainID) } byID := make(map[gid.GID]*coredata.CustomDomain) diff --git a/pkg/complianceportal/management/domain_service.go b/pkg/complianceportal/management/domain_service.go index 6ca8d0309..b5b79a49c 100644 --- a/pkg/complianceportal/management/domain_service.go +++ b/pkg/complianceportal/management/domain_service.go @@ -21,27 +21,13 @@ import ( "time" "go.gearno.de/kit/pg" - "go.probo.inc/probo/pkg/complianceportal" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/validator" ) -// The compliance portal service owns the relationship between a compliance -// page (trust center) and its domains. A page has two slots stored on the -// trust center row: a default {slug}.probopage.com domain provided by Probo and -// an optional custom domain. It provisions each domain's TLS certificate -// through the generic certmanager service within the trust center's transaction -// so slot changes stay atomic with the page. - -// ErrCustomDomainSlotTaken is returned when a compliance page already has a -// custom domain and another one is added. var ErrCustomDomainSlotTaken = errors.New("compliance page already has a custom domain") -// AddCustomDomain provisions the compliance page's custom domain. It fails -// when the page already has one. The default probopage subdomain, provisioned -// at page creation, keeps serving as a fallback while the new certificate -// provisions. func (s *Service) AddCustomDomain( ctx context.Context, scope coredata.Scoper, @@ -60,12 +46,12 @@ func (s *Service) AddCustomDomain( err := s.pg.WithTx( ctx, func(ctx context.Context, tx pg.Tx) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, tx, scope, compliancePageID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, tx, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - if trustCenter.CustomDomainID != nil { + if compliancePage.CustomDomainID != nil { return ErrCustomDomainSlotTaken } @@ -76,7 +62,7 @@ func (s *Service) AddCustomDomain( customDomain = coredata.NewCustomDomain( scope.GetTenantID(), - trustCenter.OrganizationID, + compliancePage.OrganizationID, domain, false, ) @@ -86,11 +72,11 @@ func (s *Service) AddCustomDomain( return fmt.Errorf("cannot insert custom domain: %w", err) } - trustCenter.CustomDomainID = &customDomain.ID - trustCenter.UpdatedAt = time.Now() + compliancePage.CustomDomainID = &customDomain.ID + compliancePage.UpdatedAt = time.Now() - if err := trustCenter.Update(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot update trust center: %w", err) + if err := compliancePage.Update(ctx, tx, scope); err != nil { + return fmt.Errorf("cannot update compliance page: %w", err) } return nil @@ -103,9 +89,6 @@ func (s *Service) AddCustomDomain( return customDomain, nil } -// RemoveCustomDomain clears the compliance page's custom domain and deletes -// the underlying domain together with its certificate. The default domain -// cannot be removed. func (s *Service) RemoveCustomDomain( ctx context.Context, scope coredata.Scoper, @@ -120,24 +103,24 @@ func (s *Service) RemoveCustomDomain( } if domain.Managed { - return complianceportal.ErrCustomDomainManaged + return ErrCustomDomainManaged } - trustCenter := &coredata.TrustCenter{} - err := trustCenter.LoadByDomainID(ctx, tx, customDomainID) + compliancePage := &coredata.TrustCenter{} + err := compliancePage.LoadByDomainID(ctx, tx, customDomainID) switch { case err == nil: - if trustCenter.CustomDomainID != nil && *trustCenter.CustomDomainID == customDomainID { - trustCenter.CustomDomainID = nil - trustCenter.UpdatedAt = time.Now() + if compliancePage.CustomDomainID != nil && *compliancePage.CustomDomainID == customDomainID { + compliancePage.CustomDomainID = nil + compliancePage.UpdatedAt = time.Now() - if err := trustCenter.Update(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot update trust center: %w", err) + if err := compliancePage.Update(ctx, tx, scope); err != nil { + return fmt.Errorf("cannot update compliance page: %w", err) } } case errors.Is(err, coredata.ErrResourceNotFound): default: - return fmt.Errorf("cannot load trust center by domain id: %w", err) + return fmt.Errorf("cannot load compliance page by domain id: %w", err) } if err := domain.Delete(ctx, tx, scope); err != nil { @@ -155,78 +138,37 @@ func (s *Service) RemoveCustomDomain( ) } -// GetCertificate returns the certificate backing a custom domain, or nil when -// the domain has no certificate yet. -func (s *Service) GetCertificate( - ctx context.Context, - scope coredata.Scoper, - domain *coredata.CustomDomain, -) (*coredata.Certificate, error) { - if domain == nil || domain.CertificateID == nil { - return nil, nil - } - - return s.certManager.Get(ctx, scope, *domain.CertificateID) -} - // GetDefaultDomain returns the compliance page's default probopage subdomain, // or nil when it has not been provisioned yet. func (s *Service) GetDefaultDomain( ctx context.Context, scope coredata.Scoper, compliancePageID gid.GID, -) (*coredata.CustomDomain, error) { - return s.domainSlot(ctx, scope, compliancePageID, func(tc *coredata.TrustCenter) *gid.GID { - return tc.DefaultDomainID - }, - ) -} - -// GetCustomDomain returns the compliance page's custom domain, or nil when -// none is configured. -func (s *Service) GetCustomDomain( - ctx context.Context, - scope coredata.Scoper, - compliancePageID gid.GID, -) (*coredata.CustomDomain, error) { - return s.domainSlot(ctx, scope, compliancePageID, func(tc *coredata.TrustCenter) *gid.GID { - return tc.CustomDomainID - }, - ) -} - -func (s *Service) domainSlot( - ctx context.Context, - scope coredata.Scoper, - compliancePageID gid.GID, - slot func(*coredata.TrustCenter) *gid.GID, ) (*coredata.CustomDomain, error) { var domain *coredata.CustomDomain err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, compliancePageID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - domainID := slot(trustCenter) - if domainID == nil { + if compliancePage.DefaultDomainID == nil { return nil } - loaded := &coredata.CustomDomain{} - if err := loaded.LoadByID(ctx, conn, scope, *domainID); err != nil { + domain = &coredata.CustomDomain{} + if err := domain.LoadByID(ctx, conn, scope, *compliancePage.DefaultDomainID); err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { + domain = nil return nil } return fmt.Errorf("cannot load custom domain: %w", err) } - domain = loaded - return nil }, ) @@ -237,31 +179,34 @@ func (s *Service) domainSlot( return domain, nil } -// EffectiveDomain returns the domain a compliance page is served under: the -// custom domain when it has an active certificate, otherwise the default -// subdomain when its certificate is active. It returns nil when no serving -// domain is available yet. -func (s *Service) EffectiveDomain( +func (s *Service) GetCustomDomain( ctx context.Context, scope coredata.Scoper, compliancePageID gid.GID, ) (*coredata.CustomDomain, error) { - var effective *coredata.CustomDomain + var domain *coredata.CustomDomain err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, compliancePageID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - d, err := complianceportal.EffectiveDomainForTrustCenter(ctx, conn, scope, trustCenter) - if err != nil { - return err + if compliancePage.CustomDomainID == nil { + return nil } - effective = d + domain = &coredata.CustomDomain{} + if err := domain.LoadByID(ctx, conn, scope, *compliancePage.CustomDomainID); err != nil { + if errors.Is(err, coredata.ErrResourceNotFound) { + domain = nil + return nil + } + + return fmt.Errorf("cannot load custom domain: %w", err) + } return nil }, @@ -270,26 +215,7 @@ func (s *Service) EffectiveDomain( return nil, err } - return effective, nil -} - -// EffectiveCanonicalHost returns the host a compliance page should be served -// under, or an empty string when no serving host is available yet. -func (s *Service) EffectiveCanonicalHost( - ctx context.Context, - scope coredata.Scoper, - compliancePageID gid.GID, -) (string, error) { - domain, err := s.EffectiveDomain(ctx, scope, compliancePageID) - if err != nil { - return "", err - } - - if domain == nil { - return "", nil - } - - return domain.Domain, nil + return domain, nil } // PublicURL returns the canonical public URL of a compliance page on its @@ -304,18 +230,17 @@ func (s *Service) PublicURL( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, compliancePageID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - url, err := complianceportal.PublicURLForTrustCenter(ctx, conn, scope, trustCenter, s.baseDomain) + var err error + publicURL, err = s.PublicURLForCompliancePage(ctx, conn, scope, compliancePage) if err != nil { - return err + return fmt.Errorf("cannot resolve public url: %w", err) } - publicURL = url - return nil }, ) diff --git a/pkg/complianceportal/errors.go b/pkg/complianceportal/management/errors.go similarity index 98% rename from pkg/complianceportal/errors.go rename to pkg/complianceportal/management/errors.go index 6b6cc01d7..7319cad85 100644 --- a/pkg/complianceportal/errors.go +++ b/pkg/complianceportal/management/errors.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package complianceportal +package management import "errors" diff --git a/pkg/complianceportal/management/file_service.go b/pkg/complianceportal/management/file_service.go index d2ff8eb70..0679df7d6 100644 --- a/pkg/complianceportal/management/file_service.go +++ b/pkg/complianceportal/management/file_service.go @@ -92,7 +92,7 @@ func (s *Service) ListFilesForOrganizationID( ctx, func(ctx context.Context, conn pg.Querier) error { if err := files.LoadByOrganizationID(ctx, conn, scope, organizationID, cursor, filter); err != nil { - return fmt.Errorf("cannot load trust center files: %w", err) + return fmt.Errorf("cannot load compliance page files: %w", err) } return nil @@ -119,7 +119,7 @@ func (s *Service) CountFilesForOrganizationID( count, err = (&coredata.TrustCenterFiles{}).CountByOrganizationID(ctx, conn, scope, organizationID) if err != nil { - return fmt.Errorf("cannot count trust center files: %w", err) + return fmt.Errorf("cannot count compliance page files: %w", err) } return nil @@ -144,7 +144,7 @@ func (s *Service) GetFile( func(ctx context.Context, conn pg.Querier) error { file = &coredata.TrustCenterFile{} if err := file.LoadByID(ctx, conn, scope, id); err != nil { - return fmt.Errorf("cannot load trust center file: %w", err) + return fmt.Errorf("cannot load compliance page file: %w", err) } return nil @@ -210,7 +210,7 @@ func (s *Service) CreateFile( } if err := file.Insert(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot insert trust center file: %w", err) + return fmt.Errorf("cannot insert compliance page file: %w", err) } return nil @@ -243,7 +243,7 @@ func (s *Service) UpdateFile( file = &coredata.TrustCenterFile{} if err := file.LoadByID(ctx, tx, scope, req.ID); err != nil { - return fmt.Errorf("cannot load trust center file: %w", err) + return fmt.Errorf("cannot load compliance page file: %w", err) } if req.Name != nil { @@ -261,7 +261,7 @@ func (s *Service) UpdateFile( file.UpdatedAt = now if err := file.Update(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot update trust center file: %w", err) + return fmt.Errorf("cannot update compliance page file: %w", err) } return nil @@ -285,11 +285,11 @@ func (s *Service) DeleteFile( file := &coredata.TrustCenterFile{} if err := file.LoadByID(ctx, tx, scope, trustCenterFileID); err != nil { - return fmt.Errorf("cannot load trust center file: %w", err) + return fmt.Errorf("cannot load compliance page file: %w", err) } if err := file.Delete(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot delete trust center file: %w", err) + return fmt.Errorf("cannot delete compliance page file: %w", err) } return nil @@ -311,7 +311,7 @@ func (s *Service) GenerateFileURL( func(ctx context.Context, conn pg.Querier) error { file := &coredata.TrustCenterFile{} if err := file.LoadByID(ctx, conn, scope, trustCenterFileID); err != nil { - return fmt.Errorf("cannot load trust center file: %w", err) + return fmt.Errorf("cannot load compliance page file: %w", err) } storedFile = &coredata.File{} @@ -405,9 +405,9 @@ func (s *Service) uploadFile( ContentType: new(contentType), CacheControl: new("private, max-age=3600"), Metadata: map[string]string{ - "type": "trust-center-file", - "trust-center-file-id": trustCenterFileID.String(), - "organization-id": organizationID.String(), + "type": "compliance-page-file", + "compliance-page-file-id": trustCenterFileID.String(), + "organization-id": organizationID.String(), }, }, ) diff --git a/pkg/complianceportal/management/framework_service.go b/pkg/complianceportal/management/framework_service.go index bcd5dc50d..4b5c5c1dc 100644 --- a/pkg/complianceportal/management/framework_service.go +++ b/pkg/complianceportal/management/framework_service.go @@ -76,7 +76,7 @@ func (r *DeleteFrameworkRequest) Validate() error { func (s *Service) ListFrameworksWithHidden( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, cursor *page.Cursor[coredata.ComplianceFrameworkOrderField], ) (*page.Page[*coredata.ComplianceFramework, coredata.ComplianceFrameworkOrderField], error) { var cfs coredata.ComplianceFrameworks @@ -84,7 +84,7 @@ func (s *Service) ListFrameworksWithHidden( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - if err := cfs.LoadWithHiddenByTrustCenterID(ctx, conn, scope, trustCenterID, cursor); err != nil { + if err := cfs.LoadWithHiddenByTrustCenterID(ctx, conn, scope, compliancePageID, cursor); err != nil { return fmt.Errorf("cannot load frameworks with hidden: %w", err) } @@ -116,9 +116,9 @@ func (s *Service) CreateFramework( err := s.pg.WithTx( ctx, func(ctx context.Context, tx pg.Tx) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, tx, scope, req.TrustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, tx, scope, req.TrustCenterID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } framework := &coredata.Framework{} @@ -128,7 +128,7 @@ func (s *Service) CreateFramework( cf = &coredata.ComplianceFramework{ ID: cfID, - OrganizationID: trustCenter.OrganizationID, + OrganizationID: compliancePage.OrganizationID, TrustCenterID: req.TrustCenterID, FrameworkID: req.FrameworkID, CreatedAt: now, diff --git a/pkg/complianceportal/oauth2_scopes.go b/pkg/complianceportal/management/oauth2_scopes.go similarity index 99% rename from pkg/complianceportal/oauth2_scopes.go rename to pkg/complianceportal/management/oauth2_scopes.go index c2e86058f..7e041fa0e 100644 --- a/pkg/complianceportal/oauth2_scopes.go +++ b/pkg/complianceportal/management/oauth2_scopes.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package complianceportal +package management import ( "go.probo.inc/probo/pkg/coredata" diff --git a/pkg/complianceportal/policies.go b/pkg/complianceportal/management/policies.go similarity index 99% rename from pkg/complianceportal/policies.go rename to pkg/complianceportal/management/policies.go index 658064958..2c3908ec6 100644 --- a/pkg/complianceportal/policies.go +++ b/pkg/complianceportal/management/policies.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package complianceportal +package management import ( "go.probo.inc/probo/pkg/iam" diff --git a/pkg/complianceportal/management/portal_service.go b/pkg/complianceportal/management/portal_service.go index ae0b24751..ce5eeb441 100644 --- a/pkg/complianceportal/management/portal_service.go +++ b/pkg/complianceportal/management/portal_service.go @@ -33,7 +33,6 @@ import ( "go.gearno.de/crypto/uuid" "go.gearno.de/kit/pg" "go.probo.inc/probo/packages/emails" - "go.probo.inc/probo/pkg/complianceportal" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/filevalidation" "go.probo.inc/probo/pkg/gid" @@ -134,26 +133,26 @@ func (req *UpdateBrandRequest) Validate() error { func (s *Service) Get( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) (*coredata.TrustCenter, error) { - var trustCenter *coredata.TrustCenter + var compliancePage *coredata.TrustCenter err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter = &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, trustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage = &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } return nil }, ) if err != nil { - return nil, fmt.Errorf("cannot load trust center: %w", err) + return nil, fmt.Errorf("cannot load compliance page: %w", err) } - return trustCenter, nil + return compliancePage, nil } func (s *Service) GetByOrganizationID( @@ -161,14 +160,14 @@ func (s *Service) GetByOrganizationID( scope coredata.Scoper, organizationID gid.GID, ) (*coredata.TrustCenter, error) { - var trustCenter *coredata.TrustCenter + var compliancePage *coredata.TrustCenter err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter = &coredata.TrustCenter{} - if err := trustCenter.LoadByOrganizationID(ctx, conn, scope, organizationID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage = &coredata.TrustCenter{} + if err := compliancePage.LoadByOrganizationID(ctx, conn, scope, organizationID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } return nil @@ -178,7 +177,7 @@ func (s *Service) GetByOrganizationID( return nil, err } - return trustCenter, nil + return compliancePage, nil } func (s *Service) Update( @@ -191,40 +190,40 @@ func (s *Service) Update( } var ( - trustCenter *coredata.TrustCenter - file *coredata.File + compliancePage *coredata.TrustCenter + file *coredata.File ) err := s.pg.WithTx( ctx, func(ctx context.Context, conn pg.Tx) error { - trustCenter = &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, req.ID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage = &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, req.ID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } if req.Active != nil { - trustCenter.Active = *req.Active + compliancePage.Active = *req.Active } if req.Slug != nil { - trustCenter.Slug = *req.Slug + compliancePage.Slug = *req.Slug } if req.SearchEngineIndexing != nil { - trustCenter.SearchEngineIndexing = *req.SearchEngineIndexing + compliancePage.SearchEngineIndexing = *req.SearchEngineIndexing } if req.Title != nil { - trustCenter.Title = *req.Title + compliancePage.Title = *req.Title } if req.Description != nil { - trustCenter.Description = *req.Description + compliancePage.Description = *req.Description } if req.WebsiteURL != nil { - trustCenter.WebsiteURL = *req.WebsiteURL + compliancePage.WebsiteURL = *req.WebsiteURL } if req.Email != nil { @@ -234,22 +233,22 @@ func (s *Service) Update( } } - trustCenter.Email = *req.Email + compliancePage.Email = *req.Email } if req.HeadquarterAddress != nil { - trustCenter.HeadquarterAddress = *req.HeadquarterAddress + compliancePage.HeadquarterAddress = *req.HeadquarterAddress } - trustCenter.UpdatedAt = time.Now() + compliancePage.UpdatedAt = time.Now() - if err := trustCenter.Update(ctx, conn, scope); err != nil { - return fmt.Errorf("cannot update trust center: %w", err) + if err := compliancePage.Update(ctx, conn, scope); err != nil { + return fmt.Errorf("cannot update compliance page: %w", err) } - if trustCenter.NonDisclosureAgreementFileID != nil { + if compliancePage.NonDisclosureAgreementFileID != nil { file = &coredata.File{} - if err := file.LoadByID(ctx, conn, scope, *trustCenter.NonDisclosureAgreementFileID); err != nil { + if err := file.LoadByID(ctx, conn, scope, *compliancePage.NonDisclosureAgreementFileID); err != nil { return fmt.Errorf("cannot load file: %w", err) } } @@ -261,7 +260,7 @@ func (s *Service) Update( return nil, nil, err } - return trustCenter, file, nil + return compliancePage, file, nil } func (s *Service) UploadNDA( @@ -274,20 +273,20 @@ func (s *Service) UploadNDA( } var ( - trustCenter *coredata.TrustCenter - file *coredata.File + compliancePage *coredata.TrustCenter + file *coredata.File ) err := s.pg.WithTx( ctx, func(ctx context.Context, conn pg.Tx) error { - trustCenter = &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, req.TrustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage = &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, req.TrustCenterID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - if trustCenter.OrganizationID == gid.Nil { - return fmt.Errorf("trust center %s has no organization", req.TrustCenterID) + if compliancePage.OrganizationID == gid.Nil { + return fmt.Errorf("compliance page %s has no organization", req.TrustCenterID) } objectKey, err := uuid.NewV7() @@ -305,7 +304,7 @@ func (s *Service) UploadNDA( file = &coredata.File{ ID: fileID, - OrganizationID: trustCenter.OrganizationID, + OrganizationID: compliancePage.OrganizationID, BucketName: s.bucket, MimeType: mimeType, FileName: req.FileName, @@ -320,9 +319,9 @@ func (s *Service) UploadNDA( file, req.File, map[string]string{ - "type": "trust-center-nda", - "trust-center-id": req.TrustCenterID.String(), - "organization-id": trustCenter.OrganizationID.String(), + "type": "compliance-page-nda", + "compliance-page-id": req.TrustCenterID.String(), + "organization-id": compliancePage.OrganizationID.String(), }, ) if err != nil { @@ -335,11 +334,11 @@ func (s *Service) UploadNDA( return fmt.Errorf("cannot insert file: %w", err) } - trustCenter.NonDisclosureAgreementFileID = &fileID - trustCenter.UpdatedAt = now + compliancePage.NonDisclosureAgreementFileID = &fileID + compliancePage.UpdatedAt = now - if err := trustCenter.Update(ctx, conn, scope); err != nil { - return fmt.Errorf("cannot update trust center: %w", err) + if err := compliancePage.Update(ctx, conn, scope); err != nil { + return fmt.Errorf("cannot update compliance page: %w", err) } return nil @@ -349,29 +348,29 @@ func (s *Service) UploadNDA( return nil, nil, err } - return trustCenter, file, nil + return compliancePage, file, nil } func (s *Service) DeleteNDA( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) (*coredata.TrustCenter, *coredata.File, error) { - var trustCenter *coredata.TrustCenter + var compliancePage *coredata.TrustCenter err := s.pg.WithTx( ctx, func(ctx context.Context, conn pg.Tx) error { - trustCenter = &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, trustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage = &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - trustCenter.NonDisclosureAgreementFileID = nil - trustCenter.UpdatedAt = time.Now() + compliancePage.NonDisclosureAgreementFileID = nil + compliancePage.UpdatedAt = time.Now() - if err := trustCenter.Update(ctx, conn, scope); err != nil { - return fmt.Errorf("cannot update trust center: %w", err) + if err := compliancePage.Update(ctx, conn, scope); err != nil { + return fmt.Errorf("cannot update compliance page: %w", err) } return nil @@ -381,7 +380,7 @@ func (s *Service) DeleteNDA( return nil, nil, err } - return trustCenter, nil, nil + return compliancePage, nil, nil } func (s *Service) UpdateBrand( @@ -394,55 +393,55 @@ func (s *Service) UpdateBrand( } var ( - trustCenter *coredata.TrustCenter - ndaFile *coredata.File + compliancePage *coredata.TrustCenter + ndaFile *coredata.File ) err := s.pg.WithTx( ctx, func(ctx context.Context, conn pg.Tx) error { - trustCenter = &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, req.TrustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage = &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, req.TrustCenterID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } now := time.Now() if req.LogoFile != nil { if *req.LogoFile == nil { - trustCenter.LogoFileID = nil + compliancePage.LogoFileID = nil } else { - file, err := s.uploadBrandFile(ctx, scope, conn, *req.LogoFile, "trust-center-logo", trustCenter) + file, err := s.uploadBrandFile(ctx, scope, conn, *req.LogoFile, "compliance-page-logo", compliancePage) if err != nil { return fmt.Errorf("cannot upload logo file: %w", err) } - trustCenter.LogoFileID = &file.ID + compliancePage.LogoFileID = &file.ID } } if req.DarkLogoFile != nil { if *req.DarkLogoFile == nil { - trustCenter.DarkLogoFileID = nil + compliancePage.DarkLogoFileID = nil } else { - file, err := s.uploadBrandFile(ctx, scope, conn, *req.DarkLogoFile, "trust-center-dark-logo", trustCenter) + file, err := s.uploadBrandFile(ctx, scope, conn, *req.DarkLogoFile, "compliance-page-dark-logo", compliancePage) if err != nil { return fmt.Errorf("cannot upload dark logo file: %w", err) } - trustCenter.DarkLogoFileID = &file.ID + compliancePage.DarkLogoFileID = &file.ID } } - trustCenter.UpdatedAt = now + compliancePage.UpdatedAt = now - if err := trustCenter.Update(ctx, conn, scope); err != nil { - return fmt.Errorf("cannot update trust center: %w", err) + if err := compliancePage.Update(ctx, conn, scope); err != nil { + return fmt.Errorf("cannot update compliance page: %w", err) } - if trustCenter.NonDisclosureAgreementFileID != nil { + if compliancePage.NonDisclosureAgreementFileID != nil { ndaFile = &coredata.File{} - if err := ndaFile.LoadByID(ctx, conn, scope, *trustCenter.NonDisclosureAgreementFileID); err != nil { + if err := ndaFile.LoadByID(ctx, conn, scope, *compliancePage.NonDisclosureAgreementFileID); err != nil { return fmt.Errorf("cannot load nda file: %w", err) } } @@ -454,7 +453,7 @@ func (s *Service) UpdateBrand( return nil, nil, err } - return trustCenter, ndaFile, nil + return compliancePage, ndaFile, nil } func (s *Service) uploadBrandFile( @@ -463,7 +462,7 @@ func (s *Service) uploadBrandFile( conn pg.Tx, fileUpload *FileUpload, fileType string, - trustCenter *coredata.TrustCenter, + compliancePage *coredata.TrustCenter, ) (*coredata.File, error) { objectKey, err := uuid.NewV7() if err != nil { @@ -482,9 +481,9 @@ func (s *Service) uploadBrandFile( ContentType: &mimeType, CacheControl: new("max-age=3600, public"), Metadata: map[string]string{ - "type": fileType, - "trust-center-id": trustCenter.ID.String(), - "organization-id": trustCenter.OrganizationID.String(), + "type": fileType, + "compliance-page-id": compliancePage.ID.String(), + "organization-id": compliancePage.OrganizationID.String(), }, }) if err != nil { @@ -504,7 +503,7 @@ func (s *Service) uploadBrandFile( file := &coredata.File{ ID: fileID, - OrganizationID: trustCenter.OrganizationID, + OrganizationID: compliancePage.OrganizationID, BucketName: s.bucket, MimeType: mimeType, FileName: fileUpload.Filename, @@ -525,26 +524,26 @@ func (s *Service) uploadBrandFile( func (s *Service) GenerateNDAFileURL( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, expiresIn time.Duration, ) (*string, error) { var file *coredata.File - trustCenter := &coredata.TrustCenter{} + compliancePage := &coredata.TrustCenter{} err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - if err := trustCenter.LoadByID(ctx, conn, scope, trustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - if trustCenter.NonDisclosureAgreementFileID == nil { + if compliancePage.NonDisclosureAgreementFileID == nil { return nil } file = &coredata.File{} - if err := file.LoadByID(ctx, conn, scope, *trustCenter.NonDisclosureAgreementFileID); err != nil { + if err := file.LoadByID(ctx, conn, scope, *compliancePage.NonDisclosureAgreementFileID); err != nil { return fmt.Errorf("cannot load file: %w", err) } @@ -555,7 +554,7 @@ func (s *Service) GenerateNDAFileURL( return nil, err } - if trustCenter.NonDisclosureAgreementFileID == nil { + if compliancePage.NonDisclosureAgreementFileID == nil { return nil, nil } @@ -691,13 +690,7 @@ func (s *Service) EmailPresenterConfig( return fmt.Errorf("cannot load organization: %w", err) } - publicURL, err := complianceportal.PublicURLForTrustCenter( - ctx, - conn, - scope, - compliancePage, - s.baseDomain, - ) + publicURL, err := s.PublicURLForCompliancePage(ctx, conn, scope, compliancePage) if err != nil { return fmt.Errorf("cannot resolve compliance page URL: %w", err) } @@ -736,24 +729,24 @@ func (s *Service) EmailPresenterConfig( func (s *Service) GetMailingList( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) (*coredata.MailingList, error) { var mailingList *coredata.MailingList err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, trustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - if trustCenter.MailingListID == nil { + if compliancePage.MailingListID == nil { return nil } mailingList = &coredata.MailingList{} - if err := mailingList.LoadByID(ctx, conn, scope, *trustCenter.MailingListID); err != nil { + if err := mailingList.LoadByID(ctx, conn, scope, *compliancePage.MailingListID); err != nil { return fmt.Errorf("cannot load mailing list: %w", err) } diff --git a/pkg/complianceportal/management/reference_service.go b/pkg/complianceportal/management/reference_service.go index 1ebdd1605..25ffa3308 100644 --- a/pkg/complianceportal/management/reference_service.go +++ b/pkg/complianceportal/management/reference_service.go @@ -82,7 +82,7 @@ func (utcrr *UpdateReferenceRequest) Validate() error { func (s *Service) ListReferences( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, cursor *page.Cursor[coredata.TrustCenterReferenceOrderField], ) (*page.Page[*coredata.TrustCenterReference, coredata.TrustCenterReferenceOrderField], error) { var references coredata.TrustCenterReferences @@ -90,9 +90,9 @@ func (s *Service) ListReferences( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - err := references.LoadByTrustCenterID(ctx, conn, scope, trustCenterID, cursor) + err := references.LoadByTrustCenterID(ctx, conn, scope, compliancePageID, cursor) if err != nil { - return fmt.Errorf("cannot load trust center references: %w", err) + return fmt.Errorf("cannot load compliance page references: %w", err) } return nil @@ -108,7 +108,7 @@ func (s *Service) ListReferences( func (s *Service) CountReferences( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) (int, error) { var count int @@ -117,9 +117,9 @@ func (s *Service) CountReferences( func(ctx context.Context, conn pg.Querier) (err error) { references := coredata.TrustCenterReferences{} - count, err = references.CountByTrustCenterID(ctx, conn, scope, trustCenterID) + count, err = references.CountByTrustCenterID(ctx, conn, scope, compliancePageID) if err != nil { - return fmt.Errorf("cannot count trust center references: %w", err) + return fmt.Errorf("cannot count compliance page references: %w", err) } return nil @@ -144,7 +144,7 @@ func (s *Service) GetReference( func(ctx context.Context, conn pg.Querier) error { err := reference.LoadByID(ctx, conn, scope, referenceID) if err != nil { - return fmt.Errorf("cannot load trust center reference: %w", err) + return fmt.Errorf("cannot load compliance page reference: %w", err) } return nil @@ -177,9 +177,9 @@ func (s *Service) CreateReference( err := s.pg.WithTx( ctx, func(ctx context.Context, tx pg.Tx) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, tx, scope, req.TrustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, tx, scope, req.TrustCenterID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } fileID, s3Key, err := s.uploadReferenceLogoFile(ctx, scope, tx, req.LogoFile, referenceID, req.TrustCenterID, now) @@ -191,7 +191,7 @@ func (s *Service) CreateReference( reference = &coredata.TrustCenterReference{ ID: referenceID, - OrganizationID: trustCenter.OrganizationID, + OrganizationID: compliancePage.OrganizationID, TrustCenterID: req.TrustCenterID, Name: req.Name, Description: req.Description, @@ -202,7 +202,7 @@ func (s *Service) CreateReference( } if err := reference.Insert(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot insert trust center reference: %w", err) + return fmt.Errorf("cannot insert compliance page reference: %w", err) } return nil @@ -239,7 +239,7 @@ func (s *Service) UpdateReference( reference = &coredata.TrustCenterReference{} if err := reference.LoadByID(ctx, tx, scope, req.ID); err != nil { - return fmt.Errorf("cannot load trust center reference: %w", err) + return fmt.Errorf("cannot load compliance page reference: %w", err) } if req.LogoFile != nil { @@ -278,7 +278,7 @@ func (s *Service) UpdateReference( } if err := reference.Update(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot update trust center reference: %w", err) + return fmt.Errorf("cannot update compliance page reference: %w", err) } return nil @@ -303,11 +303,11 @@ func (s *Service) DeleteReference( reference := &coredata.TrustCenterReference{} if err := reference.LoadByID(ctx, tx, scope, trustCenterReferenceID); err != nil { - return fmt.Errorf("cannot load trust center reference: %w", err) + return fmt.Errorf("cannot load compliance page reference: %w", err) } if err := reference.Delete(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot delete trust center reference: %w", err) + return fmt.Errorf("cannot delete compliance page reference: %w", err) } return nil @@ -331,7 +331,7 @@ func (s *Service) GenerateReferenceLogoURL( }, ) if err != nil { - return "", fmt.Errorf("cannot load trust center reference: %w", err) + return "", fmt.Errorf("cannot load compliance page reference: %w", err) } file, err := s.fileManager.GetPublicFile(ctx, reference.LogoFileID) @@ -348,7 +348,7 @@ func (s *Service) uploadReferenceLogoFile( tx pg.Tx, file File, referenceID gid.GID, - trustCenterID gid.GID, + compliancePageID gid.GID, now time.Time, ) (gid.GID, string, error) { fileID := gid.New(scope.GetTenantID(), coredata.FileEntityType) @@ -358,9 +358,9 @@ func (s *Service) uploadReferenceLogoFile( return gid.GID{}, "", fmt.Errorf("cannot generate object key: %w", err) } - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, tx, scope, trustCenterID); err != nil { - return gid.GID{}, "", fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, tx, scope, compliancePageID); err != nil { + return gid.GID{}, "", fmt.Errorf("cannot load compliance page: %w", err) } var ( @@ -418,9 +418,9 @@ func (s *Service) uploadReferenceLogoFile( ContentType: new(contentType), CacheControl: new("max-age=3600, public"), Metadata: map[string]string{ - "type": "trust-center-reference-logo", - "trust-center-reference-id": referenceID.String(), - "organization-id": trustCenter.OrganizationID.String(), + "type": "compliance-page-reference-logo", + "compliance-page-reference-id": referenceID.String(), + "organization-id": compliancePage.OrganizationID.String(), }, }, ) @@ -430,7 +430,7 @@ func (s *Service) uploadReferenceLogoFile( fileRecord := &coredata.File{ ID: fileID, - OrganizationID: trustCenter.OrganizationID, + OrganizationID: compliancePage.OrganizationID, BucketName: s.bucket, MimeType: contentType, FileName: filename, diff --git a/pkg/complianceportal/management/service.go b/pkg/complianceportal/management/service.go index e3f82ca2e..292c92fd2 100644 --- a/pkg/complianceportal/management/service.go +++ b/pkg/complianceportal/management/service.go @@ -13,7 +13,7 @@ // PERFORMANCE OF THIS SOFTWARE. // Package management holds the scoped, admin-facing compliance portal services -// (trust center CRUD, domains, frameworks, external URLs, references, files and +// (compliance page CRUD, domains, frameworks, external URLs, references, files and // accesses). It is the write side of the compliance portal feature. package management @@ -37,7 +37,7 @@ const ( type ( // Service is the admin-facing compliance portal service. It exposes the - // scoped CRUD operations for the trust center and its related resources as + // scoped CRUD operations for the compliance page and its related resources as // methods on a single type. Service struct { pg *pg.Client diff --git a/pkg/complianceportal/brand.go b/pkg/complianceportal/visitor/brand.go similarity index 98% rename from pkg/complianceportal/brand.go rename to pkg/complianceportal/visitor/brand.go index 56973974f..fca799724 100644 --- a/pkg/complianceportal/brand.go +++ b/pkg/complianceportal/visitor/brand.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package complianceportal +package visitor import ( "fmt" diff --git a/pkg/complianceportal/cimd.go b/pkg/complianceportal/visitor/cimd.go similarity index 99% rename from pkg/complianceportal/cimd.go rename to pkg/complianceportal/visitor/cimd.go index 6b2bd671d..6f07fbc7f 100644 --- a/pkg/complianceportal/cimd.go +++ b/pkg/complianceportal/visitor/cimd.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package complianceportal +package visitor import ( "fmt" diff --git a/pkg/complianceportal/cimd_test.go b/pkg/complianceportal/visitor/cimd_test.go similarity index 95% rename from pkg/complianceportal/cimd_test.go rename to pkg/complianceportal/visitor/cimd_test.go index 38b4ec750..b337369ff 100644 --- a/pkg/complianceportal/cimd_test.go +++ b/pkg/complianceportal/visitor/cimd_test.go @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -package complianceportal +package visitor import ( "testing" @@ -66,7 +66,7 @@ func TestBuildClientMetadataDocument(t *testing.T) { websiteURL := "https://www.acme.com" portal := &coredata.TrustCenter{ - Title: "Acme Trust Center", + Title: "Acme Compliance Page", WebsiteURL: &websiteURL, } @@ -76,7 +76,7 @@ func TestBuildClientMetadataDocument(t *testing.T) { ) require.NoError(t, err) assert.Equal(t, "https://acme.example.com/.well-known/oauth-client-metadata", doc.ClientID) - assert.Equal(t, "Acme Trust Center", doc.ClientName) + assert.Equal(t, "Acme Compliance Page", doc.ClientName) assert.Equal(t, []string{"https://acme.example.com/callback"}, doc.RedirectURIs) assert.Equal(t, "https://acme.example.com", doc.ClientURI) assert.Equal(t, VisitorOAuthScope, doc.Scope) @@ -88,7 +88,7 @@ func TestBuildClientMetadataDocument_LogoURIUsesBrandLogoEndpoint(t *testing.T) logoFileID := gid.MustParseGID("WR-qMrB5AAEAGQAAAZ9mIO8B8vDFQ-i3") portal := &coredata.TrustCenter{ - Title: "Acme Trust Center", + Title: "Acme Compliance Page", LogoFileID: &logoFileID, } diff --git a/pkg/complianceportal/visitor/compliance_framework_service.go b/pkg/complianceportal/visitor/compliance_framework_service.go index 594bdeb79..de7c6f32d 100644 --- a/pkg/complianceportal/visitor/compliance_framework_service.go +++ b/pkg/complianceportal/visitor/compliance_framework_service.go @@ -58,7 +58,7 @@ func (s *Service) GetComplianceFramework( func (s *Service) ListComplianceFrameworksByPortalID( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, cursor *page.Cursor[coredata.ComplianceFrameworkOrderField], ) (*page.Page[*coredata.ComplianceFramework, coredata.ComplianceFrameworkOrderField], error) { var complianceFrameworks coredata.ComplianceFrameworks @@ -66,7 +66,7 @@ func (s *Service) ListComplianceFrameworksByPortalID( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - err := complianceFrameworks.LoadByTrustCenterID(ctx, conn, scope, trustCenterID, cursor) + err := complianceFrameworks.LoadByTrustCenterID(ctx, conn, scope, compliancePageID, cursor) if err != nil { return fmt.Errorf("cannot load compliance frameworks: %w", err) } diff --git a/pkg/complianceportal/visitor/compliance_page_service.go b/pkg/complianceportal/visitor/compliance_page_service.go index 9ae2debb0..bf4865d87 100644 --- a/pkg/complianceportal/visitor/compliance_page_service.go +++ b/pkg/complianceportal/visitor/compliance_page_service.go @@ -122,40 +122,40 @@ type ( func (s *Service) RenderCompliancePageMarkdown( ctx context.Context, w io.Writer, - trustCenterID gid.GID, + compliancePageID gid.GID, scope coredata.Scoper, ) error { - org, err := s.GetPortalOrganization(ctx, trustCenterID) + org, err := s.GetPortalOrganization(ctx, compliancePageID) if err != nil { return fmt.Errorf("cannot load organization for compliance page: %w", err) } - trustCenter, err := s.GetPortalByID(ctx, trustCenterID) + compliancePage, err := s.GetPortalByID(ctx, compliancePageID) if err != nil { - return fmt.Errorf("cannot load trust center for compliance page: %w", err) + return fmt.Errorf("cannot load compliance page: %w", err) } data := &compliancePageData{ OrgName: org.Name, } - if trustCenter.Description != nil && *trustCenter.Description != "" { - data.Description = *trustCenter.Description + if compliancePage.Description != nil && *compliancePage.Description != "" { + data.Description = *compliancePage.Description } - if trustCenter.WebsiteURL != nil && *trustCenter.WebsiteURL != "" { - data.Details = append(data.Details, compliancePageDetail{Label: "Website", Value: *trustCenter.WebsiteURL}) + if compliancePage.WebsiteURL != nil && *compliancePage.WebsiteURL != "" { + data.Details = append(data.Details, compliancePageDetail{Label: "Website", Value: *compliancePage.WebsiteURL}) } - if trustCenter.Email != nil && *trustCenter.Email != "" { - data.Details = append(data.Details, compliancePageDetail{Label: "Email", Value: *trustCenter.Email}) + if compliancePage.Email != nil && *compliancePage.Email != "" { + data.Details = append(data.Details, compliancePageDetail{Label: "Email", Value: *compliancePage.Email}) } - if trustCenter.HeadquarterAddress != nil && *trustCenter.HeadquarterAddress != "" { - data.Details = append(data.Details, compliancePageDetail{Label: "Headquarters", Value: *trustCenter.HeadquarterAddress}) + if compliancePage.HeadquarterAddress != nil && *compliancePage.HeadquarterAddress != "" { + data.Details = append(data.Details, compliancePageDetail{Label: "Headquarters", Value: *compliancePage.HeadquarterAddress}) } - data.Frameworks, err = s.fetchComplianceFrameworks(ctx, scope, trustCenterID) + data.Frameworks, err = s.fetchComplianceFrameworks(ctx, scope, compliancePageID) if err != nil { return fmt.Errorf("cannot fetch compliance frameworks: %w", err) } @@ -175,12 +175,12 @@ func (s *Service) RenderCompliancePageMarkdown( return fmt.Errorf("cannot fetch thirdParties: %w", err) } - data.References, err = s.fetchReferences(ctx, scope, trustCenterID) + data.References, err = s.fetchReferences(ctx, scope, compliancePageID) if err != nil { return fmt.Errorf("cannot fetch references: %w", err) } - data.CustomLinks, err = s.fetchCustomLinks(ctx, scope, trustCenterID) + data.CustomLinks, err = s.fetchCustomLinks(ctx, scope, compliancePageID) if err != nil { return fmt.Errorf("cannot fetch external links: %w", err) } @@ -207,11 +207,11 @@ type ( func (s *Service) RenderSitemap( ctx context.Context, w io.Writer, - trustCenterID gid.GID, + compliancePageID gid.GID, scope coredata.Scoper, baseURL string, ) error { - org, err := s.GetPortalOrganization(ctx, trustCenterID) + org, err := s.GetPortalOrganization(ctx, compliancePageID) if err != nil { return fmt.Errorf("cannot load organization for sitemap: %w", err) } @@ -322,7 +322,7 @@ func (s *Service) fetchDocumentIDs( coredata.NewTrustCenterFileFilter(), ) if err != nil { - return nil, fmt.Errorf("cannot list trust center files: %w", err) + return nil, fmt.Errorf("cannot list compliance page files: %w", err) } for _, file := range result.Data { @@ -401,7 +401,7 @@ func (s *Service) fetchDocumentIDs( func (s *Service) fetchComplianceFrameworks( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) ([]compliancePageFramework, error) { var frameworks []compliancePageFramework @@ -417,7 +417,7 @@ func (s *Service) fetchComplianceFrameworks( }, ) - result, err := s.ListComplianceFrameworksByPortalID(ctx, scope, trustCenterID, cursor) + result, err := s.ListComplianceFrameworksByPortalID(ctx, scope, compliancePageID, cursor) if err != nil { return nil, fmt.Errorf("cannot list compliance frameworks: %w", err) } @@ -621,7 +621,7 @@ func (s *Service) fetchThirdParties( func (s *Service) fetchReferences( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) ([]compliancePageReference, error) { var refs []compliancePageReference @@ -637,7 +637,7 @@ func (s *Service) fetchReferences( }, ) - result, err := s.ListPortalReferencesForPortalID(ctx, scope, trustCenterID, cursor) + result, err := s.ListPortalReferencesForPortalID(ctx, scope, compliancePageID, cursor) if err != nil { return nil, fmt.Errorf("cannot list references: %w", err) } @@ -669,7 +669,7 @@ func (s *Service) fetchReferences( func (s *Service) fetchCustomLinks( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) ([]compliancePageCustomLink, error) { var links []compliancePageCustomLink @@ -685,7 +685,7 @@ func (s *Service) fetchCustomLinks( }, ) - result, err := s.ListCustomLinksForPortalID(ctx, scope, trustCenterID, cursor) + result, err := s.ListCustomLinksForPortalID(ctx, scope, compliancePageID, cursor) if err != nil { return nil, fmt.Errorf("cannot list custom links: %w", err) } diff --git a/pkg/complianceportal/visitor/custom_link_service.go b/pkg/complianceportal/visitor/custom_link_service.go index de8192017..2580683fb 100644 --- a/pkg/complianceportal/visitor/custom_link_service.go +++ b/pkg/complianceportal/visitor/custom_link_service.go @@ -33,7 +33,7 @@ import ( func (s *Service) ListCustomLinksForPortalID( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, cursor *page.Cursor[coredata.ComplianceCustomLinkOrderField], ) (*page.Page[*coredata.ComplianceCustomLink, coredata.ComplianceCustomLinkOrderField], error) { var links coredata.ComplianceCustomLinks @@ -41,7 +41,7 @@ func (s *Service) ListCustomLinksForPortalID( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - err := links.LoadByTrustCenterID(ctx, conn, scope, trustCenterID, cursor) + err := links.LoadByTrustCenterID(ctx, conn, scope, compliancePageID, cursor) if err != nil { return fmt.Errorf("cannot load custom links: %w", err) } diff --git a/pkg/complianceportal/visitor/document_service.go b/pkg/complianceportal/visitor/document_service.go index 6c3dae866..b728f80ca 100644 --- a/pkg/complianceportal/visitor/document_service.go +++ b/pkg/complianceportal/visitor/document_service.go @@ -159,7 +159,7 @@ func (s *Service) exportDocumentPDFData( } if document.TrustCenterVisibility == coredata.TrustCenterVisibilityNone { - return fmt.Errorf("document not visible on trust center") + return fmt.Errorf("document not visible on compliance page") } if err := version.LoadLatestPublishedVersion(ctx, conn, scope, documentID); err != nil { diff --git a/pkg/complianceportal/visitor/errors.go b/pkg/complianceportal/visitor/errors.go index e07cbbfdf..ca539acfb 100644 --- a/pkg/complianceportal/visitor/errors.go +++ b/pkg/complianceportal/visitor/errors.go @@ -23,17 +23,17 @@ package visitor import "errors" var ( - ErrOAuthStateNotFound = errors.New("oauth state not found") - ErrOAuthStateExpired = errors.New("oauth state expired") - ErrPageNotFound = errors.New("page not found") - ErrMembershipNotFound = errors.New("membership not found") - ErrUserNotFound = errors.New("user not found") - ErrUserInactive = errors.New("user inactive") - ErrDocumentAccessNotFound = errors.New("document access not found") - ErrNDAFileNotFound = errors.New("NDA file not found") - ErrDocumentNotFound = errors.New("document not found") - ErrDocumentNotVisible = errors.New("document not visible") - ErrReportNotFound = errors.New("report not found") - ErrTrustCenterFileNotFound = errors.New("trust center file not found") - ErrTrustCenterFileNotVisible = errors.New("trust center file not visible") + ErrOAuthStateNotFound = errors.New("oauth state not found") + ErrOAuthStateExpired = errors.New("oauth state expired") + ErrPageNotFound = errors.New("page not found") + ErrMembershipNotFound = errors.New("membership not found") + ErrUserNotFound = errors.New("user not found") + ErrUserInactive = errors.New("user inactive") + ErrDocumentAccessNotFound = errors.New("document access not found") + ErrNDAFileNotFound = errors.New("NDA file not found") + ErrDocumentNotFound = errors.New("document not found") + ErrDocumentNotVisible = errors.New("document not visible") + ErrReportNotFound = errors.New("report not found") + ErrPortalFileNotFound = errors.New("portal file not found") + ErrPortalFileNotVisible = errors.New("portal file not visible") ) diff --git a/pkg/complianceportal/visitor/portal_access_service.go b/pkg/complianceportal/visitor/portal_access_service.go index 1786be118..d3067b38d 100644 --- a/pkg/complianceportal/visitor/portal_access_service.go +++ b/pkg/complianceportal/visitor/portal_access_service.go @@ -60,9 +60,9 @@ func (s *Service) RequestPortalAccess( err := s.pg.WithTx( ctx, func(ctx context.Context, tx pg.Tx) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, tx, scope, req.TrustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, tx, scope, req.TrustCenterID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } access = &coredata.TrustCenterAccess{} @@ -70,7 +70,7 @@ func (s *Service) RequestPortalAccess( return fmt.Errorf("cannot load compliance page membership: %w", err) } - organizationID := trustCenter.OrganizationID + organizationID := compliancePage.OrganizationID documentIDs := req.DocumentIDs if req.DocumentIDs == nil { @@ -145,7 +145,7 @@ func (s *Service) RequestPortalAccess( func(ctx context.Context, cursor *page.Cursor[coredata.TrustCenterFileOrderField]) ([]*coredata.TrustCenterFile, error) { var batch coredata.TrustCenterFiles if err := batch.LoadByOrganizationID(ctx, tx, scope, organizationID, cursor, filter); err != nil { - return nil, fmt.Errorf("cannot list trust center files: %w", err) + return nil, fmt.Errorf("cannot list compliance page files: %w", err) } return batch, nil @@ -196,7 +196,7 @@ func (s *Service) RequestPortalAccess( coredata.TrustCenterDocumentAccessStatusRequested, now, ); err != nil { - return fmt.Errorf("cannot bulk insert trust center document accesses: %w", err) + return fmt.Errorf("cannot bulk insert compliance page document accesses: %w", err) } if err := accesses.BulkInsertReportFileAccesses( @@ -209,7 +209,7 @@ func (s *Service) RequestPortalAccess( coredata.TrustCenterDocumentAccessStatusRequested, now, ); err != nil { - return fmt.Errorf("cannot bulk insert trust center report accesses: %w", err) + return fmt.Errorf("cannot bulk insert compliance page report accesses: %w", err) } if err := accesses.BulkInsertTrustCenterFileAccesses( @@ -222,7 +222,7 @@ func (s *Service) RequestPortalAccess( coredata.TrustCenterDocumentAccessStatusRequested, now, ); err != nil { - return fmt.Errorf("cannot bulk insert trust center file accesses: %w", err) + return fmt.Errorf("cannot bulk insert compliance page file accesses: %w", err) } return nil @@ -242,7 +242,7 @@ func (s *Service) RequestPortalAccess( func (s *Service) GetPortalAccess( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, identityID gid.GID, ) (coredata.TrustCenterAccess, error) { var access coredata.TrustCenterAccess @@ -250,7 +250,7 @@ func (s *Service) GetPortalAccess( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - return access.LoadByTrustCenterIDAndIdentityID(ctx, conn, scope, trustCenterID, identityID) + return access.LoadByTrustCenterIDAndIdentityID(ctx, conn, scope, compliancePageID, identityID) }, ) @@ -260,7 +260,7 @@ func (s *Service) GetPortalAccess( func (s *Service) GetPortalDocumentAccess( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, identityID gid.GID, documentID gid.GID, ) (*coredata.TrustCenterDocumentAccess, error) { @@ -271,13 +271,13 @@ func (s *Service) GetPortalDocumentAccess( func(ctx context.Context, conn pg.Querier) error { access := &coredata.TrustCenterAccess{} - err := access.LoadByTrustCenterIDAndIdentityID(ctx, conn, scope, trustCenterID, identityID) + err := access.LoadByTrustCenterIDAndIdentityID(ctx, conn, scope, compliancePageID, identityID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return ErrMembershipNotFound } - return fmt.Errorf("cannot load trust center access: %w", err) + return fmt.Errorf("cannot load compliance page access: %w", err) } profile := &coredata.MembershipProfile{} @@ -315,7 +315,7 @@ func (s *Service) GetPortalDocumentAccess( func (s *Service) GetPortalReportFileAccess( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, identityID gid.GID, reportFileID gid.GID, ) (*coredata.TrustCenterDocumentAccess, error) { @@ -326,13 +326,13 @@ func (s *Service) GetPortalReportFileAccess( func(ctx context.Context, conn pg.Querier) error { access := &coredata.TrustCenterAccess{} - err := access.LoadByTrustCenterIDAndIdentityID(ctx, conn, scope, trustCenterID, identityID) + err := access.LoadByTrustCenterIDAndIdentityID(ctx, conn, scope, compliancePageID, identityID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return ErrMembershipNotFound } - return fmt.Errorf("cannot load trust center access: %w", err) + return fmt.Errorf("cannot load compliance page access: %w", err) } profile := &coredata.MembershipProfile{} @@ -370,7 +370,7 @@ func (s *Service) GetPortalReportFileAccess( func (s *Service) GetPortalFileAccess( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, identityID gid.GID, trustCenterFileID gid.GID, ) (*coredata.TrustCenterDocumentAccess, error) { @@ -381,13 +381,13 @@ func (s *Service) GetPortalFileAccess( func(ctx context.Context, conn pg.Querier) error { access := &coredata.TrustCenterAccess{} - err := access.LoadByTrustCenterIDAndIdentityID(ctx, conn, scope, trustCenterID, identityID) + err := access.LoadByTrustCenterIDAndIdentityID(ctx, conn, scope, compliancePageID, identityID) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return ErrMembershipNotFound } - return fmt.Errorf("cannot load trust center access: %w", err) + return fmt.Errorf("cannot load compliance page access: %w", err) } profile := &coredata.MembershipProfile{} @@ -409,7 +409,7 @@ func (s *Service) GetPortalFileAccess( return ErrDocumentAccessNotFound } - return fmt.Errorf("cannot load trust center file access: %w", err) + return fmt.Errorf("cannot load compliance page file access: %w", err) } return nil @@ -434,9 +434,9 @@ func (s *Service) GrantPortalAccessByIDs( return s.pg.WithTx( ctx, func(ctx context.Context, tx pg.Tx) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByOrganizationID(ctx, tx, scope, organizationID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByOrganizationID(ctx, tx, scope, organizationID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } identity := &coredata.Identity{} @@ -445,8 +445,8 @@ func (s *Service) GrantPortalAccessByIDs( } access := &coredata.TrustCenterAccess{} - if err := access.LoadByTrustCenterIDAndIdentityID(ctx, tx, scope, trustCenter.ID, identity.ID); err != nil { - return fmt.Errorf("cannot load trust center access: %w", err) + if err := access.LoadByTrustCenterIDAndIdentityID(ctx, tx, scope, compliancePage.ID, identity.ID); err != nil { + return fmt.Errorf("cannot load compliance page access: %w", err) } profile := &coredata.MembershipProfile{} @@ -477,7 +477,7 @@ func (s *Service) GrantPortalAccessByIDs( if len(fileIDs) > 0 { if err := coredata.GrantByTrustCenterFileIDs(ctx, tx, scope, access.ID, fileIDs, now); err != nil { - return fmt.Errorf("cannot grant trust center file accesses: %w", err) + return fmt.Errorf("cannot grant compliance page file accesses: %w", err) } } @@ -515,7 +515,7 @@ func (s *Service) sendPortalAccessEmail( access.UpdatedAt = now if err := access.Update(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot update trust center access with expiration: %w", err) + return fmt.Errorf("cannot update compliance page access with expiration: %w", err) } emailPresenterCfg, err := s.GetPortalEmailPresenterConfig(ctx, scope, access.TrustCenterID) @@ -527,7 +527,7 @@ func (s *Service) sendPortalAccessEmail( subject, textBody, htmlBody, err := emailPresenter.RenderTrustCenterAccess(ctx, organization.Name) if err != nil { - return fmt.Errorf("cannot render trust center access email: %w", err) + return fmt.Errorf("cannot render compliance page access email: %w", err) } accessEmail := coredata.NewEmail( @@ -560,9 +560,9 @@ func (s *Service) RejectOrRevokePortalAccessByIDs( return s.pg.WithTx( ctx, func(ctx context.Context, tx pg.Tx) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByOrganizationID(ctx, tx, scope, organizationID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByOrganizationID(ctx, tx, scope, organizationID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } identity := &coredata.Identity{} @@ -571,8 +571,8 @@ func (s *Service) RejectOrRevokePortalAccessByIDs( } access := &coredata.TrustCenterAccess{} - if err := access.LoadByTrustCenterIDAndIdentityID(ctx, tx, scope, trustCenter.ID, identity.ID); err != nil { - return fmt.Errorf("cannot load trust center access: %w", err) + if err := access.LoadByTrustCenterIDAndIdentityID(ctx, tx, scope, compliancePage.ID, identity.ID); err != nil { + return fmt.Errorf("cannot load compliance page access: %w", err) } profile := &coredata.MembershipProfile{} @@ -603,7 +603,7 @@ func (s *Service) RejectOrRevokePortalAccessByIDs( shouldSendEmail = true if err := coredata.RejectOrRevokeByTrustCenterFileIDs(ctx, tx, scope, access.ID, fileIDs, now); err != nil { - return fmt.Errorf("cannot reject/revoke trust center file accesses: %w", err) + return fmt.Errorf("cannot reject/revoke compliance page file accesses: %w", err) } } @@ -681,7 +681,7 @@ func (s *Service) sendPortalDocumentAccessRejectedEmail( organization.Name, ) if err != nil { - return fmt.Errorf("cannot render trust center documents access rejected email: %w", err) + return fmt.Errorf("cannot render compliance page documents access rejected email: %w", err) } accessEmail := coredata.NewEmail( diff --git a/pkg/complianceportal/visitor/portal_file_service.go b/pkg/complianceportal/visitor/portal_file_service.go index fb3d2553f..2b70118e6 100644 --- a/pkg/complianceportal/visitor/portal_file_service.go +++ b/pkg/complianceportal/visitor/portal_file_service.go @@ -47,7 +47,7 @@ func (s *Service) GetPortalFile( func(ctx context.Context, conn pg.Querier) error { err := trustCenterFile.LoadByID(ctx, conn, scope, trustCenterFileID) if err != nil { - return fmt.Errorf("cannot load trust center file: %w", err) + return fmt.Errorf("cannot load compliance page file: %w", err) } return nil @@ -58,11 +58,11 @@ func (s *Service) GetPortalFile( } if trustCenterFile.OrganizationID != organizationID { - return nil, ErrTrustCenterFileNotFound + return nil, ErrPortalFileNotFound } if trustCenterFile.TrustCenterVisibility == coredata.TrustCenterVisibilityNone { - return nil, ErrTrustCenterFileNotVisible + return nil, ErrPortalFileNotVisible } return trustCenterFile, nil @@ -82,7 +82,7 @@ func (s *Service) ListPortalFilesForOrganizationID( func(ctx context.Context, conn pg.Querier) error { err := trustCenterFiles.LoadByOrganizationID(ctx, conn, scope, organizationID, cursor, filter) if err != nil { - return fmt.Errorf("cannot load trust center files: %w", err) + return fmt.Errorf("cannot load compliance page files: %w", err) } return nil @@ -103,7 +103,7 @@ func (s *Service) ExportPortalFile( ) ([]byte, string, error) { fileData, mimeType, err := s.exportPortalFileData(ctx, scope, trustCenterFileID) if err != nil { - return nil, "", fmt.Errorf("cannot export trust center file: %w", err) + return nil, "", fmt.Errorf("cannot export compliance page file: %w", err) } if mimeType == "application/pdf" { @@ -141,7 +141,7 @@ func (s *Service) exportPortalFileData( func(ctx context.Context, conn pg.Querier) error { trustCenterFile = &coredata.TrustCenterFile{} if err := trustCenterFile.LoadByID(ctx, conn, scope, trustCenterFileID); err != nil { - return fmt.Errorf("cannot load trust center file: %w", err) + return fmt.Errorf("cannot load compliance page file: %w", err) } file = &coredata.File{} diff --git a/pkg/complianceportal/visitor/portal_reference_service.go b/pkg/complianceportal/visitor/portal_reference_service.go index 06de68ba6..88498ddd2 100644 --- a/pkg/complianceportal/visitor/portal_reference_service.go +++ b/pkg/complianceportal/visitor/portal_reference_service.go @@ -33,7 +33,7 @@ import ( func (s *Service) ListPortalReferencesForPortalID( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, cursor *page.Cursor[coredata.TrustCenterReferenceOrderField], ) (*page.Page[*coredata.TrustCenterReference, coredata.TrustCenterReferenceOrderField], error) { var references coredata.TrustCenterReferences @@ -43,9 +43,9 @@ func (s *Service) ListPortalReferencesForPortalID( ctx, func(ctx context.Context, conn pg.Querier) error { - err := references.LoadByTrustCenterID(ctx, conn, scope, trustCenterID, cursor) + err := references.LoadByTrustCenterID(ctx, conn, scope, compliancePageID, cursor) if err != nil { - return fmt.Errorf("cannot load trust center references: %w", err) + return fmt.Errorf("cannot load compliance page references: %w", err) } return nil @@ -72,7 +72,7 @@ func (s *Service) GeneratePortalReferenceLogoURL( }, ) if err != nil { - return "", fmt.Errorf("cannot load trust center reference: %w", err) + return "", fmt.Errorf("cannot load compliance page reference: %w", err) } file, err := s.fileManager.GetPublicFile(ctx, reference.LogoFileID) @@ -95,7 +95,7 @@ func (s *Service) GetPortalReference( func(ctx context.Context, conn pg.Querier) error { err := reference.LoadByID(ctx, conn, scope, referenceID) if err != nil { - return fmt.Errorf("cannot load trust center reference: %w", err) + return fmt.Errorf("cannot load compliance page reference: %w", err) } return nil diff --git a/pkg/complianceportal/visitor/portal_service.go b/pkg/complianceportal/visitor/portal_service.go index 68bbadd07..23d02c2a5 100644 --- a/pkg/complianceportal/visitor/portal_service.go +++ b/pkg/complianceportal/visitor/portal_service.go @@ -28,7 +28,6 @@ import ( "go.gearno.de/kit/pg" "go.probo.inc/probo/packages/emails" - "go.probo.inc/probo/pkg/complianceportal" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" ) @@ -36,26 +35,26 @@ import ( func (s *Service) GetPortal( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) (*coredata.TrustCenter, error) { - var trustCenter *coredata.TrustCenter + var compliancePage *coredata.TrustCenter err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter = &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, trustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage = &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } return nil }, ) if err != nil { - return nil, fmt.Errorf("cannot load trust center: %w", err) + return nil, fmt.Errorf("cannot load compliance page: %w", err) } - return trustCenter, nil + return compliancePage, nil } func (s *Service) GetPortalByOrganizationID( @@ -63,14 +62,14 @@ func (s *Service) GetPortalByOrganizationID( scope coredata.Scoper, organizationID gid.GID, ) (*coredata.TrustCenter, error) { - trustCenter := &coredata.TrustCenter{} + compliancePage := &coredata.TrustCenter{} err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - err := trustCenter.LoadByOrganizationID(ctx, conn, scope, organizationID) + err := compliancePage.LoadByOrganizationID(ctx, conn, scope, organizationID) if err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + return fmt.Errorf("cannot load compliance page: %w", err) } return nil @@ -80,30 +79,30 @@ func (s *Service) GetPortalByOrganizationID( return nil, err } - return trustCenter, nil + return compliancePage, nil } func (s *Service) GetPortalNDAFile( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) (*coredata.File, error) { var file *coredata.File err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, trustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - if trustCenter.NonDisclosureAgreementFileID == nil { + if compliancePage.NonDisclosureAgreementFileID == nil { return nil } file = &coredata.File{} - if err := file.LoadByID(ctx, conn, scope, *trustCenter.NonDisclosureAgreementFileID); err != nil { + if err := file.LoadByID(ctx, conn, scope, *compliancePage.NonDisclosureAgreementFileID); err != nil { return fmt.Errorf("cannot load file: %w", err) } @@ -120,7 +119,7 @@ func (s *Service) GetPortalNDAFile( func (s *Service) GeneratePortalNDAFileURL( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, expiresIn time.Duration, ) (string, error) { var file *coredata.File @@ -128,17 +127,17 @@ func (s *Service) GeneratePortalNDAFileURL( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, trustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - if trustCenter.NonDisclosureAgreementFileID == nil { + if compliancePage.NonDisclosureAgreementFileID == nil { return fmt.Errorf("no NDA file found") } file = &coredata.File{} - if err := file.LoadByID(ctx, conn, scope, *trustCenter.NonDisclosureAgreementFileID); err != nil { + if err := file.LoadByID(ctx, conn, scope, *compliancePage.NonDisclosureAgreementFileID); err != nil { return fmt.Errorf("cannot load file: %w", err) } @@ -281,12 +280,11 @@ func (s *Service) GetPortalEmailPresenterConfig( return fmt.Errorf("cannot load organization: %w", err) } - publicURL, err := complianceportal.PublicURLForTrustCenter( + publicURL, err := s.management.PublicURLForCompliancePage( ctx, conn, scope, compliancePage, - s.baseDomain, ) if err != nil { return fmt.Errorf("cannot resolve compliance page URL: %w", err) @@ -327,24 +325,24 @@ func (s *Service) GetPortalEmailPresenterConfig( func (s *Service) GetPortalMailingList( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, ) (*coredata.MailingList, error) { var mailingList *coredata.MailingList err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, trustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - if trustCenter.MailingListID == nil { + if compliancePage.MailingListID == nil { return nil } mailingList = &coredata.MailingList{} - if err := mailingList.LoadByID(ctx, conn, scope, *trustCenter.MailingListID); err != nil { + if err := mailingList.LoadByID(ctx, conn, scope, *compliancePage.MailingListID); err != nil { return fmt.Errorf("cannot load mailing list: %w", err) } diff --git a/pkg/complianceportal/visitor/service.go b/pkg/complianceportal/visitor/service.go index 5df688b05..d3429ab94 100644 --- a/pkg/complianceportal/visitor/service.go +++ b/pkg/complianceportal/visitor/service.go @@ -30,7 +30,7 @@ import ( "go.gearno.de/kit/log" "go.gearno.de/kit/pg" "go.probo.inc/probo/packages/emails" - "go.probo.inc/probo/pkg/complianceportal" + "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/esign" "go.probo.inc/probo/pkg/filemanager" @@ -45,7 +45,7 @@ const NDAConsentText = "By clicking \"Review and sign\", I consent to sign this type ( // Service is the visitor-facing compliance portal service. It exposes the - // public read operations for the trust center and its related resources as + // public read operations for the compliance page and its related resources as // methods on a single type. Service struct { pg *pg.Client @@ -61,6 +61,7 @@ type ( logger *log.Logger slack *slack.Service resourceAlias *resourcealias.Service + management *management.Service } ) @@ -78,6 +79,7 @@ func NewService( logger *log.Logger, slack *slack.Service, resourceAliasSvc *resourcealias.Service, + managementSvc *management.Service, ) *Service { svc := &Service{ pg: pgClient, @@ -93,6 +95,7 @@ func NewService( logger: logger, slack: slack, resourceAlias: resourceAliasSvc, + management: managementSvc, } return svc @@ -102,18 +105,18 @@ func (s *Service) GetPortalByID( ctx context.Context, id gid.GID, ) (*coredata.TrustCenter, error) { - trustCenter := &coredata.TrustCenter{} + compliancePage := &coredata.TrustCenter{} err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - err := trustCenter.LoadByID(ctx, conn, coredata.NewNoScope(), id) + err := compliancePage.LoadByID(ctx, conn, coredata.NewNoScope(), id) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return ErrPageNotFound } - return fmt.Errorf("cannot load trust center: %w", err) + return fmt.Errorf("cannot load compliance page: %w", err) } return nil @@ -123,25 +126,25 @@ func (s *Service) GetPortalByID( return nil, err } - return trustCenter, nil + return compliancePage, nil } func (s *Service) GetPortalBySlug( ctx context.Context, slug string, ) (*coredata.TrustCenter, error) { - trustCenter := &coredata.TrustCenter{} + compliancePage := &coredata.TrustCenter{} err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - err := trustCenter.LoadBySlug(ctx, conn, slug) + err := compliancePage.LoadBySlug(ctx, conn, slug) if err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return ErrPageNotFound } - return fmt.Errorf("cannot load trust center: %w", err) + return fmt.Errorf("cannot load compliance page: %w", err) } return nil @@ -151,25 +154,25 @@ func (s *Service) GetPortalBySlug( return nil, err } - return trustCenter, nil + return compliancePage, nil } // GetEffectiveCanonicalHost returns the host a compliance page should be // served under. It prefers the primary domain when its certificate is active, // and otherwise falls back to the managed probopage subdomain. An empty string // is returned when no serving host can be determined. -func (s *Service) GetPortalEffectiveCanonicalHost(ctx context.Context, trustCenterID gid.GID) (string, error) { +func (s *Service) GetPortalEffectiveCanonicalHost(ctx context.Context, compliancePageID gid.GID) (string, error) { var host string err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, coredata.NewNoScope(), trustCenterID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, coredata.NewNoScope(), compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - domain, err := complianceportal.EffectiveDomainForTrustCenter(ctx, conn, coredata.NewNoScope(), trustCenter) + domain, err := s.management.EffectiveDomainForCompliancePage(ctx, conn, coredata.NewNoScope(), compliancePage) if err != nil { return err } @@ -189,7 +192,7 @@ func (s *Service) GetPortalEffectiveCanonicalHost(ctx context.Context, trustCent } func (s *Service) GetPortalByDomainName(ctx context.Context, domain string) (*coredata.TrustCenter, error) { - trustCenter := &coredata.TrustCenter{} + compliancePage := &coredata.TrustCenter{} err := s.pg.WithConn( ctx, @@ -203,13 +206,13 @@ func (s *Service) GetPortalByDomainName(ctx context.Context, domain string) (*co return fmt.Errorf("cannot load custom domain: %w", err) } - trustCenter = &coredata.TrustCenter{} - if err := trustCenter.LoadByDomainID(ctx, conn, customDomain.ID); err != nil { + compliancePage = &coredata.TrustCenter{} + if err := compliancePage.LoadByDomainID(ctx, conn, customDomain.ID); err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return ErrPageNotFound } - return fmt.Errorf("cannot load trust center: %w", err) + return fmt.Errorf("cannot load compliance page: %w", err) } return nil @@ -219,37 +222,37 @@ func (s *Service) GetPortalByDomainName(ctx context.Context, domain string) (*co return nil, err } - return trustCenter, err + return compliancePage, err } // GetPortalEmailPresenterConfigByOrganizationID resolves the emails.PresenterConfig for -// the trust center that belongs to the given organization. This is used by the +// the compliance page that belongs to the given organization. This is used by the // esign certificate worker which needs per-org branding at render time. func (s *Service) GetPortalEmailPresenterConfigByOrganizationID(ctx context.Context, orgID gid.GID) (emails.PresenterConfig, error) { - var trustCenter coredata.TrustCenter + var compliancePage coredata.TrustCenter scope := coredata.NewScopeFromObjectID(orgID) err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - return trustCenter.LoadByOrganizationID(ctx, conn, scope, orgID) + return compliancePage.LoadByOrganizationID(ctx, conn, scope, orgID) }, ) if err != nil { - return emails.PresenterConfig{}, fmt.Errorf("cannot load trust center for org %s: %w", orgID, err) + return emails.PresenterConfig{}, fmt.Errorf("cannot load compliance page for org %s: %w", orgID, err) } - return s.GetPortalEmailPresenterConfig(ctx, scope, trustCenter.ID) + return s.GetPortalEmailPresenterConfig(ctx, scope, compliancePage.ID) } func (s *Service) GetPortalOrganization( ctx context.Context, - trustCenterID gid.GID, + compliancePageID gid.GID, ) (*coredata.Organization, error) { - trustCenter, err := s.GetPortalByID(ctx, trustCenterID) + compliancePage, err := s.GetPortalByID(ctx, compliancePageID) if err != nil { - return nil, fmt.Errorf("cannot load trust center: %w", err) + return nil, fmt.Errorf("cannot load compliance page: %w", err) } org := &coredata.Organization{} @@ -257,7 +260,7 @@ func (s *Service) GetPortalOrganization( err = s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - return org.LoadByID(ctx, conn, coredata.NewNoScope(), trustCenter.OrganizationID) + return org.LoadByID(ctx, conn, coredata.NewNoScope(), compliancePage.OrganizationID) }, ) if err != nil { @@ -305,17 +308,17 @@ func (s *Service) GetPortalNDAFileByID( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) error { - trustCenter := &coredata.TrustCenter{} - if err := trustCenter.LoadByID(ctx, conn, scope, compliancePageID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + compliancePage := &coredata.TrustCenter{} + if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { + return fmt.Errorf("cannot load compliance page: %w", err) } - if trustCenter.NonDisclosureAgreementFileID == nil { + if compliancePage.NonDisclosureAgreementFileID == nil { return ErrNDAFileNotFound } file = &coredata.File{} - if err := file.LoadByID(ctx, conn, scope, *trustCenter.NonDisclosureAgreementFileID); err != nil { + if err := file.LoadByID(ctx, conn, scope, *compliancePage.NonDisclosureAgreementFileID); err != nil { if errors.Is(err, coredata.ErrResourceNotFound) { return ErrNDAFileNotFound } @@ -349,7 +352,7 @@ func (s *Service) ProvisionPortalMember( func(ctx context.Context, tx pg.Tx) error { compliancePage := &coredata.TrustCenter{} if err := compliancePage.LoadByID(ctx, tx, scope, compliancePageID); err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + return fmt.Errorf("cannot load compliance page: %w", err) } identity := &coredata.Identity{} @@ -360,7 +363,7 @@ func (s *Service) ProvisionPortalMember( access = &coredata.TrustCenterAccess{} if err := access.LoadByTrustCenterIDAndIdentityID(ctx, tx, scope, compliancePageID, identityID); err != nil { if !errors.Is(err, coredata.ErrResourceNotFound) { - return fmt.Errorf("cannot load trust center access: %w", err) + return fmt.Errorf("cannot load compliance page access: %w", err) } access = &coredata.TrustCenterAccess{ @@ -399,7 +402,7 @@ func (s *Service) ProvisionPortalMember( } if err := access.Insert(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot insert trust center access: %w", err) + return fmt.Errorf("cannot insert compliance page access: %w", err) } } diff --git a/pkg/complianceportal/visitor/third_party_service.go b/pkg/complianceportal/visitor/third_party_service.go index 1c9fc73e8..94f8d72e9 100644 --- a/pkg/complianceportal/visitor/third_party_service.go +++ b/pkg/complianceportal/visitor/third_party_service.go @@ -87,7 +87,7 @@ func (s *Service) ListThirdPartiesForOrganizationID( return page.NewPage(thirdParties, cursor), nil } -func (s *Service) ListDistinctTrustCenterCategoriesForOrganizationID( +func (s *Service) ListDistinctPortalCategoriesForOrganizationID( ctx context.Context, scope coredata.Scoper, organizationID gid.GID, @@ -116,7 +116,7 @@ func (s *Service) ListDistinctTrustCenterCategoriesForOrganizationID( return categories, nil } -func (s *Service) ListDistinctTrustCenterCountriesForOrganizationID( +func (s *Service) ListDistinctPortalCountriesForOrganizationID( ctx context.Context, scope coredata.Scoper, organizationID gid.GID, @@ -148,7 +148,7 @@ func (s *Service) ListDistinctTrustCenterCountriesForOrganizationID( func (s *Service) CountThirdPartiesForPortalID( ctx context.Context, scope coredata.Scoper, - trustCenterID gid.GID, + compliancePageID gid.GID, filter *coredata.ThirdPartyFilter, ) (int, error) { if filter == nil { @@ -161,14 +161,14 @@ func (s *Service) CountThirdPartiesForPortalID( err := s.pg.WithConn( ctx, func(ctx context.Context, conn pg.Querier) (err error) { - trustCenter, err := s.GetPortal(ctx, scope, trustCenterID) + compliancePage, err := s.GetPortal(ctx, scope, compliancePageID) if err != nil { - return fmt.Errorf("cannot load trust center: %w", err) + return fmt.Errorf("cannot load compliance page: %w", err) } thirdParties := &coredata.ThirdParties{} - count, err = thirdParties.CountByOrganizationID(ctx, conn, scope, trustCenter.OrganizationID, filter) + count, err = thirdParties.CountByOrganizationID(ctx, conn, scope, compliancePage.OrganizationID, filter) if err != nil { return fmt.Errorf("cannot count thirdParties: %w", err) } diff --git a/pkg/coredata/migrations/20260717T121103Z.sql b/pkg/coredata/migrations/20260717T121103Z.sql new file mode 100644 index 000000000..5eab3dfa3 --- /dev/null +++ b/pkg/coredata/migrations/20260717T121103Z.sql @@ -0,0 +1,21 @@ +-- Copyright (c) 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. + +-- Append a random hex suffix to every compliance page slug so public URLs +-- are no longer guessable from the organization name. + +UPDATE trust_centers +SET + slug = slug || '-' || encode(gen_random_bytes(4), 'hex'), + updated_at = clock_timestamp(); diff --git a/pkg/iam/auth_service.go b/pkg/iam/auth_service.go index 29b17d455..ee3945a20 100644 --- a/pkg/iam/auth_service.go +++ b/pkg/iam/auth_service.go @@ -65,10 +65,6 @@ type ( Email mail.Addr URLPath string Continue *string - // If users tries to connect to compliance page, we must brand the emails accordingly - CompliancePageID *gid.GID - // OrganizationID brands compliance portal magic-link emails. - OrganizationID *gid.GID // OAuth2ClientIDRaw brands connect authorize magic-link emails. OAuth2ClientIDRaw *string MagicLinkBaseURL *string @@ -621,27 +617,10 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques if branding != nil { senderName = branding.Name } - } else if req.OrganizationID != nil { - organization := &coredata.Organization{} - - if err := organization.LoadByID(ctx, tx, coredata.NewNoScope(), *req.OrganizationID); err != nil { - return fmt.Errorf("cannot load organization: %w", err) - } - - senderName = organization.Name } emailPresenterCfg := emails.DefaultPresenterConfig(s.baseURL) - if req.CompliancePageID != nil { - var err error - - emailPresenterCfg, err = s.CompliancePageService.EmailPresenterConfig(ctx, *req.CompliancePageID) - if err != nil { - return fmt.Errorf("cannot get compliance page email presenter config: %w", err) - } - } - if req.MagicLinkBaseURL != nil { emailPresenterCfg.BaseURL = *req.MagicLinkBaseURL } @@ -659,20 +638,13 @@ func (s AuthService) SendMagicLink(ctx context.Context, req *SendMagicLinkReques return fmt.Errorf("cannot render magic link email: %w", err) } - var emailOpts *coredata.EmailOptions - if req.CompliancePageID != nil { - emailOpts = &coredata.EmailOptions{ - SenderName: &senderName, - } - } - magicLinkEmail := coredata.NewEmail( fullName, req.Email, subject, textBody, htmlBody, - emailOpts, + nil, ) if err := magicLinkEmail.Insert(ctx, tx); err != nil { diff --git a/pkg/iam/compliance_page_service.go b/pkg/iam/compliance_page_service.go deleted file mode 100644 index 0b78a021f..000000000 --- a/pkg/iam/compliance_page_service.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2026 Probo Inc . -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -package iam - -import ( - "context" - "fmt" - "path/filepath" - "time" - - "go.gearno.de/kit/pg" - "go.probo.inc/probo/packages/emails" - "go.probo.inc/probo/pkg/complianceportal/resolver" - "go.probo.inc/probo/pkg/coredata" - "go.probo.inc/probo/pkg/gid" -) - -type ( - CompliancePageService struct { - *Service - } -) - -func NewCompliancePageService(svc *Service) *CompliancePageService { - return &CompliancePageService{Service: svc} -} - -func (s *CompliancePageService) GenerateLogoURL( - ctx context.Context, - compliancePageID gid.GID, - expiresIn time.Duration, -) (*string, error) { - file := &coredata.File{} - compliancePage := &coredata.TrustCenter{} - - scope := coredata.NewScopeFromObjectID(compliancePageID) - - err := s.pg.WithConn( - ctx, - func(ctx context.Context, conn pg.Querier) error { - if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { - return fmt.Errorf("cannot load compliance page: %w", err) - } - - if compliancePage.LogoFileID == nil { - return nil - } - - if err := file.LoadByID(ctx, conn, scope, *compliancePage.LogoFileID); err != nil { - return fmt.Errorf("cannot load file: %w", err) - } - - return nil - }, - ) - if err != nil { - return nil, err - } - - if compliancePage.LogoFileID == nil { - return nil, nil - } - - if file.FileKey == "" { - return nil, nil - } - - presignedURL, err := s.fm.GeneratePresignedURL(ctx, file, expiresIn) - if err != nil { - return nil, fmt.Errorf("cannot generate file URL: %w", err) - } - - return &presignedURL, nil -} - -func (s *CompliancePageService) EmailPresenterConfig(ctx context.Context, compliancePageID gid.GID) (emails.PresenterConfig, error) { - var ( - compliancePage = &coredata.TrustCenter{} - organization = &coredata.Organization{} - compliancePageURL string - logoFile = &coredata.File{} - emailPresenterCfg = emails.DefaultPresenterConfig(s.baseURL) - ) - - scope := coredata.NewScopeFromObjectID(compliancePageID) - - err := s.pg.WithConn( - ctx, - func(ctx context.Context, conn pg.Querier) error { - if err := compliancePage.LoadByID(ctx, conn, scope, compliancePageID); err != nil { - return fmt.Errorf("cannot load compliance page: %w", err) - } - - if compliancePage.LogoFileID != nil { - if err := logoFile.LoadByID(ctx, conn, scope, *compliancePage.LogoFileID); err != nil { - return fmt.Errorf("cannot load logoFile: %w", err) - } - } - - if err := organization.LoadByID(ctx, conn, scope, compliancePage.OrganizationID); err != nil { - return fmt.Errorf("cannot load organization: %w", err) - } - - publicURL, err := resolver.PublicURLForTrustCenter( - ctx, - conn, - scope, - compliancePage, - s.trustCenterBaseDomain, - ) - if err != nil { - return fmt.Errorf("cannot resolve compliance page URL: %w", err) - } - - compliancePageURL = publicURL - - return nil - }, - ) - if err != nil { - return emailPresenterCfg, err - } - - emailPresenterCfg.BaseURL = compliancePageURL - - if compliancePage.LogoFileID != nil { - if logoFile.FileKey == "" { - return emailPresenterCfg, nil - } - - // If logo exists, then we will brand the emails with the org as a sender - emailPresenterCfg.SenderCompanyLogoPath = filepath.Join("/api/files/v1/public/", logoFile.ID.String()) - emailPresenterCfg.SenderCompanyName = organization.Name - - if compliancePage.WebsiteURL != nil { - emailPresenterCfg.SenderCompanyWebsiteURL = *compliancePage.WebsiteURL - } - - if compliancePage.HeadquarterAddress != nil { - emailPresenterCfg.SenderCompanyHeadquarterAddress = *compliancePage.HeadquarterAddress - } - } - - return emailPresenterCfg, nil -} diff --git a/pkg/iam/organization_service.go b/pkg/iam/organization_service.go index e1ea3ebca..f11d7d0d0 100644 --- a/pkg/iam/organization_service.go +++ b/pkg/iam/organization_service.go @@ -613,7 +613,7 @@ func (s *OrganizationService) CreateOrganization( OrganizationID: organization.ID, TenantID: organization.TenantID, Active: false, - Slug: slug.Make(organization.Name), + Slug: slug.MakeWithEntropy(organization.Name), Title: organization.Name, SearchEngineIndexing: coredata.SearchEngineIndexingNotIndexable, MailingListID: &mailingList.ID, diff --git a/pkg/iam/service.go b/pkg/iam/service.go index f3428add3..b3cfc7f76 100644 --- a/pkg/iam/service.go +++ b/pkg/iam/service.go @@ -69,18 +69,17 @@ type ( privateKey *rsa.PrivateKey logger *log.Logger - AccountService *AccountService - OrganizationService *OrganizationService - CompliancePageService *CompliancePageService - SessionService *SessionService - AuthService *AuthService - SAMLService *saml.Service - OIDCService *oidc.Service - SCIMService *scim.Service - APIKeyService *APIKeyService - OAuth2ServerService *oauth2.Service - Authorizer *Authorizer - OAuth2ScopeRegistry *oauth2scope.Registry + AccountService *AccountService + OrganizationService *OrganizationService + SessionService *SessionService + AuthService *AuthService + SAMLService *saml.Service + OIDCService *oidc.Service + SCIMService *scim.Service + APIKeyService *APIKeyService + OAuth2ServerService *oauth2.Service + Authorizer *Authorizer + OAuth2ScopeRegistry *oauth2scope.Registry samlDomainVerifier *SAMLDomainVerifier } @@ -174,7 +173,6 @@ func NewService( svc.AccountService = NewAccountService(svc) svc.OrganizationService = NewOrganizationService(svc) - svc.CompliancePageService = NewCompliancePageService(svc) svc.SessionService = NewSessionService(svc) svc.AuthService = NewAuthService(svc) svc.APIKeyService = NewAPIKeyService(svc) diff --git a/pkg/mailman/compliance_mailing_list.go b/pkg/mailman/compliance_mailing_list.go index 268e6bf22..a43a3ebf8 100644 --- a/pkg/mailman/compliance_mailing_list.go +++ b/pkg/mailman/compliance_mailing_list.go @@ -29,7 +29,6 @@ import ( "go.gearno.de/kit/pg" "go.probo.inc/probo/packages/emails" "go.probo.inc/probo/pkg/baseurl" - "go.probo.inc/probo/pkg/complianceportal/resolver" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/mail" @@ -98,12 +97,11 @@ func (s *Service) mailingListEmailConfig( return fmt.Errorf("cannot load organization: %w", err) } - publicURL, err := resolver.PublicURLForTrustCenter( + publicURL, err := s.compliancePortal.PublicURLForCompliancePage( ctx, conn, scope, compliancePage, - s.trustCenterBaseDomain, ) if err != nil { return fmt.Errorf("cannot resolve compliance page URL: %w", err) diff --git a/pkg/mailman/service.go b/pkg/mailman/service.go index eb2f2600a..392c93840 100644 --- a/pkg/mailman/service.go +++ b/pkg/mailman/service.go @@ -30,6 +30,7 @@ import ( "go.gearno.de/kit/pg" "go.probo.inc/probo/packages/emails" "go.probo.inc/probo/pkg/baseurl" + "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/crypto/cipher" "go.probo.inc/probo/pkg/filemanager" @@ -51,14 +52,14 @@ const ( ) type Service struct { - pg *pg.Client - fm *filemanager.Service - tokenSecret string - apiBaseURL *baseurl.BaseURL - trustCenterBaseDomain string - bucket string - encryptionKey cipher.EncryptionKey - logger *log.Logger + pg *pg.Client + fm *filemanager.Service + tokenSecret string + apiBaseURL *baseurl.BaseURL + compliancePortal *management.Service + bucket string + encryptionKey cipher.EncryptionKey + logger *log.Logger } func NewService( @@ -66,20 +67,20 @@ func NewService( fm *filemanager.Service, tokenSecret string, apiBaseURL *baseurl.BaseURL, - trustCenterBaseDomain string, + compliancePortal *management.Service, bucket string, encryptionKey cipher.EncryptionKey, logger *log.Logger, ) *Service { return &Service{ - pg: pgClient, - fm: fm, - tokenSecret: tokenSecret, - apiBaseURL: apiBaseURL, - trustCenterBaseDomain: trustCenterBaseDomain, - bucket: bucket, - encryptionKey: encryptionKey, - logger: logger, + pg: pgClient, + fm: fm, + tokenSecret: tokenSecret, + apiBaseURL: apiBaseURL, + compliancePortal: compliancePortal, + bucket: bucket, + encryptionKey: encryptionKey, + logger: logger, } } diff --git a/pkg/probod/probod.go b/pkg/probod/probod.go index f353ab1e2..b1e8b4d1b 100644 --- a/pkg/probod/probod.go +++ b/pkg/probod/probod.go @@ -52,7 +52,6 @@ import ( "go.probo.inc/probo/pkg/awsconfig" "go.probo.inc/probo/pkg/baseurl" "go.probo.inc/probo/pkg/certmanager" - "go.probo.inc/probo/pkg/complianceportal" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/complianceportal/visitor" "go.probo.inc/probo/pkg/connector" @@ -495,7 +494,7 @@ func (impl *Implm) Run( oauth2ScopeRegistry := oauth2scope.NewRegistry(). Register(iam.IAMOAuth2ScopeMappings). Register(probo.OAuth2ScopeMappings). - Register(complianceportal.OAuth2ScopeMappings). + Register(management.OAuth2ScopeMappings). Register(agentrun.OAuth2ScopeMappings). Register(accessreview.OAuth2ScopeMappings). Register(resourcealias.OAuth2ScopeMappings) @@ -618,12 +617,26 @@ func (impl *Implm) Run( l.Named("esign"), ) + resourceAliasService := resourcealias.NewService(pgClient) + + managementService := management.NewService( + pgClient, + s3Client, + impl.cfg.AWS.Bucket, + baseURL.String(), + impl.cfg.TrustCenter.BaseDomain, + fileManagerService, + certManagerService, + slackService, + l.Named("compliance-portal-management"), + ) + mailmanService := mailman.NewService( pgClient, fileManagerService, impl.cfg.Auth.Cookie.Secret, baseURL, - impl.cfg.TrustCenter.BaseDomain, + managementService, impl.cfg.AWS.Bucket, encryptionKey, l, @@ -658,20 +671,6 @@ func (impl *Implm) Run( return fmt.Errorf("cannot create probo service: %w", err) } - resourceAliasService := resourcealias.NewService(pgClient) - - managementService := management.NewService( - pgClient, - s3Client, - impl.cfg.AWS.Bucket, - baseURL.String(), - impl.cfg.TrustCenter.BaseDomain, - fileManagerService, - certManagerService, - slackService, - l.Named("compliance-portal-management"), - ) - trustService := visitor.NewService( pgClient, s3Client, @@ -686,6 +685,7 @@ func (impl *Implm) Run( l, slackService, resourceAliasService, + managementService, ) staticCIMDAllow := oauth2.CIMDAllowFromClientIDs(impl.cfg.Auth.OAuth2Server.CIMDAllowedClientIDs) @@ -716,7 +716,7 @@ func (impl *Implm) Run( iamService.Authorizer.RegisterPolicySet(agentrun.PolicySet()) iamService.Authorizer.RegisterPolicySet(accessreview.PolicySet()) iamService.Authorizer.RegisterPolicySet(resourcealias.PolicySet()) - iamService.Authorizer.RegisterPolicySet(complianceportal.PolicySet()) + iamService.Authorizer.RegisterPolicySet(management.PolicySet()) thirdPartyService := thirdparty.NewService(pgClient, fileManagerService, thirdPartyVetter) riskManagementService := riskmanagement.NewService(pgClient) @@ -732,6 +732,7 @@ func (impl *Implm) Run( Trust: trustService, ESign: esignService, Management: managementService, + CertManager: certManagerService, AccessReview: accessReviewService, AgentRun: agentRunService, Mailman: mailmanService, diff --git a/pkg/server/api/api.go b/pkg/server/api/api.go index 5cbfab174..4410e4821 100644 --- a/pkg/server/api/api.go +++ b/pkg/server/api/api.go @@ -34,6 +34,7 @@ import ( "go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/agentrun" "go.probo.inc/probo/pkg/baseurl" + "go.probo.inc/probo/pkg/certmanager" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/complianceportal/visitor" "go.probo.inc/probo/pkg/connector" @@ -70,6 +71,7 @@ type ( Trust *visitor.Service ESign *esign.Service Management *management.Service + CertManager *certmanager.Service AccessReview *accessreview.Service AgentRun *agentrun.Service Slack *slack.Service @@ -192,6 +194,7 @@ func NewServer(cfg Config) (*Server, error) { cfg.IAM, cfg.ESign, cfg.Management, + cfg.CertManager, cfg.AccessReview, cfg.AgentRun, cfg.Mailman, @@ -225,6 +228,7 @@ func NewServer(cfg Config) (*Server, error) { cfg.Logger.Named("mcp.v1"), cfg.Probo, cfg.Management, + cfg.CertManager, cfg.ResourceAlias, cfg.ThirdParty, cfg.IAM, diff --git a/pkg/server/api/complianceportal/oauth.go b/pkg/server/api/complianceportal/oauth.go index 98ce4e141..ede557d52 100644 --- a/pkg/server/api/complianceportal/oauth.go +++ b/pkg/server/api/complianceportal/oauth.go @@ -15,23 +15,23 @@ package complianceportal import ( - portal "go.probo.inc/probo/pkg/complianceportal" + "go.probo.inc/probo/pkg/complianceportal/visitor" ) const ( - VisitorOAuthScope = portal.VisitorOAuthScope + VisitorOAuthScope = visitor.VisitorOAuthScope GraphQLPath = "/graphql" - CIMDMetadataPath = portal.CIMDMetadataPath - BrandLogoPath = portal.BrandLogoPath - BrandDarkLogoPath = portal.BrandDarkLogoPath + CIMDMetadataPath = visitor.CIMDMetadataPath + BrandLogoPath = visitor.BrandLogoPath + BrandDarkLogoPath = visitor.BrandDarkLogoPath OAuthInitiatePath = "/initiate" - OAuthCallbackPath = portal.OAuthCallbackPath + OAuthCallbackPath = visitor.OAuthCallbackPath ) func CIMDClientIDURL(portalBaseURL string) (string, error) { - return portal.CIMDClientIDURL(portalBaseURL) + return visitor.CIMDClientIDURL(portalBaseURL) } func OAuthCallbackURL(portalBaseURL string) (string, error) { - return portal.OAuthCallbackURL(portalBaseURL) + return visitor.OAuthCallbackURL(portalBaseURL) } diff --git a/pkg/server/api/complianceportal/v1/auth_resolvers.go b/pkg/server/api/complianceportal/v1/auth_resolvers.go index b4b2dec61..c657be49b 100644 --- a/pkg/server/api/complianceportal/v1/auth_resolvers.go +++ b/pkg/server/api/complianceportal/v1/auth_resolvers.go @@ -10,150 +10,14 @@ import ( "errors" "go.gearno.de/kit/log" - "go.probo.inc/probo/pkg/baseurl" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/iam" - "go.probo.inc/probo/pkg/saferedirect" "go.probo.inc/probo/pkg/server/api/authn" "go.probo.inc/probo/pkg/server/api/complianceportal" "go.probo.inc/probo/pkg/server/api/complianceportal/v1/types" "go.probo.inc/probo/pkg/server/gqlutils" ) -// SendMagicLink is the resolver for the sendMagicLink field. -func (r *mutationResolver) SendMagicLink(ctx context.Context, input types.SendMagicLinkInput) (*types.SendMagicLinkPayload, error) { - trustCenter := complianceportal.CompliancePageFromContext(ctx) - - baseURL := complianceportal.CompliancePageBaseURLFromContext(ctx) - - safeRedirect := saferedirect.New(saferedirect.StaticHosts(baseurl.MustParse(*baseURL).Host())) - - if input.Continue != nil { - _, ok := safeRedirect.Validate(ctx, *input.Continue) - if !ok { - return nil, gqlutils.Invalidf(ctx, "invalid continue URL") - } - } - - req := &iam.SendMagicLinkRequest{ - Email: input.Email, - CompliancePageID: &trustCenter.ID, - OrganizationID: &trustCenter.OrganizationID, - URLPath: "verify-magic-link", - Continue: input.Continue, - } - - if err := r.iam.AuthService.SendMagicLink(ctx, req); err != nil { - r.logger.ErrorCtx(ctx, "cannot send magic link", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - return nil, nil -} - -// VerifyMagicLink is the resolver for the verifyMagicLink field. -func (r *mutationResolver) VerifyMagicLink(ctx context.Context, input types.VerifyMagicLinkInput) (*types.VerifyMagicLinkPayload, error) { - session := authn.SessionFromContext(ctx) - identity := authn.IdentityFromContext(ctx) - - email, err := r.iam.AuthService.GetMagicLinkEmail(ctx, input.Token) - if err != nil { - if _, ok := errors.AsType[*iam.ErrExpiredToken](err); ok { - return nil, gqlutils.TokenExpired(ctx, err) - } - - if _, ok := errors.AsType[*iam.ErrInvalidToken](err); ok { - return nil, gqlutils.Invalid(ctx, err) - } - - r.logger.ErrorCtx(ctx, "cannot get magic link email", log.Error(err)) - - return nil, gqlutils.Internal(ctx) - } - - var continueURL *string - - switch { - case session == nil: - var err error - - identity, session, continueURL, err = r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token) - if err != nil { - if _, ok := errors.AsType[*iam.ErrExpiredToken](err); ok { - return nil, gqlutils.TokenExpired(ctx, err) - } - - if _, ok := errors.AsType[*iam.ErrTokenAlreadyUsed](err); ok { - return nil, gqlutils.TokenAlreadyUsed(ctx, err) - } - - if _, ok := errors.AsType[*iam.ErrInvalidToken](err); ok { - return nil, gqlutils.Invalid(ctx, err) - } - - r.logger.ErrorCtx(ctx, "cannot open session with magic link", log.Error(err)) - - return nil, gqlutils.Internal(ctx) - } - case identity.EmailAddress != email: - if err := r.iam.SessionService.CloseSession(ctx, session.ID); err != nil { - r.logger.ErrorCtx(ctx, "cannot close session", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - var err error - - identity, session, continueURL, err = r.iam.AuthService.OpenSessionWithMagicLink(ctx, input.Token) - if err != nil { - if _, ok := errors.AsType[*iam.ErrExpiredToken](err); ok { - return nil, gqlutils.TokenExpired(ctx, err) - } - - if _, ok := errors.AsType[*iam.ErrTokenAlreadyUsed](err); ok { - return nil, gqlutils.TokenAlreadyUsed(ctx, err) - } - - if _, ok := errors.AsType[*iam.ErrInvalidToken](err); ok { - return nil, gqlutils.Invalid(ctx, err) - } - - r.logger.ErrorCtx(ctx, "cannot open session with magic link", log.Error(err)) - - return nil, gqlutils.Internal(ctx) - } - } - - req := gqlutils.HTTPRequestFromContext(ctx) - if req == nil { - return nil, gqlutils.Internal(ctx) - } - - host, ok := complianceportal.TrustedRequestHost(req) - if !ok { - return nil, gqlutils.Internal(ctx) - } - - session.Data = coredata.SessionDataForHost(host) - if err := r.iam.SessionService.UpdateSessionData(ctx, session.ID, session.Data); err != nil { - r.logger.ErrorCtx(ctx, "cannot bind session to host", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - trustCenter := complianceportal.CompliancePageFromContext(ctx) - - if _, err := r.trust.ProvisionPortalMember(ctx, trustCenter.ID, identity.ID); err != nil { - r.logger.ErrorCtx(ctx, "cannot provision member", log.Error(err)) - return nil, gqlutils.Internal(ctx) - } - - w := gqlutils.HTTPResponseWriterFromContext(ctx) - r.sessionCookie.Set(w, session) - - return &types.VerifyMagicLinkPayload{ - Continue: continueURL, - }, nil -} - // UpdateFullName is the resolver for the updateFullName field. func (r *mutationResolver) UpdateFullName(ctx context.Context, input types.UpdateFullNameInput) (*types.UpdateFullNamePayload, error) { identity := authn.IdentityFromContext(ctx) diff --git a/pkg/server/api/complianceportal/v1/base_resolvers.go b/pkg/server/api/complianceportal/v1/base_resolvers.go index d16624f6f..5eab20c4e 100644 --- a/pkg/server/api/complianceportal/v1/base_resolvers.go +++ b/pkg/server/api/complianceportal/v1/base_resolvers.go @@ -132,7 +132,7 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error trustCenterFile, err := trustService.GetPortalFile(ctx, scope, trustCenter.OrganizationID, id) if err != nil { - if errors.Is(err, visitor.ErrTrustCenterFileNotFound) || errors.Is(err, visitor.ErrTrustCenterFileNotVisible) { + if errors.Is(err, visitor.ErrPortalFileNotFound) || errors.Is(err, visitor.ErrPortalFileNotVisible) { return nil, gqlutils.NotFoundf(ctx, "node %q not found", id) } diff --git a/pkg/server/api/complianceportal/v1/graphql/auth.graphql b/pkg/server/api/complianceportal/v1/graphql/auth.graphql index d1ee32af0..cc0b4f5ca 100644 --- a/pkg/server/api/complianceportal/v1/graphql/auth.graphql +++ b/pkg/server/api/complianceportal/v1/graphql/auth.graphql @@ -1,30 +1,9 @@ extend type Mutation { - sendMagicLink(input: SendMagicLinkInput!): SendMagicLinkPayload - @authentication(required: OPTIONAL) - verifyMagicLink(input: VerifyMagicLinkInput!): VerifyMagicLinkPayload - @authentication(required: OPTIONAL) updateFullName(input: UpdateFullNameInput!): UpdateFullNamePayload @authentication(required: PRESENT) @sessionOnly signOut: SignOutPayload! @authentication(required: PRESENT) @sessionOnly } -input SendMagicLinkInput { - email: EmailAddr! - continue: String -} - -type SendMagicLinkPayload { - success: Boolean! -} - -input VerifyMagicLinkInput { - token: String! -} - -type VerifyMagicLinkPayload { - continue: String -} - input UpdateFullNameInput { fullName: String! } diff --git a/pkg/server/api/complianceportal/v1/mux.go b/pkg/server/api/complianceportal/v1/mux.go index 05a5a9650..19b00c192 100644 --- a/pkg/server/api/complianceportal/v1/mux.go +++ b/pkg/server/api/complianceportal/v1/mux.go @@ -22,7 +22,6 @@ import ( "go.gearno.de/kit/log" "go.gearno.de/x/ref" "go.probo.inc/probo/pkg/baseurl" - page "go.probo.inc/probo/pkg/complianceportal" visitor "go.probo.inc/probo/pkg/complianceportal/visitor" "go.probo.inc/probo/pkg/esign" "go.probo.inc/probo/pkg/filemanager" @@ -148,7 +147,7 @@ func compliancePageHeadData() HeadDataFunc { } if tc.LogoFileID != nil && compliancePageBaseURL != nil { - faviconURL, err := page.BrandLogoURL(*compliancePageBaseURL) + faviconURL, err := visitor.BrandLogoURL(*compliancePageBaseURL) if err == nil { headData.FaviconURL = faviconURL } diff --git a/pkg/server/api/complianceportal/v1/oauth_client_metadata_handler.go b/pkg/server/api/complianceportal/v1/oauth_client_metadata_handler.go index a97953880..1e7cdb1f0 100644 --- a/pkg/server/api/complianceportal/v1/oauth_client_metadata_handler.go +++ b/pkg/server/api/complianceportal/v1/oauth_client_metadata_handler.go @@ -19,7 +19,7 @@ import ( "net/http" "go.gearno.de/kit/httpserver" - portal "go.probo.inc/probo/pkg/complianceportal" + "go.probo.inc/probo/pkg/complianceportal/visitor" "go.probo.inc/probo/pkg/server/api/complianceportal" ) @@ -38,7 +38,7 @@ func (h *oauthClientMetadataHandler) ServeHTTP(w http.ResponseWriter, r *http.Re return } - doc, err := portal.BuildClientMetadataDocument(compliancePage, *baseURL) + doc, err := visitor.BuildClientMetadataDocument(compliancePage, *baseURL) if err != nil { httpserver.RenderError(w, http.StatusInternalServerError, errInternal) return diff --git a/pkg/server/api/complianceportal/v1/trust_center_resolvers.go b/pkg/server/api/complianceportal/v1/trust_center_resolvers.go index 202c482e2..0e54fabfa 100644 --- a/pkg/server/api/complianceportal/v1/trust_center_resolvers.go +++ b/pkg/server/api/complianceportal/v1/trust_center_resolvers.go @@ -467,7 +467,7 @@ func (r *mutationResolver) ExportTrustCenterFile(ctx context.Context, input type trustCenterFile, err := trustService.GetPortalFile(ctx, scope, trustCenter.OrganizationID, input.TrustCenterFileID) if err != nil { - if errors.Is(err, visitor.ErrTrustCenterFileNotFound) || errors.Is(err, visitor.ErrTrustCenterFileNotVisible) { + if errors.Is(err, visitor.ErrPortalFileNotFound) || errors.Is(err, visitor.ErrPortalFileNotVisible) { return nil, gqlutils.NotFoundf(ctx, "trust center file %q not found", input.TrustCenterFileID) } @@ -620,7 +620,7 @@ func (r *mutationResolver) RequestTrustCenterFileAccess(ctx context.Context, inp trustCenterFile, err := trustService.GetPortalFile(ctx, scope, trustCenter.OrganizationID, input.TrustCenterFileID) if err != nil { - if errors.Is(err, visitor.ErrTrustCenterFileNotFound) || errors.Is(err, visitor.ErrTrustCenterFileNotVisible) { + if errors.Is(err, visitor.ErrPortalFileNotFound) || errors.Is(err, visitor.ErrPortalFileNotVisible) { return nil, gqlutils.NotFoundf(ctx, "trust center file %q not found", input.TrustCenterFileID) } @@ -836,7 +836,7 @@ func (r *trustCenterResolver) SubprocessorCategories(ctx context.Context, obj *t trustCenter := complianceportal.CompliancePageFromContext(ctx) scope := coredata.NewScopeFromObjectID(obj.ID) - categories, err := r.trust.ListDistinctTrustCenterCategoriesForOrganizationID(ctx, scope, trustCenter.OrganizationID) + categories, err := r.trust.ListDistinctPortalCategoriesForOrganizationID(ctx, scope, trustCenter.OrganizationID) if err != nil { r.logger.ErrorCtx(ctx, "cannot list subprocessor categories", log.Error(err)) return nil, gqlutils.Internal(ctx) @@ -850,7 +850,7 @@ func (r *trustCenterResolver) SubprocessorCountries(ctx context.Context, obj *ty trustCenter := complianceportal.CompliancePageFromContext(ctx) scope := coredata.NewScopeFromObjectID(obj.ID) - countries, err := r.trust.ListDistinctTrustCenterCountriesForOrganizationID(ctx, scope, trustCenter.OrganizationID) + countries, err := r.trust.ListDistinctPortalCountriesForOrganizationID(ctx, scope, trustCenter.OrganizationID) if err != nil { r.logger.ErrorCtx(ctx, "cannot list subprocessor countries", log.Error(err)) return nil, gqlutils.Internal(ctx) @@ -986,7 +986,7 @@ func (r *trustCenterFileResolver) IsUserAuthorized(ctx context.Context, obj *typ trustCenterFile, err := trustService.GetPortalFile(ctx, scope, trustCenter.OrganizationID, obj.ID) if err != nil { - if errors.Is(err, visitor.ErrTrustCenterFileNotFound) || errors.Is(err, visitor.ErrTrustCenterFileNotVisible) { + if errors.Is(err, visitor.ErrPortalFileNotFound) || errors.Is(err, visitor.ErrPortalFileNotVisible) { return false, gqlutils.NotFoundf(ctx, "trust center file %q not found", obj.ID) } diff --git a/pkg/server/api/console/v1/base_resolvers.go b/pkg/server/api/console/v1/base_resolvers.go index 066d3c825..8345b4d47 100644 --- a/pkg/server/api/console/v1/base_resolvers.go +++ b/pkg/server/api/console/v1/base_resolvers.go @@ -14,7 +14,7 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/agentrun" - "go.probo.inc/probo/pkg/complianceportal" + "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/probo" @@ -335,7 +335,7 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error return types.NewTransferImpactAssessment(tia), nil } case coredata.TrustCenterEntityType: - action = complianceportal.ActionCompliancePortalGet + action = management.ActionCompliancePortalGet loadNode = func(ctx context.Context, scope *coredata.Scope, id gid.GID) (types.Node, error) { trustCenter, err := r.management.Get(ctx, scope, id) if err != nil { @@ -345,7 +345,7 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error return types.NewTrustCenter(trustCenter), nil } case coredata.TrustCenterAccessEntityType: - action = complianceportal.ActionCompliancePortalAccessGet + action = management.ActionCompliancePortalAccessGet loadNode = func(ctx context.Context, scope *coredata.Scope, id gid.GID) (types.Node, error) { trustCenterAccess, err := r.management.GetAccess(ctx, scope, id) if err != nil { diff --git a/pkg/server/api/console/v1/graphql_handler.go b/pkg/server/api/console/v1/graphql_handler.go index 334e7201d..f3d240d5d 100644 --- a/pkg/server/api/console/v1/graphql_handler.go +++ b/pkg/server/api/console/v1/graphql_handler.go @@ -27,6 +27,7 @@ import ( "go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/agentrun" "go.probo.inc/probo/pkg/baseurl" + "go.probo.inc/probo/pkg/certmanager" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/connector" "go.probo.inc/probo/pkg/connector/provider" @@ -51,6 +52,7 @@ func NewGraphQLHandler( resourceAliasSvc *resourcealias.Service, esignSvc *esign.Service, managementSvc *management.Service, + certManagerSvc *certmanager.Service, accessReviewSvc *accessreview.Service, agentRunSvc *agentrun.Service, mailmanSvc *mailman.Service, @@ -75,6 +77,7 @@ func NewGraphQLHandler( iam: iamSvc, esign: esignSvc, management: managementSvc, + certManager: certManagerSvc, accessReview: accessReviewSvc, agentRun: agentRunSvc, mailman: mailmanSvc, diff --git a/pkg/server/api/console/v1/mailing_list_resolvers.go b/pkg/server/api/console/v1/mailing_list_resolvers.go index 4c3af4132..cb500cc0a 100644 --- a/pkg/server/api/console/v1/mailing_list_resolvers.go +++ b/pkg/server/api/console/v1/mailing_list_resolvers.go @@ -11,7 +11,7 @@ import ( "fmt" "go.gearno.de/kit/log" - "go.probo.inc/probo/pkg/complianceportal" + "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/mailman" "go.probo.inc/probo/pkg/page" @@ -23,7 +23,7 @@ import ( // Subscribers is the resolver for the subscribers field on MailingList. func (r *mailingListResolver) Subscribers(ctx context.Context, obj *types.MailingList, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.MailingListSubscriberConnection, error) { - if _, err := r.authorize(ctx, obj.ID, complianceportal.ActionMailingListSubscriberList); err != nil { + if _, err := r.authorize(ctx, obj.ID, management.ActionMailingListSubscriberList); err != nil { return nil, err } @@ -45,7 +45,7 @@ func (r *mailingListResolver) Subscribers(ctx context.Context, obj *types.Mailin // Updates is the resolver for the updates field on MailingList. func (r *mailingListResolver) Updates(ctx context.Context, obj *types.MailingList, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.MailingListUpdateConnection, error) { - if _, err := r.authorize(ctx, obj.ID, complianceportal.ActionMailingListUpdateList); err != nil { + if _, err := r.authorize(ctx, obj.ID, management.ActionMailingListUpdateList); err != nil { return nil, err } @@ -67,7 +67,7 @@ func (r *mailingListResolver) Updates(ctx context.Context, obj *types.MailingLis // TotalCount is the resolver for the totalCount field. func (r *mailingListSubscriberConnectionResolver) TotalCount(ctx context.Context, obj *types.MailingListSubscriberConnection) (int, error) { - if _, err := r.authorize(ctx, obj.ParentID, complianceportal.ActionMailingListSubscriberList); err != nil { + if _, err := r.authorize(ctx, obj.ParentID, management.ActionMailingListSubscriberList); err != nil { return 0, err } @@ -89,7 +89,7 @@ func (r *mailingListSubscriberConnectionResolver) TotalCount(ctx context.Context // TotalCount is the resolver for the totalCount field on MailingListUpdateConnection. func (r *mailingListUpdateConnectionResolver) TotalCount(ctx context.Context, obj *types.MailingListUpdateConnection) (int, error) { - if _, err := r.authorize(ctx, obj.ParentID, complianceportal.ActionMailingListUpdateList); err != nil { + if _, err := r.authorize(ctx, obj.ParentID, management.ActionMailingListUpdateList); err != nil { return 0, err } @@ -104,7 +104,7 @@ func (r *mailingListUpdateConnectionResolver) TotalCount(ctx context.Context, ob // CreateMailingListUpdate is the resolver for the createMailingListUpdate field. func (r *mutationResolver) CreateMailingListUpdate(ctx context.Context, input types.CreateMailingListUpdateInput) (*types.CreateMailingListUpdatePayload, error) { - if _, err := r.authorize(ctx, input.MailingListID, complianceportal.ActionMailingListUpdateCreate); err != nil { + if _, err := r.authorize(ctx, input.MailingListID, management.ActionMailingListUpdateCreate); err != nil { return nil, err } @@ -133,7 +133,7 @@ func (r *mutationResolver) CreateMailingListUpdate(ctx context.Context, input ty // UpdateMailingListUpdate is the resolver for the updateMailingListUpdate field. func (r *mutationResolver) UpdateMailingListUpdate(ctx context.Context, input types.UpdateMailingListUpdateInput) (*types.UpdateMailingListUpdatePayload, error) { - if _, err := r.authorize(ctx, input.ID, complianceportal.ActionMailingListUpdateUpdate); err != nil { + if _, err := r.authorize(ctx, input.ID, management.ActionMailingListUpdateUpdate); err != nil { return nil, err } @@ -170,7 +170,7 @@ func (r *mutationResolver) UpdateMailingListUpdate(ctx context.Context, input ty // SendMailingListUpdate is the resolver for the sendMailingListUpdate field. func (r *mutationResolver) SendMailingListUpdate(ctx context.Context, input types.SendMailingListUpdateInput) (*types.SendMailingListUpdatePayload, error) { - if _, err := r.authorize(ctx, input.ID, complianceportal.ActionMailingListUpdateUpdate); err != nil { + if _, err := r.authorize(ctx, input.ID, management.ActionMailingListUpdateUpdate); err != nil { return nil, err } @@ -196,7 +196,7 @@ func (r *mutationResolver) SendMailingListUpdate(ctx context.Context, input type // DeleteMailingListUpdate is the resolver for the deleteMailingListUpdate field. func (r *mutationResolver) DeleteMailingListUpdate(ctx context.Context, input types.DeleteMailingListUpdateInput) (*types.DeleteMailingListUpdatePayload, error) { - if _, err := r.authorize(ctx, input.ID, complianceportal.ActionMailingListUpdateDelete); err != nil { + if _, err := r.authorize(ctx, input.ID, management.ActionMailingListUpdateDelete); err != nil { return nil, err } @@ -217,7 +217,7 @@ func (r *mutationResolver) DeleteMailingListUpdate(ctx context.Context, input ty // UpdateMailingList is the resolver for the updateMailingList field. func (r *mutationResolver) UpdateMailingList(ctx context.Context, input types.UpdateMailingListInput) (*types.UpdateMailingListPayload, error) { - if _, err := r.authorize(ctx, input.ID, complianceportal.ActionMailingListUpdate); err != nil { + if _, err := r.authorize(ctx, input.ID, management.ActionMailingListUpdate); err != nil { return nil, err } @@ -234,7 +234,7 @@ func (r *mutationResolver) UpdateMailingList(ctx context.Context, input types.Up // CreateMailingListSubscriber is the resolver for the createMailingListSubscriber field. func (r *mutationResolver) CreateMailingListSubscriber(ctx context.Context, input types.CreateMailingListSubscriberInput) (*types.CreateMailingListSubscriberPayload, error) { - if _, err := r.authorize(ctx, input.MailingListID, complianceportal.ActionMailingListSubscriberCreate); err != nil { + if _, err := r.authorize(ctx, input.MailingListID, management.ActionMailingListSubscriberCreate); err != nil { return nil, err } @@ -268,7 +268,7 @@ func (r *mutationResolver) CreateMailingListSubscriber(ctx context.Context, inpu // DeleteMailingListSubscriber is the resolver for the deleteMailingListSubscriber field. func (r *mutationResolver) DeleteMailingListSubscriber(ctx context.Context, input types.DeleteMailingListSubscriberInput) (*types.DeleteMailingListSubscriberPayload, error) { - if _, err := r.authorize(ctx, input.ID, complianceportal.ActionMailingListSubscriberDelete); err != nil { + if _, err := r.authorize(ctx, input.ID, management.ActionMailingListSubscriberDelete); err != nil { return nil, err } diff --git a/pkg/server/api/console/v1/organization_resolvers.go b/pkg/server/api/console/v1/organization_resolvers.go index 9626327fa..322c1ef0b 100644 --- a/pkg/server/api/console/v1/organization_resolvers.go +++ b/pkg/server/api/console/v1/organization_resolvers.go @@ -13,7 +13,7 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/agentrun" - "go.probo.inc/probo/pkg/complianceportal" + "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/iam" @@ -1159,7 +1159,7 @@ func (r *organizationResolver) AgentRuns(ctx context.Context, obj *types.Organiz // TrustCenter is the resolver for the trustCenter field. func (r *organizationResolver) TrustCenter(ctx context.Context, obj *types.Organization) (*types.TrustCenter, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalGet) + scope, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalGet) if err != nil { return nil, err } @@ -1175,7 +1175,7 @@ func (r *organizationResolver) TrustCenter(ctx context.Context, obj *types.Organ // 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) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalFileList) + scope, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalFileList) if err != nil { return nil, err } diff --git a/pkg/server/api/console/v1/resolver.go b/pkg/server/api/console/v1/resolver.go index b1f5f2e39..3524b1249 100644 --- a/pkg/server/api/console/v1/resolver.go +++ b/pkg/server/api/console/v1/resolver.go @@ -35,6 +35,7 @@ import ( "go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/agentrun" "go.probo.inc/probo/pkg/baseurl" + "go.probo.inc/probo/pkg/certmanager" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/connector" "go.probo.inc/probo/pkg/connector/provider" @@ -67,6 +68,7 @@ type ( iam *iam.Service esign *esign.Service management *management.Service + certManager *certmanager.Service accessReview *accessreview.Service agentRun *agentrun.Service mailman *mailman.Service @@ -90,10 +92,14 @@ func (r *Resolver) newCustomDomainType( scope coredata.Scoper, domain *coredata.CustomDomain, ) (*types.CustomDomain, error) { - cert, err := r.management.GetCertificate(ctx, scope, domain) - if err != nil { - r.logger.ErrorCtx(ctx, "cannot load certificate", log.Error(err)) - return nil, gqlutils.Internal(ctx) + var cert *coredata.Certificate + if domain != nil && domain.CertificateID != nil { + var err error + cert, err = r.certManager.Get(ctx, scope, *domain.CertificateID) + if err != nil { + r.logger.ErrorCtx(ctx, "cannot load certificate", log.Error(err)) + return nil, gqlutils.Internal(ctx) + } } return types.NewCustomDomain(domain, cert, r.customDomainCname), nil @@ -106,6 +112,7 @@ func NewMux( iamSvc *iam.Service, esignSvc *esign.Service, managementSvc *management.Service, + certManagerSvc *certmanager.Service, accessReviewSvc *accessreview.Service, agentRunSvc *agentrun.Service, mailmanSvc *mailman.Service, @@ -131,6 +138,7 @@ func NewMux( resourceAliasSvc, esignSvc, managementSvc, + certManagerSvc, accessReviewSvc, agentRunSvc, mailmanSvc, diff --git a/pkg/server/api/console/v1/trust_center_resolvers.go b/pkg/server/api/console/v1/trust_center_resolvers.go index 9b702511b..a68f66fc7 100644 --- a/pkg/server/api/console/v1/trust_center_resolvers.go +++ b/pkg/server/api/console/v1/trust_center_resolvers.go @@ -12,7 +12,6 @@ import ( "github.com/vikstrous/dataloadgen" "go.gearno.de/kit/log" - "go.probo.inc/probo/pkg/complianceportal" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/coredata" "go.probo.inc/probo/pkg/iam" @@ -60,7 +59,7 @@ func (r *customDomainResolver) Permission(ctx context.Context, obj *types.Custom // UpdateTrustCenter is the resolver for the updateTrustCenter field. func (r *mutationResolver) UpdateTrustCenter(ctx context.Context, input types.UpdateTrustCenterInput) (*types.UpdateTrustCenterPayload, error) { - scope, err := r.authorize(ctx, input.TrustCenterID, complianceportal.ActionCompliancePortalUpdate) + scope, err := r.authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalUpdate) if err != nil { return nil, err } @@ -95,7 +94,7 @@ 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) { - scope, err := r.authorize(ctx, input.TrustCenterID, complianceportal.ActionCompliancePortalNonDisclosureAgreementUpload) + scope, err := r.authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalNonDisclosureAgreementUpload) if err != nil { return nil, err } @@ -125,7 +124,7 @@ 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) { - scope, err := r.authorize(ctx, input.TrustCenterID, complianceportal.ActionCompliancePortalNonDisclosureAgreementDelete) + scope, err := r.authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalNonDisclosureAgreementDelete) if err != nil { return nil, err } @@ -143,7 +142,7 @@ func (r *mutationResolver) DeleteTrustCenterNda(ctx context.Context, input types // UpdateTrustCenterBrand is the resolver for the updateTrustCenterBrand field. func (r *mutationResolver) UpdateTrustCenterBrand(ctx context.Context, input types.UpdateTrustCenterBrandInput) (*types.UpdateTrustCenterBrandPayload, error) { - scope, err := r.authorize(ctx, input.TrustCenterID, complianceportal.ActionCompliancePortalUpdate) + scope, err := r.authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalUpdate) if err != nil { return nil, err } @@ -204,7 +203,7 @@ func (r *mutationResolver) UpdateTrustCenterBrand(ctx context.Context, input typ // UpdateTrustCenterAccess is the resolver for the updateTrustCenterAccess field. func (r *mutationResolver) UpdateTrustCenterAccess(ctx context.Context, input types.UpdateTrustCenterAccessInput) (*types.UpdateTrustCenterAccessPayload, error) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionCompliancePortalAccessUpdate) + scope, err := r.authorize(ctx, input.ID, management.ActionCompliancePortalAccessUpdate) if err != nil { return nil, err } @@ -262,7 +261,7 @@ 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) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionCompliancePortalAccessDelete) + scope, err := r.authorize(ctx, input.ID, management.ActionCompliancePortalAccessDelete) if err != nil { return nil, err } @@ -279,7 +278,7 @@ 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) { - scope, err := r.authorize(ctx, input.TrustCenterID, complianceportal.ActionCompliancePortalReferenceCreate) + scope, err := r.authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalReferenceCreate) if err != nil { return nil, err } @@ -316,7 +315,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) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionCompliancePortalReferenceUpdate) + scope, err := r.authorize(ctx, input.ID, management.ActionCompliancePortalReferenceUpdate) if err != nil { return nil, err } @@ -356,7 +355,7 @@ 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) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionCompliancePortalReferenceDelete) + scope, err := r.authorize(ctx, input.ID, management.ActionCompliancePortalReferenceDelete) if err != nil { return nil, err } @@ -373,7 +372,7 @@ func (r *mutationResolver) DeleteTrustCenterReference(ctx context.Context, input // CreateComplianceFramework is the resolver for the createComplianceFramework field. func (r *mutationResolver) CreateComplianceFramework(ctx context.Context, input types.CreateComplianceFrameworkInput) (*types.CreateComplianceFrameworkPayload, error) { - scope, err := r.authorize(ctx, input.TrustCenterID, complianceportal.ActionComplianceFrameworkCreate) + scope, err := r.authorize(ctx, input.TrustCenterID, management.ActionComplianceFrameworkCreate) if err != nil { return nil, err } @@ -402,7 +401,7 @@ func (r *mutationResolver) CreateComplianceFramework(ctx context.Context, input // UpdateComplianceFramework is the resolver for the updateComplianceFramework field. func (r *mutationResolver) UpdateComplianceFramework(ctx context.Context, input types.UpdateComplianceFrameworkInput) (*types.UpdateComplianceFrameworkPayload, error) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionComplianceFrameworkUpdateRank) + scope, err := r.authorize(ctx, input.ID, management.ActionComplianceFrameworkUpdateRank) if err != nil { return nil, err } @@ -428,7 +427,7 @@ func (r *mutationResolver) UpdateComplianceFramework(ctx context.Context, input // DeleteComplianceFramework is the resolver for the deleteComplianceFramework field. func (r *mutationResolver) DeleteComplianceFramework(ctx context.Context, input types.DeleteComplianceFrameworkInput) (*types.DeleteComplianceFrameworkPayload, error) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionComplianceFrameworkDelete) + scope, err := r.authorize(ctx, input.ID, management.ActionComplianceFrameworkDelete) if err != nil { return nil, err } @@ -455,7 +454,7 @@ func (r *mutationResolver) DeleteComplianceFramework(ctx context.Context, input // CreateComplianceCustomLink is the resolver for the createComplianceCustomLink field. func (r *mutationResolver) CreateComplianceCustomLink(ctx context.Context, input types.CreateComplianceCustomLinkInput) (*types.CreateComplianceCustomLinkPayload, error) { - scope, err := r.authorize(ctx, input.TrustCenterID, complianceportal.ActionComplianceCustomLinkCreate) + scope, err := r.authorize(ctx, input.TrustCenterID, management.ActionComplianceCustomLinkCreate) if err != nil { return nil, err } @@ -485,7 +484,7 @@ func (r *mutationResolver) CreateComplianceCustomLink(ctx context.Context, input // UpdateComplianceCustomLink is the resolver for the updateComplianceCustomLink field. func (r *mutationResolver) UpdateComplianceCustomLink(ctx context.Context, input types.UpdateComplianceCustomLinkInput) (*types.UpdateComplianceCustomLinkPayload, error) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionComplianceCustomLinkUpdate) + scope, err := r.authorize(ctx, input.ID, management.ActionComplianceCustomLinkUpdate) if err != nil { return nil, err } @@ -513,7 +512,7 @@ func (r *mutationResolver) UpdateComplianceCustomLink(ctx context.Context, input // DeleteComplianceCustomLink is the resolver for the deleteComplianceCustomLink field. func (r *mutationResolver) DeleteComplianceCustomLink(ctx context.Context, input types.DeleteComplianceCustomLinkInput) (*types.DeleteComplianceCustomLinkPayload, error) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionComplianceCustomLinkDelete) + scope, err := r.authorize(ctx, input.ID, management.ActionComplianceCustomLinkDelete) if err != nil { return nil, err } @@ -535,7 +534,7 @@ func (r *mutationResolver) DeleteComplianceCustomLink(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) { - scope, err := r.authorize(ctx, input.OrganizationID, complianceportal.ActionCompliancePortalFileCreate) + scope, err := r.authorize(ctx, input.OrganizationID, management.ActionCompliancePortalFileCreate) if err != nil { return nil, err } @@ -572,7 +571,7 @@ 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) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionCompliancePortalFileUpdate) + scope, err := r.authorize(ctx, input.ID, management.ActionCompliancePortalFileUpdate) if err != nil { return nil, err } @@ -603,7 +602,7 @@ 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) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionCompliancePortalFileGet) + scope, err := r.authorize(ctx, input.ID, management.ActionCompliancePortalFileGet) if err != nil { return nil, err } @@ -621,7 +620,7 @@ 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) { - scope, err := r.authorize(ctx, input.ID, complianceportal.ActionCompliancePortalFileDelete) + scope, err := r.authorize(ctx, input.ID, management.ActionCompliancePortalFileDelete) if err != nil { return nil, err } @@ -638,7 +637,7 @@ func (r *mutationResolver) DeleteTrustCenterFile(ctx context.Context, input type // CreateCustomDomain is the resolver for the createCustomDomain field. func (r *mutationResolver) CreateCustomDomain(ctx context.Context, input types.CreateCustomDomainInput) (*types.CreateCustomDomainPayload, error) { - scope, err := r.authorize(ctx, input.TrustCenterID, complianceportal.ActionCustomDomainCreate) + scope, err := r.authorize(ctx, input.TrustCenterID, management.ActionCustomDomainCreate) if err != nil { return nil, err } @@ -674,13 +673,13 @@ 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) { - scope, err := r.authorize(ctx, input.CustomDomainID, complianceportal.ActionCustomDomainDelete) + scope, err := r.authorize(ctx, input.CustomDomainID, management.ActionCustomDomainDelete) if err != nil { return nil, err } if err := r.management.RemoveCustomDomain(ctx, scope, input.CustomDomainID); err != nil { - if errors.Is(err, complianceportal.ErrCustomDomainManaged) { + if errors.Is(err, management.ErrCustomDomainManaged) { return nil, gqlutils.Conflictf(ctx, "managed domain cannot be deleted") } @@ -696,7 +695,7 @@ func (r *mutationResolver) DeleteCustomDomain(ctx context.Context, input types.D // 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, complianceportal.ActionCompliancePortalGet); err != nil { + if _, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalGet); err != nil { return nil, err } @@ -709,7 +708,7 @@ func (r *trustCenterResolver) Logo(ctx context.Context, obj *types.TrustCenter) // DarkLogo is the resolver for the darkLogo field. func (r *trustCenterResolver) DarkLogo(ctx context.Context, obj *types.TrustCenter) (*types.File, error) { - if _, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalGet); err != nil { + if _, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalGet); err != nil { return nil, err } @@ -722,7 +721,7 @@ func (r *trustCenterResolver) DarkLogo(ctx context.Context, obj *types.TrustCent // Nda is the resolver for the nda field. func (r *trustCenterResolver) Nda(ctx context.Context, obj *types.TrustCenter) (*types.File, error) { - hasPermission, err := r.Resolver.Permission(ctx, obj, complianceportal.ActionCompliancePortalGetNda) + hasPermission, err := r.Resolver.Permission(ctx, obj, management.ActionCompliancePortalGetNda) if err != nil { r.logger.ErrorCtx(ctx, "cannot authorize", log.Error(err)) return nil, gqlutils.Internal(ctx) @@ -764,7 +763,7 @@ func (r *trustCenterResolver) Organization(ctx context.Context, obj *types.Trust // Accesses is the resolver for the accesses field. func (r *trustCenterResolver) Accesses(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterAccessOrderField]) (*types.TrustCenterAccessConnection, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalAccessList) + scope, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalAccessList) if err != nil { return nil, err } @@ -794,7 +793,7 @@ func (r *trustCenterResolver) Accesses(ctx context.Context, obj *types.TrustCent // References is the resolver for the references field. func (r *trustCenterResolver) References(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterReferenceOrderField]) (*types.TrustCenterReferenceConnection, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalReferenceList) + scope, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalReferenceList) if err != nil { return nil, err } @@ -824,7 +823,7 @@ func (r *trustCenterResolver) References(ctx context.Context, obj *types.TrustCe // ComplianceFrameworks is the resolver for the complianceFrameworks field. func (r *trustCenterResolver) ComplianceFrameworks(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.ComplianceFrameworkOrderField]) (*types.ComplianceFrameworkConnection, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionComplianceFrameworkList) + scope, err := r.authorize(ctx, obj.ID, management.ActionComplianceFrameworkList) if err != nil { return nil, err } @@ -854,7 +853,7 @@ func (r *trustCenterResolver) ComplianceFrameworks(ctx context.Context, obj *typ // CustomLinks is the resolver for the customLinks field. func (r *trustCenterResolver) CustomLinks(ctx context.Context, obj *types.TrustCenter, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.ComplianceCustomLinkOrderField]) (*types.ComplianceCustomLinkConnection, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionComplianceCustomLinkList) + scope, err := r.authorize(ctx, obj.ID, management.ActionComplianceCustomLinkList) if err != nil { return nil, err } @@ -884,7 +883,7 @@ func (r *trustCenterResolver) CustomLinks(ctx context.Context, obj *types.TrustC // MailingList is the resolver for the mailingList field. func (r *trustCenterResolver) MailingList(ctx context.Context, obj *types.TrustCenter) (*types.MailingList, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionMailingListSubscriberList) + scope, err := r.authorize(ctx, obj.ID, management.ActionMailingListSubscriberList) if err != nil { return nil, err } @@ -908,7 +907,7 @@ func (r *trustCenterResolver) MailingList(ctx context.Context, obj *types.TrustC // DefaultDomain is the resolver for the defaultDomain field. func (r *trustCenterResolver) DefaultDomain(ctx context.Context, obj *types.TrustCenter) (*types.CustomDomain, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCustomDomainGet) + scope, err := r.authorize(ctx, obj.ID, management.ActionCustomDomainGet) if err != nil { return nil, err } @@ -928,7 +927,7 @@ func (r *trustCenterResolver) DefaultDomain(ctx context.Context, obj *types.Trus // CustomDomain is the resolver for the customDomain field. func (r *trustCenterResolver) CustomDomain(ctx context.Context, obj *types.TrustCenter) (*types.CustomDomain, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCustomDomainGet) + scope, err := r.authorize(ctx, obj.ID, management.ActionCustomDomainGet) if err != nil { return nil, err } @@ -948,7 +947,7 @@ func (r *trustCenterResolver) CustomDomain(ctx context.Context, obj *types.Trust // PublicURL is the resolver for the publicUrl field. func (r *trustCenterResolver) PublicURL(ctx context.Context, obj *types.TrustCenter) (string, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalGet) + scope, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalGet) if err != nil { return "", err } @@ -969,7 +968,7 @@ func (r *trustCenterResolver) Permission(ctx context.Context, obj *types.TrustCe // NdaSignature is the resolver for the ndaSignature field. func (r *trustCenterAccessResolver) NdaSignature(ctx context.Context, obj *types.TrustCenterAccess) (*types.ElectronicSignature, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalAccessGet) + scope, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalAccessGet) if err != nil { return nil, err } @@ -993,7 +992,7 @@ func (r *trustCenterAccessResolver) NdaSignature(ctx context.Context, obj *types // PendingRequestCount is the resolver for the pendingRequestCount field. func (r *trustCenterAccessResolver) PendingRequestCount(ctx context.Context, obj *types.TrustCenterAccess) (int, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalAccessGet) + scope, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalAccessGet) if err != nil { return 0, err } @@ -1009,7 +1008,7 @@ func (r *trustCenterAccessResolver) PendingRequestCount(ctx context.Context, obj // ActiveCount is the resolver for the activeCount field. func (r *trustCenterAccessResolver) ActiveCount(ctx context.Context, obj *types.TrustCenterAccess) (int, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalAccessGet) + scope, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalAccessGet) if err != nil { return 0, err } @@ -1045,7 +1044,7 @@ func (r *trustCenterAccessResolver) Profile(ctx context.Context, obj *types.Trus // AvailableDocumentAccesses is the resolver for the availableDocumentAccesses field. func (r *trustCenterAccessResolver) AvailableDocumentAccesses(ctx context.Context, obj *types.TrustCenterAccess, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.OrderBy[coredata.TrustCenterDocumentAccessOrderField]) (*types.TrustCenterDocumentAccessConnection, error) { - scope, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalAccessGet) + scope, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalAccessGet) if err != nil { return nil, err } @@ -1156,7 +1155,7 @@ func (r *trustCenterDocumentAccessResolver) Audit(ctx context.Context, obj *type // TrustCenterFile is the resolver for the trustCenterFile field. func (r *trustCenterDocumentAccessResolver) TrustCenterFile(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.TrustCenterFile, error) { - scope, err := r.authorize(ctx, obj.TrustCenterAccessID, complianceportal.ActionCompliancePortalFileGet) + scope, err := r.authorize(ctx, obj.TrustCenterAccessID, management.ActionCompliancePortalFileGet) if err != nil { return nil, err } @@ -1176,7 +1175,7 @@ func (r *trustCenterDocumentAccessResolver) TrustCenterFile(ctx context.Context, // TotalCount is the resolver for the totalCount field. func (r *trustCenterDocumentAccessConnectionResolver) TotalCount(ctx context.Context, obj *types.TrustCenterDocumentAccessConnection) (int, error) { - scope, err := r.authorize(ctx, obj.ParentID, complianceportal.ActionCompliancePortalDocumentAccessList) + scope, err := r.authorize(ctx, obj.ParentID, management.ActionCompliancePortalDocumentAccessList) if err != nil { return 0, err } @@ -1192,7 +1191,7 @@ func (r *trustCenterDocumentAccessConnectionResolver) TotalCount(ctx context.Con // File is the resolver for the file field. func (r *trustCenterFileResolver) File(ctx context.Context, obj *types.TrustCenterFile) (*types.File, error) { - if _, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalFileGetFileUrl); err != nil { + if _, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalFileGetFileUrl); err != nil { return nil, err } @@ -1243,7 +1242,7 @@ func (r *trustCenterFileResolver) Permission(ctx context.Context, obj *types.Tru // TotalCount is the resolver for the totalCount field. func (r *trustCenterFileConnectionResolver) TotalCount(ctx context.Context, obj *types.TrustCenterFileConnection) (int, error) { - scope, err := r.authorize(ctx, obj.ParentID, complianceportal.ActionCompliancePortalFileList) + scope, err := r.authorize(ctx, obj.ParentID, management.ActionCompliancePortalFileList) if err != nil { return 0, err } @@ -1259,7 +1258,7 @@ func (r *trustCenterFileConnectionResolver) TotalCount(ctx context.Context, obj // Logo is the resolver for the logo field. func (r *trustCenterReferenceResolver) Logo(ctx context.Context, obj *types.TrustCenterReference) (*types.File, error) { - if _, err := r.authorize(ctx, obj.ID, complianceportal.ActionCompliancePortalReferenceGetLogoUrl); err != nil { + if _, err := r.authorize(ctx, obj.ID, management.ActionCompliancePortalReferenceGetLogoUrl); err != nil { return nil, err } @@ -1273,7 +1272,7 @@ func (r *trustCenterReferenceResolver) Permission(ctx context.Context, obj *type // TotalCount is the resolver for the totalCount field. func (r *trustCenterReferenceConnectionResolver) TotalCount(ctx context.Context, obj *types.TrustCenterReferenceConnection) (int, error) { - scope, err := r.authorize(ctx, obj.ParentID, complianceportal.ActionCompliancePortalReferenceList) + scope, err := r.authorize(ctx, obj.ParentID, management.ActionCompliancePortalReferenceList) if err != nil { return 0, err } diff --git a/pkg/server/api/mcp/v1/resolver.go b/pkg/server/api/mcp/v1/resolver.go index 34fe074e1..de4341d85 100644 --- a/pkg/server/api/mcp/v1/resolver.go +++ b/pkg/server/api/mcp/v1/resolver.go @@ -31,6 +31,7 @@ import ( "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/baseurl" + "go.probo.inc/probo/pkg/certmanager" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/cookiebanner" "go.probo.inc/probo/pkg/coredata" @@ -49,6 +50,7 @@ import ( type Resolver struct { proboSvc *probo.Service management *management.Service + certManager *certmanager.Service resourceAlias *resourcealias.Service thirdPartySvc *thirdparty.Service iamSvc *iam.Service diff --git a/pkg/server/api/mcp/v1/schema.resolvers.go b/pkg/server/api/mcp/v1/schema.resolvers.go index b6b6617d4..03a62e38b 100644 --- a/pkg/server/api/mcp/v1/schema.resolvers.go +++ b/pkg/server/api/mcp/v1/schema.resolvers.go @@ -14,7 +14,6 @@ import ( "github.com/modelcontextprotocol/go-sdk/mcp" "go.gearno.de/kit/log" "go.probo.inc/probo/pkg/accessreview" - "go.probo.inc/probo/pkg/complianceportal" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/cookiebanner" "go.probo.inc/probo/pkg/coredata" @@ -4884,7 +4883,7 @@ func (r *Resolver) DeleteRightsRequestTool(ctx context.Context, req *mcp.CallToo // GetTrustCenterTool handles the getTrustCenter tool // Get the trust center for an organization func (r *Resolver) GetTrustCenterTool(ctx context.Context, req *mcp.CallToolRequest, input *types.GetTrustCenterInput) (*mcp.CallToolResult, types.GetTrustCenterOutput, error) { - scope, err := r.Authorize(ctx, input.OrganizationID, complianceportal.ActionCompliancePortalGet) + scope, err := r.Authorize(ctx, input.OrganizationID, management.ActionCompliancePortalGet) if err != nil { return nil, types.GetTrustCenterOutput{}, err } @@ -4931,7 +4930,7 @@ func (r *Resolver) GetTrustCenterTool(ctx context.Context, req *mcp.CallToolRequ // UpdateTrustCenterTool handles the updateTrustCenter tool // Update the trust center settings func (r *Resolver) UpdateTrustCenterTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateTrustCenterInput) (*mcp.CallToolResult, types.UpdateTrustCenterOutput, error) { - scope, err := r.Authorize(ctx, input.TrustCenterID, complianceportal.ActionCompliancePortalUpdate) + scope, err := r.Authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalUpdate) if err != nil { return nil, types.UpdateTrustCenterOutput{}, err } @@ -4969,7 +4968,7 @@ func (r *Resolver) UpdateTrustCenterTool(ctx context.Context, req *mcp.CallToolR // ListTrustCenterReferencesTool handles the listTrustCenterReferences tool // List all references for a trust center func (r *Resolver) ListTrustCenterReferencesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListTrustCenterReferencesInput) (*mcp.CallToolResult, types.ListTrustCenterReferencesOutput, error) { - scope, err := r.Authorize(ctx, input.TrustCenterID, complianceportal.ActionCompliancePortalReferenceList) + scope, err := r.Authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalReferenceList) if err != nil { return nil, types.ListTrustCenterReferencesOutput{}, err } @@ -5015,7 +5014,7 @@ func (r *Resolver) ListTrustCenterReferencesTool(ctx context.Context, req *mcp.C // AddTrustCenterReferenceTool handles the addTrustCenterReference tool // Add a new reference to the trust center func (r *Resolver) AddTrustCenterReferenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddTrustCenterReferenceInput) (*mcp.CallToolResult, types.AddTrustCenterReferenceOutput, error) { - scope, err := r.Authorize(ctx, input.TrustCenterID, complianceportal.ActionCompliancePortalReferenceCreate) + scope, err := r.Authorize(ctx, input.TrustCenterID, management.ActionCompliancePortalReferenceCreate) if err != nil { return nil, types.AddTrustCenterReferenceOutput{}, err } @@ -5046,7 +5045,7 @@ func (r *Resolver) AddTrustCenterReferenceTool(ctx context.Context, req *mcp.Cal // UpdateTrustCenterReferenceTool handles the updateTrustCenterReference tool // Update a trust center reference func (r *Resolver) UpdateTrustCenterReferenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateTrustCenterReferenceInput) (*mcp.CallToolResult, types.UpdateTrustCenterReferenceOutput, error) { - scope, err := r.Authorize(ctx, input.ID, complianceportal.ActionCompliancePortalReferenceUpdate) + scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalReferenceUpdate) if err != nil { return nil, types.UpdateTrustCenterReferenceOutput{}, err } @@ -5081,7 +5080,7 @@ func (r *Resolver) UpdateTrustCenterReferenceTool(ctx context.Context, req *mcp. // DeleteTrustCenterReferenceTool handles the deleteTrustCenterReference tool // Delete a trust center reference func (r *Resolver) DeleteTrustCenterReferenceTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteTrustCenterReferenceInput) (*mcp.CallToolResult, types.DeleteTrustCenterReferenceOutput, error) { - scope, err := r.Authorize(ctx, input.ID, complianceportal.ActionCompliancePortalReferenceDelete) + scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalReferenceDelete) if err != nil { return nil, types.DeleteTrustCenterReferenceOutput{}, err } @@ -5099,7 +5098,7 @@ func (r *Resolver) DeleteTrustCenterReferenceTool(ctx context.Context, req *mcp. // ListTrustCenterFilesTool handles the listTrustCenterFiles tool // List all files for the trust center func (r *Resolver) ListTrustCenterFilesTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListTrustCenterFilesInput) (*mcp.CallToolResult, types.ListTrustCenterFilesOutput, error) { - scope, err := r.Authorize(ctx, input.OrganizationID, complianceportal.ActionCompliancePortalFileList) + scope, err := r.Authorize(ctx, input.OrganizationID, management.ActionCompliancePortalFileList) if err != nil { return nil, types.ListTrustCenterFilesOutput{}, err } @@ -5142,7 +5141,7 @@ func (r *Resolver) ListTrustCenterFilesTool(ctx context.Context, req *mcp.CallTo // DeleteTrustCenterFileTool handles the deleteTrustCenterFile tool // Delete a trust center file func (r *Resolver) DeleteTrustCenterFileTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteTrustCenterFileInput) (*mcp.CallToolResult, types.DeleteTrustCenterFileOutput, error) { - scope, err := r.Authorize(ctx, input.ID, complianceportal.ActionCompliancePortalFileDelete) + scope, err := r.Authorize(ctx, input.ID, management.ActionCompliancePortalFileDelete) if err != nil { return nil, types.DeleteTrustCenterFileOutput{}, err } @@ -5160,7 +5159,7 @@ func (r *Resolver) DeleteTrustCenterFileTool(ctx context.Context, req *mcp.CallT // ListComplianceCustomLinksTool handles the listComplianceCustomLinks tool // List all custom links for a trust center func (r *Resolver) ListComplianceCustomLinksTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ListComplianceCustomLinksInput) (*mcp.CallToolResult, types.ListComplianceCustomLinksOutput, error) { - scope, err := r.Authorize(ctx, input.TrustCenterID, complianceportal.ActionComplianceCustomLinkList) + scope, err := r.Authorize(ctx, input.TrustCenterID, management.ActionComplianceCustomLinkList) if err != nil { return nil, types.ListComplianceCustomLinksOutput{}, err } @@ -5192,7 +5191,7 @@ func (r *Resolver) ListComplianceCustomLinksTool(ctx context.Context, req *mcp.C // AddComplianceCustomLinkTool handles the addComplianceCustomLink tool // Add a new custom link to the trust center func (r *Resolver) AddComplianceCustomLinkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.AddComplianceCustomLinkInput) (*mcp.CallToolResult, types.AddComplianceCustomLinkOutput, error) { - scope, err := r.Authorize(ctx, input.TrustCenterID, complianceportal.ActionComplianceCustomLinkCreate) + scope, err := r.Authorize(ctx, input.TrustCenterID, management.ActionComplianceCustomLinkCreate) if err != nil { return nil, types.AddComplianceCustomLinkOutput{}, err } @@ -5217,7 +5216,7 @@ func (r *Resolver) AddComplianceCustomLinkTool(ctx context.Context, req *mcp.Cal // UpdateComplianceCustomLinkTool handles the updateComplianceCustomLink tool // Update a compliance custom link func (r *Resolver) UpdateComplianceCustomLinkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.UpdateComplianceCustomLinkInput) (*mcp.CallToolResult, types.UpdateComplianceCustomLinkOutput, error) { - scope, err := r.Authorize(ctx, input.ID, complianceportal.ActionComplianceCustomLinkUpdate) + scope, err := r.Authorize(ctx, input.ID, management.ActionComplianceCustomLinkUpdate) if err != nil { return nil, types.UpdateComplianceCustomLinkOutput{}, err } @@ -5251,7 +5250,7 @@ func (r *Resolver) UpdateComplianceCustomLinkTool(ctx context.Context, req *mcp. // DeleteComplianceCustomLinkTool handles the deleteComplianceCustomLink tool // Delete a compliance custom link func (r *Resolver) DeleteComplianceCustomLinkTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteComplianceCustomLinkInput) (*mcp.CallToolResult, types.DeleteComplianceCustomLinkOutput, error) { - scope, err := r.Authorize(ctx, input.ID, complianceportal.ActionComplianceCustomLinkDelete) + scope, err := r.Authorize(ctx, input.ID, management.ActionComplianceCustomLinkDelete) if err != nil { return nil, types.DeleteComplianceCustomLinkOutput{}, err } @@ -5274,7 +5273,7 @@ func (r *Resolver) DeleteComplianceCustomLinkTool(ctx context.Context, req *mcp. // CreateCustomDomainTool handles the createCustomDomain tool // Create a custom domain for a compliance page func (r *Resolver) CreateCustomDomainTool(ctx context.Context, req *mcp.CallToolRequest, input *types.CreateCustomDomainInput) (*mcp.CallToolResult, types.CreateCustomDomainOutput, error) { - scope, err := r.Authorize(ctx, input.TrustCenterID, complianceportal.ActionCustomDomainCreate) + scope, err := r.Authorize(ctx, input.TrustCenterID, management.ActionCustomDomainCreate) if err != nil { return nil, types.CreateCustomDomainOutput{}, err } @@ -5288,9 +5287,12 @@ func (r *Resolver) CreateCustomDomainTool(ctx context.Context, req *mcp.CallTool return nil, types.CreateCustomDomainOutput{}, fmt.Errorf("cannot create custom domain: %w", err) } - cert, err := r.management.GetCertificate(ctx, scope, domain) - if err != nil { - return nil, types.CreateCustomDomainOutput{}, fmt.Errorf("cannot load certificate: %w", err) + var cert *coredata.Certificate + if domain.CertificateID != nil { + cert, err = r.certManager.Get(ctx, scope, *domain.CertificateID) + if err != nil { + return nil, types.CreateCustomDomainOutput{}, fmt.Errorf("cannot load certificate: %w", err) + } } return nil, types.CreateCustomDomainOutput{CustomDomain: types.NewCustomDomain(domain, cert)}, nil @@ -5299,7 +5301,7 @@ func (r *Resolver) CreateCustomDomainTool(ctx context.Context, req *mcp.CallTool // DeleteCustomDomainTool handles the deleteCustomDomain tool // Delete the custom domain of a compliance page func (r *Resolver) DeleteCustomDomainTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteCustomDomainInput) (*mcp.CallToolResult, types.DeleteCustomDomainOutput, error) { - scope, err := r.Authorize(ctx, input.TrustCenterID, complianceportal.ActionCustomDomainDelete) + scope, err := r.Authorize(ctx, input.TrustCenterID, management.ActionCustomDomainDelete) if err != nil { return nil, types.DeleteCustomDomainOutput{}, err } @@ -5313,9 +5315,12 @@ func (r *Resolver) DeleteCustomDomainTool(ctx context.Context, req *mcp.CallTool return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("compliance page has no custom domain") } - cert, err := r.management.GetCertificate(ctx, scope, domain) - if err != nil { - return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("cannot load certificate: %w", err) + var cert *coredata.Certificate + if domain.CertificateID != nil { + cert, err = r.certManager.Get(ctx, scope, *domain.CertificateID) + if err != nil { + return nil, types.DeleteCustomDomainOutput{}, fmt.Errorf("cannot load certificate: %w", err) + } } deletedDomain := types.NewCustomDomain(domain, cert) diff --git a/pkg/server/api/mcp/v1/v1_handler.go b/pkg/server/api/mcp/v1/v1_handler.go index 5253d96eb..84987833a 100644 --- a/pkg/server/api/mcp/v1/v1_handler.go +++ b/pkg/server/api/mcp/v1/v1_handler.go @@ -29,6 +29,7 @@ import ( mcpgenmcp "go.probo.inc/mcpgen/mcp" "go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/baseurl" + "go.probo.inc/probo/pkg/certmanager" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/cookiebanner" "go.probo.inc/probo/pkg/filemanager" @@ -46,6 +47,7 @@ func NewMux( logger *log.Logger, proboSvc *probo.Service, managementSvc *management.Service, + certManagerSvc *certmanager.Service, resourceAliasSvc *resourcealias.Service, thirdPartySvc *thirdparty.Service, iamSvc *iam.Service, @@ -63,6 +65,7 @@ func NewMux( resolver := &Resolver{ proboSvc: proboSvc, management: managementSvc, + certManager: certManagerSvc, resourceAlias: resourceAliasSvc, thirdPartySvc: thirdPartySvc, iamSvc: iamSvc, diff --git a/pkg/server/server.go b/pkg/server/server.go index 42131a9a7..39505f7e9 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -29,6 +29,7 @@ import ( "go.probo.inc/probo/pkg/accessreview" "go.probo.inc/probo/pkg/agentrun" "go.probo.inc/probo/pkg/baseurl" + "go.probo.inc/probo/pkg/certmanager" "go.probo.inc/probo/pkg/complianceportal/management" "go.probo.inc/probo/pkg/complianceportal/visitor" "go.probo.inc/probo/pkg/connector" @@ -64,6 +65,7 @@ type Config struct { Trust *visitor.Service ESign *esign.Service Management *management.Service + CertManager *certmanager.Service AccessReview *accessreview.Service AgentRun *agentrun.Service Slack *slack.Service @@ -105,6 +107,7 @@ func NewServer(cfg Config) (*Server, error) { Trust: cfg.Trust, ESign: cfg.ESign, Management: cfg.Management, + CertManager: cfg.CertManager, AccessReview: cfg.AccessReview, AgentRun: cfg.AgentRun, Slack: cfg.Slack, diff --git a/pkg/slug/slug.go b/pkg/slug/slug.go index 5f137c79a..6fc09fd7a 100644 --- a/pkg/slug/slug.go +++ b/pkg/slug/slug.go @@ -23,6 +23,8 @@ package slug import ( "regexp" "strings" + + "go.probo.inc/probo/pkg/crypto/rand" ) var ( @@ -42,3 +44,14 @@ func Make(s string) string { return s } + +func MakeWithEntropy(s string) string { + base := Make(s) + suffix := rand.MustHexString(4) + + if base == "" { + return suffix + } + + return base + "-" + suffix +} diff --git a/pkg/slug/slug_test.go b/pkg/slug/slug_test.go index 1207df68f..dbe9ca95d 100644 --- a/pkg/slug/slug_test.go +++ b/pkg/slug/slug_test.go @@ -22,30 +22,73 @@ package slug import ( "testing" + + "github.com/stretchr/testify/assert" ) func TestMake(t *testing.T) { + t.Parallel() + tests := []struct { + name string input string expected string }{ - {"Hello World", "hello-world"}, - {"This is a test", "this-is-a-test"}, - {"Special characters: !@#$%^&*()", "special-characters"}, - {"Multiple---Hyphens", "multiple-hyphens"}, - {"-Trim-Hyphens-", "trim-hyphens"}, - {"123 Numbers", "123-numbers"}, - {" Spaces ", "spaces"}, - {"", ""}, - {"UPPERCASE", "uppercase"}, - {"under_score", "under-score"}, - {"dots.and.more.dots", "dotsandmoredots"}, + {name: "hello world", input: "Hello World", expected: "hello-world"}, + {name: "this is a test", input: "This is a test", expected: "this-is-a-test"}, + {name: "special characters", input: "Special characters: !@#$%^&*()", expected: "special-characters"}, + {name: "multiple hyphens", input: "Multiple---Hyphens", expected: "multiple-hyphens"}, + {name: "trim hyphens", input: "-Trim-Hyphens-", expected: "trim-hyphens"}, + {name: "numbers", input: "123 Numbers", expected: "123-numbers"}, + {name: "spaces", input: " Spaces ", expected: "spaces"}, + {name: "empty", input: "", expected: ""}, + {name: "uppercase", input: "UPPERCASE", expected: "uppercase"}, + {name: "underscore", input: "under_score", expected: "under-score"}, + {name: "dots", input: "dots.and.more.dots", expected: "dotsandmoredots"}, } - for _, test := range tests { - slug := Make(test.input) - if slug != test.expected { - t.Errorf("Slug(%q) = %q; expected %q", test.input, slug, test.expected) - } + for _, tt := range tests { + t.Run( + tt.name, + func(t *testing.T) { + t.Parallel() + + assert.Equal(t, tt.expected, Make(tt.input)) + }, + ) } } + +func TestMakeWithEntropy(t *testing.T) { + t.Parallel() + + t.Run( + "empty input returns hex only", + func(t *testing.T) { + t.Parallel() + + assert.Regexp(t, `^[0-9a-f]{8}$`, MakeWithEntropy("")) + }, + ) + + t.Run( + "non-empty input returns base with hex suffix", + func(t *testing.T) { + t.Parallel() + + got := MakeWithEntropy("Hello World") + assert.Regexp(t, `^hello-world-[0-9a-f]{8}$`, got) + }, + ) + + t.Run( + "successive calls differ", + func(t *testing.T) { + t.Parallel() + + first := MakeWithEntropy("Acme Corp") + second := MakeWithEntropy("Acme Corp") + assert.NotEqual(t, first, second, "MakeWithEntropy should produce distinct slugs") + }, + ) +}