From c770935433c59abd154d75021d8a1a7acb6fc17f Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Mon, 20 Jul 2026 18:08:35 +0200 Subject: [PATCH] Update e2e tests for compliance portal Rename trust center coverage to compliance portal so console, MCP, and trust suites assert against the new API surface. Signed-off-by: Bryan Frimin --- e2e/console/compliance_framework_test.go | 26 +- ..._test.go => compliance_portal_nda_test.go} | 52 +- ...t.go => compliance_portal_profile_test.go} | 40 +- e2e/console/document_test.go | 20 +- e2e/console/security_write_gap_test.go | 42 +- e2e/internal/testutil/client.go | 4 +- e2e/internal/testutil/graphql.go | 12 +- e2e/mcp/compliance_portal_test.go | 517 +++++++++++++++++ e2e/mcp/trust_center_test.go | 526 ------------------ ...test.go => compliance_portal_logo_test.go} | 80 +-- ...> compliance_portal_nda_signature_test.go} | 36 +- ...> compliance_portal_oauth_connect_test.go} | 26 +- ...> compliance_portal_report_export_test.go} | 64 +-- ...test.go => compliance_portal_slug_test.go} | 12 +- e2e/trust/helpers_test.go | 42 +- e2e/trust/subprocessors_filter_test.go | 68 +-- 16 files changed, 779 insertions(+), 788 deletions(-) rename e2e/console/{trust_center_nda_test.go => compliance_portal_nda_test.go} (63%) rename e2e/console/{trust_center_profile_test.go => compliance_portal_profile_test.go} (75%) create mode 100644 e2e/mcp/compliance_portal_test.go delete mode 100644 e2e/mcp/trust_center_test.go rename e2e/trust/{trust_center_logo_test.go => compliance_portal_logo_test.go} (76%) rename e2e/trust/{trust_center_nda_signature_test.go => compliance_portal_nda_signature_test.go} (85%) rename e2e/trust/{trust_center_oauth_connect_test.go => compliance_portal_oauth_connect_test.go} (83%) rename e2e/trust/{trust_center_report_export_test.go => compliance_portal_report_export_test.go} (65%) rename e2e/trust/{trust_center_slug_test.go => compliance_portal_slug_test.go} (87%) diff --git a/e2e/console/compliance_framework_test.go b/e2e/console/compliance_framework_test.go index 9c0306650..a533ddab1 100644 --- a/e2e/console/compliance_framework_test.go +++ b/e2e/console/compliance_framework_test.go @@ -28,15 +28,15 @@ import ( "go.probo.inc/probo/e2e/internal/testutil" ) -// trustCenterID looks up the caller's own organization's trust center id. -func trustCenterID(t *testing.T, c *testutil.Client) string { +// compliancePortalID looks up the caller's own organization's compliance portal id. +func compliancePortalID(t *testing.T, c *testutil.Client) string { t.Helper() var result struct { Node struct { - TrustCenter struct { + CompliancePortal struct { ID string `json:"id"` - } `json:"trustCenter"` + } `json:"compliancePortal"` } `json:"node"` } @@ -44,7 +44,7 @@ func trustCenterID(t *testing.T, c *testutil.Client) string { query($organizationId: ID!) { node(id: $organizationId) { ... on Organization { - trustCenter { id } + compliancePortal { id } } } } @@ -52,16 +52,16 @@ func trustCenterID(t *testing.T, c *testutil.Client) string { "organizationId": c.GetOrganizationID().String(), }, &result) require.NoError(t, err) - require.NotEmpty(t, result.Node.TrustCenter.ID) + require.NotEmpty(t, result.Node.CompliancePortal.ID) - return result.Node.TrustCenter.ID + return result.Node.CompliancePortal.ID } func TestComplianceFramework_Create(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - trustCenterID := trustCenterID(t, owner) + compliancePortalID := compliancePortalID(t, owner) frameworkID := factory.CreateFramework(owner) var result struct { @@ -82,8 +82,8 @@ func TestComplianceFramework_Create(t *testing.T) { } `, map[string]any{ "input": map[string]any{ - "trustCenterId": trustCenterID, - "frameworkId": frameworkID, + "compliancePortalId": compliancePortalID, + "frameworkId": frameworkID, }, }, &result) require.NoError(t, err) @@ -102,7 +102,7 @@ func TestComplianceFramework_TenantIsolation(t *testing.T) { org1Owner := testutil.NewClient(t, testutil.RoleOwner) org2Owner := testutil.NewClient(t, testutil.RoleOwner) - org1TrustCenterID := trustCenterID(t, org1Owner) + org1CompliancePortalID := compliancePortalID(t, org1Owner) org2FrameworkID := factory.CreateFramework(org2Owner) _, err := org1Owner.Do(` @@ -113,8 +113,8 @@ func TestComplianceFramework_TenantIsolation(t *testing.T) { } `, map[string]any{ "input": map[string]any{ - "trustCenterId": org1TrustCenterID, - "frameworkId": org2FrameworkID, + "compliancePortalId": org1CompliancePortalID, + "frameworkId": org2FrameworkID, }, }) require.Error(t, err, "must not accept a frameworkId belonging to another organization") diff --git a/e2e/console/trust_center_nda_test.go b/e2e/console/compliance_portal_nda_test.go similarity index 63% rename from e2e/console/trust_center_nda_test.go rename to e2e/console/compliance_portal_nda_test.go index fed8ff0e1..ba7a4b8b3 100644 --- a/e2e/console/trust_center_nda_test.go +++ b/e2e/console/compliance_portal_nda_test.go @@ -29,17 +29,17 @@ import ( "go.probo.inc/probo/e2e/internal/testutil" ) -func TestTrustCenter_UploadNDA(t *testing.T) { +func TestCompliancePortal_UploadNDA(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) organizationID := owner.GetOrganizationID().String() - const trustCenterQuery = ` + const compliancePortalQuery = ` query($organizationId: ID!) { node(id: $organizationId) { ... on Organization { - trustCenter { + compliancePortal { id } } @@ -47,26 +47,26 @@ func TestTrustCenter_UploadNDA(t *testing.T) { } ` - var trustCenterLookup struct { + var compliancePortalLookup struct { Node struct { - TrustCenter struct { + CompliancePortal struct { ID string `json:"id"` - } `json:"trustCenter"` + } `json:"compliancePortal"` } `json:"node"` } - err := owner.Execute(trustCenterQuery, map[string]any{ + err := owner.Execute(compliancePortalQuery, map[string]any{ "organizationId": organizationID, - }, &trustCenterLookup) + }, &compliancePortalLookup) require.NoError(t, err) - require.NotEmpty(t, trustCenterLookup.Node.TrustCenter.ID) + require.NotEmpty(t, compliancePortalLookup.Node.CompliancePortal.ID) - trustCenterID := trustCenterLookup.Node.TrustCenter.ID + compliancePortalID := compliancePortalLookup.Node.CompliancePortal.ID const uploadMutation = ` - mutation UploadTrustCenterNDA($input: UploadTrustCenterNDAInput!) { - uploadTrustCenterNDA(input: $input) { - trustCenter { + mutation UploadCompliancePortalNDA($input: UploadCompliancePortalNDAInput!) { + uploadCompliancePortalNDA(input: $input) { + compliancePortal { id nda { id @@ -81,23 +81,23 @@ func TestTrustCenter_UploadNDA(t *testing.T) { pdfContent := []byte("%PDF-1.4\n1 0 obj\n<< /Type /Catalog >>\nendobj\ntrailer\n<< /Root 1 0 R >>\n%%EOF") var uploadResult struct { - UploadTrustCenterNDA struct { - TrustCenter struct { + UploadCompliancePortalNDA struct { + CompliancePortal struct { ID string `json:"id"` Nda *struct { ID string `json:"id"` FileName string `json:"fileName"` DownloadURL string `json:"downloadUrl"` } `json:"nda"` - } `json:"trustCenter"` - } `json:"uploadTrustCenterNDA"` + } `json:"compliancePortal"` + } `json:"uploadCompliancePortalNDA"` } err = owner.ExecuteWithFile(uploadMutation, map[string]any{ "input": map[string]any{ - "trustCenterId": trustCenterID, - "fileName": "nda.pdf", - "file": nil, + "compliancePortalId": compliancePortalID, + "fileName": "nda.pdf", + "file": nil, }, }, "input.file", testutil.UploadFile{ Filename: "nda.pdf", @@ -106,14 +106,14 @@ func TestTrustCenter_UploadNDA(t *testing.T) { }, &uploadResult) require.NoError(t, err) - assert.Equal(t, trustCenterID, uploadResult.UploadTrustCenterNDA.TrustCenter.ID) - require.NotNil(t, uploadResult.UploadTrustCenterNDA.TrustCenter.Nda) - assert.Equal(t, "nda.pdf", uploadResult.UploadTrustCenterNDA.TrustCenter.Nda.FileName) - assert.NotEmpty(t, uploadResult.UploadTrustCenterNDA.TrustCenter.Nda.DownloadURL) + assert.Equal(t, compliancePortalID, uploadResult.UploadCompliancePortalNDA.CompliancePortal.ID) + require.NotNil(t, uploadResult.UploadCompliancePortalNDA.CompliancePortal.Nda) + assert.Equal(t, "nda.pdf", uploadResult.UploadCompliancePortalNDA.CompliancePortal.Nda.FileName) + assert.NotEmpty(t, uploadResult.UploadCompliancePortalNDA.CompliancePortal.Nda.DownloadURL) assert.True( t, - strings.Contains(uploadResult.UploadTrustCenterNDA.TrustCenter.Nda.DownloadURL, "/api/files/v1/"), + strings.Contains(uploadResult.UploadCompliancePortalNDA.CompliancePortal.Nda.DownloadURL, "/api/files/v1/"), "downloadUrl must route through the files API, got %q", - uploadResult.UploadTrustCenterNDA.TrustCenter.Nda.DownloadURL, + uploadResult.UploadCompliancePortalNDA.CompliancePortal.Nda.DownloadURL, ) } diff --git a/e2e/console/trust_center_profile_test.go b/e2e/console/compliance_portal_profile_test.go similarity index 75% rename from e2e/console/trust_center_profile_test.go rename to e2e/console/compliance_portal_profile_test.go index 9fa88ef21..c978a57a6 100644 --- a/e2e/console/trust_center_profile_test.go +++ b/e2e/console/compliance_portal_profile_test.go @@ -22,17 +22,17 @@ import ( "go.probo.inc/probo/e2e/internal/testutil" ) -func TestTrustCenter_UpdateProfile(t *testing.T) { +func TestCompliancePortal_UpdateProfile(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) organizationID := owner.GetOrganizationID().String() - const trustCenterQuery = ` + const compliancePortalQuery = ` query($organizationId: ID!) { node(id: $organizationId) { ... on Organization { - trustCenter { + compliancePortal { id } } @@ -40,26 +40,26 @@ func TestTrustCenter_UpdateProfile(t *testing.T) { } ` - var trustCenterLookup struct { + var compliancePortalLookup struct { Node struct { - TrustCenter struct { + CompliancePortal struct { ID string `json:"id"` - } `json:"trustCenter"` + } `json:"compliancePortal"` } `json:"node"` } - err := owner.Execute(trustCenterQuery, map[string]any{ + err := owner.Execute(compliancePortalQuery, map[string]any{ "organizationId": organizationID, - }, &trustCenterLookup) + }, &compliancePortalLookup) require.NoError(t, err) - require.NotEmpty(t, trustCenterLookup.Node.TrustCenter.ID) + require.NotEmpty(t, compliancePortalLookup.Node.CompliancePortal.ID) - trustCenterID := trustCenterLookup.Node.TrustCenter.ID + compliancePortalID := compliancePortalLookup.Node.CompliancePortal.ID const updateMutation = ` - mutation UpdateTrustCenter($input: UpdateTrustCenterInput!) { - updateTrustCenter(input: $input) { - trustCenter { + mutation UpdateCompliancePortal($input: UpdateCompliancePortalInput!) { + updateCompliancePortal(input: $input) { + compliancePortal { id title description @@ -72,21 +72,21 @@ func TestTrustCenter_UpdateProfile(t *testing.T) { ` var result struct { - UpdateTrustCenter struct { - TrustCenter struct { + UpdateCompliancePortal struct { + CompliancePortal struct { ID string `json:"id"` Title string `json:"title"` Description *string `json:"description"` WebsiteURL *string `json:"websiteUrl"` Email *string `json:"email"` HeadquarterAddress *string `json:"headquarterAddress"` - } `json:"trustCenter"` - } `json:"updateTrustCenter"` + } `json:"compliancePortal"` + } `json:"updateCompliancePortal"` } err = owner.Execute(updateMutation, map[string]any{ "input": map[string]any{ - "trustCenterId": trustCenterID, + "compliancePortalId": compliancePortalID, "title": "Acme Security", "description": "We keep your data safe.", "websiteUrl": "https://example.com", @@ -96,8 +96,8 @@ func TestTrustCenter_UpdateProfile(t *testing.T) { }, &result) require.NoError(t, err) - tc := result.UpdateTrustCenter.TrustCenter - assert.Equal(t, trustCenterID, tc.ID) + tc := result.UpdateCompliancePortal.CompliancePortal + assert.Equal(t, compliancePortalID, tc.ID) assert.Equal(t, "Acme Security", tc.Title) require.NotNil(t, tc.Description) assert.Equal(t, "We keep your data safe.", *tc.Description) diff --git a/e2e/console/document_test.go b/e2e/console/document_test.go index f100d9cc4..059540f54 100644 --- a/e2e/console/document_test.go +++ b/e2e/console/document_test.go @@ -645,8 +645,8 @@ func TestDocument_Timestamps(t *testing.T) { err = owner.Execute(updateQuery, map[string]any{ "input": map[string]any{ - "id": documentID, - "trustCenterVisibility": "PRIVATE", + "id": documentID, + "compliancePortalVisibility": "PRIVATE", }, }, &updateResult) require.NoError(t, err) @@ -778,8 +778,8 @@ func TestDocument_RBAC(t *testing.T) { } `, map[string]any{ "input": map[string]any{ - "id": documentID, - "trustCenterVisibility": "PRIVATE", + "id": documentID, + "compliancePortalVisibility": "PRIVATE", }, }) require.NoError(t, err, "owner should be able to update document") @@ -799,8 +799,8 @@ func TestDocument_RBAC(t *testing.T) { } `, map[string]any{ "input": map[string]any{ - "id": documentID, - "trustCenterVisibility": "PRIVATE", + "id": documentID, + "compliancePortalVisibility": "PRIVATE", }, }) require.NoError(t, err, "admin should be able to update document") @@ -820,8 +820,8 @@ func TestDocument_RBAC(t *testing.T) { } `, map[string]any{ "input": map[string]any{ - "id": documentID, - "trustCenterVisibility": "PRIVATE", + "id": documentID, + "compliancePortalVisibility": "PRIVATE", }, }) testutil.RequireForbiddenError(t, err, "viewer should not be able to update document") @@ -1240,8 +1240,8 @@ func TestDocument_TenantIsolation(t *testing.T) { _, err := org2Owner.Do(query, map[string]any{ "input": map[string]any{ - "id": documentID, - "trustCenterVisibility": "PRIVATE", + "id": documentID, + "compliancePortalVisibility": "PRIVATE", }, }) require.Error(t, err, "Should not be able to update document from another org") diff --git a/e2e/console/security_write_gap_test.go b/e2e/console/security_write_gap_test.go index faf48c26d..9320a582b 100644 --- a/e2e/console/security_write_gap_test.go +++ b/e2e/console/security_write_gap_test.go @@ -71,40 +71,40 @@ func TestSecurity_WriteGap_PublishRiskListApproverIDs(t *testing.T) { require.Error(t, err, "must not accept an approverId belonging to another organization") } -// TestSecurity_WriteGap_TrustCenterAccessDocuments covers a write-gap found -// while auditing GHSA-c74x-79w6-63jh's blast radius: TrustCenterAccessService.Update +// TestSecurity_WriteGap_CompliancePortalAccessDocuments covers a write-gap found +// while auditing GHSA-c74x-79w6-63jh's blast radius: CompliancePortalAccessService.Update // persisted caller-supplied document/report-file/trust-center-file ids into // trust_center_document_accesses (via coredata's MergeDocumentAccesses/ -// MergeReportFileAccesses/MergeTrustCenterFileAccesses) without validating -// they belong to the trust center's own organization -- the DB-level FK check +// MergeReportFileAccesses/MergeCompliancePortalFileAccesses) without validating +// they belong to the compliance portal's own organization -- the DB-level FK check // alone doesn't catch this because those primary keys are globally unique, // not per-tenant. // -// TrustCenterAccess rows are normally created through the trust/v1 public +// CompliancePortalAccess rows are normally created through the trust/v1 public // portal's visitor request flow (requestAllAccesses), which needs a // separate authenticated visitor identity and NDA acceptance. To keep this // test focused on the fix under test (the Update mutation's FK validation) // rather than that unrelated flow, the access row's prerequisite state is // seeded directly via SQL against the same Postgres database the e2e probod -// instance runs against, then the real updateTrustCenterAccess mutation is +// instance runs against, then the real updateCompliancePortalAccess mutation is // exercised through the live GraphQL API. -func TestSecurity_WriteGap_TrustCenterAccessDocuments(t *testing.T) { +func TestSecurity_WriteGap_CompliancePortalAccessDocuments(t *testing.T) { t.Parallel() org1Owner := testutil.NewClient(t, testutil.RoleOwner) org2Owner := testutil.NewClient(t, testutil.RoleOwner) - org1TrustCenterID := trustCenterID(t, org1Owner) - org1DocumentID := factory.NewDocument(org1Owner).WithTitle("Org1 Document for trust center access").Create() + org1CompliancePortalID := compliancePortalID(t, org1Owner) + org1DocumentID := factory.NewDocument(org1Owner).WithTitle("Org1 Document for compliance portal access").Create() org2DocumentID := factory.NewDocument(org2Owner).WithTitle("Org2 Secret Document").Create() - accessID := seedTrustCenterAccess(t, org1Owner, org1TrustCenterID) + accessID := seedCompliancePortalAccess(t, org1Owner, org1CompliancePortalID) t.Run("cannot grant access to a document from another organization", func(t *testing.T) { _, err := org1Owner.Do(` - mutation($input: UpdateTrustCenterAccessInput!) { - updateTrustCenterAccess(input: $input) { - trustCenterAccess { id } + mutation($input: UpdateCompliancePortalAccessInput!) { + updateCompliancePortalAccess(input: $input) { + compliancePortalAccess { id } } } `, map[string]any{ @@ -118,9 +118,9 @@ func TestSecurity_WriteGap_TrustCenterAccessDocuments(t *testing.T) { t.Run("can grant access to a document from the same organization", func(t *testing.T) { _, err := org1Owner.Do(` - mutation($input: UpdateTrustCenterAccessInput!) { - updateTrustCenterAccess(input: $input) { - trustCenterAccess { id } + mutation($input: UpdateCompliancePortalAccessInput!) { + updateCompliancePortalAccess(input: $input) { + compliancePortalAccess { id } } } `, map[string]any{ @@ -133,20 +133,20 @@ func TestSecurity_WriteGap_TrustCenterAccessDocuments(t *testing.T) { }) } -// seedTrustCenterAccess inserts a minimal trust_center_accesses row directly +// seedCompliancePortalAccess inserts a minimal trust_center_accesses row directly // via SQL, bypassing the trust/v1 visitor request flow (which requires a // separate authenticated visitor identity and NDA acceptance) so that -// updateTrustCenterAccess -- the mutation under test -- can be exercised in +// updateCompliancePortalAccess -- the mutation under test -- can be exercised in // isolation. owner's own identity id is reused to satisfy the row's // identity_id foreign key; which identity it is doesn't matter for this test. -func seedTrustCenterAccess(t *testing.T, owner *testutil.Client, trustCenterID string) string { +func seedCompliancePortalAccess(t *testing.T, owner *testutil.Client, compliancePortalID string) string { t.Helper() - tcID, err := gid.ParseGID(trustCenterID) + tcID, err := gid.ParseGID(compliancePortalID) require.NoError(t, err) tenantID := owner.GetOrganizationID().TenantID() - accessID := gid.New(tenantID, coredata.TrustCenterAccessEntityType) + accessID := gid.New(tenantID, coredata.CompliancePortalAccessEntityType) now := time.Now().UTC() client := test.PGClient(t) diff --git a/e2e/internal/testutil/client.go b/e2e/internal/testutil/client.go index 87c293d4b..f197f5365 100644 --- a/e2e/internal/testutil/client.go +++ b/e2e/internal/testutil/client.go @@ -549,7 +549,7 @@ func NewClientWithNewSession(t testing.TB, from *Client) *Client { return client } -func SelfProvisionTrustCenterVisitor(t testing.TB, trustHost string) *Client { +func SelfProvisionCompliancePortalVisitor(t testing.TB, trustHost string) *Client { t.Helper() jar, err := cookiejar.New(nil) @@ -582,7 +582,7 @@ func SelfProvisionTrustCenterVisitor(t testing.TB, trustHost string) *Client { func (c *Client) connectViaCIMD(email string) { c.T.Helper() - WaitForTrustCenterHTTPS(c.T, c.trustHost) + WaitForCompliancePortalHTTPS(c.T, c.trustHost) initiateURL := fmt.Sprintf( "https://%s/initiate?continue=/overview", diff --git a/e2e/internal/testutil/graphql.go b/e2e/internal/testutil/graphql.go index 763e4c3ea..fe047523e 100644 --- a/e2e/internal/testutil/graphql.go +++ b/e2e/internal/testutil/graphql.go @@ -37,11 +37,11 @@ import ( "github.com/stretchr/testify/require" ) -// trustCenterHTTPSAddr is the loopback address of the dedicated trust-center +// compliancePortalHTTPSAddr is the loopback address of the dedicated trust-center // HTTPS listener started by the e2e probod (see generateConfig). Compliance // pages are served here exclusively, routed by TLS SNI / Host header. Uses a // non-privileged port so the e2e suite doesn't require root/CAP_NET_BIND_SERVICE. -const trustCenterHTTPSAddr = "127.0.0.1:8443" +const compliancePortalHTTPSAddr = "127.0.0.1:8443" type GraphQLRequest struct { Query string `json:"query"` @@ -231,7 +231,7 @@ func trustHTTPClientWithJar(serverName string, jar http.CookieJar) *http.Client Timeout: 30 * time.Second, Transport: &http.Transport{ DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { - return dialer.DialContext(ctx, "tcp", trustCenterHTTPSAddr) + return dialer.DialContext(ctx, "tcp", compliancePortalHTTPSAddr) }, TLSClientConfig: &tls.Config{ ServerName: serverName, @@ -241,10 +241,10 @@ func trustHTTPClientWithJar(serverName string, jar http.CookieJar) *http.Client } } -// WaitForTrustCenterHTTPS blocks until the dedicated trust-center listener +// WaitForCompliancePortalHTTPS blocks until the dedicated trust-center listener // serves the page over TLS. Managed domains provision certificates // asynchronously after activation. -func WaitForTrustCenterHTTPS(t testing.TB, host string) { +func WaitForCompliancePortalHTTPS(t testing.TB, host string) { t.Helper() client := TrustHTTPClient(host) @@ -263,7 +263,7 @@ func WaitForTrustCenterHTTPS(t testing.TB, host string) { }, 30*time.Second, 500*time.Millisecond, - "trust center did not become servable on the dedicated listener", + "compliance portal did not become servable on the dedicated listener", ) } diff --git a/e2e/mcp/compliance_portal_test.go b/e2e/mcp/compliance_portal_test.go new file mode 100644 index 000000000..c790d4fc3 --- /dev/null +++ b/e2e/mcp/compliance_portal_test.go @@ -0,0 +1,517 @@ +// Copyright (c) 2025-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 mcp_test + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.probo.inc/probo/e2e/internal/factory" + "go.probo.inc/probo/e2e/internal/testutil" +) + +type mcpFile struct { + DownloadURL string `json:"download_url"` +} + +type compliancePortal struct { + ID string `json:"id"` + Title string `json:"title"` + Active bool `json:"active"` + Logo *mcpFile `json:"logo,omitempty"` +} + +type compliancePortalReference struct { + ID string `json:"id"` + Name string `json:"name"` + WebsiteURL *string `json:"website_url"` + Description *string `json:"description"` +} + +type complianceCustomLink struct { + ID string `json:"id"` + Name string `json:"name"` + URL string `json:"url"` +} + +func TestMCP_GetCompliancePortal(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + const compliancePortalQuery = ` + query($organizationId: ID!) { + node(id: $organizationId) { + ... on Organization { + compliancePortal { + id + } + } + } + } + ` + + var compliancePortalLookup struct { + Node struct { + CompliancePortal struct { + ID string `json:"id"` + } `json:"compliancePortal"` + } `json:"node"` + } + + err := owner.Execute(compliancePortalQuery, map[string]any{ + "organizationId": orgID, + }, &compliancePortalLookup) + require.NoError(t, err) + require.NotEmpty(t, compliancePortalLookup.Node.CompliancePortal.ID) + + compliancePortalID := compliancePortalLookup.Node.CompliancePortal.ID + + const uploadMutation = ` + mutation UpdateCompliancePortalBrand($input: UpdateCompliancePortalBrandInput!) { + updateCompliancePortalBrand(input: $input) { + compliancePortal { + id + logo { + id + downloadUrl + } + } + } + } + ` + + pngContent := []byte{ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, + 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x15, 0xc4, + 0x89, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, + 0x54, 0x78, 0x9c, 0x63, 0x00, 0x01, 0x00, 0x00, + 0x05, 0x00, 0x01, 0x0d, 0x0a, 0x2d, 0xb4, 0x00, + 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, + 0x42, 0x60, 0x82, + } + + var uploadResult struct { + UpdateCompliancePortalBrand struct { + CompliancePortal struct { + ID string `json:"id"` + Logo *struct { + ID string `json:"id"` + DownloadURL string `json:"downloadUrl"` + } `json:"logo"` + } `json:"compliancePortal"` + } `json:"updateCompliancePortalBrand"` + } + + err = owner.ExecuteWithFile(uploadMutation, map[string]any{ + "input": map[string]any{ + "compliancePortalId": compliancePortalID, + "logoFile": nil, + }, + }, "input.logoFile", testutil.UploadFile{ + Filename: "mcp-compliance-portal-logo.png", + ContentType: "image/png", + Content: pngContent, + }, &uploadResult) + require.NoError(t, err) + require.NotNil(t, uploadResult.UpdateCompliancePortalBrand.CompliancePortal.Logo) + + var result struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &result) + + assert.NotEmpty(t, result.CompliancePortal.ID) + require.NotNil(t, result.CompliancePortal.Logo) + assert.True( + t, + strings.Contains(result.CompliancePortal.Logo.DownloadURL, "/api/files/v1/public/"), + "download_url must route through the public files API, got %q", + result.CompliancePortal.Logo.DownloadURL, + ) +} + +func TestMCP_UpdateCompliancePortal(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // Get compliance portal ID + var getResult struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &getResult) + require.NotEmpty(t, getResult.CompliancePortal.ID) + + // Update + var updateResult struct { + CompliancePortal struct { + ID string `json:"id"` + Title string `json:"title"` + Description *string `json:"description"` + WebsiteURL *string `json:"website_url"` + Email *string `json:"email"` + HeadquarterAddress *string `json:"headquarter_address"` + } `json:"compliance_portal"` + } + mc.CallToolInto("updateCompliancePortal", map[string]any{ + "compliance_portal_id": getResult.CompliancePortal.ID, + "title": "Acme Security", + "description": "We keep your data safe.", + "website_url": "https://example.com", + "email": "security@example.com", + "headquarter_address": "123 Main St, San Francisco, CA 94102", + }, &updateResult) + + assert.Equal(t, getResult.CompliancePortal.ID, updateResult.CompliancePortal.ID) + assert.Equal(t, "Acme Security", updateResult.CompliancePortal.Title) + require.NotNil(t, updateResult.CompliancePortal.Description) + assert.Equal(t, "We keep your data safe.", *updateResult.CompliancePortal.Description) + require.NotNil(t, updateResult.CompliancePortal.WebsiteURL) + assert.Equal(t, "https://example.com", *updateResult.CompliancePortal.WebsiteURL) + require.NotNil(t, updateResult.CompliancePortal.Email) + assert.Equal(t, "security@example.com", *updateResult.CompliancePortal.Email) + require.NotNil(t, updateResult.CompliancePortal.HeadquarterAddress) + assert.Equal(t, "123 Main St, San Francisco, CA 94102", *updateResult.CompliancePortal.HeadquarterAddress) +} + +func TestMCP_AddCompliancePortalReference(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // Get compliance portal ID + var getResult struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &getResult) + portalID := getResult.CompliancePortal.ID + + var result struct { + CompliancePortalReference compliancePortalReference `json:"compliance_portal_reference"` + } + mc.CallToolInto("addCompliancePortalReference", map[string]any{ + "compliance_portal_id": portalID, + "name": "SOC 2 Report", + "website_url": "https://example.com/soc2", + }, &result) + + assert.NotEmpty(t, result.CompliancePortalReference.ID) + assert.Equal(t, "SOC 2 Report", result.CompliancePortalReference.Name) +} + +func TestMCP_UpdateCompliancePortalReference(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // Get compliance portal ID + var getResult struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &getResult) + portalID := getResult.CompliancePortal.ID + + // Create reference + var addResult struct { + CompliancePortalReference compliancePortalReference `json:"compliance_portal_reference"` + } + mc.CallToolInto("addCompliancePortalReference", map[string]any{ + "compliance_portal_id": portalID, + "name": "Original Reference", + "website_url": "https://example.com/original", + }, &addResult) + require.NotEmpty(t, addResult.CompliancePortalReference.ID) + + // Update reference + var updateResult struct { + CompliancePortalReference compliancePortalReference `json:"compliance_portal_reference"` + } + mc.CallToolInto("updateCompliancePortalReference", map[string]any{ + "id": addResult.CompliancePortalReference.ID, + "name": "Updated Reference", + "website_url": "https://example.com/updated", + }, &updateResult) + + assert.Equal(t, addResult.CompliancePortalReference.ID, updateResult.CompliancePortalReference.ID) + assert.Equal(t, "Updated Reference", updateResult.CompliancePortalReference.Name) +} + +func TestMCP_DeleteCompliancePortalReference(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // Get compliance portal ID + var getResult struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &getResult) + portalID := getResult.CompliancePortal.ID + + // Create reference + var addResult struct { + CompliancePortalReference compliancePortalReference `json:"compliance_portal_reference"` + } + mc.CallToolInto("addCompliancePortalReference", map[string]any{ + "compliance_portal_id": portalID, + "name": "Reference to delete", + "website_url": "https://example.com/delete", + }, &addResult) + require.NotEmpty(t, addResult.CompliancePortalReference.ID) + + // Delete + var deleteResult struct { + DeletedCompliancePortalReferenceID string `json:"deleted_compliance_portal_reference_id"` + } + mc.CallToolInto("deleteCompliancePortalReference", map[string]any{ + "id": addResult.CompliancePortalReference.ID, + }, &deleteResult) + + assert.Equal(t, addResult.CompliancePortalReference.ID, deleteResult.DeletedCompliancePortalReferenceID) +} + +func TestMCP_ListCompliancePortalReferences(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // Get compliance portal ID + var getResult struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &getResult) + portalID := getResult.CompliancePortal.ID + + // Create references + for i := range 2 { + var result struct { + CompliancePortalReference compliancePortalReference `json:"compliance_portal_reference"` + } + mc.CallToolInto("addCompliancePortalReference", map[string]any{ + "compliance_portal_id": portalID, + "name": factory.SafeName("Ref"), + "website_url": "https://example.com/" + factory.SafeName("path"), + }, &result) + require.NotEmpty(t, result.CompliancePortalReference.ID) + + _ = i + } + + // List + var listResult struct { + CompliancePortalReferences []compliancePortalReference `json:"compliance_portal_references"` + } + mc.CallToolInto("listCompliancePortalReferences", map[string]any{ + "compliance_portal_id": portalID, + }, &listResult) + + assert.GreaterOrEqual(t, len(listResult.CompliancePortalReferences), 2) +} + +func TestMCP_ListCompliancePortalFiles(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // List files (may be empty, just verify the tool works) + var listResult struct { + CompliancePortalFiles []struct { + ID string `json:"id"` + Name string `json:"name"` + } `json:"compliance_portal_files"` + } + mc.CallToolInto("listCompliancePortalFiles", map[string]any{ + "organization_id": orgID, + }, &listResult) + + // Just assert the call succeeded — files require multipart upload + assert.NotNil(t, listResult.CompliancePortalFiles) +} + +func TestMCP_AddComplianceCustomLink(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // Get compliance portal ID + var getResult struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &getResult) + portalID := getResult.CompliancePortal.ID + + var result struct { + ComplianceCustomLink complianceCustomLink `json:"compliance_custom_link"` + } + mc.CallToolInto("addComplianceCustomLink", map[string]any{ + "compliance_portal_id": portalID, + "name": "ISO 27001 Certificate", + "url": "https://example.com/iso27001", + }, &result) + + assert.NotEmpty(t, result.ComplianceCustomLink.ID) + assert.Equal(t, "ISO 27001 Certificate", result.ComplianceCustomLink.Name) +} + +func TestMCP_UpdateComplianceCustomLink(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // Get compliance portal ID + var getResult struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &getResult) + portalID := getResult.CompliancePortal.ID + + // Create + var addResult struct { + ComplianceCustomLink complianceCustomLink `json:"compliance_custom_link"` + } + mc.CallToolInto("addComplianceCustomLink", map[string]any{ + "compliance_portal_id": portalID, + "name": "Original URL", + "url": "https://example.com/original", + }, &addResult) + require.NotEmpty(t, addResult.ComplianceCustomLink.ID) + + // Update + var updateResult struct { + ComplianceCustomLink complianceCustomLink `json:"compliance_custom_link"` + } + mc.CallToolInto("updateComplianceCustomLink", map[string]any{ + "id": addResult.ComplianceCustomLink.ID, + "name": "Updated URL", + "url": "https://example.com/updated", + }, &updateResult) + + assert.Equal(t, addResult.ComplianceCustomLink.ID, updateResult.ComplianceCustomLink.ID) + assert.Equal(t, "Updated URL", updateResult.ComplianceCustomLink.Name) +} + +func TestMCP_DeleteComplianceCustomLink(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // Get compliance portal ID + var getResult struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &getResult) + portalID := getResult.CompliancePortal.ID + + // Create + var addResult struct { + ComplianceCustomLink complianceCustomLink `json:"compliance_custom_link"` + } + mc.CallToolInto("addComplianceCustomLink", map[string]any{ + "compliance_portal_id": portalID, + "name": "URL to delete", + "url": "https://example.com/delete", + }, &addResult) + require.NotEmpty(t, addResult.ComplianceCustomLink.ID) + + // Delete + var deleteResult struct { + DeletedComplianceCustomLinkID string `json:"deleted_compliance_custom_link_id"` + } + mc.CallToolInto("deleteComplianceCustomLink", map[string]any{ + "id": addResult.ComplianceCustomLink.ID, + }, &deleteResult) + + assert.Equal(t, addResult.ComplianceCustomLink.ID, deleteResult.DeletedComplianceCustomLinkID) +} + +func TestMCP_ListComplianceCustomLinks(t *testing.T) { + t.Parallel() + owner := testutil.NewClient(t, testutil.RoleOwner) + mc := testutil.NewMCPClient(t, owner) + orgID := owner.GetOrganizationID().String() + + // Get compliance portal ID + var getResult struct { + CompliancePortal compliancePortal `json:"compliance_portal"` + } + mc.CallToolInto("getCompliancePortal", map[string]any{ + "organization_id": orgID, + }, &getResult) + portalID := getResult.CompliancePortal.ID + + // Create URLs + for i := range 2 { + var result struct { + ComplianceCustomLink complianceCustomLink `json:"compliance_custom_link"` + } + mc.CallToolInto("addComplianceCustomLink", map[string]any{ + "compliance_portal_id": portalID, + "name": factory.SafeName("URL"), + "url": "https://example.com/" + factory.SafeName("path"), + }, &result) + require.NotEmpty(t, result.ComplianceCustomLink.ID) + + _ = i + } + + // List + var listResult struct { + ComplianceCustomLinks []complianceCustomLink `json:"compliance_custom_links"` + } + mc.CallToolInto("listComplianceCustomLinks", map[string]any{ + "compliance_portal_id": portalID, + }, &listResult) + + assert.GreaterOrEqual(t, len(listResult.ComplianceCustomLinks), 2) +} diff --git a/e2e/mcp/trust_center_test.go b/e2e/mcp/trust_center_test.go deleted file mode 100644 index 7108cc850..000000000 --- a/e2e/mcp/trust_center_test.go +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright (c) 2025-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 mcp_test - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.probo.inc/probo/e2e/internal/factory" - "go.probo.inc/probo/e2e/internal/testutil" -) - -type mcpFile struct { - DownloadURL string `json:"download_url"` -} - -type trustCenter struct { - ID string `json:"id"` - Title string `json:"title"` - TrustCenterVisible bool `json:"trustCenterVisible"` - Logo *mcpFile `json:"logo,omitempty"` -} - -type trustCenterReference struct { - ID string `json:"id"` - Name string `json:"name"` - URL string `json:"url"` - Order int `json:"order"` -} - -type complianceCustomLink struct { - ID string `json:"id"` - Name string `json:"name"` - URL string `json:"url"` -} - -func TestMCP_GetTrustCenter(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - const trustCenterQuery = ` - query($organizationId: ID!) { - node(id: $organizationId) { - ... on Organization { - trustCenter { - id - } - } - } - } - ` - - var trustCenterLookup struct { - Node struct { - TrustCenter struct { - ID string `json:"id"` - } `json:"trustCenter"` - } `json:"node"` - } - - err := owner.Execute(trustCenterQuery, map[string]any{ - "organizationId": orgID, - }, &trustCenterLookup) - require.NoError(t, err) - require.NotEmpty(t, trustCenterLookup.Node.TrustCenter.ID) - - trustCenterID := trustCenterLookup.Node.TrustCenter.ID - - const uploadMutation = ` - mutation UpdateTrustCenterBrand($input: UpdateTrustCenterBrandInput!) { - updateTrustCenterBrand(input: $input) { - trustCenter { - id - logo { - id - downloadUrl - } - } - } - } - ` - - pngContent := []byte{ - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, - 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, - 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x15, 0xc4, - 0x89, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, - 0x54, 0x78, 0x9c, 0x63, 0x00, 0x01, 0x00, 0x00, - 0x05, 0x00, 0x01, 0x0d, 0x0a, 0x2d, 0xb4, 0x00, - 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, - 0x42, 0x60, 0x82, - } - - var uploadResult struct { - UpdateTrustCenterBrand struct { - TrustCenter struct { - ID string `json:"id"` - Logo *struct { - ID string `json:"id"` - DownloadURL string `json:"downloadUrl"` - } `json:"logo"` - } `json:"trustCenter"` - } `json:"updateTrustCenterBrand"` - } - - err = owner.ExecuteWithFile(uploadMutation, map[string]any{ - "input": map[string]any{ - "trustCenterId": trustCenterID, - "logoFile": nil, - }, - }, "input.logoFile", testutil.UploadFile{ - Filename: "mcp-trust-center-logo.png", - ContentType: "image/png", - Content: pngContent, - }, &uploadResult) - require.NoError(t, err) - require.NotNil(t, uploadResult.UpdateTrustCenterBrand.TrustCenter.Logo) - - var result struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &result) - - assert.NotEmpty(t, result.TrustCenter.ID) - require.NotNil(t, result.TrustCenter.Logo) - assert.True( - t, - strings.Contains(result.TrustCenter.Logo.DownloadURL, "/api/files/v1/public/"), - "download_url must route through the public files API, got %q", - result.TrustCenter.Logo.DownloadURL, - ) -} - -func TestMCP_UpdateTrustCenter(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - require.NotEmpty(t, getResult.TrustCenter.ID) - - // Update - var updateResult struct { - TrustCenter struct { - ID string `json:"id"` - Title string `json:"title"` - Description *string `json:"description"` - WebsiteURL *string `json:"website_url"` - Email *string `json:"email"` - HeadquarterAddress *string `json:"headquarter_address"` - } `json:"trustCenter"` - } - mc.CallToolInto("updateTrustCenter", map[string]any{ - "trust_center_id": getResult.TrustCenter.ID, - "title": "Acme Security", - "description": "We keep your data safe.", - "website_url": "https://example.com", - "email": "security@example.com", - "headquarter_address": "123 Main St, San Francisco, CA 94102", - }, &updateResult) - - assert.Equal(t, getResult.TrustCenter.ID, updateResult.TrustCenter.ID) - assert.Equal(t, "Acme Security", updateResult.TrustCenter.Title) - require.NotNil(t, updateResult.TrustCenter.Description) - assert.Equal(t, "We keep your data safe.", *updateResult.TrustCenter.Description) - require.NotNil(t, updateResult.TrustCenter.WebsiteURL) - assert.Equal(t, "https://example.com", *updateResult.TrustCenter.WebsiteURL) - require.NotNil(t, updateResult.TrustCenter.Email) - assert.Equal(t, "security@example.com", *updateResult.TrustCenter.Email) - require.NotNil(t, updateResult.TrustCenter.HeadquarterAddress) - assert.Equal(t, "123 Main St, San Francisco, CA 94102", *updateResult.TrustCenter.HeadquarterAddress) -} - -func TestMCP_AddTrustCenterReference(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - tcID := getResult.TrustCenter.ID - - var result struct { - TrustCenterReference trustCenterReference `json:"trustCenterReference"` - } - mc.CallToolInto("addTrustCenterReference", map[string]any{ - "trustCenterId": tcID, - "name": "SOC 2 Report", - "url": "https://example.com/soc2", - }, &result) - - assert.NotEmpty(t, result.TrustCenterReference.ID) - assert.Equal(t, "SOC 2 Report", result.TrustCenterReference.Name) -} - -func TestMCP_UpdateTrustCenterReference(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - tcID := getResult.TrustCenter.ID - - // Create reference - var addResult struct { - TrustCenterReference trustCenterReference `json:"trustCenterReference"` - } - mc.CallToolInto("addTrustCenterReference", map[string]any{ - "trustCenterId": tcID, - "name": "Original Reference", - "url": "https://example.com/original", - }, &addResult) - require.NotEmpty(t, addResult.TrustCenterReference.ID) - - // Update reference - var updateResult struct { - TrustCenterReference trustCenterReference `json:"trustCenterReference"` - } - mc.CallToolInto("updateTrustCenterReference", map[string]any{ - "id": addResult.TrustCenterReference.ID, - "name": "Updated Reference", - "url": "https://example.com/updated", - }, &updateResult) - - assert.Equal(t, addResult.TrustCenterReference.ID, updateResult.TrustCenterReference.ID) - assert.Equal(t, "Updated Reference", updateResult.TrustCenterReference.Name) -} - -func TestMCP_DeleteTrustCenterReference(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - tcID := getResult.TrustCenter.ID - - // Create reference - var addResult struct { - TrustCenterReference trustCenterReference `json:"trustCenterReference"` - } - mc.CallToolInto("addTrustCenterReference", map[string]any{ - "trustCenterId": tcID, - "name": "Reference to delete", - "url": "https://example.com/delete", - }, &addResult) - require.NotEmpty(t, addResult.TrustCenterReference.ID) - - // Delete - var deleteResult struct { - DeletedTrustCenterReferenceID string `json:"deletedTrustCenterReferenceId"` - } - mc.CallToolInto("deleteTrustCenterReference", map[string]any{ - "id": addResult.TrustCenterReference.ID, - }, &deleteResult) - - assert.Equal(t, addResult.TrustCenterReference.ID, deleteResult.DeletedTrustCenterReferenceID) -} - -func TestMCP_ListTrustCenterReferences(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - tcID := getResult.TrustCenter.ID - - // Create references - for i := range 2 { - var result struct { - TrustCenterReference trustCenterReference `json:"trustCenterReference"` - } - mc.CallToolInto("addTrustCenterReference", map[string]any{ - "trustCenterId": tcID, - "name": factory.SafeName("Ref"), - "url": "https://example.com/" + factory.SafeName("path"), - }, &result) - require.NotEmpty(t, result.TrustCenterReference.ID) - - _ = i - } - - // List - var listResult struct { - TrustCenterReferences []trustCenterReference `json:"trustCenterReferences"` - } - mc.CallToolInto("listTrustCenterReferences", map[string]any{ - "trustCenterId": tcID, - }, &listResult) - - assert.GreaterOrEqual(t, len(listResult.TrustCenterReferences), 2) -} - -func TestMCP_ListTrustCenterFiles(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - tcID := getResult.TrustCenter.ID - - // List files (may be empty, just verify the tool works) - var listResult struct { - TrustCenterFiles []struct { - ID string `json:"id"` - Name string `json:"name"` - } `json:"trustCenterFiles"` - } - mc.CallToolInto("listTrustCenterFiles", map[string]any{ - "trustCenterId": tcID, - }, &listResult) - - // Just assert the call succeeded — files require multipart upload - assert.NotNil(t, listResult.TrustCenterFiles) -} - -func TestMCP_AddComplianceCustomLink(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - tcID := getResult.TrustCenter.ID - - var result struct { - ComplianceCustomLink complianceCustomLink `json:"complianceCustomLink"` - } - mc.CallToolInto("addComplianceCustomLink", map[string]any{ - "trustCenterId": tcID, - "name": "ISO 27001 Certificate", - "url": "https://example.com/iso27001", - }, &result) - - assert.NotEmpty(t, result.ComplianceCustomLink.ID) - assert.Equal(t, "ISO 27001 Certificate", result.ComplianceCustomLink.Name) -} - -func TestMCP_UpdateComplianceCustomLink(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - tcID := getResult.TrustCenter.ID - - // Create - var addResult struct { - ComplianceCustomLink complianceCustomLink `json:"complianceCustomLink"` - } - mc.CallToolInto("addComplianceCustomLink", map[string]any{ - "trustCenterId": tcID, - "name": "Original URL", - "url": "https://example.com/original", - }, &addResult) - require.NotEmpty(t, addResult.ComplianceCustomLink.ID) - - // Update - var updateResult struct { - ComplianceCustomLink complianceCustomLink `json:"complianceCustomLink"` - } - mc.CallToolInto("updateComplianceCustomLink", map[string]any{ - "id": addResult.ComplianceCustomLink.ID, - "name": "Updated URL", - "url": "https://example.com/updated", - }, &updateResult) - - assert.Equal(t, addResult.ComplianceCustomLink.ID, updateResult.ComplianceCustomLink.ID) - assert.Equal(t, "Updated URL", updateResult.ComplianceCustomLink.Name) -} - -func TestMCP_DeleteComplianceCustomLink(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - tcID := getResult.TrustCenter.ID - - // Create - var addResult struct { - ComplianceCustomLink complianceCustomLink `json:"complianceCustomLink"` - } - mc.CallToolInto("addComplianceCustomLink", map[string]any{ - "trustCenterId": tcID, - "name": "URL to delete", - "url": "https://example.com/delete", - }, &addResult) - require.NotEmpty(t, addResult.ComplianceCustomLink.ID) - - // Delete - var deleteResult struct { - DeletedComplianceCustomLinkID string `json:"deletedComplianceCustomLinkId"` - } - mc.CallToolInto("deleteComplianceCustomLink", map[string]any{ - "id": addResult.ComplianceCustomLink.ID, - }, &deleteResult) - - assert.Equal(t, addResult.ComplianceCustomLink.ID, deleteResult.DeletedComplianceCustomLinkID) -} - -func TestMCP_ListComplianceCustomLinks(t *testing.T) { - t.Parallel() - owner := testutil.NewClient(t, testutil.RoleOwner) - mc := testutil.NewMCPClient(t, owner) - orgID := owner.GetOrganizationID().String() - - // Get trust center ID - var getResult struct { - TrustCenter trustCenter `json:"trustCenter"` - } - mc.CallToolInto("getTrustCenter", map[string]any{ - "organizationId": orgID, - }, &getResult) - tcID := getResult.TrustCenter.ID - - // Create URLs - for i := range 2 { - var result struct { - ComplianceCustomLink complianceCustomLink `json:"complianceCustomLink"` - } - mc.CallToolInto("addComplianceCustomLink", map[string]any{ - "trustCenterId": tcID, - "name": factory.SafeName("URL"), - "url": "https://example.com/" + factory.SafeName("path"), - }, &result) - require.NotEmpty(t, result.ComplianceCustomLink.ID) - - _ = i - } - - // List - var listResult struct { - ComplianceCustomLinks []complianceCustomLink `json:"complianceCustomLinks"` - } - mc.CallToolInto("listComplianceCustomLinks", map[string]any{ - "trustCenterId": tcID, - }, &listResult) - - assert.GreaterOrEqual(t, len(listResult.ComplianceCustomLinks), 2) -} diff --git a/e2e/trust/trust_center_logo_test.go b/e2e/trust/compliance_portal_logo_test.go similarity index 76% rename from e2e/trust/trust_center_logo_test.go rename to e2e/trust/compliance_portal_logo_test.go index 98e772e71..9bfa75de8 100644 --- a/e2e/trust/trust_center_logo_test.go +++ b/e2e/trust/compliance_portal_logo_test.go @@ -33,17 +33,17 @@ import ( "go.probo.inc/probo/e2e/internal/testutil" ) -func TestTrustCenter_LogoFileDownloadURL(t *testing.T) { +func TestCompliancePortal_LogoFileDownloadURL(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) organizationID := owner.GetOrganizationID().String() - const trustCenterQuery = ` + const compliancePortalQuery = ` query($organizationId: ID!) { node(id: $organizationId) { ... on Organization { - trustCenter { + compliancePortal { id } } @@ -51,26 +51,26 @@ func TestTrustCenter_LogoFileDownloadURL(t *testing.T) { } ` - var trustCenterLookup struct { + var compliancePortalLookup struct { Node struct { - TrustCenter struct { + CompliancePortal struct { ID string `json:"id"` - } `json:"trustCenter"` + } `json:"compliancePortal"` } `json:"node"` } - err := owner.Execute(trustCenterQuery, map[string]any{ + err := owner.Execute(compliancePortalQuery, map[string]any{ "organizationId": organizationID, - }, &trustCenterLookup) + }, &compliancePortalLookup) require.NoError(t, err) - require.NotEmpty(t, trustCenterLookup.Node.TrustCenter.ID) + require.NotEmpty(t, compliancePortalLookup.Node.CompliancePortal.ID) - trustCenterID := trustCenterLookup.Node.TrustCenter.ID + compliancePortalID := compliancePortalLookup.Node.CompliancePortal.ID const activateMutation = ` - mutation($input: UpdateTrustCenterInput!) { - updateTrustCenter(input: $input) { - trustCenter { + mutation($input: UpdateCompliancePortalInput!) { + updateCompliancePortal(input: $input) { + compliancePortal { id active publicUrl @@ -80,19 +80,19 @@ func TestTrustCenter_LogoFileDownloadURL(t *testing.T) { ` var activateResult struct { - UpdateTrustCenter struct { - TrustCenter struct { + UpdateCompliancePortal struct { + CompliancePortal struct { ID string `json:"id"` Active bool `json:"active"` PublicURL string `json:"publicUrl"` - } `json:"trustCenter"` - } `json:"updateTrustCenter"` + } `json:"compliancePortal"` + } `json:"updateCompliancePortal"` } err = owner.Execute(activateMutation, map[string]any{ "input": map[string]any{ - "trustCenterId": trustCenterID, - "active": true, + "compliancePortalId": compliancePortalID, + "active": true, }, }, &activateResult) require.NoError(t, err) @@ -100,18 +100,18 @@ func TestTrustCenter_LogoFileDownloadURL(t *testing.T) { // Publishing the page provisions a managed {slug}.probopage.localhost // domain; the effective public URL resolves to it while no customer // custom domain is primary. - require.NotEmpty(t, activateResult.UpdateTrustCenter.TrustCenter.PublicURL) + require.NotEmpty(t, activateResult.UpdateCompliancePortal.CompliancePortal.PublicURL) - publicURL, err := url.Parse(activateResult.UpdateTrustCenter.TrustCenter.PublicURL) + publicURL, err := url.Parse(activateResult.UpdateCompliancePortal.CompliancePortal.PublicURL) require.NoError(t, err) trustHost := publicURL.Host require.NotEmpty(t, trustHost) const uploadMutation = ` - mutation UpdateTrustCenterBrand($input: UpdateTrustCenterBrandInput!) { - updateTrustCenterBrand(input: $input) { - trustCenter { + mutation UpdateCompliancePortalBrand($input: UpdateCompliancePortalBrandInput!) { + updateCompliancePortalBrand(input: $input) { + compliancePortal { id logo { id @@ -136,22 +136,22 @@ func TestTrustCenter_LogoFileDownloadURL(t *testing.T) { } var uploadResult struct { - UpdateTrustCenterBrand struct { - TrustCenter struct { + UpdateCompliancePortalBrand struct { + CompliancePortal struct { ID string `json:"id"` Logo *struct { ID string `json:"id"` FileName string `json:"fileName"` DownloadURL string `json:"downloadUrl"` } `json:"logo"` - } `json:"trustCenter"` - } `json:"updateTrustCenterBrand"` + } `json:"compliancePortal"` + } `json:"updateCompliancePortalBrand"` } err = owner.ExecuteWithFile(uploadMutation, map[string]any{ "input": map[string]any{ - "trustCenterId": trustCenterID, - "logoFile": nil, + "compliancePortalId": compliancePortalID, + "logoFile": nil, }, }, "input.logoFile", testutil.UploadFile{ Filename: "trust-center-logo.png", @@ -159,11 +159,11 @@ func TestTrustCenter_LogoFileDownloadURL(t *testing.T) { Content: pngContent, }, &uploadResult) require.NoError(t, err) - require.NotNil(t, uploadResult.UpdateTrustCenterBrand.TrustCenter.Logo) + require.NotNil(t, uploadResult.UpdateCompliancePortalBrand.CompliancePortal.Logo) const trustGraphQLQuery = ` query { - currentTrustCenter { + currentCompliancePortal { logo { id fileName @@ -174,31 +174,31 @@ func TestTrustCenter_LogoFileDownloadURL(t *testing.T) { ` var trustResult struct { - CurrentTrustCenter struct { + CurrentCompliancePortal struct { Logo *struct { ID string `json:"id"` FileName string `json:"fileName"` DownloadURL string `json:"downloadUrl"` } `json:"logo"` - } `json:"currentTrustCenter"` + } `json:"currentCompliancePortal"` } // The dedicated HTTPS listener only serves the page once the managed // domain's certificate has been provisioned (async, ~1s poll in e2e), so // retry until the TLS handshake and query succeed. require.Eventually(t, func() bool { - trustResult.CurrentTrustCenter.Logo = nil + trustResult.CurrentCompliancePortal.Logo = nil if err := owner.ExecuteTrust(trustHost, trustGraphQLQuery, nil, &trustResult); err != nil { return false } - return trustResult.CurrentTrustCenter.Logo != nil - }, 30*time.Second, 500*time.Millisecond, "trust center did not become servable on the dedicated listener") + return trustResult.CurrentCompliancePortal.Logo != nil + }, 30*time.Second, 500*time.Millisecond, "compliance portal did not become servable on the dedicated listener") - require.NotNil(t, trustResult.CurrentTrustCenter.Logo) - assert.Equal(t, uploadResult.UpdateTrustCenterBrand.TrustCenter.Logo.ID, trustResult.CurrentTrustCenter.Logo.ID) + require.NotNil(t, trustResult.CurrentCompliancePortal.Logo) + assert.Equal(t, uploadResult.UpdateCompliancePortalBrand.CompliancePortal.Logo.ID, trustResult.CurrentCompliancePortal.Logo.ID) - downloadURL := trustResult.CurrentTrustCenter.Logo.DownloadURL + downloadURL := trustResult.CurrentCompliancePortal.Logo.DownloadURL assert.True( t, strings.Contains(downloadURL, "/api/files/v1/public/"), diff --git a/e2e/trust/trust_center_nda_signature_test.go b/e2e/trust/compliance_portal_nda_signature_test.go similarity index 85% rename from e2e/trust/trust_center_nda_signature_test.go rename to e2e/trust/compliance_portal_nda_signature_test.go index 675abb885..1d5cdc685 100644 --- a/e2e/trust/trust_center_nda_signature_test.go +++ b/e2e/trust/compliance_portal_nda_signature_test.go @@ -49,21 +49,21 @@ const minimalPDFBase64 = "JVBERi0xLjcKJeLjz9MKMSAwIG9iago8PC9QYWdlcyAyIDAgUi9UeX "ES//AhpppZNeBhllklmyLLLKJrsclh/4AgAA//9tzQSTZW5kc3RyZWFtCmVuZG9iagoKc3RhcnR4" + "cmVmCjUxMgolJUVPRg==" -// TestTrustCenter_AcceptElectronicSignature_RejectsForeignSignature is a +// TestCompliancePortal_AcceptElectronicSignature_RejectsForeignSignature is a // regression test for GHSA-22xj-f767-ppw6: any self-provisioned trust // center visitor could accept another visitor's NDA signature, or inject // audit-trail events into it, simply by knowing its GID. -func TestTrustCenter_AcceptElectronicSignature_RejectsForeignSignature(t *testing.T) { +func TestCompliancePortal_AcceptElectronicSignature_RejectsForeignSignature(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - trustCenterID := lookupTrustCenterID(t, owner) + compliancePortalID := lookupCompliancePortalID(t, owner) - uploadTrustCenterNDA(t, owner, trustCenterID) - trustHost := lookupTrustHost(t, owner, trustCenterID) + uploadCompliancePortalNDA(t, owner, compliancePortalID) + trustHost := lookupTrustHost(t, owner, compliancePortalID) - victim := testutil.SelfProvisionTrustCenterVisitor(t, trustHost) - attacker := testutil.SelfProvisionTrustCenterVisitor(t, trustHost) + victim := testutil.SelfProvisionCompliancePortalVisitor(t, trustHost) + attacker := testutil.SelfProvisionCompliancePortalVisitor(t, trustHost) victimSignatureID, victimSignatureStatus := viewerSignature(t, victim, trustHost) require.NotEmpty(t, victimSignatureID) @@ -119,13 +119,13 @@ func TestTrustCenter_AcceptElectronicSignature_RejectsForeignSignature(t *testin assert.Equal(t, "ACCEPTED", acceptResult.AcceptElectronicSignature.Signature.Status) } -func uploadTrustCenterNDA(t *testing.T, owner *testutil.Client, trustCenterID string) { +func uploadCompliancePortalNDA(t *testing.T, owner *testutil.Client, compliancePortalID string) { t.Helper() const query = ` - mutation($input: UploadTrustCenterNDAInput!) { - uploadTrustCenterNDA(input: $input) { - trustCenter { id } + mutation($input: UploadCompliancePortalNDAInput!) { + uploadCompliancePortalNDA(input: $input) { + compliancePortal { id } } } ` @@ -135,9 +135,9 @@ func uploadTrustCenterNDA(t *testing.T, owner *testutil.Client, trustCenterID st err = owner.ExecuteWithFile(query, map[string]any{ "input": map[string]any{ - "trustCenterId": trustCenterID, - "fileName": "nda.pdf", - "file": nil, + "compliancePortalId": compliancePortalID, + "fileName": "nda.pdf", + "file": nil, }, }, "input.file", testutil.UploadFile{ Filename: "nda.pdf", @@ -152,7 +152,7 @@ func viewerSignature(t *testing.T, visitor *testutil.Client, trustHost string) ( const query = ` query { - currentTrustCenter { + currentCompliancePortal { nonDisclosureAgreement { viewerSignature { id status } } @@ -161,20 +161,20 @@ func viewerSignature(t *testing.T, visitor *testutil.Client, trustHost string) ( ` var result struct { - CurrentTrustCenter struct { + CurrentCompliancePortal struct { NonDisclosureAgreement struct { ViewerSignature struct { ID string `json:"id"` Status string `json:"status"` } `json:"viewerSignature"` } `json:"nonDisclosureAgreement"` - } `json:"currentTrustCenter"` + } `json:"currentCompliancePortal"` } err := visitor.ExecuteTrust(trustHost, query, nil, &result) require.NoError(t, err) - sig := result.CurrentTrustCenter.NonDisclosureAgreement.ViewerSignature + sig := result.CurrentCompliancePortal.NonDisclosureAgreement.ViewerSignature return sig.ID, sig.Status } diff --git a/e2e/trust/trust_center_oauth_connect_test.go b/e2e/trust/compliance_portal_oauth_connect_test.go similarity index 83% rename from e2e/trust/trust_center_oauth_connect_test.go rename to e2e/trust/compliance_portal_oauth_connect_test.go index d3c9c8360..23e157e59 100644 --- a/e2e/trust/trust_center_oauth_connect_test.go +++ b/e2e/trust/compliance_portal_oauth_connect_test.go @@ -26,13 +26,13 @@ import ( "go.probo.inc/probo/e2e/internal/testutil" ) -func TestTrustCenter_CIMDMetadataDocument(t *testing.T) { +func TestCompliancePortal_CIMDMetadataDocument(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - trustCenterID := lookupTrustCenterID(t, owner) - trustHost := lookupTrustHost(t, owner, trustCenterID) - testutil.WaitForTrustCenterHTTPS(t, trustHost) + compliancePortalID := lookupCompliancePortalID(t, owner) + trustHost := lookupTrustHost(t, owner, compliancePortalID) + testutil.WaitForCompliancePortalHTTPS(t, trustHost) client := testutil.TrustHTTPClient(trustHost) resp, err := client.Get("https://" + trustHost + "/.well-known/oauth-client-metadata") @@ -71,35 +71,35 @@ func TestTrustCenter_CIMDMetadataDocument(t *testing.T) { assert.NotEmpty(t, doc.ClientName) } -func TestTrustCenter_VisitorConnectViaCIMD(t *testing.T) { +func TestCompliancePortal_VisitorConnectViaCIMD(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - trustCenterID := lookupTrustCenterID(t, owner) - trustHost := lookupTrustHost(t, owner, trustCenterID) + compliancePortalID := lookupCompliancePortalID(t, owner) + trustHost := lookupTrustHost(t, owner, compliancePortalID) - visitor := testutil.SelfProvisionTrustCenterVisitor(t, trustHost) + visitor := testutil.SelfProvisionCompliancePortalVisitor(t, trustHost) const query = ` query { - currentTrustCenter { + currentCompliancePortal { title } } ` var result struct { - CurrentTrustCenter struct { + CurrentCompliancePortal struct { Title string `json:"title"` - } `json:"currentTrustCenter"` + } `json:"currentCompliancePortal"` } err := visitor.ExecuteTrust(trustHost, query, nil, &result) require.NoError(t, err, "visitor session must authenticate trust GraphQL after CIMD connect") - assert.NotEmpty(t, result.CurrentTrustCenter.Title) + assert.NotEmpty(t, result.CurrentCompliancePortal.Title) } -func TestTrustCenter_UnknownCIMDClientRejected(t *testing.T) { +func TestCompliancePortal_UnknownCIMDClientRejected(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) diff --git a/e2e/trust/trust_center_report_export_test.go b/e2e/trust/compliance_portal_report_export_test.go similarity index 65% rename from e2e/trust/trust_center_report_export_test.go rename to e2e/trust/compliance_portal_report_export_test.go index e441688f3..24f9bd247 100644 --- a/e2e/trust/trust_center_report_export_test.go +++ b/e2e/trust/compliance_portal_report_export_test.go @@ -46,30 +46,30 @@ const nodeQuery = ` } ` -// TestTrustCenter_ExportReportPDF_TenantIsolation verifies that a public +// TestCompliancePortal_ExportReportPDF_TenantIsolation verifies that a public // audit-report PDF can only be exported through its own organization's trust -// center. A visitor on another organization's trust center must not be able to +// center. A visitor on another organization's compliance portal must not be able to // download it by supplying the foreign report GID (cross-tenant IDOR). -func TestTrustCenter_ExportReportPDF_TenantIsolation(t *testing.T) { +func TestCompliancePortal_ExportReportPDF_TenantIsolation(t *testing.T) { t.Parallel() victimOwner := testutil.NewClient(t, testutil.RoleOwner) attackerOwner := testutil.NewClient(t, testutil.RoleOwner) - victimTrustCenterID, victimReportID := setupPublicAuditReport(t, victimOwner) - attackerTrustCenterID, _ := setupPublicAuditReport(t, attackerOwner) + victimCompliancePortalID, victimReportID := setupPublicAuditReport(t, victimOwner) + attackerCompliancePortalID, _ := setupPublicAuditReport(t, attackerOwner) - t.Run("owning trust center can export its report", func(t *testing.T) { + t.Run("owning compliance portal can export its report", func(t *testing.T) { var result struct { ExportReportPDF struct { Data string `json:"data"` } `json:"exportReportPDF"` } - err := victimOwner.ExecuteTrust(victimTrustCenterID, exportReportPDFMutation, map[string]any{ + err := victimOwner.ExecuteTrust(victimCompliancePortalID, exportReportPDFMutation, map[string]any{ "input": map[string]any{"reportId": victimReportID}, }, &result) - require.NoError(t, err, "the owning trust center must serve its own public report") + require.NoError(t, err, "the owning compliance portal must serve its own public report") assert.True( t, strings.HasPrefix(result.ExportReportPDF.Data, "data:application/pdf;base64,"), @@ -78,11 +78,11 @@ func TestTrustCenter_ExportReportPDF_TenantIsolation(t *testing.T) { ) }) - t.Run("foreign trust center cannot export another org's report", func(t *testing.T) { - err := attackerOwner.ExecuteTrust(attackerTrustCenterID, exportReportPDFMutation, map[string]any{ + t.Run("foreign compliance portal cannot export another org's report", func(t *testing.T) { + err := attackerOwner.ExecuteTrust(attackerCompliancePortalID, exportReportPDFMutation, map[string]any{ "input": map[string]any{"reportId": victimReportID}, }, nil) - require.Error(t, err, "a foreign trust center must not export another org's report") + require.Error(t, err, "a foreign compliance portal must not export another org's report") assert.Contains( t, err.Error(), @@ -92,37 +92,37 @@ func TestTrustCenter_ExportReportPDF_TenantIsolation(t *testing.T) { }) } -// TestTrustCenter_Node_TenantIsolation exercises the generic node(id:) resolver: -// a visitor on one organization's trust center must not resolve a node that +// TestCompliancePortal_Node_TenantIsolation exercises the generic node(id:) resolver: +// a visitor on one organization's compliance portal must not resolve a node that // belongs to another organization, even with a valid foreign GID. -func TestTrustCenter_Node_TenantIsolation(t *testing.T) { +func TestCompliancePortal_Node_TenantIsolation(t *testing.T) { t.Parallel() victimOwner := testutil.NewClient(t, testutil.RoleOwner) attackerOwner := testutil.NewClient(t, testutil.RoleOwner) - victimTrustCenterID, _ := setupPublicAuditReport(t, victimOwner) - attackerTrustCenterID, _ := setupPublicAuditReport(t, attackerOwner) + victimCompliancePortalID, _ := setupPublicAuditReport(t, victimOwner) + attackerCompliancePortalID, _ := setupPublicAuditReport(t, attackerOwner) - t.Run("owning trust center resolves its own node", func(t *testing.T) { + t.Run("owning compliance portal resolves its own node", func(t *testing.T) { var result struct { Node struct { Typename string `json:"__typename"` } `json:"node"` } - err := victimOwner.ExecuteTrust(victimTrustCenterID, nodeQuery, map[string]any{ - "id": victimTrustCenterID, + err := victimOwner.ExecuteTrust(victimCompliancePortalID, nodeQuery, map[string]any{ + "id": victimCompliancePortalID, }, &result) - require.NoError(t, err, "the owning trust center must resolve its own node") + require.NoError(t, err, "the owning compliance portal must resolve its own node") assert.NotEmpty(t, result.Node.Typename, "expected the node to resolve to a concrete type") }) - t.Run("foreign trust center cannot resolve another org's node", func(t *testing.T) { - err := attackerOwner.ExecuteTrust(attackerTrustCenterID, nodeQuery, map[string]any{ - "id": victimTrustCenterID, + t.Run("foreign compliance portal cannot resolve another org's node", func(t *testing.T) { + err := attackerOwner.ExecuteTrust(attackerCompliancePortalID, nodeQuery, map[string]any{ + "id": victimCompliancePortalID, }, nil) - require.Error(t, err, "a foreign trust center must not resolve another org's node") + require.Error(t, err, "a foreign compliance portal must not resolve another org's node") assert.Contains( t, err.Error(), @@ -133,9 +133,9 @@ func TestTrustCenter_Node_TenantIsolation(t *testing.T) { } // setupPublicAuditReport creates an audit with an uploaded report file, marks it -// as publicly visible on the trust center, activates the trust center, and -// returns the trust center ID and the report file ID. -func setupPublicAuditReport(t *testing.T, owner *testutil.Client) (trustCenterID string, reportID string) { +// as publicly visible on the compliance portal, activates the compliance portal, and +// returns the compliance portal ID and the report file ID. +func setupPublicAuditReport(t *testing.T, owner *testutil.Client) (compliancePortalID string, reportID string) { t.Helper() frameworkID := factory.NewFramework(owner).WithName(factory.SafeName("Framework")).Create() @@ -188,14 +188,14 @@ func setupPublicAuditReport(t *testing.T, owner *testutil.Client) (trustCenterID err = owner.Execute(setVisibilityMutation, map[string]any{ "input": map[string]any{ - "id": auditID, - "trustCenterVisibility": "PUBLIC", + "id": auditID, + "compliancePortalVisibility": "PUBLIC", }, }, nil) require.NoError(t, err) - trustCenterID = lookupTrustCenterID(t, owner) - activateTrustCenter(t, owner, trustCenterID) + compliancePortalID = lookupCompliancePortalID(t, owner) + activateCompliancePortal(t, owner, compliancePortalID) - return trustCenterID, reportID + return compliancePortalID, reportID } diff --git a/e2e/trust/trust_center_slug_test.go b/e2e/trust/compliance_portal_slug_test.go similarity index 87% rename from e2e/trust/trust_center_slug_test.go rename to e2e/trust/compliance_portal_slug_test.go index 3efc8152c..c8712875d 100644 --- a/e2e/trust/trust_center_slug_test.go +++ b/e2e/trust/compliance_portal_slug_test.go @@ -29,7 +29,7 @@ import ( "go.probo.inc/probo/e2e/internal/testutil" ) -func TestTrustCenter_SlugHasEntropySuffix(t *testing.T) { +func TestCompliancePortal_SlugHasEntropySuffix(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) @@ -39,7 +39,7 @@ func TestTrustCenter_SlugHasEntropySuffix(t *testing.T) { query($organizationId: ID!) { node(id: $organizationId) { ... on Organization { - trustCenter { + compliancePortal { slug } } @@ -49,9 +49,9 @@ func TestTrustCenter_SlugHasEntropySuffix(t *testing.T) { var result struct { Node struct { - TrustCenter struct { + CompliancePortal struct { Slug string `json:"slug"` - } `json:"trustCenter"` + } `json:"compliancePortal"` } `json:"node"` } @@ -59,8 +59,8 @@ func TestTrustCenter_SlugHasEntropySuffix(t *testing.T) { "organizationId": organizationID, }, &result) require.NoError(t, err) - require.NotEmpty(t, result.Node.TrustCenter.Slug) + require.NotEmpty(t, result.Node.CompliancePortal.Slug) slugWithEntropy := regexp.MustCompile(`^[a-z0-9-]+-[0-9a-f]{8}$`) - assert.Regexp(t, slugWithEntropy, result.Node.TrustCenter.Slug) + assert.Regexp(t, slugWithEntropy, result.Node.CompliancePortal.Slug) } diff --git a/e2e/trust/helpers_test.go b/e2e/trust/helpers_test.go index fedc28a3b..2c7f51112 100644 --- a/e2e/trust/helpers_test.go +++ b/e2e/trust/helpers_test.go @@ -28,15 +28,15 @@ import ( "go.probo.inc/probo/e2e/internal/testutil" ) -// lookupTrustCenterID resolves the trust center ID of the owner's organization. -func lookupTrustCenterID(t *testing.T, owner *testutil.Client) string { +// lookupCompliancePortalID resolves the compliance portal ID of the owner's organization. +func lookupCompliancePortalID(t *testing.T, owner *testutil.Client) string { t.Helper() const query = ` query($organizationId: ID!) { node(id: $organizationId) { ... on Organization { - trustCenter { id } + compliancePortal { id } } } } @@ -44,9 +44,9 @@ func lookupTrustCenterID(t *testing.T, owner *testutil.Client) string { var result struct { Node struct { - TrustCenter struct { + CompliancePortal struct { ID string `json:"id"` - } `json:"trustCenter"` + } `json:"compliancePortal"` } `json:"node"` } @@ -54,21 +54,21 @@ func lookupTrustCenterID(t *testing.T, owner *testutil.Client) string { "organizationId": owner.GetOrganizationID().String(), }, &result) require.NoError(t, err) - require.NotEmpty(t, result.Node.TrustCenter.ID) + require.NotEmpty(t, result.Node.CompliancePortal.ID) - return result.Node.TrustCenter.ID + return result.Node.CompliancePortal.ID } -func lookupTrustHost(t *testing.T, owner *testutil.Client, trustCenterID string) string { +func lookupTrustHost(t *testing.T, owner *testutil.Client, compliancePortalID string) string { t.Helper() - activateTrustCenter(t, owner, trustCenterID) + activateCompliancePortal(t, owner, compliancePortalID) const query = ` query($organizationId: ID!) { node(id: $organizationId) { ... on Organization { - trustCenter { publicUrl } + compliancePortal { publicUrl } } } } @@ -76,9 +76,9 @@ func lookupTrustHost(t *testing.T, owner *testutil.Client, trustCenterID string) var result struct { Node struct { - TrustCenter struct { + CompliancePortal struct { PublicURL string `json:"publicUrl"` - } `json:"trustCenter"` + } `json:"compliancePortal"` } `json:"node"` } @@ -86,32 +86,32 @@ func lookupTrustHost(t *testing.T, owner *testutil.Client, trustCenterID string) "organizationId": owner.GetOrganizationID().String(), }, &result) require.NoError(t, err) - require.NotEmpty(t, result.Node.TrustCenter.PublicURL) + require.NotEmpty(t, result.Node.CompliancePortal.PublicURL) - publicURL, err := url.Parse(result.Node.TrustCenter.PublicURL) + publicURL, err := url.Parse(result.Node.CompliancePortal.PublicURL) require.NoError(t, err) require.NotEmpty(t, publicURL.Host) return publicURL.Host } -// activateTrustCenter flips the trust center to active so its public surface +// activateCompliancePortal flips the compliance portal to active so its public surface // (NDA, subprocessors, reports, branding) becomes reachable by visitors. -func activateTrustCenter(t *testing.T, owner *testutil.Client, trustCenterID string) { +func activateCompliancePortal(t *testing.T, owner *testutil.Client, compliancePortalID string) { t.Helper() const query = ` - mutation($input: UpdateTrustCenterInput!) { - updateTrustCenter(input: $input) { - trustCenter { id active } + mutation($input: UpdateCompliancePortalInput!) { + updateCompliancePortal(input: $input) { + compliancePortal { id active } } } ` err := owner.Execute(query, map[string]any{ "input": map[string]any{ - "trustCenterId": trustCenterID, - "active": true, + "compliancePortalId": compliancePortalID, + "active": true, }, }, nil) require.NoError(t, err) diff --git a/e2e/trust/subprocessors_filter_test.go b/e2e/trust/subprocessors_filter_test.go index 06efcf3a0..52a8c4ca7 100644 --- a/e2e/trust/subprocessors_filter_test.go +++ b/e2e/trust/subprocessors_filter_test.go @@ -29,12 +29,12 @@ import ( "go.probo.inc/probo/e2e/internal/testutil" ) -func TestTrustCenter_SubprocessorsFilter(t *testing.T) { +func TestCompliancePortal_SubprocessorsFilter(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - trustCenterID := lookupTrustCenterID(t, owner) - activateTrustCenter(t, owner, trustCenterID) + compliancePortalID := lookupCompliancePortalID(t, owner) + activateCompliancePortal(t, owner, compliancePortalID) awsName := factory.SafeName("AWS") awsID := factory.NewThirdParty(owner).WithName(awsName).WithCategory("CLOUD_PROVIDER").Create() @@ -51,69 +51,69 @@ func TestTrustCenter_SubprocessorsFilter(t *testing.T) { t.Run("no filter returns every published subprocessor", func(t *testing.T) { t.Parallel() - result := querySubprocessors(t, owner, trustCenterID, nil) - assert.Equal(t, 3, result.CurrentTrustCenter.Subprocessors.TotalCount) - assert.Len(t, result.CurrentTrustCenter.Subprocessors.Edges, 3) + result := querySubprocessors(t, owner, compliancePortalID, nil) + assert.Equal(t, 3, result.CurrentCompliancePortal.Subprocessors.TotalCount) + assert.Len(t, result.CurrentCompliancePortal.Subprocessors.Edges, 3) }) t.Run("category filter narrows to one category", func(t *testing.T) { t.Parallel() - result := querySubprocessors(t, owner, trustCenterID, map[string]any{ + result := querySubprocessors(t, owner, compliancePortalID, map[string]any{ "category": "CLOUD_PROVIDER", }) - require.Equal(t, 1, result.CurrentTrustCenter.Subprocessors.TotalCount) - require.Len(t, result.CurrentTrustCenter.Subprocessors.Edges, 1) - assert.Equal(t, awsName, result.CurrentTrustCenter.Subprocessors.Edges[0].Node.Name) + require.Equal(t, 1, result.CurrentCompliancePortal.Subprocessors.TotalCount) + require.Len(t, result.CurrentCompliancePortal.Subprocessors.Edges, 1) + assert.Equal(t, awsName, result.CurrentCompliancePortal.Subprocessors.Edges[0].Node.Name) }) t.Run("country filter matches array membership", func(t *testing.T) { t.Parallel() - result := querySubprocessors(t, owner, trustCenterID, map[string]any{ + result := querySubprocessors(t, owner, compliancePortalID, map[string]any{ "country": "IE", }) - require.Equal(t, 1, result.CurrentTrustCenter.Subprocessors.TotalCount) - require.Len(t, result.CurrentTrustCenter.Subprocessors.Edges, 1) - assert.Equal(t, stripeName, result.CurrentTrustCenter.Subprocessors.Edges[0].Node.Name) + require.Equal(t, 1, result.CurrentCompliancePortal.Subprocessors.TotalCount) + require.Len(t, result.CurrentCompliancePortal.Subprocessors.Edges, 1) + assert.Equal(t, stripeName, result.CurrentCompliancePortal.Subprocessors.Edges[0].Node.Name) }) t.Run("query filter matches name substring", func(t *testing.T) { t.Parallel() - result := querySubprocessors(t, owner, trustCenterID, map[string]any{ + result := querySubprocessors(t, owner, compliancePortalID, map[string]any{ "query": slackName, }) - require.Equal(t, 1, result.CurrentTrustCenter.Subprocessors.TotalCount) - require.Len(t, result.CurrentTrustCenter.Subprocessors.Edges, 1) - assert.Equal(t, slackName, result.CurrentTrustCenter.Subprocessors.Edges[0].Node.Name) + require.Equal(t, 1, result.CurrentCompliancePortal.Subprocessors.TotalCount) + require.Len(t, result.CurrentCompliancePortal.Subprocessors.Edges, 1) + assert.Equal(t, slackName, result.CurrentCompliancePortal.Subprocessors.Edges[0].Node.Name) }) t.Run("combined filters intersect", func(t *testing.T) { t.Parallel() - result := querySubprocessors(t, owner, trustCenterID, map[string]any{ + result := querySubprocessors(t, owner, compliancePortalID, map[string]any{ "category": "FINANCE", "country": "US", }) - require.Equal(t, 1, result.CurrentTrustCenter.Subprocessors.TotalCount) - require.Len(t, result.CurrentTrustCenter.Subprocessors.Edges, 1) - assert.Equal(t, stripeName, result.CurrentTrustCenter.Subprocessors.Edges[0].Node.Name) + require.Equal(t, 1, result.CurrentCompliancePortal.Subprocessors.TotalCount) + require.Len(t, result.CurrentCompliancePortal.Subprocessors.Edges, 1) + assert.Equal(t, stripeName, result.CurrentCompliancePortal.Subprocessors.Edges[0].Node.Name) }) t.Run("non-matching filter returns empty set", func(t *testing.T) { t.Parallel() - result := querySubprocessors(t, owner, trustCenterID, map[string]any{ + result := querySubprocessors(t, owner, compliancePortalID, map[string]any{ "category": "SECURITY", }) - assert.Equal(t, 0, result.CurrentTrustCenter.Subprocessors.TotalCount) - assert.Empty(t, result.CurrentTrustCenter.Subprocessors.Edges) + assert.Equal(t, 0, result.CurrentCompliancePortal.Subprocessors.TotalCount) + assert.Empty(t, result.CurrentCompliancePortal.Subprocessors.Edges) }) } type subprocessorsResult struct { - CurrentTrustCenter struct { + CurrentCompliancePortal struct { Subprocessors struct { TotalCount int `json:"totalCount"` Edges []struct { @@ -125,20 +125,20 @@ type subprocessorsResult struct { } `json:"node"` } `json:"edges"` } `json:"subprocessors"` - } `json:"currentTrustCenter"` + } `json:"currentCompliancePortal"` } func querySubprocessors( t *testing.T, owner *testutil.Client, - trustCenterID string, + compliancePortalID string, filter map[string]any, ) subprocessorsResult { t.Helper() const query = ` query($filter: SubprocessorFilter) { - currentTrustCenter { + currentCompliancePortal { subprocessors(first: 50, filter: $filter) { totalCount edges { @@ -156,7 +156,7 @@ func querySubprocessors( var result subprocessorsResult - err := owner.ExecuteTrust(trustCenterID, query, map[string]any{"filter": filter}, &result) + err := owner.ExecuteTrust(compliancePortalID, query, map[string]any{"filter": filter}, &result) require.NoError(t, err) return result @@ -168,16 +168,16 @@ func publishSubprocessor(t *testing.T, owner *testutil.Client, thirdPartyID stri const mutation = ` mutation($input: UpdateThirdPartyInput!) { updateThirdParty(input: $input) { - thirdParty { id showOnTrustCenter countries } + thirdParty { id showOnCompliancePortal countries } } } ` err := owner.Execute(mutation, map[string]any{ "input": map[string]any{ - "id": thirdPartyID, - "showOnTrustCenter": true, - "countries": countries, + "id": thirdPartyID, + "showOnCompliancePortal": true, + "countries": countries, }, }, nil) require.NoError(t, err)