Skip to content

Commit c465985

Browse files
committed
fix: harden atlas route status paths
1 parent bd55ae2 commit c465985

2 files changed

Lines changed: 66 additions & 3 deletions

File tree

scripts/build_atlas_route.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,13 @@ def _meta(content: str) -> str:
240240
return html.escape(content, quote=True)
241241

242242

243+
def _display_path(path: Path, root: Path) -> str:
244+
try:
245+
return path.relative_to(root).as_posix()
246+
except ValueError:
247+
return path.as_posix()
248+
249+
243250
def _share_page_url(site_url: str, stop_id: str) -> str:
244251
return f"{_normalize_site_url(site_url)}/atlas/share/{quote(stop_id, safe='-._~')}/"
245252

@@ -397,17 +404,17 @@ def main() -> int:
397404

398405
if args.check:
399406
if added_count:
400-
print(f"{added_count} downloaded sound file(s) are missing from {route_path.relative_to(root)}.")
407+
print(f"{added_count} downloaded sound file(s) are missing from {_display_path(route_path, root)}.")
401408
return 1
402-
print(f"All {len(media)} downloaded sound file(s) are represented in {route_path.relative_to(root)}.")
409+
print(f"All {len(media)} downloaded sound file(s) are represented in {_display_path(route_path, root)}.")
403410
return 0
404411

405412
site_url = args.site_url or _site_url_from_cname(root)
406413
write_route(output_path, merged)
407414
write_share_pages(root, merged, site_url)
408415
write_discovery_files(root, merged, site_url)
409416
print(
410-
f"Wrote {len(merged)} atlas stop(s) to {output_path.relative_to(root)}; "
417+
f"Wrote {len(merged)} atlas stop(s) to {_display_path(output_path, root)}; "
411418
f"{added_count} stop(s) added; generated {len(merged)} share page(s).",
412419
)
413420
return 0

tests/test_atlas_route_builder.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,62 @@ def test_check_mode_does_not_write_output(tmp_path):
144144
assert not (tmp_path / "atlas" / "dawn-to-night.draft.json").exists()
145145

146146

147+
def test_check_mode_reports_absolute_route_outside_root(tmp_path):
148+
root = tmp_path / "site"
149+
root.mkdir()
150+
route_path = tmp_path / "external-route.json"
151+
route_path.write_text("[]\n", encoding="utf-8")
152+
153+
result = subprocess.run(
154+
[
155+
sys.executable,
156+
str(SCRIPT_PATH),
157+
"--root",
158+
str(root),
159+
"--route",
160+
str(route_path),
161+
"--check",
162+
],
163+
check=False,
164+
capture_output=True,
165+
text=True,
166+
)
167+
168+
assert result.returncode == 0
169+
assert str(route_path) in result.stdout
170+
assert "ValueError" not in result.stderr
171+
172+
173+
def test_default_cli_reports_absolute_output_outside_root(tmp_path):
174+
root = tmp_path / "site"
175+
root.mkdir()
176+
route_path = root / "atlas" / "dawn-to-night.json"
177+
output_path = tmp_path / "external-route.json"
178+
route_path.parent.mkdir()
179+
route_path.write_text("[]\n", encoding="utf-8")
180+
181+
result = subprocess.run(
182+
[
183+
sys.executable,
184+
str(SCRIPT_PATH),
185+
"--root",
186+
str(root),
187+
"--route",
188+
"atlas/dawn-to-night.json",
189+
"--output",
190+
str(output_path),
191+
],
192+
check=False,
193+
capture_output=True,
194+
text=True,
195+
)
196+
197+
assert result.returncode == 0
198+
assert output_path.exists()
199+
assert str(output_path) in result.stdout
200+
assert "ValueError" not in result.stderr
201+
202+
147203
def test_write_share_pages_creates_per_specimen_social_preview_and_redirect(tmp_path):
148204
stop = {
149205
"id": "american-coots",

0 commit comments

Comments
 (0)