Skip to content

Commit 9faa17f

Browse files
committed
🐛 fix(manifest): reject duplicate fields in command example entries
- Track seen keys during manifest parsing to detect duplicate keys - Return explicit error instead of silently overwriting earlier values - Add test coverage for duplicate field rejection
1 parent 9dd2249 commit 9faa17f

3 files changed

Lines changed: 26 additions & 0 deletions

File tree

docs/go/maintainer/development-tracker.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ Immediate next tasks:
151151

152152
### 2026-03-18 Session Update
153153

154+
- Completed: Tightened command-example manifest parsing to reject duplicate fields inside one entry instead of silently letting a later value overwrite an earlier one. Parser tests now cover duplicate-key rejection alongside missing metadata and malformed tag lists, which makes hand-edited catalog drift easier to catch before it reaches the embedded binary.
155+
- In progress: none.
156+
- Blockers: none.
157+
- Next step: keep chipping away at ambiguous or silent-fallback cases in the operator catalog path rather than adding more surface area.
158+
159+
### 2026-03-18 Session Update
160+
154161
- Completed: Tightened command-example manifest parsing so each entry must now carry non-empty `tags` and `summary` metadata, not just the required command/name/format/path fields. Parser coverage now explicitly rejects missing metadata alongside malformed or empty tag lists, so the embedded example catalog contract is enforced at parse time instead of only by higher-level tests.
155162
- In progress: none.
156163
- Blockers: none.

internal/app/command_example_manifest.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,16 @@ func parseCommandExampleManifestEntry(line string) (commandExampleManifestEntry,
167167
return commandExampleManifestEntry{}, err
168168
}
169169
entry := commandExampleManifestEntry{}
170+
seenKeys := make(map[string]struct{}, len(fields))
170171
for _, field := range fields {
171172
key, value, ok := strings.Cut(field, "=")
172173
if !ok {
173174
return commandExampleManifestEntry{}, fmt.Errorf("invalid command example manifest field %q", field)
174175
}
176+
if _, exists := seenKeys[key]; exists {
177+
return commandExampleManifestEntry{}, fmt.Errorf("duplicate command example manifest field %q in %q", key, line)
178+
}
179+
seenKeys[key] = struct{}{}
175180
if strings.HasPrefix(value, `"`) {
176181
unquoted, err := strconv.Unquote(value)
177182
if err != nil {

internal/app/command_example_manifest_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,20 @@ func TestParseCommandExampleManifestEntryRejectsEmptyTag(t *testing.T) {
5858
}
5959
}
6060

61+
func TestParseCommandExampleManifestEntryRejectsDuplicateField(t *testing.T) {
62+
line := `command=follow-imports example=audit-only-single-text format=text tags="audit-only,single-input" summary="First summary." summary="Second summary." path=testdata/follow-imports-audit-only-single.txt`
63+
64+
_, err := parseCommandExampleManifestEntry(line)
65+
if err == nil {
66+
t.Fatal("expected duplicate field error")
67+
}
68+
for _, fragment := range []string{`duplicate command example manifest field "summary"`, "audit-only-single-text"} {
69+
if !strings.Contains(err.Error(), fragment) {
70+
t.Fatalf("error %q missing fragment %q", err.Error(), fragment)
71+
}
72+
}
73+
}
74+
6175
func TestParseCommandExampleManifestEntryRejectsMissingTags(t *testing.T) {
6276
line := `command=follow-imports example=audit-only-single-text format=text summary="Audit-only follow report." path=testdata/follow-imports-audit-only-single.txt`
6377

0 commit comments

Comments
 (0)