ir: Fix nil pointer deref in Unmarshal() when handling IsSetStmt (#7430)

Fixes: #7415

Signed-off-by: Kris Kennaway <kris.kennaway@datadoghq.com>
This commit is contained in:
Kris Kennaway
2025-03-11 18:07:50 +00:00
committed by GitHub
parent f6c20b0a46
commit 8ff85cbc34
2 changed files with 86 additions and 53 deletions
+74 -51
View File
@@ -11,62 +11,85 @@ import (
)
func TestRoundTrip(t *testing.T) {
// Note: v1 module
c, err := ast.CompileModules(map[string]string{
"test.rego": `
package test
p if {
input.foo == 7
}
`,
})
if err != nil {
t.Fatal(err)
}
modules := []*ast.Module{}
for _, m := range c.Modules {
modules = append(modules, m)
}
planner := planner.New().
WithQueries([]planner.QuerySet{
{
Name: "main",
Queries: []ast.Body{
ast.MustParseBody("data.test.p = true"),
},
tests := []struct {
note string
modules map[string]string
}{
{
note: "simple",
modules: map[string]string{
"test.rego": `
package test
p if {
input.foo == 7
}
`,
},
}).
WithModules(modules).
WithBuiltinDecls(ast.BuiltinMap)
plan, err := planner.Plan()
if err != nil {
t.Fatal(err)
},
{
note: "every",
modules: map[string]string{
"test.rego": `
package test
p if {
every i in input.foo { i > 0 }
}
`,
},
},
}
bs, err := json.MarshalIndent(plan, "", " ")
if err != nil {
t.Fatal(err)
}
for _, tc := range tests {
t.Run(tc.note, func(t *testing.T) {
// Note: v1 module
c, err := ast.CompileModules(tc.modules)
var cpy ir.Policy
err = json.Unmarshal(bs, &cpy)
if err != nil {
t.Fatal(err)
}
if err != nil {
t.Fatal(err)
}
bs2, err := json.MarshalIndent(plan, "", " ")
if err != nil {
t.Fatal(err)
}
modules := []*ast.Module{}
if !bytes.Equal(bs, bs2) {
t.Fatal("expected bytes to be equal")
for _, m := range c.Modules {
modules = append(modules, m)
}
planner := planner.New().
WithQueries([]planner.QuerySet{
{
Name: "main",
Queries: []ast.Body{
ast.MustParseBody("data.test.p = true"),
},
},
}).
WithModules(modules).
WithBuiltinDecls(ast.BuiltinMap)
plan, err := planner.Plan()
if err != nil {
t.Fatal(err)
}
bs, err := json.MarshalIndent(plan, "", " ")
if err != nil {
t.Fatal(err)
}
var cpy ir.Policy
err = json.Unmarshal(bs, &cpy)
if err != nil {
t.Fatal(err)
}
bs2, err := json.MarshalIndent(plan, "", " ")
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(bs, bs2) {
t.Fatal("expected bytes to be equal")
}
})
}
}
+12 -2
View File
@@ -6,6 +6,7 @@ package ir
import (
"encoding/json"
"fmt"
"reflect"
)
@@ -50,7 +51,11 @@ func (a *Operand) UnmarshalJSON(bs []byte) error {
if err := json.Unmarshal(bs, &typed); err != nil {
return err
}
x := valFactories[typed.Type]()
f, ok := valFactories[typed.Type]
if !ok {
return fmt.Errorf("unrecognized value type %q", typed.Type)
}
x := f()
if err := json.Unmarshal(typed.Value, &x); err != nil {
return err
}
@@ -77,7 +82,11 @@ type rawTypedStmt struct {
}
func (raw rawTypedStmt) Unmarshal() (Stmt, error) {
x := stmtFactories[raw.Type]()
f, ok := stmtFactories[raw.Type]
if !ok {
return nil, fmt.Errorf("unrecognized statement type %q", raw.Type)
}
x := f()
if err := json.Unmarshal(raw.Stmt, &x); err != nil {
return nil, err
}
@@ -119,6 +128,7 @@ var stmtFactories = map[string]func() Stmt{
"IsArrayStmt": func() Stmt { return &IsArrayStmt{} },
"IsObjectStmt": func() Stmt { return &IsObjectStmt{} },
"IsDefinedStmt": func() Stmt { return &IsDefinedStmt{} },
"IsSetStmt": func() Stmt { return &IsSetStmt{} },
"IsUndefinedStmt": func() Stmt { return &IsUndefinedStmt{} },
"ArrayAppendStmt": func() Stmt { return &ArrayAppendStmt{} },
"ObjectInsertStmt": func() Stmt { return &ObjectInsertStmt{} },