"""CLI distribution domain: manifest projection, presign, download route. The service reads ``cli-dist/latest/manifest.json`` from S3 and mints presigned download URLs. Tests stub the two storage primitives (``get_object_bytes`` / ``presign_get``) so no real S3 is touched, and exercise the graceful "unavailable" path (storage unconfigured in the test env) end-to-end through the HTTP route. """ from __future__ import annotations import json import pytest from app.domains.cli_dist import service _MANIFEST = { "version": "1.2.3", "generated_at": "2026-06-18T00:00:00+00:00", "commit": "deadbeef", "artifacts": [ { "platform": "macos-arm64", "kind": "binary", "filename": "helix-macos-arm64", "key": "cli-dist/1.2.3/helix-macos-arm64", "sha256": "a" * 64, "size": 1234, }, { "platform": "wheel", "kind": "wheel", "filename": "helix_cli-1.2.3-py3-none-any.whl", "key": "cli-dist/1.2.3/helix_cli-1.2.3-py3-none-any.whl", "sha256": "b" * 64, "size": 5678, }, # An unknown platform must be ignored, never surfaced. {"platform": "solaris-sparc", "kind": "binary", "key": "x", "filename": "x"}, ], } @pytest.fixture def stub_manifest(monkeypatch): async def _get(db, *, object_key): assert object_key == service.MANIFEST_KEY return json.dumps(_MANIFEST).encode() async def _presign(db, *, object_key, expires_in=600): return f"https://s3.example.com/{object_key}?sig=xyz&ttl={expires_in}" monkeypatch.setattr(service, "get_object_bytes", _get) monkeypatch.setattr(service, "presign_get", _presign) # ---- service ---- async def test_get_manifest_unavailable_when_storage_returns_none(monkeypatch, db_session): async def _none(db, *, object_key): return None monkeypatch.setattr(service, "get_object_bytes", _none) out = await service.get_manifest(db_session) assert out["available"] is False assert out["platforms"] == [] assert "min_supported" in out # surfaced even when no release published async def test_get_manifest_projects_public_shape(stub_manifest, db_session): out = await service.get_manifest(db_session) assert out["available"] is True assert out["version"] == "1.2.3" platforms = {p["platform"] for p in out["platforms"]} # known platforms surfaced, unknown dropped, no S3 keys leaked assert platforms == {"macos-arm64", "wheel"} for p in out["platforms"]: assert "key" not in p assert p["label"] # allowlist-driven stable order: macos-arm64 before wheel assert [p["platform"] for p in out["platforms"]] == ["macos-arm64", "wheel"] async def test_presign_download_known_platform(stub_manifest, db_session): res = await service.presign_download(db_session, platform="macos-arm64") assert res is not None assert "cli-dist/1.2.3/helix-macos-arm64" in res["url"] assert res["sha256"] == "a" * 64 assert res["version"] == "1.2.3" async def test_presign_download_unknown_platform_is_none(stub_manifest, db_session): assert await service.presign_download(db_session, platform="bogus-os") is None async def test_presign_download_when_manifest_absent_is_none(monkeypatch, db_session): async def _none(db, *, object_key): return None monkeypatch.setattr(service, "get_object_bytes", _none) assert await service.presign_download(db_session, platform="macos-arm64") is None # ---- HTTP route ---- async def test_manifest_route_requires_auth(client): resp = await client.get("/api/v1/cli/manifest") assert resp.status_code in (401, 403) async def test_manifest_route_unavailable_in_unconfigured_env(client, employee_headers): # No storage.s3.* platform settings in the test DB → graceful # available=false rather than 500. resp = await client.get("/api/v1/cli/manifest", headers=employee_headers) assert resp.status_code == 200 body = resp.json()["data"] assert body["available"] is False assert body["platforms"] == [] # min_supported is always surfaced so `helix version` can compare. assert "min_supported" in body async def test_download_missing_platform_param_is_422(client, employee_headers): resp = await client.get("/api/v1/cli/download", headers=employee_headers) assert resp.status_code == 422 async def test_download_unavailable_is_404(client, employee_headers): resp = await client.get( "/api/v1/cli/download?platform=macos-arm64", headers=employee_headers ) assert resp.status_code == 404 async def test_download_returns_url_when_available(client, employee_headers, monkeypatch): async def _presign(db, *, platform): return { "url": "https://s3.example.com/cli-dist/1.2.3/helix-macos-arm64?sig=xyz", "platform": platform, "filename": "helix-macos-arm64", "sha256": "a" * 64, "size": 1234, "version": "1.2.3", "expires_in": 300, } monkeypatch.setattr(service, "presign_download", _presign) resp = await client.get( "/api/v1/cli/download?platform=macos-arm64", headers=employee_headers ) assert resp.status_code == 200 data = resp.json()["data"] assert data["url"].startswith("https://s3.example.com/cli-dist/") assert data["filename"] == "helix-macos-arm64" # ---- server-side CLI min-version kill-switch (app/mcp/middleware) ---- def test_release_tuple_ignores_local_segment(): from app.mcp.middleware import _release_tuple assert _release_tuple("0.1.0+g1a2b3c4") == (0, 1, 0) assert _release_tuple("2.10.3") == (2, 10, 3) assert _release_tuple("not-a-version") is None def test_cli_version_below_min_gate(monkeypatch): from app.core import config as cfg from app.mcp import middleware as mw # Floor disabled (default) → never gates, even a 0.0.1 client. monkeypatch.setattr(cfg.settings, "CLI_MIN_SUPPORTED_VERSION", "0.0.0") assert mw._cli_version_below_min("helix-cli/0.0.1") is False # Floor 0.2.0 → older CLI blocked, equal/newer allowed. monkeypatch.setattr(cfg.settings, "CLI_MIN_SUPPORTED_VERSION", "0.2.0") assert mw._cli_version_below_min("helix-cli/0.1.9") is True assert mw._cli_version_below_min("helix-cli/0.2.0") is False assert mw._cli_version_below_min("helix-cli/0.2.0+gabc1234") is False assert mw._cli_version_below_min("helix-cli/1.0.0") is False # Non-CLI clients (Claude Desktop / Cursor / scripts) are never gated. assert mw._cli_version_below_min("Claude-Desktop/1.0") is False assert mw._cli_version_below_min(None) is False