Skip to content

Commit

Permalink
fix: properly validate max index
Browse files Browse the repository at this point in the history
Signed-off-by: Philippe Scorsolini <p.scorsolini@gmail.com>
(cherry picked from commit 0aac4ba)
  • Loading branch information
phisco committed Mar 9, 2023
1 parent 7b5d269 commit 547289b
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 16 deletions.
39 changes: 30 additions & 9 deletions pkg/fieldpath/paved.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ type Paved struct {
maxFieldPathIndex uint
}

// PavedOption can be used to configure a Paved behavior.
type PavedOption func(paved *Paved)

// PaveObject paves a runtime.Object, making it possible to get and set values
Expand Down Expand Up @@ -362,13 +363,13 @@ func (p *Paved) setValue(s Segments, value interface{}) error {
// interface{} per https://golang.org/pkg/encoding/json/#Unmarshal. We
// marshal our value to JSON and unmarshal it into an interface{} to ensure
// it meets these criteria before setting it within p.object.
var v interface{}
j, err := json.Marshal(value)
v, err := toValidJSON(value)
if err != nil {
return errors.Wrap(err, "cannot marshal value to JSON")
return err
}
if err := json.Unmarshal(j, &v); err != nil {
return errors.Wrap(err, "cannot unmarshal value from JSON")

if err := p.validateSegments(s); err != nil {
return err
}

var in interface{} = p.object
Expand All @@ -382,10 +383,6 @@ func (p *Paved) setValue(s Segments, value interface{}) error {
return errors.Errorf("%s is not an array", s[:i])
}

if p.maxFieldPathIndexEnabled() && current.Index > p.maxFieldPathIndex {
return errors.Errorf("index %d is greater than max allowed index %d", current.Index, p.maxFieldPathIndex)
}

if final {
array[current.Index] = v
return nil
Expand Down Expand Up @@ -413,6 +410,18 @@ func (p *Paved) setValue(s Segments, value interface{}) error {
return nil
}

func toValidJSON(value interface{}) (interface{}, error) {
var v interface{}
j, err := json.Marshal(value)
if err != nil {
return nil, errors.Wrap(err, "cannot marshal value to JSON")
}
if err := json.Unmarshal(j, &v); err != nil {
return nil, errors.Wrap(err, "cannot unmarshal value from JSON")
}
return v, nil
}

func prepareElement(array []interface{}, current, next Segment) {
// If this segment is not the final one and doesn't exist we need to
// create it for our next segment.
Expand Down Expand Up @@ -484,6 +493,18 @@ func (p *Paved) SetValue(path string, value interface{}) error {
return p.setValue(segments, value)
}

func (p *Paved) validateSegments(s Segments) error {
if !p.maxFieldPathIndexEnabled() {
return nil
}
for _, segment := range s {
if segment.Type == SegmentIndex && segment.Index > p.maxFieldPathIndex {
return errors.Errorf("index %v is greater than max allowed index %d", segment.Index, p.maxFieldPathIndex)
}
}
return nil
}

// SetString value at the supplied field path.
func (p *Paved) SetString(path, value string) error {
return p.SetValue(path, value)
Expand Down
14 changes: 7 additions & 7 deletions pkg/fieldpath/paved_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -743,30 +743,30 @@ func TestSetValue(t *testing.T) {
reason: "Paths having indexes above the maximum default value are rejected",
data: []byte(`{"data":["a"]}`),
args: args{
path: fmt.Sprintf("data[%v]", MaxFieldPathIndex+1),
path: fmt.Sprintf("data[%v]", DefaultMaxFieldPathIndex+1),
value: "c",
},
want: want{
object: map[string]interface{}{
"data": []interface{}{"a"}},
err: errors.Wrap(errors.Errorf("found index above max (%[1]v > %[2]v): data[%[1]v]",
MaxFieldPathIndex+1, MaxFieldPathIndex), "invalid segments"),
err: errors.Errorf("index %v is greater than max allowed index %v",
DefaultMaxFieldPathIndex+1, DefaultMaxFieldPathIndex),
},
},
"NotRejectsHighIndexesIfNoDefaultOptions": {
reason: "Paths having indexes above the maximum default value are not rejected if default disabled",
data: []byte(`{"data":["a"]}`),
args: args{
path: fmt.Sprintf("data[%v]", MaxFieldPathIndex+1),
path: fmt.Sprintf("data[%v]", DefaultMaxFieldPathIndex+1),
value: "c",
opts: []PavedOption{},
opts: []PavedOption{WithMaxFieldPathIndex(0)},
},
want: want{
object: map[string]interface{}{
"data": func() []interface{} {
res := make([]interface{}, MaxFieldPathIndex+2)
res := make([]interface{}, DefaultMaxFieldPathIndex+2)
res[0] = "a"
res[MaxFieldPathIndex+1] = "c"
res[DefaultMaxFieldPathIndex+1] = "c"
return res
}()},
},
Expand Down

0 comments on commit 547289b

Please sign in to comment.