diff --git a/rego/rego.go b/rego/rego.go index a4ab65182f..0e7c63ef4d 100644 --- a/rego/rego.go +++ b/rego/rego.go @@ -1494,7 +1494,7 @@ func (r *Rego) compileModules(ctx context.Context, txn storage.Transaction, m me Ctx: ctx, Store: r.store, Txn: txn, - Compiler: r.compiler.WithPathConflictsCheck(storage.NonEmpty(ctx, r.store, txn)), + Compiler: r.compilerForTxn(ctx, r.store, txn), Metrics: m, Bundles: r.bundles, ExtraModules: r.parsedModules, @@ -1717,7 +1717,7 @@ func (r *Rego) partialResult(ctx context.Context, pCfg *PrepareConfig) (PartialR } r.metrics.Timer(metrics.RegoModuleCompile).Start() - r.compiler.Compile(r.compiler.Modules) + r.compilerForTxn(ctx, r.store, r.txn).Compile(r.compiler.Modules) r.metrics.Timer(metrics.RegoModuleCompile).Stop() if r.compiler.Failed() { @@ -1947,6 +1947,12 @@ func (r *Rego) getTxn(ctx context.Context) (storage.Transaction, transactionClos return txn, closer, nil } +func (r *Rego) compilerForTxn(ctx context.Context, store storage.Store, txn storage.Transaction) *ast.Compiler { + // Update the compiler to have a valid path conflict check + // for the current context and transaction. + return r.compiler.WithPathConflictsCheck(storage.NonEmpty(ctx, store, txn)) +} + func isTermVar(v ast.Var) bool { return strings.HasPrefix(string(v), ast.WildcardPrefix+"term") } diff --git a/rego/rego_test.go b/rego/rego_test.go index 83ca06146e..33dc67dc8a 100644 --- a/rego/rego_test.go +++ b/rego/rego_test.go @@ -1035,6 +1035,38 @@ func TestPreparedPartialResultWithTracer(t *testing.T) { } } +func TestPartialResultSetsValidConflictChecker(t *testing.T) { + mod := ` + package test + p { + true + } + ` + + c := ast.NewCompiler().WithPathConflictsCheck(func(_ []string) (bool, error) { + t.Fatal("Conflict check should not have been called") + return false, nil + }) + + r := New( + Query("data.test.p"), + Module("test.rego", mod), + PartialNamespace("test_ns1"), + Compiler(c), + ) + + ctx := context.Background() + pr, err := r.PartialResult(ctx) + + if err != nil { + t.Fatalf("unexpected error from Rego.PartialResult(): %s", err.Error()) + } + + r2 := pr.Rego() + + assertEval(t, r2, "[[true]]") +} + func TestMissingLocation(t *testing.T) { // Create a query programmatically and evaluate it. The Location information diff --git a/server/server_test.go b/server/server_test.go index 4141e23fbf..185baa161d 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -3527,6 +3527,53 @@ func TestServerReloadTrigger(t *testing.T) { } } +func TestServerClearsCompilerConflictCheck(t *testing.T) { + f := newFixture(t) + store := f.server.store + ctx := context.Background() + + // Make a new transaction + params := storage.WriteParams + params.Context = storage.NewContext() + txn := storage.NewTransactionOrDie(ctx, store, params) + + // Fresh compiler we will swap on the manager + c := ast.NewCompiler() + + // Add the policy we want to use + c.Compile(map[string]*ast.Module{"test": ast.MustParseModule("package test\np=1")}) + if len(c.Errors) > 0 { + t.Fatalf("Unexpected compile errors: %v", c.Errors) + } + + // Add in a "bad" conflict check + c = c.WithPathConflictsCheck(func(_ []string) (bool, error) { + t.Fatal("Conflict check should not have been called") + return false, nil + }) + + // Set the compiler on the transaction context and commit to trigger listeners + plugins.SetCompilerOnContext(params.Context, c) + + if err := store.UpsertPolicy(ctx, txn, "test", []byte("package test\np = 1")); err != nil { + panic(err) + } + if err := store.Commit(ctx, txn); err != nil { + panic(err) + } + + // internal helpers should now give the new compiler back + if f.server.getCompiler() != c { + t.Fatalf("Expected to get the updated compiler") + } + + // If we request for partial evaluation it will end up using the compiler set from the manager. Ensure it + // is using a correct conflict checker. + if err := f.v1(http.MethodGet, "/data/test?partial", "", 200, `{"result": {"p": 1}}`); err != nil { + t.Fatalf("Unexpected error from server: %v", err) + } +} + type queryBindingErrStore struct { storage.WritesNotSupported storage.PolicyNotSupported