Skip to content

Commit

Permalink
Move converting entities to SelectorEntity structs to providers
Browse files Browse the repository at this point in the history
  • Loading branch information
jhrozek committed Jul 11, 2024
1 parent 311a3f0 commit 35e207a
Show file tree
Hide file tree
Showing 8 changed files with 657 additions and 218 deletions.
95 changes: 95 additions & 0 deletions internal/engine/selectors/mock/selectors.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

104 changes: 3 additions & 101 deletions internal/engine/selectors/selectors.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import (

"github.com/google/cel-go/cel"
"github.com/google/cel-go/checker/decls"
"google.golang.org/protobuf/proto"

"github.com/stacklok/minder/internal/engine/entities"
internalpb "github.com/stacklok/minder/internal/proto"
minderv1 "github.com/stacklok/minder/pkg/api/protobuf/go/minder/v1"
)
Expand All @@ -42,7 +40,7 @@ func genericEnvFactory() (*cel.Env, error) {
return newEnvForEntity(
"entity",
&internalpb.SelectorEntity{},
"minder.v1.SelectorEntity")
"internal.SelectorEntity")
}

// repoEnvFactory is a factory for creating a CEL environment
Expand All @@ -51,7 +49,7 @@ func repoEnvFactory() (*cel.Env, error) {
return newEnvForEntity(
"repository",
&internalpb.SelectorRepository{},
"minder.v1.SelectorRepository")
"internal.SelectorRepository")
}

// artifactEnvFactory is a factory for creating a CEL environment
Expand All @@ -60,7 +58,7 @@ func artifactEnvFactory() (*cel.Env, error) {
return newEnvForEntity(
"artifact",
&internalpb.SelectorArtifact{},
"minder.v1.SelectorArtifact")
"internal.SelectorArtifact")
}

// newEnvForEntity creates a new CEL environment for an entity. All environments are allowed to
Expand Down Expand Up @@ -201,94 +199,9 @@ func (e *Env) envForEntity(entity minderv1.Entity) (*cel.Env, error) {
return cache.env, cache.err
}

// entityInfoConverter is an interface for converting an entity from an EntityInfoWrapper to a SelectorEntity
type entityInfoConverter interface {
toSelectorEntity(entity proto.Message) *internalpb.SelectorEntity
}

type repositoryInfoConverter struct{}

func (_ *repositoryInfoConverter) toSelectorEntity(entity proto.Message) *internalpb.SelectorEntity {
r, ok := entity.(*minderv1.Repository)
if !ok {
return nil
}

return &internalpb.SelectorEntity{
EntityType: minderv1.Entity_ENTITY_REPOSITORIES,
Name: fmt.Sprintf("%s/%s", r.GetOwner(), r.GetName()),
Entity: &internalpb.SelectorEntity_Repository{
Repository: &internalpb.SelectorRepository{
Name: fmt.Sprintf("%s/%s", r.GetOwner(), r.GetName()),
IsFork: proto.Bool(r.GetIsFork()),
IsPrivate: proto.Bool(r.GetIsPrivate()),
},
},
}
}

type artifactInfoConverter struct{}

func (_ *artifactInfoConverter) toSelectorEntity(entity proto.Message) *internalpb.SelectorEntity {
a, ok := entity.(*minderv1.Artifact)
if !ok {
return nil
}

return &internalpb.SelectorEntity{
EntityType: minderv1.Entity_ENTITY_ARTIFACTS,
Name: fmt.Sprintf("%s/%s", a.GetOwner(), a.GetName()),
Entity: &internalpb.SelectorEntity_Artifact{
Artifact: &internalpb.SelectorArtifact{
Name: fmt.Sprintf("%s/%s", a.GetOwner(), a.GetName()),
Type: a.GetType(),
},
},
}
}

// converterFactory is a map of entity types to their respective converters
type converterFactory struct {
converters map[minderv1.Entity]entityInfoConverter
}

// newConverterFactory creates a new converterFactory with the default converters for each entity type
func newConverterFactory() *converterFactory {
return &converterFactory{
converters: map[minderv1.Entity]entityInfoConverter{
minderv1.Entity_ENTITY_REPOSITORIES: &repositoryInfoConverter{},
minderv1.Entity_ENTITY_ARTIFACTS: &artifactInfoConverter{},
},
}
}

func (cf *converterFactory) getConverter(entityType minderv1.Entity) (entityInfoConverter, error) {
conv, ok := cf.converters[entityType]
if !ok {
return nil, fmt.Errorf("no converter found for entity type %v", entityType)
}

return conv, nil
}

func newSelectorEntity(eiw *entities.EntityInfoWrapper) *internalpb.SelectorEntity {
if eiw == nil {
return nil
}

convertFactory := newConverterFactory()
conv, err := convertFactory.getConverter(eiw.Type)
if err != nil {
return nil
}

return conv.toSelectorEntity(eiw.Entity)
}

// Selection is an interface for selecting entities based on a profile
type Selection interface {
Select(*internalpb.SelectorEntity) (bool, error)
SelectEiw(*entities.EntityInfoWrapper) (bool, error)
}

// EntitySelection is a struct that holds the compiled CEL expressions for a given entity type
Expand Down Expand Up @@ -326,17 +239,6 @@ func (s *EntitySelection) Select(se *internalpb.SelectorEntity) (bool, error) {
return true, nil
}

// SelectEiw selects an entity based on an EntityInfoWrapper. It is a convenience method
// around Select that creates a SelectorEntity from the EntityInfoWrapper
func (s *EntitySelection) SelectEiw(eiw *entities.EntityInfoWrapper) (bool, error) {
se := newSelectorEntity(eiw)
if se == nil {
return false, fmt.Errorf("failed to create SelectorEntity from EntityInfoWrapper")
}

return s.Select(se)
}

func inputAsMap(se *internalpb.SelectorEntity) (map[string]any, error) {
var value any

Expand Down
118 changes: 1 addition & 117 deletions internal/engine/selectors/selectors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
package selectors

import (
internalpb "github.com/stacklok/minder/internal/proto"
"testing"

"github.com/stretchr/testify/require"

"github.com/stacklok/minder/internal/engine/entities"
internalpb "github.com/stacklok/minder/internal/proto"
minderv1 "github.com/stacklok/minder/pkg/api/protobuf/go/minder/v1"
)

Expand Down Expand Up @@ -301,118 +300,3 @@ func TestSelectSelectorEntity(t *testing.T) {
})
}
}

func TestSelectEntityInfoWrapper(t *testing.T) {
t.Parallel()

scenarios := []struct {
name string
eiwConstructor func() *entities.EntityInfoWrapper
exprs []*minderv1.Profile_Selector
selected bool
expectedErr string
}{
{
name: "Simple true repository expression",
eiwConstructor: func() *entities.EntityInfoWrapper {
eiw := entities.NewEntityInfoWrapper()
eiw.WithRepository(&minderv1.Repository{
Owner: "stacklok",
Name: "minder",
IsPrivate: false,
IsFork: false,
})
return eiw
},
exprs: []*minderv1.Profile_Selector{
{
Entity: minderv1.RepositoryEntity.String(),
Selector: "entity.name == 'stacklok/minder'",
},
},
selected: true,
},
{
name: "Simple true artifact expression",
eiwConstructor: func() *entities.EntityInfoWrapper {
eiw := entities.NewEntityInfoWrapper()
eiw.WithArtifact(&minderv1.Artifact{
Owner: "stacklok",
Name: "minder",
Type: "container",
})
return eiw
},
exprs: []*minderv1.Profile_Selector{
{
Entity: minderv1.ArtifactEntity.String(),
Selector: "artifact.type == 'container'",
},
},
selected: true,
},
{
name: "Simple false artifact expression",
eiwConstructor: func() *entities.EntityInfoWrapper {
eiw := entities.NewEntityInfoWrapper()
eiw.WithArtifact(&minderv1.Artifact{
Owner: "stacklok",
Name: "minder",
Type: "container",
})
return eiw
},
exprs: []*minderv1.Profile_Selector{
{
Entity: minderv1.ArtifactEntity.String(),
Selector: "artifact.type != 'container'",
},
},
selected: false,
},
{
name: "Simple false repository expression",
eiwConstructor: func() *entities.EntityInfoWrapper {
eiw := entities.NewEntityInfoWrapper()
eiw.WithRepository(&minderv1.Repository{
Owner: "stacklok",
Name: "minder",
IsPrivate: false,
IsFork: false,
})
return eiw
},
exprs: []*minderv1.Profile_Selector{
{
Entity: minderv1.RepositoryEntity.String(),
Selector: "entity.name != 'stacklok/minder'",
},
},
selected: false,
},
}
for _, scenario := range scenarios {
t.Run(scenario.name, func(t *testing.T) {
t.Parallel()

env, err := NewEnv()
require.NoError(t, err)

eiw := scenario.eiwConstructor()

sels, err := env.NewSelectionFromProfile(eiw.Type, scenario.exprs)
if scenario.expectedErr != "" {
require.Error(t, err)
require.Contains(t, err.Error(), scenario.expectedErr)
return
}

require.NoError(t, err)
require.NotNil(t, sels)

selected, err := sels.SelectEiw(eiw)
require.NoError(t, err)
require.Equal(t, scenario.selected, selected)
})
}
}
Loading

0 comments on commit 35e207a

Please sign in to comment.