Skip to content

Commit

Permalink
opa build -t wasm|plan: fail on unmatched entrypoints
Browse files Browse the repository at this point in the history
Fixes #3957

Signed-off-by: Anders Eknert <anders@eknert.com>
  • Loading branch information
anderseknert committed Sep 7, 2022
1 parent 15412b1 commit b5cbbb5
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
4 changes: 2 additions & 2 deletions ast/builtins.go
Expand Up @@ -941,8 +941,8 @@ var RegexFind = &Builtin{
// GlobsMatch takes two strings regexp-style strings and evaluates to true if their
// intersection matches a non-empty set of non-empty strings.
// Examples:
// - "a.a." and ".b.b" -> true.
// - "[a-z]*" and [0-9]+" -> not true.
// - "a.a." and ".b.b" -> true.
// - "[a-z]*" and [0-9]+" -> not true.
var GlobsMatch = &Builtin{
Name: "regex.globs_match",
Description: `Checks if the intersection of two glob-style regular expressions matches a non-empty set of non-empty strings.
Expand Down
14 changes: 12 additions & 2 deletions compile/compile.go
Expand Up @@ -418,7 +418,7 @@ func (c *Compiler) optimize(ctx context.Context) error {
return nil
}

func (c *Compiler) compilePlan(ctx context.Context) error {
func (c *Compiler) compilePlan(context.Context) error {

// Lazily compile the modules if needed. If optimizations were run, the
// AST compiler will not be set because the default target does not require it.
Expand Down Expand Up @@ -464,6 +464,7 @@ func (c *Compiler) compilePlan(ctx context.Context) error {
// Create query sets for each of the entrypoints.
resultSym := ast.NewTerm(resultVar)
queries := make([]planner.QuerySet, len(c.entrypointrefs))
var unmappedEntrypoints []string

for i := range c.entrypointrefs {

Expand All @@ -474,13 +475,22 @@ func (c *Compiler) compilePlan(ctx context.Context) error {
return err
}

if len(c.compiler.GetRules(c.entrypointrefs[i].Value.(ast.Ref))) == 0 {
unmappedEntrypoints = append(unmappedEntrypoints, c.entrypoints[i])
}

queries[i] = planner.QuerySet{
Name: c.entrypoints[i],
Queries: []ast.Body{compiled},
RewrittenVars: qc.RewrittenVars(),
}
}

if len(unmappedEntrypoints) > 0 {
return fmt.Errorf("entrypoint %q does not refer to a rule or policy decision", unmappedEntrypoints[0])

}

// Prepare modules and builtins for the planner.
modules := []*ast.Module{}
for _, module := range c.compiler.Modules {
Expand All @@ -503,7 +513,7 @@ func (c *Compiler) compilePlan(ctx context.Context) error {
return err
}

// dump policy IR (if "debug" wasn't requested, debug.Witer will discard it)
// dump policy IR (if "debug" wasn't requested, debug.Writer will discard it)
err = ir.Pretty(c.debug.Writer(), policy)
if err != nil {
return err
Expand Down
40 changes: 40 additions & 0 deletions compile/compile_test.go
Expand Up @@ -55,6 +55,11 @@ func TestCompilerInitErrors(t *testing.T) {
c: New().WithTarget("wasm"),
want: errors.New("wasm compilation requires at least one entrypoint"),
},
{
note: "plan compilation requires at least one entrypoint",
c: New().WithTarget("plan"),
want: errors.New("plan compilation requires at least one entrypoint"),
},
}

for _, tc := range tests {
Expand Down Expand Up @@ -781,6 +786,41 @@ func TestCompilerPlanTargetPruneUnused(t *testing.T) {
})
}

func TestCompilerPlanTargetUnmatchedEntrypoints(t *testing.T) {
files := map[string]string{
"test.rego": `package test
p := 7
q := p + 1`,
}

test.WithTempFS(files, func(root string) {

compiler := New().WithPaths(root).WithTarget("plan").WithEntrypoints("test/p", "test/q", "test/no")
err := compiler.Build(context.Background())
if err == nil {
t.Error("expected error from unmatched entrypoint")
}
expectError := "entrypoint \"test/no\" does not refer to a rule or policy decision"
if err.Error() != expectError {
t.Errorf("expected error %s, got: %s", expectError, err.Error())
}
})

test.WithTempFS(files, func(root string) {

compiler := New().WithPaths(root).WithTarget("plan").WithEntrypoints("foo", "foo.bar", "test/no")
err := compiler.Build(context.Background())
if err == nil {
t.Error("expected error from unmatched entrypoints")
}
expectError := "entrypoint \"foo\" does not refer to a rule or policy decision"
if err.Error() != expectError {
t.Errorf("expected error %s, got: %s", expectError, err.Error())
}
})
}

func TestCompilerSetRevision(t *testing.T) {
files := map[string]string{
"test.rego": `package test
Expand Down

0 comments on commit b5cbbb5

Please sign in to comment.