Skip to content

Commit

Permalink
Include term locations in rule heads when requested (open-policy-agen…
Browse files Browse the repository at this point in the history
…t#6943)

When the JSON option to include term locations have been set, they should be
included in all parts of the head where terms appear.

Fixes open-policy-agent#6860

Signed-off-by: Anders Eknert <[email protected]>
  • Loading branch information
anderseknert authored Aug 20, 2024
1 parent 291825e commit 25f4cb6
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
36 changes: 36 additions & 0 deletions ast/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,42 @@ func TestHead_MarshalJSON(t *testing.T) {
}
}

func TestRuleHeadRefWithTermLocations_MarshalJSON(t *testing.T) {
policy := `package test
import rego.v1
ref.head[rule].test contains "value" if {
rule := "rule"
}`

jsonOptions := &astJSON.Options{
MarshalOptions: astJSON.MarshalOptions{
IncludeLocation: astJSON.NodeToggle{
Head: true,
Term: true,
},
},
}

module, err := ParseModuleWithOpts("test.rego", policy, ParserOptions{JSONOptions: jsonOptions})
if err != nil {
t.Fatal(err)
}

bs, err := json.Marshal(module.Rules[0].Head)
if err != nil {
t.Fatal(err)
}

// Ensure marshalled JSON includes location for any term
expectedJSON := `{"key":{"location":{"file":"test.rego","row":5,"col":30},"type":"string","value":"value"},"ref":[{"location":{"file":"test.rego","row":5,"col":1},"type":"var","value":"ref"},{"location":{"file":"test.rego","row":5,"col":5},"type":"string","value":"head"},{"location":{"file":"test.rego","row":5,"col":10},"type":"var","value":"rule"},{"location":{"file":"test.rego","row":5,"col":16},"type":"string","value":"test"}],"location":{"file":"test.rego","row":5,"col":1}}`

if string(bs) != expectedJSON {
t.Errorf("expected %s but got %s", expectedJSON, string(bs))
}
}

func TestExpr_MarshalJSON(t *testing.T) {
rawModule := `
package foo
Expand Down
10 changes: 8 additions & 2 deletions ast/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -1034,16 +1034,22 @@ func (head *Head) setJSONOptions(opts astJSON.Options) {

func (head *Head) MarshalJSON() ([]byte, error) {
var loc *Location
if head.jsonOptions.MarshalOptions.IncludeLocation.Head {
includeLoc := head.jsonOptions.MarshalOptions.IncludeLocation
if includeLoc.Head {
if head.Location != nil {
loc = head.Location
}

for _, term := range head.Reference {
if term.Location != nil {
term.jsonOptions.MarshalOptions.IncludeLocation.Term = includeLoc.Term
}
}
}

// NOTE(sr): we do this to override the rendering of `head.Reference`.
// It's still what'll be used via the default means of encoding/json
// for unmarshaling a json object into a Head struct!
// NOTE(charlieegan3): we also need to optionally include the location
type h Head
return json.Marshal(struct {
h
Expand Down

0 comments on commit 25f4cb6

Please sign in to comment.