Skip to content

Commit

Permalink
Add data source processing to rule update/create.
Browse files Browse the repository at this point in the history
This change adds code for the maintenance of references to Data
Sources during the creation or update of rule types.

To keep things simple and limit the amount of added code, the code
path is the same for both create and update, in that it always try to
delete references to data sources even in the case of rule creation,
which is always a noop.

Fixes #5049
  • Loading branch information
blkt committed Dec 2, 2024
1 parent 719d417 commit 15cb348
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 285 deletions.
54 changes: 10 additions & 44 deletions internal/controlplane/handlers_ruletype.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

datasourcesvc "github.com/mindersec/minder/internal/datasources/service"
"github.com/mindersec/minder/internal/db"
"github.com/mindersec/minder/internal/engine/engcontext"
"github.com/mindersec/minder/internal/flags"
Expand Down Expand Up @@ -176,13 +175,12 @@ func (s *Server) CreateRuleType(
return nil, util.UserVisibleError(codes.InvalidArgument, "%s", err)
}

newRuleType, err := db.WithTransaction(s.store, func(qtx db.ExtendQuerier) (*minderv1.RuleType, error) {
ruleDS := crt.GetRuleType().GetDef().GetEval().GetDataSources()
if err := s.validateDataSources(ctx, projectID, ruleDS, qtx); err != nil {
// We expect the error to be a user visible error
return nil, err
}
ruleDS := crt.GetRuleType().GetDef().GetEval().GetDataSources()
if len(ruleDS) > 0 && !flags.Bool(ctx, s.featureFlags, flags.DataSources) {
return nil, util.UserVisibleError(codes.InvalidArgument, "DataSources feature is disabled")
}

newRuleType, err := db.WithTransaction(s.store, func(qtx db.ExtendQuerier) (*minderv1.RuleType, error) {
return s.ruleTypes.CreateRuleType(ctx, projectID, uuid.Nil, crt.GetRuleType(), qtx)
})
if err != nil {
Expand Down Expand Up @@ -222,13 +220,12 @@ func (s *Server) UpdateRuleType(
return nil, util.UserVisibleError(codes.InvalidArgument, "%s", err)
}

updatedRuleType, err := db.WithTransaction(s.store, func(qtx db.ExtendQuerier) (*minderv1.RuleType, error) {
ruleDS := urt.GetRuleType().GetDef().GetEval().GetDataSources()
if err := s.validateDataSources(ctx, projectID, ruleDS, qtx); err != nil {
// We expect the error to be a user visible error
return nil, err
}
ruleDS := urt.GetRuleType().GetDef().GetEval().GetDataSources()
if len(ruleDS) > 0 && !flags.Bool(ctx, s.featureFlags, flags.DataSources) {
return nil, util.UserVisibleError(codes.InvalidArgument, "DataSources feature is disabled")
}

updatedRuleType, err := db.WithTransaction(s.store, func(qtx db.ExtendQuerier) (*minderv1.RuleType, error) {
return s.ruleTypes.UpdateRuleType(ctx, projectID, uuid.Nil, urt.GetRuleType(), qtx)
})
if err != nil {
Expand Down Expand Up @@ -376,34 +373,3 @@ func validateMarkdown(md string) error {

return nil
}

func (s *Server) validateDataSources(
ctx context.Context,
projectID uuid.UUID,
ruleDS []*minderv1.DataSourceReference,
qtx db.ExtendQuerier,
) error {
// Short circuiting to avoid accessing the database.
if len(ruleDS) == 0 {
return nil
}

if len(ruleDS) > 0 && !flags.Bool(ctx, s.featureFlags, flags.DataSources) {
return status.Errorf(codes.Unavailable, "DataSources feature is disabled")
}

opts := datasourcesvc.ReadBuilder().WithTransaction(qtx)
for _, requested := range ruleDS {
_, err := s.dataSourcesService.GetByName(
ctx,
requested.Name,
projectID,
opts,
)
if err != nil {
return util.UserVisibleError(codes.Internal, "failed retrieving data sources")
}
}

return nil
}
232 changes: 0 additions & 232 deletions internal/controlplane/handlers_ruletype_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,122 +105,6 @@ func TestCreateRuleType(t *testing.T) {
},
error: true,
},

// data sources validation
{
name: "available data sources",
mockStoreFunc: df.NewMockStore(
df.WithTransaction(),
WithSuccessfulGetProjectByID(projectID),
),
ruleTypeServiceFunc: sf.NewRuleTypeServiceMock(
sf.WithSuccessfulCreateRuleType,
),
dataSourcesServiceFunc: dsf.NewDataSourcesServiceMock(
dsf.WithSuccessfulGetByName(
projectID,
&minderv1.DataSource{
Name: "foo",
},
),
),
features: map[string]any{
"data_sources": true,
},
request: &minderv1.CreateRuleTypeRequest{
RuleType: &minderv1.RuleType{
Def: &minderv1.RuleType_Definition{
Eval: &minderv1.RuleType_Definition_Eval{
DataSources: []*minderv1.DataSourceReference{
{
Name: "foo",
},
},
},
},
},
},
},
{
name: "no data sources",
mockStoreFunc: df.NewMockStore(
df.WithRollbackTransaction(),
WithSuccessfulGetProjectByID(projectID),
),
ruleTypeServiceFunc: sf.NewRuleTypeServiceMock(),
dataSourcesServiceFunc: dsf.NewDataSourcesServiceMock(
dsf.WithNotFoundGetByName(projectID),
),
features: map[string]any{
"data_sources": true,
},
request: &minderv1.CreateRuleTypeRequest{
RuleType: &minderv1.RuleType{
Def: &minderv1.RuleType_Definition{
Eval: &minderv1.RuleType_Definition_Eval{
DataSources: []*minderv1.DataSourceReference{
{
Name: "foo",
},
},
},
},
},
},
error: true,
},
{
name: "failed data sources",
mockStoreFunc: df.NewMockStore(
df.WithRollbackTransaction(),
WithSuccessfulGetProjectByID(projectID),
),
ruleTypeServiceFunc: sf.NewRuleTypeServiceMock(),
dataSourcesServiceFunc: dsf.NewDataSourcesServiceMock(
dsf.WithFailedGetByName(),
),
features: map[string]any{
"data_sources": true,
},
request: &minderv1.CreateRuleTypeRequest{
RuleType: &minderv1.RuleType{
Def: &minderv1.RuleType_Definition{
Eval: &minderv1.RuleType_Definition_Eval{
DataSources: []*minderv1.DataSourceReference{
{
Name: "foo",
},
},
},
},
},
},
error: true,
},
{
name: "disabled data sources",
mockStoreFunc: df.NewMockStore(
df.WithRollbackTransaction(),
WithSuccessfulGetProjectByID(projectID),
),
ruleTypeServiceFunc: sf.NewRuleTypeServiceMock(),
dataSourcesServiceFunc: dsf.NewDataSourcesServiceMock(),
features: map[string]any{},
request: &minderv1.CreateRuleTypeRequest{
RuleType: &minderv1.RuleType{
Def: &minderv1.RuleType_Definition{
Eval: &minderv1.RuleType_Definition_Eval{
DataSources: []*minderv1.DataSourceReference{
{
Name: "foo",
},
},
},
},
},
},
error: true,
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -341,122 +225,6 @@ func TestUpdateRuleType(t *testing.T) {
},
error: true,
},

// data sources validation
{
name: "available data sources",
mockStoreFunc: df.NewMockStore(
df.WithTransaction(),
WithSuccessfulGetProjectByID(projectID),
),
ruleTypeServiceFunc: sf.NewRuleTypeServiceMock(
sf.WithSuccessfulUpdateRuleType,
),
dataSourcesServiceFunc: dsf.NewDataSourcesServiceMock(
dsf.WithSuccessfulGetByName(
projectID,
&minderv1.DataSource{
Name: "foo",
},
),
),
features: map[string]any{
"data_sources": true,
},
request: &minderv1.UpdateRuleTypeRequest{
RuleType: &minderv1.RuleType{
Def: &minderv1.RuleType_Definition{
Eval: &minderv1.RuleType_Definition_Eval{
DataSources: []*minderv1.DataSourceReference{
{
Name: "foo",
},
},
},
},
},
},
},
{
name: "no data sources",
mockStoreFunc: df.NewMockStore(
df.WithRollbackTransaction(),
WithSuccessfulGetProjectByID(projectID),
),
ruleTypeServiceFunc: sf.NewRuleTypeServiceMock(),
dataSourcesServiceFunc: dsf.NewDataSourcesServiceMock(
dsf.WithNotFoundGetByName(projectID),
),
features: map[string]any{
"data_sources": true,
},
request: &minderv1.UpdateRuleTypeRequest{
RuleType: &minderv1.RuleType{
Def: &minderv1.RuleType_Definition{
Eval: &minderv1.RuleType_Definition_Eval{
DataSources: []*minderv1.DataSourceReference{
{
Name: "foo",
},
},
},
},
},
},
error: true,
},
{
name: "failed data sources",
mockStoreFunc: df.NewMockStore(
df.WithRollbackTransaction(),
WithSuccessfulGetProjectByID(projectID),
),
ruleTypeServiceFunc: sf.NewRuleTypeServiceMock(),
dataSourcesServiceFunc: dsf.NewDataSourcesServiceMock(
dsf.WithFailedGetByName(),
),
features: map[string]any{
"data_sources": true,
},
request: &minderv1.UpdateRuleTypeRequest{
RuleType: &minderv1.RuleType{
Def: &minderv1.RuleType_Definition{
Eval: &minderv1.RuleType_Definition_Eval{
DataSources: []*minderv1.DataSourceReference{
{
Name: "foo",
},
},
},
},
},
},
error: true,
},
{
name: "disabled data sources",
mockStoreFunc: df.NewMockStore(
df.WithRollbackTransaction(),
WithSuccessfulGetProjectByID(projectID),
),
ruleTypeServiceFunc: sf.NewRuleTypeServiceMock(),
dataSourcesServiceFunc: dsf.NewDataSourcesServiceMock(),
features: map[string]any{},
request: &minderv1.UpdateRuleTypeRequest{
RuleType: &minderv1.RuleType{
Def: &minderv1.RuleType_Definition{
Eval: &minderv1.RuleType_Definition_Eval{
DataSources: []*minderv1.DataSourceReference{
{
Name: "foo",
},
},
},
},
},
},
error: true,
},
}

for _, tt := range tests {
Expand Down
Loading

0 comments on commit 15cb348

Please sign in to comment.