fix(release): mirror the attested installer set onto the engine release - #73
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
https://github.com/OpenAdaptAI/openadapt-desktop/releases/latest302s tov0.14.0, which carries onlyopenadapt_desktop-0.14.0-py3-none-any.whl, its sdist, and two PyPI attestations. All six installers plusSHA256SUMSlive on the prerelease tagdesktop-v0.14.0, which/releases/latestexcludes 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-releasejob in.github/workflows/native-release.yml. Onrelease: publishedfor a non-draftdesktop-v*prerelease, it:gh release download desktop-vX.Y.Z— the full attested set.native_release.py verify-checksumsagainst the attestedSHA256SUMS.gh release upload vX.Y.Z mirror/* --clobber.Ordering is safe:
needs: point-engine-release, andnative-freshness.ymlonly pushesdesktop-vX.Y.Zafter verifyingrefs/tags/vX.Y.Zexists and is an ancestor ofmain.Why this is not a maturity promotion
The prior
RELEASES.mdpolicy 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:desktop-v0.14.0stays a prerelease. Explicitly not flipped.-adhoc.dmg,-unsigned.msi,-unsigned.AppImage) and led with in the pointer block, along with thesha256sum -c/gh attestation verifycommands.<!-- installer-release -->marker is never written to the engine release, soopenadapt-web/utils/desktopRelease.jskeeps resolvingdesktop-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_notespinned"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_installersassertedgh release upload "${engine_tag}"is absent — the exact opposite of the intent now. Split out intotest_native_release_workflow_mirrors_installers_onto_the_engine_release, which pins the three invariants above (re-verification, noinstaller-releasemarker, no prerelease flip), matching against executable lines only so a comment cannot satisfy the check.RELEASES.mdrewritten: the two-lane table, the "Latest" section, the maturity rationale, the selection rule, and the post-signing convergence plan.Backfill
v0.14.0is 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.py43 passed;ruff checkclean; workflow YAML parses.🤖 Generated with Claude Code
https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM