fix(model): reject null/empty YAML mapping keys in ParseBytes
ci / vet, staticcheck, test, build (push) Failing after 2m43s
ci / vet, staticcheck, test, build (push) Failing after 2m43s
A bare '?' in YAML is an explicit-key indicator for a null key, which produced a job with an empty name (p.Jobs[""]) — a parser invariant violation caught by FuzzParseBytes. ParseBytes now returns an error when keyNode.Value is empty. Failing corpus entry retained as a seed so CI exercises this path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ func FuzzParseBytes(f *testing.F) {
|
|||||||
[]byte("job:\n stage: test\n image:\n name: golang:1.21\n entrypoint: ['']\n parallel:\n matrix:\n - PLATFORM: [linux, darwin]\n script: go build\n"),
|
[]byte("job:\n stage: test\n image:\n name: golang:1.21\n entrypoint: ['']\n parallel:\n matrix:\n - PLATFORM: [linux, darwin]\n script: go build\n"),
|
||||||
[]byte("default:\n retry: 2\n timeout: 1h30m\nvariables:\n ENV: production\nstages: [build, test, deploy]\n"),
|
[]byte("default:\n retry: 2\n timeout: 1h30m\nvariables:\n ENV: production\nstages: [build, test, deploy]\n"),
|
||||||
[]byte("&anchor\n script: [echo ok]\njob:\n <<: *anchor\n stage: build\n"),
|
[]byte("&anchor\n script: [echo ok]\njob:\n <<: *anchor\n stage: build\n"),
|
||||||
|
[]byte("?"), // null/empty YAML key — must error, not produce an empty-named job
|
||||||
}
|
}
|
||||||
for _, s := range seeds {
|
for _, s := range seeds {
|
||||||
f.Add(s)
|
f.Add(s)
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ func ParseBytes(data []byte) (*Pipeline, error) {
|
|||||||
keyNode := root.Content[i]
|
keyNode := root.Content[i]
|
||||||
valNode := root.Content[i+1]
|
valNode := root.Content[i+1]
|
||||||
key := keyNode.Value
|
key := keyNode.Value
|
||||||
|
if key == "" {
|
||||||
|
return nil, fmt.Errorf("job name cannot be empty (null or missing YAML key)")
|
||||||
|
}
|
||||||
if ReservedKeys[key] {
|
if ReservedKeys[key] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,12 @@ func TestParseBytes_EdgeCases(t *testing.T) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("wrong field type: expected error from ParseBytes (stage must be string)")
|
t.Error("wrong field type: expected error from ParseBytes (stage must be string)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Null/empty YAML key (e.g. bare "?"): job name cannot be empty.
|
||||||
|
_, err = ParseBytes([]byte("?"))
|
||||||
|
if err == nil {
|
||||||
|
t.Error("null key: expected error from ParseBytes (job name cannot be empty)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestParse_ParseBytesError exercises the Parse → ParseBytes error path (line 18).
|
// TestParse_ParseBytesError exercises the Parse → ParseBytes error path (line 18).
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
[]byte("?")
|
||||||
Reference in New Issue
Block a user