Skip to content

Commit

Permalink
ast: allow passing in []string, not only []interface{}
Browse files Browse the repository at this point in the history
With this, where before we've gotten

    ast: illegal value: []string

and had worked around it by converting all our []string inputs to
[]interface{}, it now would work to pass in the []string values as-is.

This adds a roundtrip through the JSON encoding to both the rego.Input,
and the inmem store's Write.

Signed-off-by: Stephan Renatus <[email protected]>
  • Loading branch information
srenatus authored and tsandall committed Mar 13, 2018
1 parent 39cc4ef commit 5b07711
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 0 deletions.
6 changes: 6 additions & 0 deletions rego/rego.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/open-policy-agent/opa/storage"
"github.com/open-policy-agent/opa/storage/inmem"
"github.com/open-policy-agent/opa/topdown"
"github.com/open-policy-agent/opa/util"
)

const defaultPartialNamespace = "partial"
Expand Down Expand Up @@ -462,6 +463,11 @@ func (r *Rego) compileQuery(extras []extraStage, query ast.Body) (ast.QueryCompi
var input ast.Value

if r.rawInput != nil {
// roundtrip through json: this turns slices (e.g. []string, []bool) into
// []interface{}, the only array type ast.InterfaceToValue can work with
if err := util.RoundTrip(r.rawInput); err != nil {
return nil, nil, err
}
val, err := ast.InterfaceToValue(*r.rawInput)
if err != nil {
return nil, nil, err
Expand Down
3 changes: 3 additions & 0 deletions storage/inmem/inmem.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ func (db *store) Read(ctx context.Context, txn storage.Transaction, path storage

func (db *store) Write(ctx context.Context, txn storage.Transaction, op storage.PatchOp, path storage.Path, value interface{}) error {
underlying := txn.(*transaction)
if err := util.RoundTrip(&value); err != nil {
return err
}
return underlying.Write(op, path, value)
}

Expand Down
13 changes: 13 additions & 0 deletions util/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,16 @@ func MustMarshalJSON(x interface{}) []byte {
}
return bs
}

// RoundTrip encodes to JSON, and decodes the result again.
//
// Thereby, it is converting its argument to the representation expected by
// rego.Input and inmem's Write operations. Works with both references and
// values.
func RoundTrip(x *interface{}) error {
bs, err := json.Marshal(x)
if err != nil {
return err
}
return json.Unmarshal(bs, x)
}
48 changes: 48 additions & 0 deletions util/json_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2018 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 util_test

import (
"encoding/json"
"fmt"
"testing"

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

func TestRoundTrip(t *testing.T) {
cases := []interface{}{
nil,
1,
1.1,
false,
[]int{1},
[]bool{true},
[]string{"foo"},
map[string]string{"foo": "bar"},
struct {
F string `json:"foo"`
B int `json:"bar"`
}{"x", 32},
map[string][]int{
"ones": {1, 1, 1},
},
}
for _, tc := range cases {
t.Run(fmt.Sprintf("input %v", tc), func(t *testing.T) {
err := util.RoundTrip(&tc)
if err != nil {
t.Errorf("expected error=nil, got %s", err.Error())
}
switch x := tc.(type) {
// These are the output types we want, nothing else
case nil, bool, json.Number, int64, float64, int, string, []interface{},
[]string, map[string]interface{}, map[string]string:
default:
t.Error("unexpected type %T", x)
}
})
}
}

0 comments on commit 5b07711

Please sign in to comment.