Skip to content

Commit

Permalink
Adding back v0 repl package
Browse files Browse the repository at this point in the history
Signed-off-by: Johan Fylling <[email protected]>
  • Loading branch information
johanfylling committed Nov 28, 2024
1 parent 1318f4b commit fff4204
Show file tree
Hide file tree
Showing 16 changed files with 377 additions and 15 deletions.
2 changes: 2 additions & 0 deletions cmd/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ func dofindDefinition(params findDefinitionParams, stdin io.Reader, stdout io.Wr
}
}

// FindDefinition() will instantiate a new compiler, but we don't need to set the
// default rego-version because the passed modules already have the rego-version from parsing.
result, err := oracle.New().FindDefinition(oracle.DefinitionQuery{
Buffer: bs,
Filename: filename,
Expand Down
5 changes: 4 additions & 1 deletion internal/compiler/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ func VerifyAuthorizationPolicySchema(compiler *ast.Compiler, ref ast.Ref) error
schemaSet := ast.NewSchemaSet()
schemaSet.Put(ast.SchemaRootRef, schemaDefinitions[AuthorizationPolicySchema])

errs := ast.NewCompiler().WithSchemas(schemaSet).PassesTypeCheckRules(rules)
errs := ast.NewCompiler().
WithDefaultRegoVersion(compiler.DefaultRegoVersion()).
WithSchemas(schemaSet).
PassesTypeCheckRules(rules)

if len(errs) > 0 {
return errs
Expand Down
1 change: 1 addition & 0 deletions internal/runtime/init/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func InsertAndCompile(ctx context.Context, opts InsertAndCompileOptions) (*Inser
}

compiler := ast.NewCompiler().
WithDefaultRegoVersion(opts.ParserOptions.RegoVersion).
SetErrorLimit(opts.MaxErrors).
WithPathConflictsCheck(storage.NonEmpty(ctx, opts.Store, opts.Txn)).
WithEnablePrintStatements(opts.EnablePrintStatements)
Expand Down
16 changes: 9 additions & 7 deletions rego/rego.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,13 +578,15 @@ func SetRegoVersion(version ast.RegoVersion) func(r *Rego) {

// New returns a new Rego object.
func New(options ...func(r *Rego)) *Rego {
r := v1.New(options...)

if r.RegoVersion() == ast.RegoUndefined {
SetRegoVersion(ast.DefaultRegoVersion)(r)
}

return r
opts := make([]func(r *Rego), 0, len(options)+1)
opts = append(opts, options...)
opts = append(opts, func(r *Rego) {
if r.RegoVersion() == ast.RegoUndefined {
SetRegoVersion(ast.DefaultRegoVersion)(r)
}
})

return v1.New(opts...)
}

// CompileOption defines a function to set options on Compile calls.
Expand Down
30 changes: 28 additions & 2 deletions rego/rego_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/open-policy-agent/opa/v1/util/test"
)

func TestRegoEvalDefaultRegoVersion(t *testing.T) {
func TestRegoEval_DefaultRegoVersion(t *testing.T) {
tests := []struct {
note string
module string
Expand All @@ -30,7 +30,18 @@ p[x] {
expResult: []string{"a", "b", "c"},
},
{
note: "v0 import rego.v1",
note: "v0, v1 compile-time violations",
module: `package test
import data.foo
import data.bar as foo
p[x] {
x = ["a", "b", "c"][_]
}`,
expResult: []string{"a", "b", "c"},
},
{
note: "import rego.v1",
module: `package test
import rego.v1
Expand All @@ -39,6 +50,21 @@ p contains x if {
}`,
expResult: []string{"a", "b", "c"},
},
{
note: "v0 import rego.v1, v1 compile-time violations",
module: `package test
import rego.v1
import data.foo
import data.bar as foo
p contains x if {
some x in ["a", "b", "c"]
}`,
expErrs: []string{
"test.rego:5: rego_compile_error: import must not shadow import data.foo",
},
},
{
note: "v1", // v1 is NOT the default version
module: `package test
Expand Down
6 changes: 6 additions & 0 deletions repl/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright 2024 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

// Deprecated: Use [github.com/open-policy-agent/opa/v1/repl] instead.
package repl
16 changes: 16 additions & 0 deletions repl/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2016 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package repl

import v1 "github.com/open-policy-agent/opa/v1/repl"

// Error is the error type returned by the REPL.
type Error = v1.Error

const (
// BadArgsErr indicates bad arguments were provided to a built-in REPL
// command.
BadArgsErr string = v1.BadArgsErr
)
26 changes: 26 additions & 0 deletions repl/repl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2016 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

// Package repl implements a Read-Eval-Print-Loop (REPL) for interacting with the policy engine.
//
// The REPL is typically used from the command line, however, it can also be used as a library.
// nolint: goconst // String reuse here doesn't make sense to deduplicate.
package repl

import (
"io"

"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/storage"
v1 "github.com/open-policy-agent/opa/v1/repl"
)

// REPL represents an instance of the interactive shell.
type REPL = v1.REPL

// New returns a new instance of the REPL.
func New(store storage.Store, historyPath string, output io.Writer, outputFormat string, errLimit int, banner string) *REPL {
return v1.New(store, historyPath, output, outputFormat, errLimit, banner).
WithRegoVersion(ast.DefaultRegoVersion)
}
152 changes: 152 additions & 0 deletions repl/repl_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright 2024 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.

package repl

import (
"bytes"
"context"
"strings"
"testing"

"github.com/open-policy-agent/opa/storage"
"github.com/open-policy-agent/opa/storage/inmem"
"github.com/open-policy-agent/opa/util"
)

func TestOneShot_DefaultRegoVersion(t *testing.T) {
type action struct {
line string
expOutput string
expErrs []string
}

tests := []struct {
note string
actions []action
}{
{
note: "v1 keywords used",
actions: []action{
{
line: "a contains 2 if { true }",
expErrs: []string{
"rego_unsafe_var_error: var a is unsafe",
},
},
},
},
{
note: "v1 keywords not used",
actions: []action{
{
line: "a[2] { true }",
expOutput: "Rule 'a' defined in package repl. Type 'show' to see rules.\n",
},
},
},
{
note: "v1 keywords imported",
actions: []action{
{
line: "import future.keywords",
},
{
line: "a contains 2 if { true }",
expOutput: "Rule 'a' defined in package repl. Type 'show' to see rules.\n",
},
},
},
{
note: "rego.v1 imported",
actions: []action{
{
line: "import rego.v1",
},
{
line: "a contains 2 if { true }",
expOutput: "Rule 'a' defined in package repl. Type 'show' to see rules.\n",
},
},
},
{
note: "v1 keywords",
actions: []action{
{
line: "a contains 2 if { true }",
expErrs: []string{
"rego_unsafe_var_error: var a is unsafe",
},
},
},
},
}

for _, tc := range tests {
t.Run(tc.note, func(t *testing.T) {
ctx := context.Background()
store := newTestStore()
var buffer bytes.Buffer
repl := newRepl(store, &buffer)

for _, action := range tc.actions {
err := repl.OneShot(ctx, action.line)

if len(action.expErrs) != 0 {
if err == nil {
t.Fatalf("Expected error but got: %s", buffer.String())
}

for _, e := range action.expErrs {
if !strings.Contains(err.Error(), e) {
t.Fatalf("Expected error to contain:\n\n%q\n\nbut got:\n\n%v", e, err)
}
}
} else {
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
expectOutput(t, buffer.String(), action.expOutput)
}
}
})
}
}

func expectOutput(t *testing.T, output string, expected string) {
t.Helper()
if output != expected {
t.Errorf("Repl output: expected %#v but got %#v", expected, output)
}
}

func newRepl(store storage.Store, buffer *bytes.Buffer) *REPL {
repl := New(store, "", buffer, "", 0, "")
return repl
}

func newTestStore() storage.Store {
input := `
{
"a": [
{
"b": {
"c": [true,2,false]
}
},
{
"b": {
"c": [false,true,1]
}
}
]
}
`
var data map[string]interface{}
err := util.UnmarshalJSON([]byte(input), &data)
if err != nil {
panic(err)
}
return inmem.NewFromObject(data)
}
6 changes: 6 additions & 0 deletions v1/ast/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ type Compiler struct {
defaultRegoVersion RegoVersion
}

func (c *Compiler) DefaultRegoVersion() RegoVersion {
return c.defaultRegoVersion
}

// CompilerStage defines the interface for stages in the compiler.
type CompilerStage func(*Compiler) *Error

Expand Down Expand Up @@ -894,6 +898,8 @@ func (c *Compiler) WithModuleLoader(f ModuleLoader) *Compiler {
return c
}

// WithDefaultRegoVersion sets the default Rego version to use when a module doesn't specify one;
// such as when it's hand-crafted instead of parsed.
func (c *Compiler) WithDefaultRegoVersion(regoVersion RegoVersion) *Compiler {
c.defaultRegoVersion = regoVersion
return c
Expand Down
4 changes: 3 additions & 1 deletion v1/ast/compilehelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ func CompileModulesWithOpt(modules map[string]string, opts CompileOpts) (*Compil
parsed[f] = pm
}

compiler := NewCompiler().WithEnablePrintStatements(opts.EnablePrintStatements)
compiler := NewCompiler().
WithDefaultRegoVersion(opts.ParserOptions.RegoVersion).
WithEnablePrintStatements(opts.EnablePrintStatements)
compiler.Compile(parsed)

if compiler.Failed() {
Expand Down
4 changes: 4 additions & 0 deletions v1/plugins/discovery/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,10 @@ func evaluateBundle(ctx context.Context, id string, info *ast.Term, b *bundleApi

compiler := ast.NewCompiler()

if regoVersion := b.RegoVersion(ast.DefaultRegoVersion); regoVersion != ast.RegoUndefined {
compiler = compiler.WithDefaultRegoVersion(regoVersion)
}

if compiler.Compile(modules); compiler.Failed() {
return nil, compiler.Errors
}
Expand Down
4 changes: 4 additions & 0 deletions v1/rego/rego.go
Original file line number Diff line number Diff line change
Expand Up @@ -1285,6 +1285,10 @@ func New(options ...func(r *Rego)) *Rego {
if r.target == targetWasm {
r.compiler = r.compiler.WithEvalMode(ast.EvalModeIR)
}

if r.regoVersion != ast.RegoUndefined {
r.compiler = r.compiler.WithDefaultRegoVersion(r.regoVersion)
}
}

if r.store == nil {
Expand Down
Loading

0 comments on commit fff4204

Please sign in to comment.