From 067c3c168053ec30735af45c95acef2ede11dc14 Mon Sep 17 00:00:00 2001 From: Sacha Al Himdani Date: Fri, 27 Feb 2026 17:21:32 +0100 Subject: [PATCH] Use audit name in compliance page Signed-off-by: Sacha Al Himdani --- apps/trust/src/components/AuditRow.tsx | 7 +++ .../__generated__/AuditRowFragment.graphql.ts | 23 ++++---- .../TrustGraphCurrentQuery.graphql.ts | 7 ++- .../api/trust/v1/check__nda_signature.go | 57 +++++++++++++++++++ pkg/server/api/trust/v1/schema.graphql | 1 + pkg/server/api/trust/v1/schema/schema.go | 41 +++++++++++++ pkg/server/api/trust/v1/types/audit.go | 3 +- pkg/server/api/trust/v1/types/types.go | 1 + pkg/server/api/trust/v1/v1_resolver.go | 35 ------------ 9 files changed, 126 insertions(+), 49 deletions(-) create mode 100644 pkg/server/api/trust/v1/check__nda_signature.go diff --git a/apps/trust/src/components/AuditRow.tsx b/apps/trust/src/components/AuditRow.tsx index 08b1d3a97..03b8e489a 100644 --- a/apps/trust/src/components/AuditRow.tsx +++ b/apps/trust/src/components/AuditRow.tsx @@ -45,6 +45,7 @@ const downloadMutation = graphql` const auditRowFragment = graphql` fragment AuditRowFragment on Audit { + name report { id filename @@ -129,6 +130,12 @@ export function AuditRow(props: { audit: AuditRowFragment$key }) {
{audit.framework.name} + {audit.name && ( + <> + {" "} + {audit.name} + + )}
{audit.report && audit.report.isUserAuthorized ? ( diff --git a/apps/trust/src/components/__generated__/AuditRowFragment.graphql.ts b/apps/trust/src/components/__generated__/AuditRowFragment.graphql.ts index e3ef922e2..c24672d79 100644 --- a/apps/trust/src/components/__generated__/AuditRowFragment.graphql.ts +++ b/apps/trust/src/components/__generated__/AuditRowFragment.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<3265a0991323eee4011c668b68d1b365>> + * @generated SignedSource<<9540bd74ce3b0dd5366c237b56070d9f>> * @lightSyntaxTransform * @nogrep */ @@ -17,6 +17,7 @@ export type AuditRowFragment$data = { readonly lightLogoURL: string | null | undefined; readonly name: string; }; + readonly name: string | null | undefined; readonly report: { readonly filename: string; readonly hasUserRequestedAccess: boolean; @@ -32,6 +33,13 @@ export type AuditRowFragment$key = { const node: ReaderFragment = (function(){ var v0 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null +}, +v1 = { "alias": null, "args": null, "kind": "ScalarField", @@ -44,6 +52,7 @@ return { "metadata": null, "name": "AuditRowFragment", "selections": [ + (v0/*: any*/), { "alias": null, "args": null, @@ -52,7 +61,7 @@ return { "name": "report", "plural": false, "selections": [ - (v0/*: any*/), + (v1/*: any*/), { "alias": null, "args": null, @@ -85,14 +94,8 @@ return { "name": "framework", "plural": false, "selections": [ + (v1/*: any*/), (v0/*: any*/), - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "name", - "storageKey": null - }, { "alias": null, "args": null, @@ -116,6 +119,6 @@ return { }; })(); -(node as any).hash = "417e65b500df4b4cff874dab2bea90ee"; +(node as any).hash = "ebf47a97014ba4dad0da94f2bb01666f"; export default node; diff --git a/apps/trust/src/queries/__generated__/TrustGraphCurrentQuery.graphql.ts b/apps/trust/src/queries/__generated__/TrustGraphCurrentQuery.graphql.ts index 5521a6934..7e2ce3666 100644 --- a/apps/trust/src/queries/__generated__/TrustGraphCurrentQuery.graphql.ts +++ b/apps/trust/src/queries/__generated__/TrustGraphCurrentQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<> + * @generated SignedSource<<663225cc4e0d94b50dc97084c3d51aae>> * @lightSyntaxTransform * @nogrep */ @@ -628,6 +628,7 @@ return { "plural": false, "selections": [ (v2/*: any*/), + (v10/*: any*/), { "alias": null, "args": null, @@ -691,12 +692,12 @@ return { ] }, "params": { - "cacheID": "011070e93164ecde082cc2e74651ef2e", + "cacheID": "fab59d135402a3b935f277a385d33b93", "id": null, "metadata": {}, "name": "TrustGraphCurrentQuery", "operationKind": "query", - "text": "query TrustGraphCurrentQuery {\n viewer {\n email\n fullName\n id\n }\n currentTrustCenter {\n id\n slug\n isViewerMember\n logoFileUrl\n darkLogoFileUrl\n nonDisclosureAgreement {\n fileName\n fileUrl\n viewerSignature {\n status\n id\n }\n }\n organization {\n name\n description\n websiteUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n vendorInfo: vendors(first: 0) {\n totalCount\n }\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\n lightLogoURL\n darkLogoURL\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment OverviewPageFragment on TrustCenter {\n references(first: 14) {\n edges {\n node {\n id\n name\n logoUrl\n websiteUrl\n }\n }\n }\n vendors(first: 3) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n trustCenterFiles(first: 5) {\n edges {\n node {\n id\n category\n ...TrustCenterFileRowFragment\n }\n }\n }\n}\n\nfragment TrustCenterFileRowFragment on TrustCenterFile {\n id\n name\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment VendorRowFragment on Vendor {\n name\n description\n websiteUrl\n countries\n}\n" + "text": "query TrustGraphCurrentQuery {\n viewer {\n email\n fullName\n id\n }\n currentTrustCenter {\n id\n slug\n isViewerMember\n logoFileUrl\n darkLogoFileUrl\n nonDisclosureAgreement {\n fileName\n fileUrl\n viewerSignature {\n status\n id\n }\n }\n organization {\n name\n description\n websiteUrl\n email\n headquarterAddress\n id\n }\n ...OverviewPageFragment\n vendorInfo: vendors(first: 0) {\n totalCount\n }\n audits(first: 50) {\n edges {\n node {\n id\n ...AuditRowFragment\n }\n }\n }\n }\n}\n\nfragment AuditRowFragment on Audit {\n name\n report {\n id\n filename\n isUserAuthorized\n hasUserRequestedAccess\n }\n framework {\n id\n name\n lightLogoURL\n darkLogoURL\n }\n}\n\nfragment DocumentRowFragment on Document {\n id\n title\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment OverviewPageFragment on TrustCenter {\n references(first: 14) {\n edges {\n node {\n id\n name\n logoUrl\n websiteUrl\n }\n }\n }\n vendors(first: 3) {\n edges {\n node {\n id\n countries\n ...VendorRowFragment\n }\n }\n }\n documents(first: 5) {\n edges {\n node {\n id\n ...DocumentRowFragment\n documentType\n }\n }\n }\n trustCenterFiles(first: 5) {\n edges {\n node {\n id\n category\n ...TrustCenterFileRowFragment\n }\n }\n }\n}\n\nfragment TrustCenterFileRowFragment on TrustCenterFile {\n id\n name\n isUserAuthorized\n hasUserRequestedAccess\n}\n\nfragment VendorRowFragment on Vendor {\n name\n description\n websiteUrl\n countries\n}\n" } }; })(); diff --git a/pkg/server/api/trust/v1/check__nda_signature.go b/pkg/server/api/trust/v1/check__nda_signature.go new file mode 100644 index 000000000..6cee315a9 --- /dev/null +++ b/pkg/server/api/trust/v1/check__nda_signature.go @@ -0,0 +1,57 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package trust_v1 + +import ( + "context" + + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/server/gqlutils" +) + +func (r *mutationResolver) checkNDASignature( + ctx context.Context, + trustCenter *coredata.TrustCenter, + identity *coredata.Identity, +) error { + if trustCenter.NonDisclosureAgreementFileID == nil { + return nil + } + + trustService := r.TrustService(ctx, trustCenter.ID.TenantID()) + + access, err := trustService.TrustCenterAccesses.GetAccess(ctx, trustCenter.ID, identity.EmailAddress) + if err != nil { + return gqlutils.Forbiddenf(ctx, "user has not signed the NDA") + } + + if access.ElectronicSignatureID == nil { + return nil + } + + sig, err := r.esign.GetSignatureByID(ctx, *access.ElectronicSignatureID) + if err != nil { + return gqlutils.Forbiddenf(ctx, "user has not signed the NDA") + } + + switch sig.Status { + case coredata.ElectronicSignatureStatusAccepted, + coredata.ElectronicSignatureStatusProcessing, + coredata.ElectronicSignatureStatusCompleted: + return nil + default: + return gqlutils.Forbiddenf(ctx, "user has not signed the NDA") + } +} diff --git a/pkg/server/api/trust/v1/schema.graphql b/pkg/server/api/trust/v1/schema.graphql index 25c1dd709..56d996d8e 100644 --- a/pkg/server/api/trust/v1/schema.graphql +++ b/pkg/server/api/trust/v1/schema.graphql @@ -90,6 +90,7 @@ type Report implements Node { type Audit implements Node { id: ID! + name: String framework: Framework! @goField(forceResolver: true) report: Report @goField(forceResolver: true) } diff --git a/pkg/server/api/trust/v1/schema/schema.go b/pkg/server/api/trust/v1/schema/schema.go index c362d43e9..c168efd51 100644 --- a/pkg/server/api/trust/v1/schema/schema.go +++ b/pkg/server/api/trust/v1/schema/schema.go @@ -73,6 +73,7 @@ type ComplexityRoot struct { Audit struct { Framework func(childComplexity int) int ID func(childComplexity int) int + Name func(childComplexity int) int Report func(childComplexity int) int } @@ -393,6 +394,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin } return e.complexity.Audit.ID(childComplexity), true + case "Audit.name": + if e.complexity.Audit.Name == nil { + break + } + + return e.complexity.Audit.Name(childComplexity), true case "Audit.report": if e.complexity.Audit.Report == nil { break @@ -1427,6 +1434,7 @@ type Report implements Node { type Audit implements Node { id: ID! + name: String framework: Framework! @goField(forceResolver: true) report: Report @goField(forceResolver: true) } @@ -2572,6 +2580,35 @@ func (ec *executionContext) fieldContext_Audit_id(_ context.Context, field graph return fc, nil } +func (ec *executionContext) _Audit_name(ctx context.Context, field graphql.CollectedField, obj *types.Audit) (ret graphql.Marshaler) { + return graphql.ResolveField( + ctx, + ec.OperationContext, + field, + ec.fieldContext_Audit_name, + func(ctx context.Context) (any, error) { + return obj.Name, nil + }, + nil, + ec.marshalOString2áš–string, + true, + false, + ) +} + +func (ec *executionContext) fieldContext_Audit_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Audit", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Audit_framework(ctx context.Context, field graphql.CollectedField, obj *types.Audit) (ret graphql.Marshaler) { return graphql.ResolveField( ctx, @@ -2779,6 +2816,8 @@ func (ec *executionContext) fieldContext_AuditEdge_node(_ context.Context, field switch field.Name { case "id": return ec.fieldContext_Audit_id(ctx, field) + case "name": + return ec.fieldContext_Audit_name(ctx, field) case "framework": return ec.fieldContext_Audit_framework(ctx, field) case "report": @@ -8772,6 +8811,8 @@ func (ec *executionContext) _Audit(ctx context.Context, sel ast.SelectionSet, ob if out.Values[i] == graphql.Null { atomic.AddUint32(&out.Invalids, 1) } + case "name": + out.Values[i] = ec._Audit_name(ctx, field, obj) case "framework": field := field diff --git a/pkg/server/api/trust/v1/types/audit.go b/pkg/server/api/trust/v1/types/audit.go index 2990f5f51..0c45373e0 100644 --- a/pkg/server/api/trust/v1/types/audit.go +++ b/pkg/server/api/trust/v1/types/audit.go @@ -35,7 +35,8 @@ func NewAuditConnection( func NewAudit(a *coredata.Audit) *Audit { return &Audit{ - ID: a.ID, + ID: a.ID, + Name: a.Name, } } diff --git a/pkg/server/api/trust/v1/types/types.go b/pkg/server/api/trust/v1/types/types.go index 47c8ec2e2..688536539 100644 --- a/pkg/server/api/trust/v1/types/types.go +++ b/pkg/server/api/trust/v1/types/types.go @@ -27,6 +27,7 @@ type AcceptElectronicSignaturePayload struct { type Audit struct { ID gid.GID `json:"id"` + Name *string `json:"name,omitempty"` Framework *Framework `json:"framework"` Report *Report `json:"report,omitempty"` } diff --git a/pkg/server/api/trust/v1/v1_resolver.go b/pkg/server/api/trust/v1/v1_resolver.go index 500c2b311..01f7bb762 100644 --- a/pkg/server/api/trust/v1/v1_resolver.go +++ b/pkg/server/api/trust/v1/v1_resolver.go @@ -236,41 +236,6 @@ func (r *mutationResolver) RequestAllAccesses(ctx context.Context) (*types.Reque }, nil } -func (r *mutationResolver) checkNDASignature( - ctx context.Context, - trustCenter *coredata.TrustCenter, - identity *coredata.Identity, -) error { - if trustCenter.NonDisclosureAgreementFileID == nil { - return nil - } - - trustService := r.TrustService(ctx, trustCenter.ID.TenantID()) - - access, err := trustService.TrustCenterAccesses.GetAccess(ctx, trustCenter.ID, identity.EmailAddress) - if err != nil { - return gqlutils.Forbiddenf(ctx, "user has not signed the NDA") - } - - if access.ElectronicSignatureID == nil { - return nil - } - - sig, err := r.esign.GetSignatureByID(ctx, *access.ElectronicSignatureID) - if err != nil { - return gqlutils.Forbiddenf(ctx, "user has not signed the NDA") - } - - switch sig.Status { - case coredata.ElectronicSignatureStatusAccepted, - coredata.ElectronicSignatureStatusProcessing, - coredata.ElectronicSignatureStatusCompleted: - return nil - default: - return gqlutils.Forbiddenf(ctx, "user has not signed the NDA") - } -} - // ExportDocumentPDF is the resolver for the exportDocumentPDF field. func (r *mutationResolver) ExportDocumentPDF(ctx context.Context, input types.ExportDocumentPDFInput) (*types.ExportDocumentPDFPayload, error) { trustService := r.TrustService(ctx, input.DocumentID.TenantID())