mirror of
https://github.com/github/spec-kit.git
synced 2026-08-03 06:26:30 +08:00
fix(extensions): tolerate non-string tags in catalog search (#3746)
* fix(extensions): tolerate non-string tags in catalog search ExtensionCatalog.search() assumed catalog `tags` were always strings: the tag filter called `t.lower()` and the query path did `" ".join([...] + tags)`. Extension catalog JSON is user-editable, so a hand-authored `tags: [1, 2]` crashed search with AttributeError (tag filter) or TypeError (query join). Coerce defensively by filtering to `isinstance(t, str)` and guarding the tags value as a list, matching the reference-correct sibling in integrations/catalog.py. Non-string tags are now skipped rather than raising. Adds a regression test driving search(tag=...) and search(query=...) against a catalog with mixed string/int tags; both fail pre-fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(extensions): also coerce non-string author/name in catalog search The same ExtensionCatalog.search() method had two more string assumptions on user-editable catalog fields: the author filter called `ext_data.get("author", "").lower()` (AttributeError on a numeric author) and the query searchable-text joined `name`/`description` uncoerced (TypeError on a numeric name). Coerce both defensively, matching the reference-correct integrations/catalog.py::search. Extends the regression test with non-string author/name coverage; fails pre-fix with AttributeError at the author filter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3154,22 +3154,35 @@ class ExtensionCatalog(CatalogStackBase):
|
||||
if verified_only and not ext_data.get("verified", False):
|
||||
continue
|
||||
|
||||
if author and ext_data.get("author", "").lower() != author.lower():
|
||||
continue
|
||||
if author:
|
||||
author_val = ext_data.get("author", "")
|
||||
if not isinstance(author_val, str):
|
||||
author_val = str(author_val) if author_val is not None else ""
|
||||
if author_val.lower() != author.lower():
|
||||
continue
|
||||
|
||||
if tag and tag.lower() not in [t.lower() for t in ext_data.get("tags", [])]:
|
||||
continue
|
||||
if tag:
|
||||
raw_tags = ext_data.get("tags", [])
|
||||
tags_list = raw_tags if isinstance(raw_tags, list) else []
|
||||
if tag.lower() not in [
|
||||
t.lower() for t in tags_list if isinstance(t, str)
|
||||
]:
|
||||
continue
|
||||
|
||||
if query:
|
||||
# Search in name, description, and tags
|
||||
query_lower = query.lower()
|
||||
raw_tags = ext_data.get("tags", [])
|
||||
tags_list = raw_tags if isinstance(raw_tags, list) else []
|
||||
name_val = ext_data.get("name", "")
|
||||
desc_val = ext_data.get("description", "")
|
||||
searchable_text = " ".join(
|
||||
[
|
||||
ext_data.get("name", ""),
|
||||
ext_data.get("description", ""),
|
||||
str(name_val) if name_val else "",
|
||||
str(desc_val) if desc_val else "",
|
||||
ext_id,
|
||||
]
|
||||
+ ext_data.get("tags", [])
|
||||
+ [t for t in tags_list if isinstance(t, str)]
|
||||
).lower()
|
||||
|
||||
if query_lower not in searchable_text:
|
||||
|
||||
Reference in New Issue
Block a user