Add framework import

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-03-13 16:32:30 +01:00
parent 2f229fc27d
commit 03f621ec8d
6 changed files with 453 additions and 13 deletions

View File

@@ -40,6 +40,7 @@ type (
CreatedAt time.Time `db:"created_at"`
UpdatedAt time.Time `db:"updated_at"`
Version int `db:"version"`
Standards []string `db:"standards"`
}
Controls []*Control
@@ -76,6 +77,7 @@ SELECT
content_ref,
created_at,
updated_at,
standards,
version
FROM
controls
@@ -124,6 +126,7 @@ INSERT INTO
content_ref,
created_at,
updated_at,
standards,
version
)
VALUES (
@@ -138,6 +141,7 @@ VALUES (
@content_ref,
@created_at,
@updated_at,
@standards,
@version
);
`
@@ -155,6 +159,7 @@ VALUES (
"updated_at": c.UpdatedAt,
"state": c.State,
"importance": c.Importance,
"standards": c.Standards,
}
_, err := conn.Exec(ctx, q, args)
return err
@@ -179,6 +184,7 @@ SELECT
content_ref,
created_at,
updated_at,
standards,
version
FROM
controls
@@ -237,7 +243,8 @@ RETURNING
content_ref,
created_at,
updated_at,
version
version,
standards
`
q = fmt.Sprintf(q, scope.SQLFragment())

View File

@@ -0,0 +1,2 @@
ALTER TABLE controls ADD COLUMN standards TEXT[] DEFAULT '{}' NOT NULL;
ALTER TABLE controls ALTER COLUMN standards DROP DEFAULT;

View File

@@ -43,6 +43,25 @@ type (
Name *string
Description *string
}
ImportFrameworkRequest struct {
Data struct {
Framework struct {
Name string `json:"name"`
ContentRef string `json:"content-ref"`
Description string `json:"description"`
Version string `json:"version"`
Controls []struct {
ContentRef string `json:"content-ref"`
Category string `json:"category"`
Importance coredata.ControlImportance `json:"importance"`
Standards []string `json:"standards"`
Name string `json:"name"`
Description string `json:"description"`
} `json:"controls"`
} `json:"framework"`
}
}
)
func (s FrameworkService) Create(
@@ -163,3 +182,76 @@ func (s FrameworkService) Delete(
},
)
}
func (s FrameworkService) Import(
ctx context.Context,
organizationID gid.GID,
req ImportFrameworkRequest,
) (*coredata.Framework, error) {
now := time.Now()
frameworkID, err := gid.NewGID(organizationID.TenantID(), coredata.FrameworkEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create global id: %w", err)
}
framework := &coredata.Framework{
ID: frameworkID,
OrganizationID: organizationID,
Name: req.Data.Framework.Name,
Description: req.Data.Framework.Description,
ContentRef: req.Data.Framework.ContentRef,
CreatedAt: now,
UpdatedAt: now,
}
importedControls := coredata.Controls{}
for _, control := range req.Data.Framework.Controls {
controlID, err := gid.NewGID(organizationID.TenantID(), coredata.ControlEntityType)
if err != nil {
return nil, fmt.Errorf("cannot create global id: %w", err)
}
importedControl := &coredata.Control{
ID: controlID,
FrameworkID: frameworkID,
Category: control.Category,
Importance: coredata.ControlImportance(control.Importance),
Name: control.Name,
Description: control.Description,
State: coredata.ControlStateNotStarted,
ContentRef: control.ContentRef,
CreatedAt: now,
UpdatedAt: now,
Standards: control.Standards,
}
importedControls = append(importedControls, importedControl)
}
err = s.svc.pg.WithTx(
ctx,
func(tx pg.Conn) error {
err := framework.Insert(ctx, tx, s.svc.scope)
if err != nil {
return fmt.Errorf("cannot insert framework: %w", err)
}
for _, importedControl := range importedControls {
if err := importedControl.Insert(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert control: %w", err)
}
}
return nil
},
)
if err != nil {
return nil, err
}
return framework, nil
}

View File

@@ -6,6 +6,7 @@ package console_v1
import (
"context"
"encoding/json"
"fmt"
"time"
@@ -348,7 +349,21 @@ func (r *mutationResolver) UpdateFramework(ctx context.Context, input types.Upda
// ImportFramework is the resolver for the importFramework field.
func (r *mutationResolver) ImportFramework(ctx context.Context, input types.ImportFrameworkInput) (*types.ImportFrameworkPayload, error) {
panic(fmt.Errorf("not implemented: ImportFramework - importFramework"))
svc := r.GetTenantServiceIfAuthorized(ctx, input.OrganizationID.TenantID())
req := probo.ImportFrameworkRequest{}
if err := json.NewDecoder(input.File.File).Decode(&req.Data); err != nil {
return nil, fmt.Errorf("cannot decode framework: %w", err)
}
framework, err := svc.Frameworks.Import(ctx, input.OrganizationID, req)
if err != nil {
return nil, fmt.Errorf("cannot import framework: %w", err)
}
return &types.ImportFrameworkPayload{
FrameworkEdge: types.NewFrameworkEdge(framework),
}, nil
}
// CreateControl is the resolver for the createControl field.