Skip to content

fix(release): mirror the attested installer set onto the engine release - #73

Merged
abrichr merged 1 commit into
mainfrom
launch/blockers-2026-07-27
Jul 27, 2026
Merged

fix(release): mirror the attested installer set onto the engine release#73
abrichr merged 1 commit into
mainfrom
launch/blockers-2026-07-27

Conversation

@abrichr

@abrichr abrichr commented Jul 27, 2026

Copy link
Copy Markdown
Member

Problem

https://github.com/OpenAdaptAI/openadapt-desktop/releases/latest 302s to v0.14.0, which carries only openadapt_desktop-0.14.0-py3-none-any.whl, its sdist, and two PyPI attestations. All six installers plus SHA256SUMS live on the prerelease tag desktop-v0.14.0, which /releases/latest excludes by definition. A visitor following the canonical download link finds no installer.

PR #69 added a notes pointer to v0.14.0 (verified still present and rendering). That is a link, not an installer.

Fix

New mirror-installers-to-engine-release job in .github/workflows/native-release.yml. On release: published for a non-draft desktop-v* prerelease, it:

  1. gh release download desktop-vX.Y.Z — the full attested set.
  2. native_release.py verify-checksums against the attested SHA256SUMS.
  3. gh release upload vX.Y.Z mirror/* --clobber.

Ordering is safe: needs: point-engine-release, and native-freshness.yml only pushes desktop-vX.Y.Z after verifying refs/tags/vX.Y.Z exists and is an ancestor of main.

Why this is not a maturity promotion

The prior RELEASES.md policy was "linked, not mirrored", because ~757 MB of ad-hoc-signed and unsigned binaries as the default download on "Latest" would overstate maturity. Correct concern, wrong remedy — it left the canonical path broken. Addressed directly instead:

Risk Mitigation
Native lane becomes "Latest" desktop-v0.14.0 stays a prerelease. Explicitly not flipped.
Signing state hidden Encoded in every filename (-adhoc.dmg, -unsigned.msi, -unsigned.AppImage) and led with in the pointer block, along with the sha256sum -c / gh attestation verify commands.
Unattested bytes on "Latest" Re-verified against the attested manifest before upload; the job fails closed.
Download-page selection breaks Assets only. The <!-- installer-release --> marker is never written to the engine release, so openadapt-web/utils/desktopRelease.js keeps resolving desktop-v* unchanged.

Cost

~757 MB duplicated per release (measured: 793,329,764 bytes across the six installers). GitHub release storage and bandwidth are not billed for public repositories, so the recurring cost is this job's download+upload minutes, not storage spend. Weighed against a dead canonical download link on launch day.

Tests changed in the same commit

Two assertions pinned the old behaviour and had to move:

  • test_installer_pointer_prepends_block_and_preserves_engine_notes pinned "this release has no installer", now false. Replaced with assertions that the block says the installers are attached and still leads with the signing state.
  • test_native_release_workflow_points_latest_at_the_published_installers asserted gh release upload "${engine_tag}" is absent — the exact opposite of the intent now. Split out into test_native_release_workflow_mirrors_installers_onto_the_engine_release, which pins the three invariants above (re-verification, no installer-release marker, no prerelease flip), matching against executable lines only so a comment cannot satisfy the check.

RELEASES.md rewritten: the two-lane table, the "Latest" section, the maturity rationale, the selection rule, and the post-signing convergence plan.

Backfill

v0.14.0 is backfilled manually so the fix is real today, not only on the next release.

Local: pytest tests/test_native_release.py tests/test_public_metadata.py 43 passed; ruff check clean; workflow YAML parses.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM

GitHub's /releases/latest excludes prereleases by definition, so it always
resolves to the engine release vX.Y.Z -- which carried only a wheel and an
sdist. A visitor following the canonical download link, the one cited in launch
material, found no installer. PR #69 added a notes pointer; that still made a
human read a paragraph and click through to a second tag.

Add `mirror-installers-to-engine-release`, which downloads the exact attested
asset set from desktop-vX.Y.Z, re-verifies every byte against the attested
SHA256SUMS, and uploads it to vX.Y.Z. "Latest" now carries a working installer.

The prior policy was "linked, not mirrored", on the reasoning that ~757 MB of
ad-hoc-signed and unsigned binaries on "Latest" would overstate their maturity.
That concern is addressed directly rather than by withholding the artifact:

- desktop-vX.Y.Z STAYS a prerelease. Flipping it is still forbidden.
- Every filename encodes its signing state (-adhoc.dmg, -unsigned.msi).
- The pointer block now leads with "Beta ... ad-hoc-signed (macOS) or unsigned
  (Windows, Linux)", says the OS will warn, and gives the verification commands
  before anything else.
- The mirror re-verifies against the attested manifest, so an engine release can
  never carry a byte that was not attested on the native tag.
- Assets only: the engine release never receives the `<!-- installer-release -->`
  marker, so the documented machine-readable selection rule is unchanged and
  download-page consumers keep resolving desktop-v*.

Cost: ~757 MB duplicated per release. GitHub release storage and bandwidth are
unbilled for public repositories, so the recurring cost is this one job's
download+upload minutes, not storage spend.

Tests updated in the same change: the pointer-block test pinned "this release
has no installer", which is now false, and the workflow test asserted that no
installer bytes are uploaded to vX.Y.Z, which is now the opposite of the intent.
Both are rewritten to pin the three invariants that keep mirroring safe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM
@abrichr
abrichr merged commit 92a56db into main Jul 27, 2026
15 checks passed
@abrichr
abrichr deleted the launch/blockers-2026-07-27 branch July 27, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant