docs+ci: attribute the post-tag packaging work to 22.0.1, and add a workflow to strip the portable binaries from its zip - #4382
Merged
Conversation
…nreleased The 22.0.1 release is still a pre-release, and fifteen commits of packaging and publishing work landed after the tag to make it shippable. Both changelogs filed that work under `[Unreleased]` — the section directly above `[22.0.1]` — so it read as coming *after* the release it actually ships in. Move those entries into each file's 22.0.1 section under a new "Packaging & Publishing (post-tag)" subsection. The tag stays at 0dbd4c5, so the preamble says plainly that these landed after it rather than implying the tag contains them, and notes that a per-target asset refresh is still in flight — the x86_64-linux-gnu zip predates the portable-binary removal by about six hours and still contains them. Also corrects the synthesize/profile target list, which was wrong in both directions: it claimed the x86_64 Windows targets had `profile` (they have neither `profile` nor `synthesize`) and omitted aarch64-apple-darwin (which has both, via the self-hosted macOS ARM64 workflows — publish.yml's entry for that target is commented out). Verified against each publish workflow's feature list. The 21.1.0...22.0.1 compare link only covers the tag, so a second SHA-pinned link is added for the post-tag range rather than a moving master ref. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#4368 dropped viz_static from the Windows publish targets, which left two places asserting the opposite. CHANGELOG.md's 22.0.1 viz entry claimed "Windows and macOS now compile the viz_static tier". That is false for Windows at HEAD — rust-windows.yml builds `...,ui,viz` only, because adding viz_static pushed the job from ~27min past its 90min timeout without ever reaching the tests. The entry contradicted the "Windows prebuilts: viz yes, viz_static no" note in its own section. Narrowed to macOS, with the Windows revert and its reason spelled out. rust-windows.yml's own comment still justified itself with "Windows ships viz_static in publish.yml" — the premise #4368 removed. The conclusion (no Windows viz_static coverage) happens to still hold, so only the reasoning is rewritten; the cargo test invocation is untouched. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… zip #4380 stopped publishing the portable binaries (qsvp, qsvplite, qsvpdp, qsvpmcp), but assets uploaded before it landed still contain them — the 22.0.1 x86_64-unknown-linux-gnu zip among them. Rebuilding a target to drop four files is disproportionate: that zip already postdates #4371/#4372/#4373, so the portable binaries are its only discrepancy, and a rebuild would emit non-deterministic PGO output differing from what users already downloaded. The unsign -> modify -> re-sign flow mirrors macOS-arm64-selfhosted-publish-qsvpy.yml, which already rewrites a published pre-release zip to add qsvpy binaries. Scoped to x86_64-unknown-linux-gnu, with no target input, and running on ubuntu-24.04 to match the runner publish.yml builds that artifact on — glibc is forward incompatible, so a binary built on 24.04 will not start on 22.04 and the smoke test would fail on a good archive. The post-delete assertion requires qsv + qsvlite + qsvdp + qsvmcp to survive, which holds only for this target: publish-target.yml skips qsvdp for aarch64-unknown-linux-gnu and all non-Linux targets, and skips qsvmcp for musl and aarch64-unknown-linux-gnu. The header records how to extend it properly. Deletes with `7z d -tzip`, not Info-ZIP `zip -d`: publish-target.yml creates these archives with `7z a -tzip`. Entries are resolved by exact basename rather than a glob — a `qsv*` prefix match would take `qsv` itself with them. Trust model, because this replaces a published artifact: - the DOWNLOADED asset is verified against the release tag's public key before anything touches it. Without that anchor the workflow would strip whatever signature the asset carried (or none) and apply a fresh valid one, laundering a tampered artifact into a signed release asset — every later check only attests to the signature this workflow itself created - the public key comes from the tag (`git show "$TAG:src/qsv-zipsign-public.key"`), not the branch: that is the key clients of that release embed via include_bytes!, so a rotation surfaces as a failure instead of false confidence - the private key exists for exactly three steps — fetch, sign, shred. It is materialized after checkout, after the third-party downloader action, and after all archive manipulation, and destroyed before any archive content executes. persist-credentials: false keeps a git credential out of the same window - the signature is re-verified after the smoke test, immediately before upload, so the bytes published are the bytes attested - the tag must resolve to MAJOR.MINOR.PATCH, exist, and still be a PRERELEASE. Replacing an asset changes its sha256 and a stable release is likelier to have been pinned. Fails closed on an empty or unexpected isPrerelease value - dry_run defaults to true; upload is the only gated step - finding no portable binaries is a hard error, so an already-stripped archive is never re-signed and re-uploaded unchanged - every keeper must survive and every victim must be gone before signing - zipsign signs bytes, not zip structure, so a corrupted central directory could still verify: the rewritten qsv is extracted and run - a constant concurrency group: it is evaluated from the raw input before the tag is resolved, so keying it on release_tag would let an auto-detect run and an explicit run for the same tag race anyway Validated end-to-end locally with a throwaway zipsign keypair against a 7z-created archive: an authentic asset completes the full flow, while a tampered asset and an unsigned asset are both refused at the trust anchor, before any unsign. Also covers the flat, nested and already-stripped layouts, and the prerelease guard against prerelease/stable/missing/empty outcomes. Note zipsign salts signatures with --context, defaulting to the input filename, so the asset name must stay byte-identical throughout. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
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.
22.0.1 is still a pre-release, and fifteen commits of packaging work landed after the tag to make it shippable. Both changelogs filed that work under
[Unreleased]— the section directly above[22.0.1]— so it read as coming after the release it actually ships in. That is what this PR started as; two related fixes and one new workflow came out of it.1. Attribute the post-tag work to 22.0.1 (
97191f1)Moves those entries into each changelog's 22.0.1 section under a new Packaging & Publishing (post-tag) subsection. The tag stays at
0dbd4c50, so the preamble says plainly that these landed after it rather than implying the tag contains them.The 22.0.1 assets were uploaded progressively as commits landed, so they are a mix of refs. The preamble notes a per-target refresh is still in flight — the
x86_64-unknown-linux-gnuzip (14:17 UTC) predates #4380 (20:24 UTC) and still contains the portable binaries. That is what item 3 is for.Also corrects the
synthesize/profiletarget list, which was wrong in both directions: it claimed the x86_64 Windows targets hadprofile(they have neitherprofilenorsynthesize) and omittedaarch64-apple-darwin(which has both, via the self-hosted macOS ARM64 workflows). Verified against each publish workflow.The
21.1.0...22.0.1compare link only covers the tag, so a second SHA-pinned link is added for the post-tag range.2. Correct two stale
viz_staticclaims (5c75547)#4368 dropped
viz_staticfrom the Windows publish targets and left two places asserting the opposite:viz_statictier". False for Windows at HEAD —rust-windows.ymlbuilds...,ui,vizonly, because addingviz_staticpushed the job past its 90-minute timeout. The entry contradicted the "Windows prebuilts:vizyes,viz_staticno" note in its own section.rust-windows.yml's own comment still justified itself with "Windows ships viz_static in publish.yml" — the premise ci: drop viz_static from the Windows publish targets #4368 removed. Only the reasoning changes; thecargo testinvocation is untouched.3. New workflow: strip the portable binaries from a published zip (
20f010d)#4380 stopped publishing
qsvp/qsvplite/qsvpdp/qsvpmcp, but assets uploaded before it landed still contain them. Rebuilding a target to drop four files is disproportionate — that zip already postdates #4371/#4372/#4373, so the portable binaries are its only discrepancy, and a rebuild would emit non-deterministic PGO output differing from what users already downloaded.The unsign → modify → re-sign flow mirrors
macOS-arm64-selfhosted-publish-qsvpy.yml, which already rewrites a published pre-release zip.Trust model, since this replaces a published artifact:
include_bytes!, so a rotation surfaces as a failure rather than false confidencepersist-credentials: falsekeeps a git credential out of the same windowdry_rundefaults to true; upload is the only gated stepx86_64-unknown-linux-gnuonubuntu-24.04, matching the runner that builds it — glibc is forward-incompatible, so a 24.04-built binary will not start on 22.04 and the smoke test would fail on a good archiveDeletes with
7z d -tzip(matching7z a -tzipinpublish-target.yml), resolving entries by exact basename — aqsv*prefix match would takeqsvitself.Verification
Docs changes are mechanical (each relocated bullet verified to appear exactly once). The workflow was rehearsed end-to-end locally with a throwaway zipsign keypair against 7z-created archives:
Also covers flat / nested / already-stripped layouts, and the prerelease guard against prerelease/stable/missing/empty.
actionlintclean;check-publish-matrix-sync.pypasses.Important
The workflow has never actually run. Dispatch it with
dry_run: truefirst — that is the only thing exercising the real runner,7z, zipsign and the 457 MB archive together. It will also establish whether the currently published 22.0.1 asset verifies against the tag's key, which nothing has confirmed yet.Known gap, not addressed here
Once
qsvpleaves the archive,qsvp --updatefails for existing portable users —bin_namecomes fromcurrent_exe()(src/util.rs:1571-1574). That is inherent to #4380's decision rather than this workflow, but the portable changelog bullet still says nothing about it.🤖 Generated with Claude Code