Skip to content

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
jqnatividad merged 3 commits into
masterfrom
changelog-22.0.1-post-tag-fold
Aug 10, 2026
Merged

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
jqnatividad merged 3 commits into
masterfrom
changelog-22.0.1-post-tag-fold

Conversation

@jqnatividad

Copy link
Copy Markdown
Collaborator

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-gnu zip (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/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). Verified against each publish workflow.

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.

2. Correct two stale viz_static claims (5c75547)

#4368 dropped viz_static from the Windows publish targets and left two places asserting the opposite:

  • CHANGELOG's 22.0.1 viz entry claimed "Windows and macOS now compile the viz_static tier". False for Windows at HEAD — rust-windows.yml builds ...,ui,viz only, because adding viz_static pushed the job past its 90-minute timeout. The entry contradicted the "Windows prebuilts: viz yes, viz_static no" 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; the cargo test invocation 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:

  • 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, since every later check only attests to the signature the workflow itself created
  • the public key comes from the tag, not the branch — that is the key clients of that release embed via include_bytes!, so a rotation surfaces as a failure rather than false confidence
  • the private key exists for exactly three steps (fetch → sign → shred): after checkout, after the third-party downloader action, and after all archive manipulation; 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
  • the tag must be 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
  • dry_run defaults to true; upload is the only gated step
  • scoped to x86_64-unknown-linux-gnu on ubuntu-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 archive

Deletes with 7z d -tzip (matching 7z a -tzip in publish-target.yml), resolving entries by exact basename — a qsv* prefix match would take qsv itself.

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:

Case Result
Authentic asset full flow completes (verify → unsign → delete → sign → verify → smoke → re-verify)
Tampered (bytes appended post-signing) refused at the anchor, before unsign
Never signed refused at the anchor, before unsign

Also covers flat / nested / already-stripped layouts, and the prerelease guard against prerelease/stable/missing/empty. actionlint clean; check-publish-matrix-sync.py passes.

Important

The workflow has never actually run. Dispatch it with dry_run: true first — 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 qsvp leaves the archive, qsvp --update fails for existing portable users — bin_name comes from current_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

jqnatividad and others added 3 commits August 9, 2026 20:54
…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>
@codacy-production

codacy-production Bot commented Aug 10, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@jqnatividad
jqnatividad merged commit d1136bc into master Aug 10, 2026
28 checks passed
@jqnatividad
jqnatividad deleted the changelog-22.0.1-post-tag-fold branch August 10, 2026 02:17
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