Skip to content

[bug] OverridePathInMap panics with "index out of range" when an override path indexes an array out of bounds #202

Description

@Abhishek9639

Describe the bug

framework.OverridePathInMap panics instead of returning an error when a dotted override path indexes into an array with a bad index and the path continues past that index.

The bounds checks in overridePathInArray only exist in the len(path) == 1 branch. When there are more path elements after the array index, it falls through to the type switch at framework/override_utils.go:148, which does output[pathIndex] with no check. Anything out of range panics. Negative indexes too, so -1 (which means "append" in the terminal case) also panics when something comes after it in the path.

This is reachable from user input. score-compose, score-k8s, score-helm and score-radius all pass --override-property values straight into this function, so a typo'd index crashes the CLI with a Go stack trace instead of the usual --override-property '...' could not be applied: ... message.

To Reproduce

At the library level, against main:

input := map[string]interface{}{
	"volumes": []interface{}{
		map[string]interface{}{"source": "a"},
	},
}

// index 3 is out of range and the path continues after it
_, _ = framework.OverridePathInMap(input, framework.ParseDotPathParts("volumes.3.source"), false, "x")
// panic: runtime error: index out of range [3] with length 1

// -1 followed by a nested path
_, _ = framework.OverridePathInMap(input, framework.ParseDotPathParts("volumes.-1.source"), false, "x")
// panic: runtime error: index out of range [-1]

Or end to end with score-compose 0.41.0 (pins score-go v1.18.0), using any workload that has one volume:

$ score-compose generate score.yaml --override-property 'containers.main.volumes.3.source="foo"'
INFO: Overriding 'containers.main.volumes.3.source' in workload
panic: runtime error: index out of range [3] with length 1

goroutine 1 [running]:
github.com/score-spec/score-go/framework.overridePathInArray(...)
        .../score-go@v1.18.0/framework/override_utils.go:148 +0x850
github.com/score-spec/score-go/framework.overridePathInMap(...)
        .../score-go@v1.18.0/framework/override_utils.go:108 +0x30c
github.com/score-spec/score-compose/internal/command.parseAndApplyOverrideProperty(...)
        .../internal/command/generate.go:523

The terminal versions of the same paths behave correctly: volumes.3 returns cannot set '3' in array: out of range and volumes.-1 appends. Only the nested case is unchecked.

Expected behavior

An error return, same as the terminal branch gives: cannot set '3' in array: out of range. The CLIs already wrap errors from this function in a friendly message; the panic bypasses all of that.

Screenshots

n/a, terminal output above.

Desktop (please complete the following information):

  • OS: macOS (arm64), though nothing here is platform specific
  • Version: score-go v1.18.0 and current main (f894f40), observed through score-compose 0.41.0

Additional context

The fix looks small: a bounds check in overridePathInArray before the type switch, mirroring the error the terminal branch already produces.

if pathIndex < 0 || pathIndex >= len(output) {
	return nil, fmt.Errorf("cannot set '%d' in array: out of range", pathIndex)
}
switch typed := output[pathIndex].(type) {

-1 with a nested path could arguably mean "append a new object and keep going", but returning an error seems safer and keeps the behavior consistent. Happy to open a PR with the fix plus regression tests for both cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions