Skip to content

Commit 240f715

Browse files
iamaeroplaneclaude
andcommitted
fix(extensions): validate hooks is a dict and restrict alias 3-part correction to ext_id (#2017)
- Raise ValidationError with a clear message if the manifest 'hooks' value is not a mapping (previously would AttributeError on .items()) - Restrict _try_correct_alias_name 3-part correction (speckit.X.Y → X.Y) to only apply when X == ext_id; when X differs the alias is squatting a foreign namespace and should be rejected, not silently rewritten Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent caee3e0 commit 240f715

File tree

1 file changed

+7
-2
lines changed

1 file changed

+7
-2
lines changed

src/specify_cli/extensions.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,12 @@ def _validate(self):
248248
)
249249

250250
# Rewrite any hook command references that pointed at a renamed command.
251-
for hook_name, hook_data in self.data.get("hooks", {}).items():
251+
hooks = self.data.get("hooks", {})
252+
if not isinstance(hooks, dict):
253+
raise ValidationError(
254+
f"'hooks' must be a mapping, got {type(hooks).__name__}"
255+
)
256+
for hook_name, hook_data in hooks.items():
252257
if isinstance(hook_data, dict) and hook_data.get("command") in rename_map:
253258
old_ref = hook_data["command"]
254259
hook_data["command"] = rename_map[old_ref]
@@ -294,7 +299,7 @@ def _try_correct_alias_name(name: str, ext_id: str) -> Optional[str]:
294299
candidate = f"{ext_id}.{parts[1]}"
295300
if EXTENSION_ALIAS_PATTERN.match(candidate):
296301
return candidate
297-
if len(parts) == 3 and parts[0] == 'speckit':
302+
if len(parts) == 3 and parts[0] == 'speckit' and parts[1] == ext_id:
298303
candidate = f"{parts[1]}.{parts[2]}"
299304
if EXTENSION_ALIAS_PATTERN.match(candidate):
300305
return candidate

0 commit comments

Comments
 (0)