Migrate audit reports to the files table

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
This commit is contained in:
Ludovic Vielle
2026-06-03 22:19:17 +02:00
parent b0a0f0efc9
commit 0e4d73bb0f
31 changed files with 517 additions and 947 deletions

View File

@@ -8,7 +8,6 @@ package console_v1
import (
"context"
"errors"
"time"
"github.com/vikstrous/dataloadgen"
"go.gearno.de/kit/log"
@@ -68,50 +67,30 @@ func (r *auditResolver) Framework(ctx context.Context, obj *types.Audit) (*types
return types.NewFramework(framework), nil
}
// Report is the resolver for the report field.
func (r *auditResolver) Report(ctx context.Context, obj *types.Audit) (*types.Report, error) {
// ReportFile is the resolver for the reportFile field.
func (r *auditResolver) ReportFile(ctx context.Context, obj *types.Audit) (*types.File, error) {
if _, err := r.authorize(ctx, obj.ID, probo.ActionReportGet); err != nil {
return nil, err
}
if obj.Report == nil {
if obj.ReportFile == nil {
return nil, nil
}
loaders := dataloader.FromContext(ctx)
report, err := loaders.Report.Load(ctx, obj.Report.ID)
file, err := loaders.File.Load(ctx, obj.ReportFile.ID)
if err != nil {
if errors.Is(err, dataloadgen.ErrNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot load report", log.Error(err))
r.logger.ErrorCtx(ctx, "cannot load report file", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewReport(report), nil
}
// ReportURL is the resolver for the reportUrl field.
func (r *auditResolver) ReportURL(ctx context.Context, obj *types.Audit) (*string, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionReportGetReportUrl)
if err != nil {
return nil, err
}
if obj.Report == nil {
return nil, nil
}
url, err := r.probo.Audits.GenerateReportURL(ctx, scope, obj.ID, 15*time.Minute)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot generate report URL", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return url, nil
return types.NewFile(file), nil
}
// Controls is the resolver for the controls field.
@@ -431,7 +410,7 @@ func (r *mutationResolver) CreateAudit(ctx context.Context, input types.CreateAu
},
}
audit, err = r.probo.Audits.UploadReport(ctx, scope, uploadReq)
audit, err = r.probo.Audits.UploadReport(ctx, scope, &uploadReq)
if err != nil {
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
@@ -514,7 +493,7 @@ func (r *mutationResolver) UploadAuditReport(ctx context.Context, input types.Up
},
}
audit, err := r.probo.Audits.UploadReport(ctx, scope, req)
audit, err := r.probo.Audits.UploadReport(ctx, scope, &req)
if err != nil {
if validationErrors, ok := errors.AsType[validator.ValidationErrors](err); ok {
return nil, gqlutils.InvalidValidationErrors(ctx, validationErrors)
@@ -704,43 +683,6 @@ func (r *mutationResolver) PublishFindingList(ctx context.Context, input types.P
}, nil
}
// DownloadURL is the resolver for the downloadUrl field.
func (r *reportResolver) DownloadURL(ctx context.Context, obj *types.Report) (*string, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionReportDownloadUrlGet)
if err != nil {
return nil, err
}
url, err := r.probo.Reports.GenerateDownloadURL(ctx, scope, obj.ID, 15*time.Minute)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot generate download URL", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return url, nil
}
// Audit is the resolver for the audit field.
func (r *reportResolver) Audit(ctx context.Context, obj *types.Report) (*types.Audit, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionAuditGet)
if err != nil {
return nil, err
}
audit, err := r.probo.Audits.GetByReportID(ctx, scope, obj.ID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot load audit for report", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewAudit(audit), nil
}
// Permission is the resolver for the permission field.
func (r *reportResolver) Permission(ctx context.Context, obj *types.Report, action string) (bool, error) {
return r.Resolver.Permission(ctx, obj, action)
}
// Audit returns schema.AuditResolver implementation.
func (r *Resolver) Audit() schema.AuditResolver { return &auditResolver{r} }
@@ -757,11 +699,7 @@ func (r *Resolver) FindingConnection() schema.FindingConnectionResolver {
return &findingConnectionResolver{r}
}
// Report returns schema.ReportResolver implementation.
func (r *Resolver) Report() schema.ReportResolver { return &reportResolver{r} }
type auditResolver struct{ *Resolver }
type auditConnectionResolver struct{ *Resolver }
type findingResolver struct{ *Resolver }
type findingConnectionResolver struct{ *Resolver }
type reportResolver struct{ *Resolver }

View File

@@ -279,16 +279,6 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
return types.NewObligation(obligation), nil
}
case coredata.ReportEntityType:
action = probo.ActionReportGet
loadNode = func(ctx context.Context, scope *coredata.Scope, id gid.GID) (types.Node, error) {
report, err := r.probo.Reports.Get(ctx, scope, id)
if err != nil {
return nil, err
}
return types.NewReport(report), nil
}
case coredata.ProcessingActivityEntityType:
action = probo.ActionProcessingActivityList
loadNode = func(ctx context.Context, scope *coredata.Scope, id gid.GID) (types.Node, error) {

View File

@@ -62,7 +62,6 @@ type (
Measure *dataloadgen.Loader[gid.GID, *coredata.Measure]
Task *dataloadgen.Loader[gid.GID, *coredata.Task]
File *dataloadgen.Loader[gid.GID, *coredata.File]
Report *dataloadgen.Loader[gid.GID, *coredata.Report]
CookieBanner *dataloadgen.Loader[gid.GID, *coredata.CookieBanner]
CookieCategory *dataloadgen.Loader[gid.GID, *coredata.CookieCategory]
CommonTrackerPattern *dataloadgen.Loader[gid.GID, *coredata.CommonTrackerPattern]
@@ -114,7 +113,6 @@ func (f *batchFetcher) newLoaders() *Loaders {
Measure: dataloadgen.NewMappedLoader(f.fetchMeasures),
Task: dataloadgen.NewMappedLoader(f.fetchTasks),
File: dataloadgen.NewMappedLoader(f.fetchFiles),
Report: dataloadgen.NewMappedLoader(f.fetchReports),
CookieBanner: dataloadgen.NewMappedLoader(f.fetchCookieBanners),
CookieCategory: dataloadgen.NewMappedLoader(f.fetchCookieCategories),
CommonTrackerPattern: dataloadgen.NewMappedLoader(f.fetchCommonTrackerPatterns),
@@ -286,22 +284,6 @@ func (f *batchFetcher) fetchFiles(ctx context.Context, keys []gid.GID) (map[gid.
return result, nil
}
func (f *batchFetcher) fetchReports(ctx context.Context, keys []gid.GID) (map[gid.GID]*coredata.Report, error) {
scope := coredata.NewScopeFromObjectID(keys[0])
reports, err := f.probo.Reports.GetByIDs(ctx, scope, keys...)
if err != nil {
return nil, fmt.Errorf("cannot batch load reports: %w", err)
}
result := make(map[gid.GID]*coredata.Report, len(reports))
for _, v := range reports {
result[v.ID] = v
}
return result, nil
}
func (f *batchFetcher) fetchCookieBanners(ctx context.Context, keys []gid.GID) (map[gid.GID]*coredata.CookieBanner, error) {
scope := coredata.NewScopeFromObjectID(keys[0])

View File

@@ -151,8 +151,7 @@ type Audit implements Node {
framework: Framework @goField(forceResolver: true)
validFrom: Datetime
validUntil: Datetime
report: Report @goField(forceResolver: true)
reportUrl: String @goField(forceResolver: true)
reportFile: File @goField(forceResolver: true)
state: AuditState!
controls(
@@ -208,20 +207,6 @@ type Finding implements Node {
permission(action: String!): Boolean! @goField(forceResolver: true)
}
type Report implements Node {
id: ID!
objectKey: String!
mimeType: String!
filename: String!
size: Int!
downloadUrl: String @goField(forceResolver: true)
createdAt: Datetime!
updatedAt: Datetime!
audit: Audit @goField(forceResolver: true)
permission(action: String!): Boolean! @goField(forceResolver: true)
}
type AuditConnection
@goModel(
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.AuditConnection"

View File

@@ -334,7 +334,8 @@ type TrustCenterDocumentAccess
id: ID!
status: TrustCenterDocumentAccessStatus!
document: Document @goField(forceResolver: true)
report: Report @goField(forceResolver: true)
reportFile: File @goField(forceResolver: true)
audit: Audit @goField(forceResolver: true)
trustCenterFile: TrustCenterFile @goField(forceResolver: true)
}

View File

@@ -1056,24 +1056,55 @@ func (r *trustCenterDocumentAccessResolver) Document(ctx context.Context, obj *t
return types.NewDocument(document), nil
}
// Report is the resolver for the report field.
func (r *trustCenterDocumentAccessResolver) Report(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Report, error) {
scope, err := r.authorize(ctx, obj.TrustCenterAccessID, probo.ActionReportGet)
// ReportFile is the resolver for the reportFile field.
func (r *trustCenterDocumentAccessResolver) ReportFile(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.File, error) {
if _, err := r.authorize(ctx, obj.ID, probo.ActionFileGet); err != nil {
return nil, err
}
if obj.ReportFile == nil {
return nil, nil
}
loaders := dataloader.FromContext(ctx)
file, err := loaders.File.Load(ctx, obj.ReportFile.ID)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) || errors.Is(err, dataloadgen.ErrNotFound) {
return nil, gqlutils.NotFound(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot load report file", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewFile(file), nil
}
// Audit is the resolver for the audit field.
func (r *trustCenterDocumentAccessResolver) Audit(ctx context.Context, obj *types.TrustCenterDocumentAccess) (*types.Audit, error) {
scope, err := r.authorize(ctx, obj.ID, probo.ActionAuditGet)
if err != nil {
return nil, err
}
if obj.ReportID == nil {
if obj.ReportFileID == nil {
return nil, nil
}
report, err := r.probo.Reports.Get(ctx, scope, *obj.ReportID)
audit, err := r.probo.Audits.GetByReportFileID(ctx, scope, *obj.ReportFileID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot load report", log.Error(err))
if errors.Is(err, coredata.ErrResourceNotFound) {
return nil, nil
}
r.logger.ErrorCtx(ctx, "cannot load audit for report file", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewReport(report), nil
return types.NewAudit(audit), nil
}
// TrustCenterFile is the resolver for the trustCenterFile field.

View File

@@ -77,9 +77,9 @@ func NewAudit(a *coredata.Audit) *Audit {
UpdatedAt: a.UpdatedAt,
}
if a.ReportID != nil {
node.Report = &Report{
ID: *a.ReportID,
if a.ReportFileID != nil {
node.ReportFile = &File{
ID: *a.ReportFileID,
}
}

View File

@@ -1,31 +0,0 @@
// Copyright (c) 2025-2026 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package types
import (
"go.probo.inc/probo/pkg/coredata"
)
func NewReport(r *coredata.Report) *Report {
return &Report{
ID: r.ID,
ObjectKey: r.ObjectKey,
MimeType: r.MimeType,
Filename: r.Filename,
Size: int(r.Size),
CreatedAt: r.CreatedAt,
UpdatedAt: r.UpdatedAt,
}
}

View File

@@ -42,13 +42,13 @@ type (
UpdatedAt time.Time `json:"updatedAt"`
TrustCenterAccess *TrustCenterAccess `json:"trustCenterAccess"`
Document *Document `json:"document,omitempty"`
Report *Report `json:"report,omitempty"`
ReportFile *File `json:"reportFile,omitempty"`
TrustCenterFile *TrustCenterFile `json:"trustCenterFile,omitempty"`
// Internal fields used by resolvers
TrustCenterAccessID gid.GID `json:"-"`
DocumentID *gid.GID `json:"-"`
ReportID *gid.GID `json:"-"`
ReportFileID *gid.GID `json:"-"`
TrustCenterFileID *gid.GID `json:"-"`
}
)
@@ -62,7 +62,7 @@ func NewTrustCenterDocumentAccess(tcda *coredata.TrustCenterDocumentAccess) *Tru
UpdatedAt: tcda.UpdatedAt,
TrustCenterAccessID: tcda.TrustCenterAccessID,
DocumentID: tcda.DocumentID,
ReportID: tcda.ReportID,
ReportFileID: tcda.ReportFileID,
TrustCenterFileID: tcda.TrustCenterFileID,
}
@@ -72,9 +72,9 @@ func NewTrustCenterDocumentAccess(tcda *coredata.TrustCenterDocumentAccess) *Tru
}
}
if tcda.ReportID != nil {
object.Report = &Report{
ID: *tcda.ReportID,
if tcda.ReportFileID != nil {
object.ReportFile = &File{
ID: *tcda.ReportFileID,
}
}

View File

@@ -1468,16 +1468,16 @@ func (r *Resolver) GetAuditTool(ctx context.Context, req *mcp.CallToolRequest, i
return nil, types.GetAuditOutput{}, fmt.Errorf("cannot get audit: %w", err)
}
var report *coredata.Report
if audit.ReportID != nil {
report, err = prb.Reports.Get(ctx, scope, *audit.ReportID)
var file *coredata.File
if audit.ReportFileID != nil {
file, err = prb.Files.Get(ctx, scope, *audit.ReportFileID)
if err != nil {
return nil, types.GetAuditOutput{}, fmt.Errorf("cannot get audit report: %w", err)
return nil, types.GetAuditOutput{}, fmt.Errorf("cannot get audit report file: %w", err)
}
}
return nil, types.GetAuditOutput{
Audit: types.NewAudit(audit, report),
Audit: types.NewAudit(audit, file),
}, nil
}
@@ -1532,16 +1532,16 @@ func (r *Resolver) UpdateAuditTool(ctx context.Context, req *mcp.CallToolRequest
return nil, types.UpdateAuditOutput{}, fmt.Errorf("cannot update audit: %w", err)
}
var report *coredata.Report
if audit.ReportID != nil {
report, err = svc.Reports.Get(ctx, scope, *audit.ReportID)
var file *coredata.File
if audit.ReportFileID != nil {
file, err = svc.Files.Get(ctx, scope, *audit.ReportFileID)
if err != nil {
return nil, types.UpdateAuditOutput{}, fmt.Errorf("cannot get audit report: %w", err)
return nil, types.UpdateAuditOutput{}, fmt.Errorf("cannot get audit report file: %w", err)
}
}
return nil, types.UpdateAuditOutput{
Audit: types.NewAudit(audit, report),
Audit: types.NewAudit(audit, file),
}, nil
}

View File

@@ -19,7 +19,7 @@ import (
"go.probo.inc/probo/pkg/page"
)
func NewAudit(a *coredata.Audit, report *coredata.Report) *Audit {
func NewAudit(a *coredata.Audit, file *coredata.File) *Audit {
audit := &Audit{
ID: a.ID,
Name: a.Name,
@@ -27,16 +27,16 @@ func NewAudit(a *coredata.Audit, report *coredata.Report) *Audit {
FrameworkID: a.FrameworkID,
State: a.State,
TrustCenterVisibility: a.TrustCenterVisibility,
HasReport: a.ReportID != nil,
HasReport: a.ReportFileID != nil,
ValidFrom: a.ValidFrom,
ValidUntil: a.ValidUntil,
CreatedAt: a.CreatedAt,
UpdatedAt: a.UpdatedAt,
}
if report != nil {
audit.ReportFilename = &report.Filename
audit.ReportMimeType = &report.MimeType
if file != nil {
audit.ReportFilename = &file.FileName
audit.ReportMimeType = &file.MimeType
}
return audit

View File

@@ -227,7 +227,7 @@ func SlackHandler(slackSvc *slack.Service, slackSigningSecret string, logger *lo
switch gID.EntityType() {
case coredata.DocumentEntityType:
documentIDs = []gid.GID{gID}
case coredata.ReportEntityType:
case coredata.FileEntityType:
reportIDs = []gid.GID{gID}
case coredata.TrustCenterFileEntityType:
fileIDs = []gid.GID{gID}

View File

@@ -83,21 +83,21 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
return types.NewFramework(framework), nil
case coredata.ReportEntityType:
case coredata.FileEntityType:
trustCenter := compliancepage.CompliancePageFromContext(ctx)
report, err := trustService.Reports.Get(ctx, scope, trustCenter.OrganizationID, id)
file, err := trustService.Reports.Get(ctx, scope, trustCenter.OrganizationID, id)
if err != nil {
if errors.Is(err, trust.ErrReportNotFound) || errors.Is(err, coredata.ErrResourceNotFound) {
return nil, gqlutils.NotFoundf(ctx, "node %q not found", id)
}
r.logger.ErrorCtx(ctx, "cannot get report", log.Error(err))
r.logger.ErrorCtx(ctx, "cannot get audit report file", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewReport(report), nil
return types.NewAuditReport(file), nil
case coredata.AuditEntityType:
audit, err := trustService.Audits.Get(ctx, scope, id)

View File

@@ -114,9 +114,9 @@ type Framework implements Node @nda {
darkLogoURL: String @goField(forceResolver: true)
}
type Report implements Node @nda {
type AuditReport implements Node @nda {
id: ID!
filename: String!
fileName: String!
isUserAuthorized: Boolean! @goField(forceResolver: true)
access: DocumentAccess @goField(forceResolver: true)
}
@@ -125,7 +125,7 @@ type Audit implements Node @nda {
id: ID!
name: String
framework: Framework! @goField(forceResolver: true)
report: Report @goField(forceResolver: true)
reportFile: AuditReport @goField(forceResolver: true)
}
type AuditConnection @nda {

View File

@@ -44,8 +44,8 @@ func (r *auditResolver) Framework(ctx context.Context, obj *types.Audit) (*types
return types.NewFramework(framework), nil
}
// Report is the resolver for the report field.
func (r *auditResolver) Report(ctx context.Context, obj *types.Audit) (*types.Report, error) {
// ReportFile is the resolver for the reportFile field.
func (r *auditResolver) ReportFile(ctx context.Context, obj *types.Audit) (*types.AuditReport, error) {
scope := coredata.NewScopeFromObjectID(obj.ID)
trustService := r.trust
@@ -55,19 +55,105 @@ func (r *auditResolver) Report(ctx context.Context, obj *types.Audit) (*types.Re
return nil, gqlutils.Internal(ctx)
}
if audit.ReportID == nil {
if audit.ReportFileID == nil {
return nil, nil
}
trustCenter := compliancepage.CompliancePageFromContext(ctx)
report, err := trustService.Reports.Get(ctx, scope, trustCenter.OrganizationID, *audit.ReportID)
file, err := trustService.Reports.Get(ctx, scope, trustCenter.OrganizationID, *audit.ReportFileID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot load report", log.Error(err))
r.logger.ErrorCtx(ctx, "cannot load report file", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return types.NewReport(report), nil
return types.NewAuditReport(file), nil
}
// IsUserAuthorized is the resolver for the isUserAuthorized field.
func (r *auditReportResolver) IsUserAuthorized(ctx context.Context, obj *types.AuditReport) (bool, error) {
scope := coredata.NewScopeFromObjectID(obj.ID)
trustService := r.trust
trustCenter := compliancepage.CompliancePageFromContext(ctx)
audit, err := trustService.Audits.GetByReportFileID(ctx, scope, obj.ID)
if err != nil {
if errors.Is(err, coredata.ErrResourceNotFound) {
return false, nil
}
r.logger.ErrorCtx(ctx, "cannot load audit for report file", log.Error(err))
return false, gqlutils.Internal(ctx)
}
if audit.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
return true, nil
}
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return false, nil
}
reportAccess, err := trustService.TrustCenterAccesses.GetReportFileAccess(ctx, scope,
trustCenter.ID,
identity.ID,
obj.ID,
)
if err != nil {
if errors.Is(err, trust.ErrMembershipNotFound) ||
errors.Is(err, trust.ErrUserNotFound) ||
errors.Is(err, trust.ErrUserInactive) ||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
return false, nil
}
r.logger.ErrorCtx(ctx, "cannot check report access", log.Error(err))
return false, gqlutils.Internal(ctx)
}
return reportAccess.Status == coredata.TrustCenterDocumentAccessStatusGranted, nil
}
// Access is the resolver for the access field.
func (r *auditReportResolver) Access(ctx context.Context, obj *types.AuditReport) (*types.DocumentAccess, error) {
scope := coredata.NewScopeFromObjectID(obj.ID)
trustService := r.trust
trustCenter := compliancepage.CompliancePageFromContext(ctx)
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, nil
}
access, err := trustService.TrustCenterAccesses.GetReportFileAccess(
ctx, scope,
trustCenter.ID,
identity.ID,
obj.ID,
)
if err != nil {
if errors.Is(err, trust.ErrMembershipNotFound) ||
errors.Is(err, trust.ErrUserNotFound) ||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
return nil, nil
}
if errors.Is(err, trust.ErrUserInactive) {
return nil, gqlutils.Forbidden(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot get audit report access", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.DocumentAccess{
ID: access.ID,
Status: access.Status,
}, nil
}
// Framework is the resolver for the framework field on ComplianceFramework.
@@ -294,7 +380,7 @@ func (r *mutationResolver) ExportReportPDF(ctx context.Context, input types.Expo
trustService := r.trust
trustCenter := compliancepage.CompliancePageFromContext(ctx)
audit, err := trustService.Audits.GetByReportID(ctx, scope, input.ReportID)
audit, err := trustService.Audits.GetByReportFileID(ctx, scope, input.ReportID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot load audit", log.Error(err))
return nil, gqlutils.Internal(ctx)
@@ -317,7 +403,7 @@ func (r *mutationResolver) ExportReportPDF(ctx context.Context, input types.Expo
return nil, gqlutils.Unauthenticatedf(ctx, "unauthenticated")
}
reportAccess, err := trustService.TrustCenterAccesses.GetReportAccess(
reportAccess, err := trustService.TrustCenterAccesses.GetReportFileAccess(
ctx, scope,
trustCenter.ID,
identity.ID,
@@ -458,7 +544,7 @@ func (r *mutationResolver) RequestReportAccess(ctx context.Context, input types.
scope := coredata.NewScopeFromObjectID(trustCenter.ID)
trustService := r.trust
audit, err := trustService.Audits.GetByReportID(ctx, scope, input.ReportID)
audit, err := trustService.Audits.GetByReportFileID(ctx, scope, input.ReportID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot load audit", log.Error(err))
return nil, gqlutils.Internal(ctx)
@@ -543,87 +629,6 @@ func (r *mutationResolver) RequestTrustCenterFileAccess(ctx context.Context, inp
}, nil
}
// IsUserAuthorized is the resolver for the isUserAuthorized field.
func (r *reportResolver) IsUserAuthorized(ctx context.Context, obj *types.Report) (bool, error) {
scope := coredata.NewScopeFromObjectID(obj.ID)
trustService := r.trust
trustCenter := compliancepage.CompliancePageFromContext(ctx)
audit, err := trustService.Audits.GetByReportID(ctx, scope, obj.ID)
if err != nil {
r.logger.ErrorCtx(ctx, "cannot load document", log.Error(err))
return false, gqlutils.Internal(ctx)
}
if audit.TrustCenterVisibility == coredata.TrustCenterVisibilityPublic {
return true, nil
}
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return false, nil
}
reportAccess, err := trustService.TrustCenterAccesses.GetReportAccess(ctx, scope,
trustCenter.ID,
identity.ID,
obj.ID,
)
if err != nil {
if errors.Is(err, trust.ErrMembershipNotFound) ||
errors.Is(err, trust.ErrUserNotFound) ||
errors.Is(err, trust.ErrUserInactive) ||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
return false, nil
}
r.logger.ErrorCtx(ctx, "cannot check report access", log.Error(err))
return false, gqlutils.Internal(ctx)
}
return reportAccess.Status == coredata.TrustCenterDocumentAccessStatusGranted, nil
}
// Access is the resolver for the access field.
func (r *reportResolver) Access(ctx context.Context, obj *types.Report) (*types.DocumentAccess, error) {
scope := coredata.NewScopeFromObjectID(obj.ID)
trustService := r.trust
trustCenter := compliancepage.CompliancePageFromContext(ctx)
identity := authn.IdentityFromContext(ctx)
if identity == nil {
return nil, nil // User is not authenticated, so no access requested
}
access, err := trustService.TrustCenterAccesses.GetReportAccess(
ctx, scope,
trustCenter.ID,
identity.ID,
obj.ID,
)
if err != nil {
if errors.Is(err, trust.ErrMembershipNotFound) ||
errors.Is(err, trust.ErrUserNotFound) ||
errors.Is(err, trust.ErrDocumentAccessNotFound) {
return nil, nil
}
if errors.Is(err, trust.ErrUserInactive) {
return nil, gqlutils.Forbidden(ctx, err)
}
r.logger.ErrorCtx(ctx, "cannot get audit report access", log.Error(err))
return nil, gqlutils.Internal(ctx)
}
return &types.DocumentAccess{
ID: access.ID,
Status: access.Status,
}, nil
}
// TotalCount is the resolver for the totalCount field.
func (r *subprocessorConnectionResolver) TotalCount(ctx context.Context, obj *types.SubprocessorConnection) (int, error) {
scope := coredata.NewScopeFromObjectID(obj.ParentID)
@@ -987,6 +992,9 @@ func (r *trustCenterReferenceResolver) LogoURL(ctx context.Context, obj *types.T
// Audit returns schema.AuditResolver implementation.
func (r *Resolver) Audit() schema.AuditResolver { return &auditResolver{r} }
// AuditReport returns schema.AuditReportResolver implementation.
func (r *Resolver) AuditReport() schema.AuditReportResolver { return &auditReportResolver{r} }
// ComplianceFramework returns schema.ComplianceFrameworkResolver implementation.
func (r *Resolver) ComplianceFramework() schema.ComplianceFrameworkResolver {
return &complianceFrameworkResolver{r}
@@ -998,9 +1006,6 @@ func (r *Resolver) Document() schema.DocumentResolver { return &documentResolver
// Framework returns schema.FrameworkResolver implementation.
func (r *Resolver) Framework() schema.FrameworkResolver { return &frameworkResolver{r} }
// Report returns schema.ReportResolver implementation.
func (r *Resolver) Report() schema.ReportResolver { return &reportResolver{r} }
// SubprocessorConnection returns schema.SubprocessorConnectionResolver implementation.
func (r *Resolver) SubprocessorConnection() schema.SubprocessorConnectionResolver {
return &subprocessorConnectionResolver{r}
@@ -1020,10 +1025,10 @@ func (r *Resolver) TrustCenterReference() schema.TrustCenterReferenceResolver {
}
type auditResolver struct{ *Resolver }
type auditReportResolver struct{ *Resolver }
type complianceFrameworkResolver struct{ *Resolver }
type documentResolver struct{ *Resolver }
type frameworkResolver struct{ *Resolver }
type reportResolver struct{ *Resolver }
type subprocessorConnectionResolver struct{ *Resolver }
type trustCenterResolver struct{ *Resolver }
type trustCenterFileResolver struct{ *Resolver }

View File

@@ -18,9 +18,9 @@ import (
"go.probo.inc/probo/pkg/coredata"
)
func NewReport(r *coredata.Report) *Report {
return &Report{
ID: r.ID,
Filename: r.Filename,
func NewAuditReport(f *coredata.File) *AuditReport {
return &AuditReport{
ID: f.ID,
FileName: f.FileName,
}
}