Improve framework data isolation

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-05-23 10:56:07 -07:00
parent b94a75abcf
commit bac6f1a4a0
2 changed files with 66 additions and 45 deletions

View File

@@ -250,6 +250,7 @@ func (f Framework) Delete(
ctx context.Context, ctx context.Context,
conn pg.Conn, conn pg.Conn,
scope Scoper, scope Scoper,
frameworkID gid.GID,
) error { ) error {
q := ` q := `
DELETE DELETE
@@ -260,7 +261,7 @@ WHERE
AND id = @framework_id; AND id = @framework_id;
` `
args := pgx.StrictNamedArgs{"framework_id": f.ID} args := pgx.StrictNamedArgs{"framework_id": frameworkID}
maps.Copy(args, scope.SQLArguments()) maps.Copy(args, scope.SQLArguments())
q = fmt.Sprintf(q, scope.SQLFragment()) q = fmt.Sprintf(q, scope.SQLFragment())

View File

@@ -69,22 +69,31 @@ func (s FrameworkService) Create(
req CreateFrameworkRequest, req CreateFrameworkRequest,
) (*coredata.Framework, error) { ) (*coredata.Framework, error) {
now := time.Now() now := time.Now()
frameworkID := gid.New(s.svc.scope.GetTenantID(), coredata.FrameworkEntityType) organization := &coredata.Organization{}
framework := &coredata.Framework{ framework := &coredata.Framework{
ID: frameworkID, ID: gid.New(s.svc.scope.GetTenantID(), coredata.FrameworkEntityType),
OrganizationID: req.OrganizationID, Name: req.Name,
Name: req.Name, Description: req.Description,
Description: req.Description, ReferenceID: slug.Make(req.Name),
ReferenceID: slug.Make(req.Name), CreatedAt: now,
CreatedAt: now, UpdatedAt: now,
UpdatedAt: now,
} }
err := s.svc.pg.WithConn( err := s.svc.pg.WithTx(
ctx, ctx,
func(conn pg.Conn) error { func(conn pg.Conn) error {
return framework.Insert(ctx, conn, s.svc.scope) if err := organization.LoadByID(ctx, conn, s.svc.scope, req.OrganizationID); err != nil {
return fmt.Errorf("cannot load organization: %w", err)
}
framework.OrganizationID = organization.ID
if err := framework.Insert(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert framework: %w", err)
}
return nil
}, },
) )
@@ -101,17 +110,27 @@ func (s FrameworkService) ListForOrganizationID(
cursor *page.Cursor[coredata.FrameworkOrderField], cursor *page.Cursor[coredata.FrameworkOrderField],
) (*page.Page[*coredata.Framework, coredata.FrameworkOrderField], error) { ) (*page.Page[*coredata.Framework, coredata.FrameworkOrderField], error) {
var frameworks coredata.Frameworks var frameworks coredata.Frameworks
organization := &coredata.Organization{}
err := s.svc.pg.WithConn( err := s.svc.pg.WithConn(
ctx, ctx,
func(conn pg.Conn) error { func(conn pg.Conn) error {
return frameworks.LoadByOrganizationID( if err := organization.LoadByID(ctx, conn, s.svc.scope, organizationID); err != nil {
return fmt.Errorf("cannot load organization: %w", err)
}
err := frameworks.LoadByOrganizationID(
ctx, ctx,
conn, conn,
s.svc.scope, s.svc.scope,
organizationID, organization.ID,
cursor, cursor,
) )
if err != nil {
return fmt.Errorf("cannot load frameworks: %w", err)
}
return nil
}, },
) )
@@ -177,12 +196,12 @@ func (s FrameworkService) Delete(
ctx context.Context, ctx context.Context,
frameworkID gid.GID, frameworkID gid.GID,
) error { ) error {
framework := &coredata.Framework{ID: frameworkID} framework := &coredata.Framework{}
return s.svc.pg.WithConn( return s.svc.pg.WithConn(
ctx, ctx,
func(conn pg.Conn) error { func(conn pg.Conn) error {
return framework.Delete(ctx, conn, s.svc.scope) return framework.Delete(ctx, conn, s.svc.scope, frameworkID)
}, },
) )
} }
@@ -192,46 +211,47 @@ func (s FrameworkService) Import(
organizationID gid.GID, organizationID gid.GID,
req ImportFrameworkRequest, req ImportFrameworkRequest,
) (*coredata.Framework, error) { ) (*coredata.Framework, error) {
var framework *coredata.Framework
frameworkID := gid.New(organizationID.TenantID(), coredata.FrameworkEntityType) frameworkID := gid.New(organizationID.TenantID(), coredata.FrameworkEntityType)
now := time.Now() now := time.Now()
framework := &coredata.Framework{
ID: frameworkID,
OrganizationID: organizationID,
ReferenceID: req.Framework.ID,
Name: req.Framework.Name,
CreatedAt: now,
UpdatedAt: now,
}
importedControls := coredata.Controls{}
for _, control := range req.Framework.Controls {
controlID := gid.New(organizationID.TenantID(), coredata.ControlEntityType)
now := time.Now()
control := &coredata.Control{
ID: controlID,
TenantID: organizationID.TenantID(),
FrameworkID: frameworkID,
ReferenceID: control.ID,
Name: control.Name,
Description: control.Description,
CreatedAt: now,
UpdatedAt: now,
}
importedControls = append(importedControls, control)
}
err := s.svc.pg.WithTx( err := s.svc.pg.WithTx(
ctx, ctx,
func(tx pg.Conn) error { func(tx pg.Conn) error {
organization := &coredata.Organization{}
if err := organization.LoadByID(ctx, tx, s.svc.scope, organizationID); err != nil {
return fmt.Errorf("cannot load organization: %w", err)
}
framework = &coredata.Framework{
ID: frameworkID,
OrganizationID: organization.ID,
ReferenceID: req.Framework.ID,
Name: req.Framework.Name,
CreatedAt: now,
UpdatedAt: now,
}
if err := framework.Insert(ctx, tx, s.svc.scope); err != nil { if err := framework.Insert(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert framework: %w", err) return fmt.Errorf("cannot insert framework: %w", err)
} }
for _, importedControl := range importedControls { for _, control := range req.Framework.Controls {
if err := importedControl.Insert(ctx, tx, s.svc.scope); err != nil { controlID := gid.New(organization.ID.TenantID(), coredata.ControlEntityType)
now := time.Now()
control := &coredata.Control{
ID: controlID,
TenantID: organizationID.TenantID(),
FrameworkID: frameworkID,
ReferenceID: control.ID,
Name: control.Name,
Description: control.Description,
CreatedAt: now,
UpdatedAt: now,
}
if err := control.Insert(ctx, tx, s.svc.scope); err != nil {
return fmt.Errorf("cannot insert control: %w", err) return fmt.Errorf("cannot insert control: %w", err)
} }
} }