mirror of
https://github.com/github/spec-kit.git
synced 2026-08-15 14:02:04 +02:00
fix(extensions): reject duplicate provides.templates/scripts names (#4016)
The resolver returns the first entry matching a declared name, so a later duplicate within provides.templates or provides.scripts was silently unreachable while still counted by ExtensionManifest properties. Reject duplicates at manifest-validation time instead. Also clarify EXTENSION-DEVELOPMENT-GUIDE.md's provides section: hooks and events are top-level manifest fields, not provides sub-fields, so the "at least one of ..." wording doesn't imply they can be nested under provides.
This commit is contained in:
@@ -1162,6 +1162,29 @@ class TestExtensionManifestTemplatesAndScripts:
|
||||
with pytest.raises(ValidationError, match="must be lowercase alphanumeric with hyphens only"):
|
||||
ExtensionManifest(manifest_path)
|
||||
|
||||
@pytest.mark.parametrize("section", ["templates", "scripts"])
|
||||
def test_provides_entry_duplicate_name_rejected(self, temp_dir, valid_manifest_data, section):
|
||||
"""Two entries in the same section sharing a name are rejected.
|
||||
|
||||
The resolver (PresetResolver._extension_manifest_declared_template)
|
||||
returns the first entry matching a name, so a later duplicate would
|
||||
be silently unreachable while still counted by ExtensionManifest
|
||||
properties -- reject it up front instead.
|
||||
"""
|
||||
import yaml
|
||||
|
||||
valid_manifest_data["provides"][section] = [
|
||||
{"name": "dup", "file": f"{section}/a.txt"},
|
||||
{"name": "dup", "file": f"{section}/b.txt"},
|
||||
]
|
||||
|
||||
manifest_path = temp_dir / "extension.yml"
|
||||
with open(manifest_path, 'w', encoding="utf-8") as f:
|
||||
yaml.dump(valid_manifest_data, f)
|
||||
|
||||
with pytest.raises(ValidationError, match=f"Duplicate .* name 'dup' in 'provides.{section}'"):
|
||||
ExtensionManifest(manifest_path)
|
||||
|
||||
@pytest.mark.parametrize("section", ["templates", "scripts"])
|
||||
def test_provides_entry_path_traversal_rejected(self, temp_dir, valid_manifest_data, section):
|
||||
"""The 'file' field is checked with the same path-safety policy as commands."""
|
||||
|
||||
Reference in New Issue
Block a user