Skip to content

Commit

Permalink
Validate Data Sources when creating rules.
Browse files Browse the repository at this point in the history
Rules can now specify a list of data sources names that they need for
their evaluation. This change ensures that data sources required by
the rule are available when creating the rule.

A similar change is being added in the code path implementing data
source deletion ensuring that a data source is not deleted if there
exist rules depending on it.

Fixes #5049
  • Loading branch information
blkt committed Nov 27, 2024
1 parent 27464ee commit ca14633
Show file tree
Hide file tree
Showing 5 changed files with 440 additions and 16 deletions.
61 changes: 55 additions & 6 deletions internal/controlplane/handlers_ruletype.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"database/sql"
"errors"
"fmt"
"slices"
"strings"
"unicode/utf8"

Expand All @@ -21,6 +22,7 @@ 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 @@ -175,9 +177,10 @@ func (s *Server) CreateRuleType(
return nil, util.UserVisibleError(codes.InvalidArgument, "%s", err)
}

ds := crt.GetRuleType().GetDef().GetEval().GetDataSources()
if len(ds) > 0 && !flags.Bool(ctx, s.featureFlags, flags.DataSources) {
return nil, status.Errorf(codes.Unavailable, "DataSources feature is disabled")
ruleDS := crt.GetRuleType().GetDef().GetEval().GetDataSources()
if err := s.validateDataSources(ctx, projectID, ruleDS); err != nil {
// We expect the error to be a user visible error
return nil, err
}

newRuleType, err := db.WithTransaction(s.store, func(qtx db.ExtendQuerier) (*minderv1.RuleType, error) {
Expand Down Expand Up @@ -220,9 +223,10 @@ func (s *Server) UpdateRuleType(
return nil, util.UserVisibleError(codes.InvalidArgument, "%s", err)
}

ds := urt.GetRuleType().GetDef().GetEval().GetDataSources()
if len(ds) > 0 && !flags.Bool(ctx, s.featureFlags, flags.DataSources) {
return nil, status.Errorf(codes.Unavailable, "DataSources feature is disabled")
ruleDS := urt.GetRuleType().GetDef().GetEval().GetDataSources()
if err := s.validateDataSources(ctx, projectID, ruleDS); err != nil {
// We expect the error to be a user visible error
return nil, err
}

updatedRuleType, err := db.WithTransaction(s.store, func(qtx db.ExtendQuerier) (*minderv1.RuleType, error) {
Expand Down Expand Up @@ -373,3 +377,48 @@ func validateMarkdown(md string) error {

return nil
}

func (s *Server) validateDataSources(
ctx context.Context,
projectID uuid.UUID,
ruleDS []*minderv1.DataSourceReference,
) 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")
}

requested := make([]string, 0)
for _, ds := range ruleDS {
requested = append(requested, ds.Name)
}

// List Data Sources defined in the whole project hierarchy.
availableDS, err := s.dataSourcesService.List(
ctx,
projectID,
&datasourcesvc.ReadOptions{},
)
if err != nil {
return util.UserVisibleError(codes.Internal, "failed listing data sources")
}

available := make([]string, 0)
for _, ds := range availableDS {
available = append(available, ds.Name)
}

// Validate that data sources requested by the new rule are
// effectively available.
for _, dsname := range requested {
if !slices.Contains(available, dsname) {
return util.UserVisibleError(codes.InvalidArgument, "requested DataSource is not available: %s", dsname)
}
}

return nil
}
Loading

0 comments on commit ca14633

Please sign in to comment.