Menu

#320 feat(tray): verify the MLX runtime download + wire the runtime-latest manifest URL (Approach C, Step 3 + wiring)

closed
nobody
None
2026-06-24
2026-06-19
Anonymous
No

Originally created by: Akarsh-Hegde

Summary

Step 3 closes the integrity gap in the Approach-C download path. download_runtime() was a bare fetch-and-extract; it's now manifest-driven, version-aware, and checksum-verified.

New flow: fetch runtime-manifest.jsonpreflight (arch + macOS floor) → skip if the installed version already matches → stream the tarball → verify SHA-256 before extracting → extract only on a match → stamp runtime.version. A corrupted / truncated / tampered download now fails loudly and is deleted, never extracted.

Changes (mlx_server.rs)

  • Manifest-driven: RUNTIME_TARBALL_URL/runtime_url()RUNTIME_MANIFEST_URL/manifest_url() (env MERIDIAN_RUNTIME_MANIFEST_URL). New RuntimeManifest { version, arch, min_macos, url, sha256, size } parsed from the Step-2 runtime-manifest.json.
  • Preflight: reject if manifest.arch != this arch, or running macOS < min_macos (macos_at_least compares major.minor; unparseable → permit, let the OS decide).
  • Version skip: installed_version() reads a runtime.version marker; matching the manifest returns AlreadyCurrent without re-downloading 165 MB.
  • Integrity gate: stream → flush → sha256_hex_of (1 MiB chunks, spawn_blocking) → case-insensitive compare to manifest.sha256; mismatch deletes the temp + errors. Extract + version-stamp happen only on a match.
  • download_runtime now returns DownloadOutcome { AlreadyCurrent | Installed }.

Changes (commands/setup.rs)

  • download_available uses manifest_url(); download_runtime_cmd logs the outcome.

Tests — 15 pass

Unit tests for the error-prone logic: macOS-floor comparison (extra components / missing minor / unparseable → permit); SHA-256 against the NIST "abc" vector + the case-insensitive compare the gate relies on; manifest deserialization matching the build script's exact shape. The tar-extract path itself was already proven on a real 165 MB tarball by Step 2's smoke test.

Note: the full download_runtime end-to-end isn't auto-tested here — it's pub(crate) and writes to a HOME-derived path, so an automated run would risk clobbering a real ~/.meridian/runtime. It's exercisable manually by serving a manifest+tarball locally and setting MERIDIAN_RUNTIME_MANIFEST_URL (with a sandboxed HOME), and the wizard exercises it once a real manifest URL is wired.

Roadmap

  • Wire the URL: cut a runtime-v* tag (Step 2 publishes the manifest), then set RUNTIME_MANIFEST_URL / MERIDIAN_RUNTIME_MANIFEST_URL to light up the wizard's Download button — that's also the first real end-to-end of this path.
  • Optional: signature verification alongside the hash (notarization-era), and the venv prune.

Stacked on feat/mlx-runtime-ci (#319) → feat/tray-mlx-supervision (#318) → feat/dmg-onboarding (#315) → spike/meridian-core.

🤖 Generated with Claude Code

https://claude.ai/code/session_01M7jfB95RakvdwJ8hRogrs4

Related

Tickets: #330
Tickets: #347

Discussion

  • Anonymous

    Anonymous - 2026-06-19

    Originally posted by: Akarsh-Hegde

    Added: tag + URL wiring (commit 349c14c)

    Folded the final wiring into this PR so cutting a tag lights up the wizard's Download end-to-end.

    RUNTIME_MANIFEST_URL is now wiredhttps://github.com/Meridiona/meridian/releases/download/runtime-latest/runtime-manifest.json.

    Design decision — a rolling runtime-latest release, not a version-pinned tag:

    • A shipped build must keep discovering newer runtimes without an app update (the cadence decoupling that motivates Approach C), so the pinned URL has to be stable.
    • GitHub's /releases/latest/ is unusable here — it resolves to the app's semantic-release, which carries no runtime manifest. So we maintain an explicit runtime-latest release.
    • The workflow stamps RUNTIME_TAG=runtime-latest at build time, so the manifest's embedded tarball url is stable too (both the manifest url and the tarball url it points at live at runtime-latest).

    Workflow publish job now force-updates runtime-latest (create-once as a --prerelease so it never competes for the "Latest" slot, then gh release upload --clobber) instead of a per-tag release. The triggering runtime-v* git tag is the version record; the version also lives inside the manifest.

    How to release a runtime (the one remaining manual step — not done here)

    git tag runtime-v$(grep -m1 '^version' services/pyproject.toml | sed -E 's/.*"([^"]+)".*/\1/')
    git push origin <that tag>
    

    → builds on macos-14, smoke-tests across macos-14/15/26, republishes runtime-latest. That push is also the first real end-to-end of the whole download path (manifest fetch → version check → SHA-256 verify → extract).

    Interim state (expected)

    Because the const is now non-empty, the wizard's Model step shows Download available. Until the first runtime-v* tag is pushed, clicking Download 404s gracefully ("manifest fetch failed: HTTP 404") — no crash. It starts working the moment the tag is cut.

    Deliberately deferred

    Per-version immutable retention for true rollback (keep every meridian-mlx-runtime-<ver> artifact at its own URL) is a release-eng follow-up — runtime-latest covers delivery; rollback today = re-run the workflow on an older runtime-v* tag.

     
  • Anonymous

    Anonymous - 2026-06-24

    Ticket changed by: Akarsh-Hegde

    • status: open --> closed
     

Log in to post a comment.