Skip to content

ci: publish standalone OpenVMM source releases - #4220

Open
Ben Hillis (benhillis) wants to merge 7 commits into
microsoft:mainfrom
benhillis:user/benhill/openvmm-source-release-publish
Open

ci: publish standalone OpenVMM source releases#4220
Ben Hillis (benhillis) wants to merge 7 commits into
microsoft:mainfrom
benhillis:user/benhill/openvmm-source-release-publish

Conversation

@benhillis

@benhillis Ben Hillis (benhillis) commented Aug 12, 2026

Copy link
Copy Markdown
Member

Purpose

Add the publication half of the standalone OpenVMM source-release flow now that #4200 has landed. CI already proves that a deterministic source archive can build with distribution-provided dependencies; this adds the manually dispatched workflow that turns those same validated bytes into a reviewable GitHub release.

This PR also selects 0.1.0 as the initial OpenVMM source release. The root [workspace.package] version already carries 0.1.0, and no openvmm-v0.1.0 tag or release exists, so there is no no-op Cargo.toml edit. Merging this PR is the reviewed decision to use that existing value for the initial release.

Release workflow

Add an OpenVMM Source Release workflow with no automatic triggers. When dispatched against a commit, it:

  1. assembles openvmm-<VERSION>.tar.gz and SHA256SUMS once;
  2. passes that exact artifact through the distribution-build gate from ci: assemble an OpenVMM source archive and gate distribution builds #4200;
  3. creates openvmm-v<VERSION> at the archived revision;
  4. generates GitHub build-provenance attestations for both published files and attaches them to a draft release that requires that existing tag.

A maintainer reviews the draft, writes release notes, and publishes it.

Why the tag is created before the draft

gh release create binds a draft to an existing tag as-is and ignores --target when that tag already exists. Checking only that the tag was unused at draft time left a window: a tag created during human review would silently rebind the release to a different commit at publish time, decoupling the published tag from the validated archive.

Creating the ref up front closes that window. Ref creation is atomic, so a rerun either creates the tag or finds it already present, in which case it must still name the exact archived commit or the job fails. Draft creation passes --verify-tag so it can only ever attach to that tag.

The tradeoff is that the tag is publicly visible while the release is still a draft. This is documented in the maintainer guide.

Safety properties

  • publication depends on the distribution-build validation job;
  • the archive identity supplies the target revision, tag, title, and asset names;
  • the tag is pinned to the archived revision before the draft exists, and is reused only when it already names that exact commit;
  • an existing release fails the workflow instead of being reused or overwritten;
  • only the archive and SHA256SUMS are published; internal identity metadata stays private to the workflow artifact;
  • the privileged actions/attest step is pinned to a full commit SHA;
  • the workflow creates only a draft, keeping the irreversible publish step with a human;
  • the pipeline supports only the GitHub backend, since it acts on the upstream repository.

Documentation

Add a maintainer guide covering version selection, workflow dispatch, draft review and publication, correction policy, and current limitations. The packager guide now distinguishes the release workflow's guarantees from downstream checks it does not perform.

Validation

  • cargo check -p flowey_lib_common -p flowey_lib_hvlite -p flowey_hvlite
  • cargo clippy --all-targets -p flowey_lib_common -p flowey_lib_hvlite -p flowey_hvlite
  • cargo doc --no-deps -p flowey_lib_common -p flowey_lib_hvlite -p flowey_hvlite
  • cargo test -p flowey_lib_common -p flowey_lib_hvlite -p flowey_hvlite
  • cargo xtask fmt --fix, including Flowey workflow regeneration

Out of scope

Prebuilt binaries, OpenPGP signing, generated release notes, and a commitment to service published versions remain separate decisions.

Ben Hillis added 5 commits August 12, 2026 12:59
Assembly and the distribution gate landed without anything that
publishes the result, so the archive CI validated was discarded. Add the
publication half.

A manually dispatched pipeline assembles the archive once, transfers it
to the distribution-build gate as an artifact, and then attaches those
same bytes to a draft GitHub release along with provenance attestations
for both published files. Validating a reassembled copy would be
reproducible but would no longer prove that what was tested is what ships.

Publication stops at a draft on purpose. A maintainer reviews it and
clicks Publish, and GitHub creates openvmm-v<VERSION> at the commit the
workflow pinned, so no tag exists for a release nobody approved and the
irreversible step stays a human one.

Document the maintainer procedure, and update the packaging guide now
that the archive and SHA256SUMS have somewhere to be published.
map and depending_on take the receiver by reference.
The page described the gate as validation without saying where that
validation stops, which invites more confidence than it earns. Name the
one question the gate answers, list the checks it deliberately omits,
and say that a release publishes source rather than binaries or a
servicing commitment.
Permit a release PR to explicitly select the already-committed version when that value has never been released, avoiding a meaningless Cargo.toml edit for the initial 0.1.0 release.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2f283c1b-ae06-4449-9ac9-897cd279f65e
Pin the attestation action and reject pre-existing release tags so GitHub cannot silently attach a release to a different commit than the assembled source identity.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 2f283c1b-ae06-4449-9ac9-897cd279f65e
Copilot AI lite review requested due to automatic review settings August 12, 2026 20:25
@benhillis
Ben Hillis (benhillis) requested review from a team as code owners August 12, 2026 20:25
@github-actions github-actions Bot added the Guide label Aug 12, 2026
Comment thread flowey/flowey_hvlite/src/pipelines/openvmm_source_release.rs Outdated

Copilot AI commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Install cargo-nextest

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds the “publication” half of the OpenVMM standalone source-release flow: a manually dispatched pipeline that assembles the deterministic source archive, validates it via the distro-build gate, generates build-provenance attestations, and drafts a GitHub release. It also adds maintainer documentation for cutting source releases and updates the packaging guide to reflect the new published release artifacts.

Changes:

  • Add a new Flowey pipeline + autogenerated GitHub Actions workflow for drafting OpenVMM source releases (archive + SHA256SUMS), gated by the distro-build validation.
  • Add build-provenance attestation support for the release artifacts (and pin actions/attest by commit SHA).
  • Add/extend Guide documentation for maintainers (source release process) and packagers (verification expectations).

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Guide/src/SUMMARY.md Adds the new maintainer guide page to the Guide navigation.
Guide/src/dev_guide/contrib/openvmm_source_release.md New maintainer procedure for selecting a version, dispatching the workflow, and publishing.
Guide/src/dev_guide/contrib/openvmm_packaging.md Updates packager guidance to reference GitHub releases + provenance attestation verification.
flowey/flowey_lib_hvlite/src/_jobs/publish_openvmm_gh_release.rs New job that attests and drafts the GitHub release from the assembled source archive.
flowey/flowey_lib_hvlite/src/_jobs/mod.rs Exposes the new publish job module.
flowey/flowey_lib_common/src/attest_build_provenance.rs Pins actions/attest to a full commit SHA for provenance generation.
flowey/flowey_hvlite/src/pipelines/openvmm_source_release.rs New pipeline wiring: assemble → validate distro build → attest + draft release.
flowey/flowey_hvlite/src/pipelines/mod.rs Registers the new pipeline under the ci command set.
.github/workflows/openvmm-source-release.yaml Autogenerated workflow definition for the new pipeline (manual workflow_dispatch).
.flowey.toml Registers the new Flowey pipeline for GitHub workflow generation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Guide/src/dev_guide/contrib/openvmm_source_release.md Outdated
Comment thread flowey/flowey_lib_hvlite/src/_jobs/publish_openvmm_gh_release.rs Outdated
Comment thread flowey/flowey_hvlite/src/pipelines/openvmm_source_release.rs Outdated
Comment thread Guide/src/dev_guide/contrib/openvmm_source_release.md Outdated
`gh release create` binds a draft to an existing tag as-is, and ignores
`--target` when that tag already exists. The previous "tag is unused" check
therefore only held at draft time: a tag created during the human review
window would silently rebind the release to another commit at publish time.

Create `refs/tags/openvmm-v<VERSION>` at the archived revision before the
draft. Ref creation is atomic, so a rerun either creates the tag or finds it
already present, in which case it must still name the exact archived commit.
Draft creation then passes `--verify-tag` so it can only ever attach to that
tag.

Also drop the local backend from the pipeline. It creates a tag and a release
in the upstream repository, so there is nothing meaningful for a local run to
do.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2f283c1b-ae06-4449-9ac9-897cd279f65e
Copilot AI review requested due to automatic review settings August 12, 2026 21:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Guide/src/dev_guide/contrib/openvmm_source_release.md:40

  • <COMMIT> here reads like a full SHA, but OpenVMM’s version formatting uses a short revision prefix (currently 9 chars) and may also append .dirty. Tightening the wording will help maintainers match what they see in practice.
The version stays at the released value after publication. Commits made
afterwards report `<VERSION>+g<COMMIT>` and are identifiable as
development builds, so there is no second commit to "reopen" the version.

flowey/flowey_lib_hvlite/src/_jobs/publish_openvmm_gh_release.rs:126

  • The existing-tag verification only accepts lightweight tags (object.type == "commit"). If openvmm-v<VERSION> ever exists as an annotated tag that ultimately points at the pinned commit (e.g., created out-of-band), this logic will fail even though the tag still names the correct revision. Consider resolving object.type == "tag" through git/tags/<sha> and comparing the underlying commit SHA.
                let tag_type = existing["object"]["type"].as_str();
                let tag_target = existing["object"]["sha"].as_str();
                if tag_type != Some("commit") || tag_target != Some(target.as_str()) {
                    anyhow::bail!(
                        "release tag {tag} already exists at {} ({}) instead of commit {target}",

The tag is a side effect the job cannot take back, and it was created
before anything checked whether a release already existed for that version.
`publish_gh_release` reads its prerequisites first, so the existing-release
check ran only after the tag had been pinned and the artifacts attested.

That inverted the intended failure order. If a release existed but its tag
did not -- a hand-created draft, or a tag deleted while its release was kept
-- a rerun dispatched at a different commit would recreate the tag at that
commit, silently rebinding the pre-existing release, and only then fail.
That is the rebinding this pipeline exists to prevent.

Check for the release first and feed the result into the pin step, so a
refused run leaves no tag behind. The shared publisher keeps its own check
as a backstop.

Also report an existing annotated tag as an annotated tag. `object.sha`
names the annotation rather than a commit, so comparing it against the
archived revision claimed the tag pointed at the wrong commit when the real
problem was the tag kind.

Finally, stop implying publication cannot rebind a draft. A draft tracks a
tag name and GitHub enforces immutability only after publication, so a tag
moved during review is still adopted at publish time. Creating the tag up
front rules out publication inventing one elsewhere; it does not freeze the
tag. Document confirming the target commit before publishing instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2f283c1b-ae06-4449-9ac9-897cd279f65e
Copilot AI review requested due to automatic review settings August 12, 2026 22:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants