Skip to content

Commit 6577859

Browse files
marcelsafinCopilot
andcommitted
fix: reject duplicate bundle components
Assisted-by: GitHub Copilot (model: gpt-5.6-sol, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 072ab33 commit 6577859

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

‎src/specify_cli/bundler/models/manifest.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,17 @@ def structural_errors(self) -> list[str]:
192192
"(lowercase letters, digits, '.', '_', '-'; no path separators)."
193193
)
194194

195+
seen_components: set[tuple[str, str]] = set()
195196
for ref in self.components:
196197
if not ref.id:
197198
errors.append(f"A {ref.kind[:-1]} entry is missing its 'id'.")
199+
key = (ref.kind, ref.id)
200+
if ref.id and key in seen_components:
201+
errors.append(
202+
f"Duplicate {ref.kind[:-1]} '{ref.id}' in "
203+
f"'provides.{ref.kind}'."
204+
)
205+
seen_components.add(key)
198206
if ref.kind != "steps" and not ref.version:
199207
errors.append(
200208
f"{ref.kind[:-1]} '{ref.id or '<unknown>'}' must be pinned to a 'version'."

‎tests/contract/test_manifest_schema.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,20 @@ def test_components_property_orders_by_kind():
127127
assert kinds == ["extensions", "presets", "steps", "workflows"]
128128

129129

130+
def test_duplicate_component_in_same_kind_is_rejected():
131+
data = valid_manifest_dict()
132+
data["provides"]["extensions"].append(
133+
{"id": "ext-a", "version": "9.9.9"}
134+
)
135+
136+
errors = BundleManifest.from_dict(data).structural_errors()
137+
138+
assert any(
139+
"duplicate extension 'ext-a'" in error.lower()
140+
for error in errors
141+
)
142+
143+
130144
def test_string_tags_rejected_not_split_per_character():
131145
# A bare string would otherwise be iterated character-by-character; the
132146
# schema requires a list of strings.

0 commit comments

Comments
 (0)