diff --git a/src/specify_cli/presets/__init__.py b/src/specify_cli/presets/__init__.py index de4116228e..8ad397be9f 100644 --- a/src/specify_cli/presets/__init__.py +++ b/src/specify_cli/presets/__init__.py @@ -1709,7 +1709,7 @@ def record_written(written: Dict[str, List[str]]) -> None: ext_manifest_path = ext_dir / "extension.yml" if ext_manifest_path.exists(): try: - from ..extensions import ExtensionManifest + from ..extensions import ExtensionManifest, ValidationError ext_manifest = ExtensionManifest(ext_manifest_path) # Filter to only the command being reconciled matching_cmds = [ @@ -1727,7 +1727,7 @@ def record_written(written: Dict[str, List[str]]) -> None: ) record_written(written) registered = True - except Exception: + except (TypeError, ValueError, KeyError, ValidationError): # Extension registration failed; fall back to # generic path-based registration below. pass diff --git a/tests/test_presets.py b/tests/test_presets.py index dbf6ac4ccb..2230d35041 100644 --- a/tests/test_presets.py +++ b/tests/test_presets.py @@ -1399,6 +1399,25 @@ def test_resolve_extension_command_via_manifest_skips_oserror_manifests(self, pr assert result is None, "OSError during manifest load must be silently skipped" + def test_resolve_extension_command_via_manifest_skips_validation_error(self, project_dir): + """resolve_extension_command_via_manifest skips extensions whose manifest raises ValidationError.""" + import unittest.mock as mock + + ext_dir = project_dir / ".specify" / "extensions" / "bad-ext" + cmd_dir = ext_dir / "commands" + cmd_dir.mkdir(parents=True) + (cmd_dir / "mycmd.md").write_text("---\ndescription: d\n---\n\nbody\n") + # Write a manifest with missing required fields to trigger ValidationError + (ext_dir / "extension.yml").write_text( + "schema_version: '1.0'\n" + "extension:\n id: bad-ext\n" + ) + + resolver = PresetResolver(project_dir) + result = resolver.resolve_extension_command_via_manifest("speckit.bad-ext.mycmd") + + assert result is None, "ValidationError during manifest load must be silently skipped" + class TestExtensionPriorityResolution: """Test extension priority resolution with registered and unregistered extensions."""