Skip to content

Commit 1831fff

Browse files
marcelsafinCopilot
andauthored
fix(bundler): wrap local catalog decode failures (#3902)
Assisted-by: GitHub Copilot (model: GPT-5.6 Sol, autonomous) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ba7ae79 commit 1831fff

2 files changed

Lines changed: 15 additions & 3 deletions

File tree

src/specify_cli/bundler/services/adapters.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from ..._assets import _locate_core_pack, _repo_root
1919
from ..._download_security import MAX_JSON_CATALOG_BYTES, read_response_limited
2020
from .. import BundlerError
21-
from ..lib.yamlio import loads_json
21+
from ..lib.yamlio import load_json, loads_json
2222
from ..models.catalog import CatalogSource
2323
from ..models.manifest import ComponentRef
2424

@@ -145,13 +145,13 @@ def fetch(source: CatalogSource) -> dict:
145145
path = _file_url_to_path(parsed)
146146
if not path.exists():
147147
raise BundlerError(f"Catalog file not found: {path}")
148-
return loads_json(path.read_text(encoding="utf-8"), origin=str(path))
148+
return load_json(path)
149149

150150
if scheme == "" or _is_windows_drive_path(url):
151151
path = Path(url)
152152
if not path.exists():
153153
raise BundlerError(f"Catalog file not found: {path}")
154-
return loads_json(path.read_text(encoding="utf-8"), origin=str(path))
154+
return load_json(path)
155155

156156
if scheme in ("http", "https"):
157157
if not allow_network:

tests/unit/test_bundler_adapters.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,18 @@ def test_fetch_rejects_malformed_source_url_cleanly(url):
104104
fetcher(_source(url))
105105

106106

107+
@pytest.mark.parametrize("use_file_url", [False, True], ids=["path", "file-url"])
108+
def test_local_catalog_decode_errors_are_wrapped(tmp_path, use_file_url):
109+
catalog_path = tmp_path / "catalog.json"
110+
catalog_path.write_bytes(b"\xff\xfe")
111+
url = catalog_path.as_uri() if use_file_url else str(catalog_path)
112+
113+
fetcher = adapters.make_catalog_fetcher(allow_network=False)
114+
115+
with pytest.raises(BundlerError, match="Could not read"):
116+
fetcher(_source(url))
117+
118+
107119
def test_builtin_community_catalog_fetches_repository_catalog_online(monkeypatch):
108120
captured: dict = {}
109121

0 commit comments

Comments
 (0)