@@ -64,7 +64,7 @@ const DeleteFrameworkMutation = graphql`
|
|||||||
const exportAuditMutation = graphql`
|
const exportAuditMutation = graphql`
|
||||||
mutation FrameworkLayoutViewExportAuditMutation($input: ExportAuditInput!) {
|
mutation FrameworkLayoutViewExportAuditMutation($input: ExportAuditInput!) {
|
||||||
exportAudit(input: $input) {
|
exportAudit(input: $input) {
|
||||||
success
|
url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<c25a5f65159da12ec86ca608b7583a67>>
|
* @generated SignedSource<<1517cf7236f96500239781562cff66e4>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -17,7 +17,7 @@ export type FrameworkLayoutViewExportAuditMutation$variables = {
|
|||||||
};
|
};
|
||||||
export type FrameworkLayoutViewExportAuditMutation$data = {
|
export type FrameworkLayoutViewExportAuditMutation$data = {
|
||||||
readonly exportAudit: {
|
readonly exportAudit: {
|
||||||
readonly success: boolean;
|
readonly url: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
export type FrameworkLayoutViewExportAuditMutation = {
|
export type FrameworkLayoutViewExportAuditMutation = {
|
||||||
@@ -52,7 +52,7 @@ v1 = [
|
|||||||
"alias": null,
|
"alias": null,
|
||||||
"args": null,
|
"args": null,
|
||||||
"kind": "ScalarField",
|
"kind": "ScalarField",
|
||||||
"name": "success",
|
"name": "url",
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -77,16 +77,16 @@ return {
|
|||||||
"selections": (v1/*: any*/)
|
"selections": (v1/*: any*/)
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"cacheID": "a0f656b50acde2ef3c3fef73e2155e9f",
|
"cacheID": "0dfccdfa75539c4621ec1bf7aab05ad2",
|
||||||
"id": null,
|
"id": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"name": "FrameworkLayoutViewExportAuditMutation",
|
"name": "FrameworkLayoutViewExportAuditMutation",
|
||||||
"operationKind": "mutation",
|
"operationKind": "mutation",
|
||||||
"text": "mutation FrameworkLayoutViewExportAuditMutation(\n $input: ExportAuditInput!\n) {\n exportAudit(input: $input) {\n success\n }\n}\n"
|
"text": "mutation FrameworkLayoutViewExportAuditMutation(\n $input: ExportAuditInput!\n) {\n exportAudit(input: $input) {\n url\n }\n}\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "b7347f4f8e292580e056793df6c270a5";
|
(node as any).hash = "28679b1a4e375eb17a72e9e236f2e2ee";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||||
"github.com/getprobo/probo/pkg/coredata"
|
"github.com/getprobo/probo/pkg/coredata"
|
||||||
@@ -247,7 +250,10 @@ func (s FrameworkService) Import(
|
|||||||
func (s FrameworkService) ExportAudit(
|
func (s FrameworkService) ExportAudit(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
frameworkID gid.GID,
|
frameworkID gid.GID,
|
||||||
) ([]*coredata.Control, error) {
|
) (string, error) {
|
||||||
|
var archivePath string
|
||||||
|
var objectKey string
|
||||||
|
|
||||||
err := s.svc.pg.WithConn(
|
err := s.svc.pg.WithConn(
|
||||||
ctx,
|
ctx,
|
||||||
func(conn pg.Conn) error {
|
func(conn pg.Conn) error {
|
||||||
@@ -387,13 +393,102 @@ func (s FrameworkService) ExportAudit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
archivePath = exportDir + ".tar.gz"
|
||||||
|
if err := createTarGzArchive(exportDir, archivePath); err != nil {
|
||||||
|
return fmt.Errorf("cannot create archive: %w", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(archivePath)
|
||||||
|
|
||||||
|
file, err := os.Open(archivePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot open archive file: %w", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
objectKey = fmt.Sprintf("exports/%s/%s.tar.gz", frameworkID, now.Format("2006-01-02-15-04-05"))
|
||||||
|
_, err = s.svc.s3.PutObject(
|
||||||
|
ctx,
|
||||||
|
&s3.PutObjectInput{
|
||||||
|
Bucket: aws.String(s.svc.bucket),
|
||||||
|
Key: aws.String(objectKey),
|
||||||
|
Body: file,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot upload archive to S3: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
presignClient := s3.NewPresignClient(s.svc.s3)
|
||||||
|
|
||||||
|
presignedReq, err := presignClient.PresignGetObject(ctx, &s3.GetObjectInput{
|
||||||
|
Bucket: aws.String(s.svc.bucket),
|
||||||
|
Key: aws.String(objectKey),
|
||||||
|
}, func(opts *s3.PresignOptions) {
|
||||||
|
opts.Expires = 15 * time.Minute
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("cannot generate presigned URL: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return presignedReq.URL, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTarGzArchive(sourceDir, targetFile string) error {
|
||||||
|
tarFile, err := os.Create(targetFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not create archive file: %w", err)
|
||||||
|
}
|
||||||
|
defer tarFile.Close()
|
||||||
|
|
||||||
|
gzipWriter := io.Writer(tarFile)
|
||||||
|
gzw := gzip.NewWriter(gzipWriter)
|
||||||
|
defer gzw.Close()
|
||||||
|
|
||||||
|
tarWriter := tar.NewWriter(gzw)
|
||||||
|
defer tarWriter.Close()
|
||||||
|
|
||||||
|
err = filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
header, err := tar.FileInfoHeader(info, info.Name())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not create tar header: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
relPath, err := filepath.Rel(sourceDir, path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not get relative path: %w", err)
|
||||||
|
}
|
||||||
|
header.Name = relPath
|
||||||
|
|
||||||
|
if err := tarWriter.WriteHeader(header); err != nil {
|
||||||
|
return fmt.Errorf("could not write tar header: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Mode().IsRegular() {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not open file %s: %w", path, err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if _, err := io.Copy(tarWriter, file); err != nil {
|
||||||
|
return fmt.Errorf("could not copy file content: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1738,5 +1738,5 @@ input ExportAuditInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ExportAuditPayload {
|
type ExportAuditPayload {
|
||||||
success: Boolean!
|
url: String!
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ type ComplexityRoot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExportAuditPayload struct {
|
ExportAuditPayload struct {
|
||||||
Success func(childComplexity int) int
|
URL func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
Framework struct {
|
Framework struct {
|
||||||
@@ -1415,12 +1415,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
|
|
||||||
return e.complexity.EvidenceEdge.Node(childComplexity), true
|
return e.complexity.EvidenceEdge.Node(childComplexity), true
|
||||||
|
|
||||||
case "ExportAuditPayload.success":
|
case "ExportAuditPayload.url":
|
||||||
if e.complexity.ExportAuditPayload.Success == nil {
|
if e.complexity.ExportAuditPayload.URL == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.ExportAuditPayload.Success(childComplexity), true
|
return e.complexity.ExportAuditPayload.URL(childComplexity), true
|
||||||
|
|
||||||
case "Framework.controls":
|
case "Framework.controls":
|
||||||
if e.complexity.Framework.Controls == nil {
|
if e.complexity.Framework.Controls == nil {
|
||||||
@@ -5709,7 +5709,7 @@ input ExportAuditInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ExportAuditPayload {
|
type ExportAuditPayload {
|
||||||
success: Boolean!
|
url: String!
|
||||||
}
|
}
|
||||||
`, BuiltIn: false},
|
`, BuiltIn: false},
|
||||||
}
|
}
|
||||||
@@ -12989,8 +12989,8 @@ func (ec *executionContext) fieldContext_EvidenceEdge_node(_ context.Context, fi
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _ExportAuditPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.ExportAuditPayload) (ret graphql.Marshaler) {
|
func (ec *executionContext) _ExportAuditPayload_url(ctx context.Context, field graphql.CollectedField, obj *types.ExportAuditPayload) (ret graphql.Marshaler) {
|
||||||
fc, err := ec.fieldContext_ExportAuditPayload_success(ctx, field)
|
fc, err := ec.fieldContext_ExportAuditPayload_url(ctx, field)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
}
|
}
|
||||||
@@ -13003,7 +13003,7 @@ func (ec *executionContext) _ExportAuditPayload_success(ctx context.Context, fie
|
|||||||
}()
|
}()
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (any, error) {
|
||||||
ctx = rctx // use context from middleware stack in children
|
ctx = rctx // use context from middleware stack in children
|
||||||
return obj.Success, nil
|
return obj.URL, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
@@ -13015,19 +13015,19 @@ func (ec *executionContext) _ExportAuditPayload_success(ctx context.Context, fie
|
|||||||
}
|
}
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
}
|
}
|
||||||
res := resTmp.(bool)
|
res := resTmp.(string)
|
||||||
fc.Result = res
|
fc.Result = res
|
||||||
return ec.marshalNBoolean2bool(ctx, field.Selections, res)
|
return ec.marshalNString2string(ctx, field.Selections, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_ExportAuditPayload_success(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
func (ec *executionContext) fieldContext_ExportAuditPayload_url(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
fc = &graphql.FieldContext{
|
fc = &graphql.FieldContext{
|
||||||
Object: "ExportAuditPayload",
|
Object: "ExportAuditPayload",
|
||||||
Field: field,
|
Field: field,
|
||||||
IsMethod: false,
|
IsMethod: false,
|
||||||
IsResolver: false,
|
IsResolver: false,
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
return nil, errors.New("field of type Boolean does not have child fields")
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return fc, nil
|
return fc, nil
|
||||||
@@ -17610,8 +17610,8 @@ func (ec *executionContext) fieldContext_Mutation_exportAudit(ctx context.Contex
|
|||||||
IsResolver: true,
|
IsResolver: true,
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "success":
|
case "url":
|
||||||
return ec.fieldContext_ExportAuditPayload_success(ctx, field)
|
return ec.fieldContext_ExportAuditPayload_url(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type ExportAuditPayload", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type ExportAuditPayload", field.Name)
|
||||||
},
|
},
|
||||||
@@ -35022,8 +35022,8 @@ func (ec *executionContext) _ExportAuditPayload(ctx context.Context, sel ast.Sel
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("ExportAuditPayload")
|
out.Values[i] = graphql.MarshalString("ExportAuditPayload")
|
||||||
case "success":
|
case "url":
|
||||||
out.Values[i] = ec._ExportAuditPayload_success(ctx, field, obj)
|
out.Values[i] = ec._ExportAuditPayload_url(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
out.Invalids++
|
out.Invalids++
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ type ExportAuditInput struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ExportAuditPayload struct {
|
type ExportAuditPayload struct {
|
||||||
Success bool `json:"success"`
|
URL string `json:"url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Framework struct {
|
type Framework struct {
|
||||||
|
|||||||
@@ -1292,13 +1292,13 @@ func (r *mutationResolver) CreateVendorRiskAssessment(ctx context.Context, input
|
|||||||
// ExportAudit is the resolver for the exportAudit field.
|
// ExportAudit is the resolver for the exportAudit field.
|
||||||
func (r *mutationResolver) ExportAudit(ctx context.Context, input types.ExportAuditInput) (*types.ExportAuditPayload, error) {
|
func (r *mutationResolver) ExportAudit(ctx context.Context, input types.ExportAuditInput) (*types.ExportAuditPayload, error) {
|
||||||
svc := GetTenantService(ctx, r.proboSvc, input.FrameworkID.TenantID())
|
svc := GetTenantService(ctx, r.proboSvc, input.FrameworkID.TenantID())
|
||||||
_, err := svc.Frameworks.ExportAudit(ctx, input.FrameworkID)
|
fileUrl, err := svc.Frameworks.ExportAudit(ctx, input.FrameworkID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("cannot export audit: %w", err))
|
panic(fmt.Errorf("cannot export audit: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.ExportAuditPayload{
|
return &types.ExportAuditPayload{
|
||||||
Success: true,
|
URL: fileUrl,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user