Add missing s3 metadata

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2025-10-02 19:41:09 +02:00
parent eb185c5218
commit e2f3cd1a8d
11 changed files with 274 additions and 225 deletions

View File

@@ -19,9 +19,12 @@ import (
"fmt"
"time"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/page"
"go.gearno.de/crypto/uuid"
"go.gearno.de/kit/pg"
)
@@ -283,9 +286,41 @@ func (s AuditService) UploadReport(
return fmt.Errorf("cannot load audit: %w", err)
}
report, err := s.svc.Reports.Create(ctx, req.File)
reportID := gid.New(s.svc.scope.GetTenantID(), coredata.ReportEntityType)
now := time.Now()
objectKey, err := uuid.NewV7()
if err != nil {
return fmt.Errorf("cannot create report: %w", err)
return fmt.Errorf("cannot generate object key: %w", err)
}
_, err = s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
Body: req.File.Content,
ContentType: aws.String(req.File.ContentType),
Metadata: map[string]string{
"type": "report",
"report-id": reportID.String(),
"organization-id": audit.OrganizationID.String(),
},
})
if err != nil {
return fmt.Errorf("cannot upload report to S3: %w", err)
}
report := &coredata.Report{
ID: reportID,
ObjectKey: objectKey.String(),
MimeType: req.File.ContentType,
Filename: req.File.Filename,
Size: req.File.Size,
CreatedAt: now,
UpdatedAt: now,
}
if err := report.Insert(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert report: %w", err)
}
audit.ReportID = &report.ID

View File

@@ -1226,6 +1226,17 @@ func (s *DocumentService) BuildAndUploadExport(ctx context.Context, exportJobID
return fmt.Errorf("cannot get document IDs: %w", err)
}
if len(documentIDs) == 0 {
return fmt.Errorf("no document IDs found")
}
var organizationID gid.GID
firstDocument := &coredata.Document{}
if err := firstDocument.LoadByID(ctx, tx, s.svc.scope, documentIDs[0]); err != nil {
return fmt.Errorf("cannot load document for organization ID: %w", err)
}
organizationID = firstDocument.OrganizationID
tempDir := os.TempDir()
tempFile, err := os.CreateTemp(tempDir, "probo-document-export-*.zip")
if err != nil {
@@ -1273,8 +1284,9 @@ func (s *DocumentService) BuildAndUploadExport(ctx context.Context, exportJobID
ContentLength: ref.Ref(fileInfo.Size()),
ContentType: ref.Ref("application/zip"),
Metadata: map[string]string{
"type": "document-export",
"export-job-id": exportJob.ID.String(),
"type": "document-export",
"export-job-id": exportJob.ID.String(),
"organization-id": organizationID.String(),
},
},
)

View File

@@ -155,6 +155,11 @@ func (s EvidenceService) Fulfill(
return fmt.Errorf("cannot load evidence: %w", err)
}
measure := &coredata.Measure{}
if err := measure.LoadByID(ctx, conn, s.svc.scope, evidence.MeasureID); err != nil {
return fmt.Errorf("cannot load measure: %w", err)
}
evidence.State = coredata.EvidenceStateFulfilled
if req.File != nil {
@@ -206,6 +211,11 @@ func (s EvidenceService) Fulfill(
Key: aws.String(objectKey.String()),
Body: fileContent,
ContentType: aws.String(contentType),
Metadata: map[string]string{
"type": "evidence",
"evidence-id": req.EvidenceID.String(),
"organization-id": measure.OrganizationID.String(),
},
})
if err != nil {
return fmt.Errorf("cannot upload file to S3: %w", err)
@@ -271,27 +281,7 @@ func (s EvidenceService) UploadTaskEvidence(
return nil, err
}
objectKey, err := uuid.NewV7()
if err != nil {
return nil, fmt.Errorf("cannot generate object key: %w", err)
}
_, err = s.svc.s3.PutObject(
ctx,
&s3.PutObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
Body: req.File.Content,
ContentType: aws.String(req.File.ContentType),
},
)
if err != nil {
return nil, fmt.Errorf("cannot upload file to S3: %w", err)
}
evidence.ObjectKey = objectKey.String()
evidence.MimeType = req.File.ContentType
evidence.Size = uint64(req.File.Size)
var measureOrganizationID gid.GID
err = s.svc.pg.WithTx(
ctx,
@@ -306,6 +296,38 @@ func (s EvidenceService) UploadTaskEvidence(
return fmt.Errorf("task %q has no measure", req.TaskID)
}
measure := &coredata.Measure{}
if err := measure.LoadByID(ctx, conn, s.svc.scope, *task.MeasureID); err != nil {
return fmt.Errorf("cannot load measure: %w", err)
}
measureOrganizationID = measure.OrganizationID
objectKey, err := uuid.NewV7()
if err != nil {
return fmt.Errorf("cannot generate object key: %w", err)
}
_, err = s.svc.s3.PutObject(
ctx,
&s3.PutObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
Body: req.File.Content,
ContentType: aws.String(req.File.ContentType),
Metadata: map[string]string{
"type": "evidence",
"evidence-id": evidenceID.String(),
"organization-id": measureOrganizationID.String(),
},
},
)
if err != nil {
return fmt.Errorf("cannot upload file to S3: %w", err)
}
evidence.ObjectKey = objectKey.String()
evidence.MimeType = req.File.ContentType
evidence.Size = uint64(req.File.Size)
evidence.MeasureID = *task.MeasureID
if err := evidence.Insert(ctx, conn, s.svc.scope); err != nil {
@@ -355,37 +377,40 @@ func (s EvidenceService) UploadMeasureEvidence(
return nil, err
}
objectKey, err := uuid.NewV7()
if err != nil {
return nil, fmt.Errorf("cannot generate object key: %w", err)
}
_, err = s.svc.s3.PutObject(
ctx,
&s3.PutObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
Body: req.File.Content,
ContentType: aws.String(req.File.ContentType),
},
)
if err != nil {
return nil, fmt.Errorf("cannot upload file to S3: %w", err)
}
evidence.ObjectKey = objectKey.String()
evidence.MimeType = req.File.ContentType
evidence.Size = uint64(req.File.Size)
err = s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
measure := &coredata.Measure{}
if err := measure.LoadByID(ctx, conn, s.svc.scope, req.MeasureID); err != nil {
return fmt.Errorf("cannot load measure %q: %w", req.MeasureID, err)
}
objectKey, err := uuid.NewV7()
if err != nil {
return fmt.Errorf("cannot generate object key: %w", err)
}
_, err = s.svc.s3.PutObject(
ctx,
&s3.PutObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
Body: req.File.Content,
ContentType: aws.String(req.File.ContentType),
Metadata: map[string]string{
"type": "evidence",
"evidence-id": evidenceID.String(),
"organization-id": measure.OrganizationID.String(),
},
},
)
if err != nil {
return fmt.Errorf("cannot upload file to S3: %w", err)
}
evidence.ObjectKey = objectKey.String()
evidence.MimeType = req.File.ContentType
evidence.Size = uint64(req.File.Size)
evidence.MeasureID = req.MeasureID
if err := evidence.Insert(ctx, conn, s.svc.scope); err != nil {

View File

@@ -807,8 +807,9 @@ func (s *FrameworkService) BuildAndUploadExport(ctx context.Context, exportJobID
ContentLength: ref.Ref(fileInfo.Size()),
ContentType: ref.Ref("application/zip"),
Metadata: map[string]string{
"type": "framework-export",
"export-job-id": exportJob.ID.String(),
"type": "framework-export",
"export-job-id": exportJob.ID.String(),
"organization-id": framework.OrganizationID.String(),
},
},
)

View File

@@ -248,6 +248,10 @@ func (s OrganizationService) Update(
Key: aws.String(objectKey.String()),
Body: fileContent,
ContentType: aws.String(contentType),
Metadata: map[string]string{
"type": "organization-logo",
"organization-id": organization.ID.String(),
},
})
if err != nil {

View File

@@ -23,7 +23,6 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/gid"
"go.gearno.de/crypto/uuid"
"go.gearno.de/kit/pg"
)
@@ -56,57 +55,6 @@ func (s ReportService) Get(
return report, nil
}
func (s ReportService) Create(
ctx context.Context,
file File,
) (*coredata.Report, error) {
reportID := gid.New(s.svc.scope.GetTenantID(), coredata.ReportEntityType)
now := time.Now()
objectKey, err := uuid.NewV7()
if err != nil {
return nil, fmt.Errorf("cannot generate object key: %w", err)
}
_, err = s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
Body: file.Content,
ContentType: aws.String(file.ContentType),
Metadata: map[string]string{
"report-id": reportID.String(),
},
})
if err != nil {
return nil, fmt.Errorf("cannot upload report to S3: %w", err)
}
report := &coredata.Report{
ID: reportID,
ObjectKey: objectKey.String(),
MimeType: file.ContentType,
Filename: file.Filename,
Size: file.Size,
CreatedAt: now,
UpdatedAt: now,
}
err = s.svc.pg.WithConn(ctx, func(conn pg.Conn) error {
err := report.Insert(ctx, conn, s.svc.scope)
if err != nil {
return fmt.Errorf("cannot insert report: %w", err)
}
return nil
})
if err != nil {
return nil, err
}
return report, nil
}
func (s ReportService) Delete(
ctx context.Context,
reportID gid.GID,

View File

@@ -148,7 +148,7 @@ func (s TrustCenterReferenceService) Create(
var logoKey string
err := s.svc.pg.WithTx(ctx, func(tx pg.Conn) error {
fileID, s3Key, err := s.uploadLogoFile(ctx, tx, req.LogoFile, referenceID, now)
fileID, s3Key, err := s.uploadLogoFile(ctx, tx, req.LogoFile, referenceID, req.TrustCenterID, now)
if err != nil {
return fmt.Errorf("cannot upload logo file: %w", err)
}
@@ -200,8 +200,14 @@ func (s TrustCenterReferenceService) Update(
var logoKey string
err := s.svc.pg.WithTx(ctx, func(tx pg.Conn) error {
reference = &coredata.TrustCenterReference{}
if err := reference.LoadByID(ctx, tx, s.svc.scope, req.ID); err != nil {
return fmt.Errorf("cannot load trust center reference: %w", err)
}
if req.LogoFile != nil {
fileID, s3Key, err := s.uploadLogoFile(ctx, tx, *req.LogoFile, req.ID, now)
fileID, s3Key, err := s.uploadLogoFile(ctx, tx, *req.LogoFile, req.ID, reference.TrustCenterID, now)
if err != nil {
return fmt.Errorf("cannot upload logo file: %w", err)
}
@@ -209,12 +215,6 @@ func (s TrustCenterReferenceService) Update(
logoKey = s3Key
}
reference = &coredata.TrustCenterReference{}
if err := reference.LoadByID(ctx, tx, s.svc.scope, req.ID); err != nil {
return fmt.Errorf("cannot load trust center reference: %w", err)
}
if req.Name != nil {
reference.Name = *req.Name
}
@@ -316,6 +316,7 @@ func (s TrustCenterReferenceService) uploadLogoFile(
tx pg.Conn,
file File,
referenceID gid.GID,
trustCenterID gid.GID,
now time.Time,
) (gid.GID, string, error) {
fileID := gid.New(s.svc.scope.GetTenantID(), coredata.FileEntityType)
@@ -325,6 +326,11 @@ func (s TrustCenterReferenceService) uploadLogoFile(
return gid.GID{}, "", fmt.Errorf("cannot generate object key: %w", err)
}
trustCenter := &coredata.TrustCenter{}
if err := trustCenter.LoadByID(ctx, tx, s.svc.scope, trustCenterID); err != nil {
return gid.GID{}, "", fmt.Errorf("cannot load trust center: %w", err)
}
var fileSize int64
var fileContent io.ReadSeeker
filename := file.Filename
@@ -372,6 +378,7 @@ func (s TrustCenterReferenceService) uploadLogoFile(
Metadata: map[string]string{
"type": "trust-center-reference-logo",
"trust-center-reference-id": referenceID.String(),
"organization-id": trustCenter.OrganizationID.String(),
},
})
if err != nil {

View File

@@ -175,34 +175,6 @@ func (s TrustCenterService) UploadNDA(
return nil, nil, fmt.Errorf("cannot generate object key: %w", err)
}
mimeType := mime.TypeByExtension(filepath.Ext(req.FileName))
_, err = s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: &s.svc.bucket,
Key: aws.String(objectKey.String()),
Body: req.File,
ContentType: &mimeType,
Metadata: map[string]string{
"type": "trust-center-nda",
"trust-center-id": req.TrustCenterID.String(),
},
})
if err != nil {
return nil, nil, fmt.Errorf("cannot upload file to S3: %w", err)
}
headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
})
if err != nil {
return nil, nil, fmt.Errorf("cannot get object metadata: %w", err)
}
now := time.Now()
fileID := gid.New(s.svc.scope.GetTenantID(), coredata.FileEntityType)
var trustCenter *coredata.TrustCenter
var file *coredata.File
@@ -214,6 +186,34 @@ func (s TrustCenterService) UploadNDA(
return fmt.Errorf("cannot load trust center: %w", err)
}
mimeType := mime.TypeByExtension(filepath.Ext(req.FileName))
_, err := s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: &s.svc.bucket,
Key: aws.String(objectKey.String()),
Body: req.File,
ContentType: &mimeType,
Metadata: map[string]string{
"type": "trust-center-nda",
"trust-center-id": req.TrustCenterID.String(),
"organization-id": trustCenter.OrganizationID.String(),
},
})
if err != nil {
return fmt.Errorf("cannot upload file to S3: %w", err)
}
headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
})
if err != nil {
return fmt.Errorf("cannot get object metadata: %w", err)
}
now := time.Now()
fileID := gid.New(s.svc.scope.GetTenantID(), coredata.FileEntityType)
file = &coredata.File{
ID: fileID,
BucketName: s.svc.bucket,

View File

@@ -90,31 +90,6 @@ func (s VendorBusinessAssociateAgreementService) Upload(
return nil, nil, fmt.Errorf("cannot generate object key: %w", err)
}
mimeType := mime.TypeByExtension(filepath.Ext(req.FileName))
_, err = s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: &s.svc.bucket,
Key: aws.String(objectKey.String()),
Body: req.File,
ContentType: &mimeType,
})
if err != nil {
return nil, nil, fmt.Errorf("cannot upload file to S3: %w", err)
}
headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
})
if err != nil {
return nil, nil, fmt.Errorf("cannot get object metadata: %w", err)
}
now := time.Now()
fileID := gid.New(s.svc.scope.GetTenantID(), coredata.FileEntityType)
vendorBusinessAssociateAgreementID := gid.New(s.svc.scope.GetTenantID(), coredata.VendorBusinessAssociateAgreementEntityType)
var vendorBusinessAssociateAgreement *coredata.VendorBusinessAssociateAgreement
var file *coredata.File
@@ -126,6 +101,35 @@ func (s VendorBusinessAssociateAgreementService) Upload(
return fmt.Errorf("cannot load vendor: %w", err)
}
mimeType := mime.TypeByExtension(filepath.Ext(req.FileName))
_, err := s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: &s.svc.bucket,
Key: aws.String(objectKey.String()),
Body: req.File,
ContentType: &mimeType,
Metadata: map[string]string{
"type": "vendor-business-associate-agreement",
"vendor-id": vendorID.String(),
"organization-id": vendor.OrganizationID.String(),
},
})
if err != nil {
return fmt.Errorf("cannot upload file to S3: %w", err)
}
headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
})
if err != nil {
return fmt.Errorf("cannot get object metadata: %w", err)
}
now := time.Now()
fileID := gid.New(s.svc.scope.GetTenantID(), coredata.FileEntityType)
vendorBusinessAssociateAgreementID := gid.New(s.svc.scope.GetTenantID(), coredata.VendorBusinessAssociateAgreementEntityType)
file = &coredata.File{
ID: fileID,
BucketName: s.svc.bucket,

View File

@@ -76,45 +76,56 @@ func (s VendorComplianceReportService) Upload(
return nil, fmt.Errorf("cannot generate object key: %w", err)
}
mimeType := mime.TypeByExtension(filepath.Ext(req.ReportName))
var vendorComplianceReport *coredata.VendorComplianceReport
_, err = s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: &s.svc.bucket,
Key: aws.String(objectKey.String()),
Body: req.File,
ContentType: &mimeType,
})
if err != nil {
return nil, fmt.Errorf("cannot upload file to S3: %w", err)
}
headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
})
if err != nil {
return nil, fmt.Errorf("cannot get object metadata: %w", err)
}
now := time.Now()
vendorComplianceReportID := gid.New(s.svc.scope.GetTenantID(), coredata.VendorComplianceReportEntityType)
vendorComplianceReport := &coredata.VendorComplianceReport{
ID: vendorComplianceReportID,
VendorID: vendorID,
ReportDate: req.ReportDate,
ValidUntil: req.ValidUntil,
ReportName: req.ReportName,
FileKey: objectKey.String(),
FileSize: *headOutput.ContentLength,
CreatedAt: now,
UpdatedAt: now,
}
err = s.svc.pg.WithConn(
err = s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
vendor := &coredata.Vendor{}
if err := vendor.LoadByID(ctx, conn, s.svc.scope, vendorID); err != nil {
return fmt.Errorf("cannot load vendor: %w", err)
}
mimeType := mime.TypeByExtension(filepath.Ext(req.ReportName))
_, err := s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: &s.svc.bucket,
Key: aws.String(objectKey.String()),
Body: req.File,
ContentType: &mimeType,
Metadata: map[string]string{
"type": "vendor-compliance-report",
"vendor-id": vendorID.String(),
"organization-id": vendor.OrganizationID.String(),
},
})
if err != nil {
return fmt.Errorf("cannot upload file to S3: %w", err)
}
headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
})
if err != nil {
return fmt.Errorf("cannot get object metadata: %w", err)
}
now := time.Now()
vendorComplianceReportID := gid.New(s.svc.scope.GetTenantID(), coredata.VendorComplianceReportEntityType)
vendorComplianceReport = &coredata.VendorComplianceReport{
ID: vendorComplianceReportID,
VendorID: vendorID,
ReportDate: req.ReportDate,
ValidUntil: req.ValidUntil,
ReportName: req.ReportName,
FileKey: objectKey.String(),
FileSize: *headOutput.ContentLength,
CreatedAt: now,
UpdatedAt: now,
}
return vendorComplianceReport.Insert(ctx, conn, s.svc.scope)
},
)

View File

@@ -90,42 +90,44 @@ func (s VendorDataPrivacyAgreementService) Upload(
return nil, nil, fmt.Errorf("cannot generate object key: %w", err)
}
mimeType := mime.TypeByExtension(filepath.Ext(req.FileName))
_, err = s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: &s.svc.bucket,
Key: aws.String(objectKey.String()),
Body: req.File,
ContentType: &mimeType,
})
if err != nil {
return nil, nil, fmt.Errorf("cannot upload file to S3: %w", err)
}
headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
})
if err != nil {
return nil, nil, fmt.Errorf("cannot get object metadata: %w", err)
}
now := time.Now()
fileID := gid.New(s.svc.scope.GetTenantID(), coredata.FileEntityType)
vendorDataPrivacyAgreementID := gid.New(s.svc.scope.GetTenantID(), coredata.VendorDataPrivacyAgreementEntityType)
var vendorDataPrivacyAgreement *coredata.VendorDataPrivacyAgreement
var file *coredata.File
var vendor *coredata.Vendor
err = s.svc.pg.WithTx(
ctx,
func(conn pg.Conn) error {
vendor := &coredata.Vendor{}
vendor = &coredata.Vendor{}
if err := vendor.LoadByID(ctx, conn, s.svc.scope, vendorID); err != nil {
return fmt.Errorf("cannot load vendor: %w", err)
}
mimeType := mime.TypeByExtension(filepath.Ext(req.FileName))
_, err := s.svc.s3.PutObject(ctx, &s3.PutObjectInput{
Bucket: &s.svc.bucket,
Key: aws.String(objectKey.String()),
Body: req.File,
ContentType: &mimeType,
Metadata: map[string]string{
"type": "vendor-data-privacy-agreement",
"vendor-id": vendorID.String(),
"organization-id": vendor.OrganizationID.String(),
},
})
if err != nil {
return fmt.Errorf("cannot upload file to S3: %w", err)
}
headOutput, err := s.svc.s3.HeadObject(ctx, &s3.HeadObjectInput{
Bucket: aws.String(s.svc.bucket),
Key: aws.String(objectKey.String()),
})
if err != nil {
return fmt.Errorf("cannot get object metadata: %w", err)
}
now := time.Now()
fileID := gid.New(s.svc.scope.GetTenantID(), coredata.FileEntityType)
vendorDataPrivacyAgreementID := gid.New(s.svc.scope.GetTenantID(), coredata.VendorDataPrivacyAgreementEntityType)
file = &coredata.File{
ID: fileID,
BucketName: s.svc.bucket,