From b829ec639cf080ed29414ba976cc6d0cf346d66c Mon Sep 17 00:00:00 2001 From: Anders Eknert Date: Fri, 2 Sep 2022 13:42:21 +0200 Subject: [PATCH] opa build -t wasm|plan: fail on unmatched entrypoints Fixes #3957 Signed-off-by: Anders Eknert --- ast/builtins.go | 4 ++-- compile/compile.go | 14 ++++++++++++-- compile/compile_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/ast/builtins.go b/ast/builtins.go index e493b57cc8..c24ecc6a43 100644 --- a/ast/builtins.go +++ b/ast/builtins.go @@ -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. diff --git a/compile/compile.go b/compile/compile.go index dabe3314e2..7e8825d0bf 100644 --- a/compile/compile.go +++ b/compile/compile.go @@ -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. @@ -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 { @@ -474,6 +475,10 @@ 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}, @@ -481,6 +486,11 @@ func (c *Compiler) compilePlan(ctx context.Context) error { } } + 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 { @@ -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 diff --git a/compile/compile_test.go b/compile/compile_test.go index b1387035eb..303ee6c4c1 100644 --- a/compile/compile_test.go +++ b/compile/compile_test.go @@ -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 { @@ -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