ci: gate on the distribution build configuration - #4075
Conversation
There was a problem hiding this comment.
Pull request overview
Adds CI coverage for the Linux distribution-style build of openvmm (GNU toolchain, system dependencies, no .packages/-provided native libs), including a post-build linkage check to ensure OpenSSL is dynamically linked from the system.
Changes:
- Introduces a new Flowey job (
check_distro_build) that buildsopenvmmwith packager-like env overrides (PROTOCfrom system,OPENSSL_NO_VENDOR=1) and validates linkage vialdd. - Wires the new job into the checkin gates pipeline so it runs as a PR gate.
- Regenerates CI pipeline YAMLs to include the new job in both ADO and GitHub Actions workflows.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| flowey/flowey_lib_hvlite/src/_jobs/mod.rs | Exposes the new distro-build check job module. |
| flowey/flowey_lib_hvlite/src/_jobs/check_distro_build.rs | Implements the distro-style build + ldd-based linkage assertion. |
| flowey/flowey_hvlite/src/pipelines/checkin_gates.rs | Adds the distro-build job to checkin gates on Ubuntu x64. |
| ci-flowey/openvmm-pr.yaml | Adds the new distro-build job to the ADO PR pipeline. |
| .github/workflows/openvmm-pr.yaml | Adds the new distro-build job to the GitHub PR workflow and updates job dependencies. |
| .github/workflows/openvmm-pr-release.yaml | Adds the new distro-build job to the release-required PR workflow. |
| .github/workflows/openvmm-ci.yaml | Regenerated CI workflow to incorporate the new distro-build job and updated artifact UID references. |
| { | ||
| let distro_build_job = pipeline | ||
| .new_job( | ||
| FlowPlatform::Linux(FlowPlatformLinuxDistro::Ubuntu), |
There was a problem hiding this comment.
Our first consumer is Azure Linux, so it might be better to have an Azure Linux image. I can look into this as a follow-up.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
flowey/flowey_lib_common/src/publish_gh_release.rs:167
String::from_utf8(existing_release.stdout)?can fail with a context-less error ifghever emits non-UTF8 output (or if output is unexpectedly empty/garbled). Adding context here makes failures significantly easier to diagnose.
let is_draft = String::from_utf8(existing_release.stdout)?;
flowey/flowey_lib_hvlite/src/_jobs/validate_openvmm_release_tag.rs:10
- Avoid duplicating the release tag prefix constant: this job defines its own
RELEASE_TAG_PREFIX, whilebuild_openvmm_source_archivealready exports the canonical prefix. Reusing the shared constant prevents these two tag validators from drifting if the prefix ever changes.
use anyhow::Context;
use flowey::node::prelude::*;
const RELEASE_TAG_PREFIX: &str = "openvmm-v";
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:97
- Release notes are currently hard-coded to the placeholder text "TODO". This would publish releases with unhelpful notes and makes it easy to forget to update them later. Prefer auto-generated notes (or real notes text) instead of a placeholder.
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
flowey/flowey_lib_hvlite/src/_jobs/validate_openvmm_release_tag.rs:10
- This job defines its own
RELEASE_TAG_PREFIX, duplicating the canonical prefix already exported bybuild_openvmm_source_archive. Reusing the shared constant avoids accidental drift between tag validation and archive publishing.
use anyhow::Context;
use flowey::node::prelude::*;
const RELEASE_TAG_PREFIX: &str = "openvmm-v";
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:97
- Release notes are hard-coded to "TODO", which will create/leave a GitHub release with placeholder notes. Prefer generated notes (or real notes text) so draft releases don’t start with a misleading placeholder.
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
flowey/flowey_lib_hvlite/src/_jobs/validate_openvmm_release_tag.rs:13
- This job redefines
RELEASE_TAG_PREFIXand reimplements release-tag parsing that already exists incrate::build_openvmm_source_archive(RELEASE_TAG_PREFIX+parse_release_tag). Keeping two parsers in sync risks subtle divergence in what tags are considered valid.
const RELEASE_TAG_PREFIX: &str = "openvmm-v";
#[derive(Debug, PartialEq, Eq)]
struct ReleaseVersion {
major: u16,
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
flowey/flowey_lib_hvlite/src/assemble_openvmm_source_release.rs:161
gzipis executed via.output()?and the full compressed archive is buffered in memory before being written to disk. For a repo-sized tarball this can be tens/hundreds of MB and is avoidable—rungzipto create a.gzfile on disk and then rename it to the final archive name to keep memory usage low and make CI more stable.
let source_archive = output_dir.join(identity.archive_name());
let compressed = flowey::shell_cmd!(rt, "gzip -n --best --stdout {source_tar}")
.output()?;
fs_err::write(&source_archive, compressed.stdout)?;
fs_err::remove_file(source_tar)?;
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:97
- Release notes are currently hard-coded to "TODO". Even for draft releases this tends to leak into the release UI and makes it harder to audit what was published; if you don't have curated notes yet, prefer GitHub's generated notes.
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 19 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:100
- The release notes are currently hard-coded to the literal string "TODO". This will publish a draft release with unhelpful placeholder notes, and (if later made non-draft) could leak placeholder text publicly. Prefer generated notes (or real notes) instead of a placeholder.
ctx.req(flowey_lib_common::publish_gh_release::Request(
flowey_lib_common::publish_gh_release::GhReleaseParams {
repo_owner: "microsoft".into(),
repo_name: "openvmm".into(),
target,
tag,
title,
files,
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
draft: true,
prerequisites: Vec::new(),
done,
flowey/flowey_lib_hvlite/src/assemble_openvmm_source_release.rs:161
- This compresses the tarball by capturing
gzipstdout into memory (.output()?) and then writing it to disk. For a large source tree, this can significantly increase peak RSS and potentially OOM the runner. Prefer streaminggzipoutput directly to the destination file.
let source_archive = output_dir.join(identity.archive_name());
let compressed = flowey::shell_cmd!(rt, "gzip -n --best --stdout {source_tar}")
.output()?;
fs_err::write(&source_archive, compressed.stdout)?;
fs_err::remove_file(source_tar)?;
flowey/flowey_lib_hvlite/src/_jobs/validate_openvmm_release_tag.rs:23
- This tag parsing/validation logic largely duplicates
assemble_openvmm_source_release::parse_release_tag(prefix check, 3 components, leading-zero rejection, u16 range). Keeping two independent implementations increases the risk they drift and accept/reject different tags over time. Consider reusing the sharedparse_release_taghere and then parsing the returnedmajor/minor/patchforprevious_patch_tag()logic.
fn parse_tag(tag: &str) -> anyhow::Result<Self> {
let version = tag.strip_prefix(RELEASE_TAG_PREFIX).with_context(|| {
format!("OpenVMM release tag must start with {RELEASE_TAG_PREFIX:?}, got {tag:?}")
})?;
let components = version.split('.').collect::<Vec<_>>();
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
flowey/flowey_lib_hvlite/src/assemble_openvmm_source_release.rs:161
gzipoutput is captured into memory via.output()and then written to disk. For a source tarball this can be large enough to cause high memory usage / OOM on CI runners; it also does extra copying. Prefer streaminggzipdirectly to the destination file.
let source_archive = output_dir.join(identity.archive_name());
let compressed = flowey::shell_cmd!(rt, "gzip -n --best --stdout {source_tar}")
.output()?;
fs_err::write(&source_archive, compressed.stdout)?;
fs_err::remove_file(source_tar)?;
flowey/flowey_lib_common/src/publish_gh_release.rs:154
- This uses
std::process::Commandto invokegh release view, which bypasses Flowey’s command wrapping (e.g. nix-shell wrappers) and splits command execution logic between two APIs. Sinceflowey::shell_cmd!(..).output()already provides access to the exit status, consider using it here for consistency and to preserve wrappers.
let existing_release = std::process::Command::new(&gh_cli)
.args([
"release",
"view",
&tag,
"--repo",
&repo,
"--json",
"isDraft",
"--jq",
".isDraft",
])
.output()
.context("failed to run gh release view")?;
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:99
- Release notes are currently hard-coded to the placeholder string "TODO". If this job is ever used to publish a non-draft release, that placeholder would ship. Consider switching to generated notes or providing real text.
ctx.req(flowey_lib_common::publish_gh_release::Request(
flowey_lib_common::publish_gh_release::GhReleaseParams {
repo_owner: "microsoft".into(),
repo_name: "openvmm".into(),
target,
tag,
title,
files,
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
draft: true,
prerequisites: Vec::new(),
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:97
- Release notes are currently hard-coded to "TODO", which would end up published on the GitHub release. If you don’t have custom notes here, use generated notes (or provide real text) so reruns don’t publish placeholder content.
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
flowey/flowey_lib_hvlite/src/_jobs/check_distro_build.rs:215
- The ldd parsing only treats lines containing
=> /pathas resolved.lddcan also print resolved libraries as an absolute path without a=>(e.g./lib/.../libssl.so.3 (...)), which would make this gate fail even though the library is system-resolved. Consider accepting either form, while still rejecting=> not found.
.filter(|line| line.contains(lib))
.any(|line| match line.split_once("=>") {
Some((_, target)) => target.contains('/'),
None => false,
});
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:97
- The VmgsTool release is still being created with release notes literally set to "TODO". This will end up in the GitHub release metadata and isn’t useful for consumers; consider using generated notes (or real notes) instead.
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
flowey/flowey_lib_common/src/publish_gh_release.rs:161
- The PR description calls out that OpenVMM releases are published as drafts so re-runs on the same tag can replace assets. However,
publish_gh_releasecurrently skips publishing entirely whenevergh release view <tag>succeeds, which means a re-run cannot update draft assets/notes and will silently no-op instead of repairing a partial release attempt.
GhReleaseNotes::Generated => vec!["--generate-notes".to_owned()],
GhReleaseNotes::Text(notes) => vec!["--notes".to_owned(), notes],
};
let draft = draft.then_some("--draft");
flowey::shell_cmd!(rt, "{gh_cli} release create {tag} {files...} --repo {repo} --target {target} --title {title} {notes...} {draft...}").run()?;
flowey/flowey_lib_hvlite/src/assemble_openvmm_source_release.rs:161
gzip -n --stdoutis executed via.output()and then written to disk, which buffers the entire compressed tarball in memory. For a source release archive this can be large enough to cause unnecessary memory pressure or OOMs on CI runners; it’s safer to streamgzipstdout directly into the destination file.
let source_archive = output_dir.join(identity.archive_name());
let compressed = flowey::shell_cmd!(rt, "gzip -n --best --stdout {source_tar}")
.output()?;
fs_err::write(&source_archive, compressed.stdout)?;
fs_err::remove_file(source_tar)?;
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (5)
flowey/flowey_lib_hvlite/src/assemble_openvmm_source_release.rs:161
gzipoutput is currently captured into memory via.output()and then written to disk. For a full source tarball this can consume a large amount of RAM unnecessarily and risks OOM on CI runners. Prefer writing the compressed output directly to a file (or letgzipcreate the.gz) instead of buffering stdout.
let source_archive = output_dir.join(identity.archive_name());
let compressed = flowey::shell_cmd!(rt, "gzip -n --best --stdout {source_tar}")
.output()?;
fs_err::write(&source_archive, compressed.stdout)?;
fs_err::remove_file(source_tar)?;
flowey/flowey_lib_hvlite/src/_jobs/check_distro_build.rs:215
- The
lddverification only checks that the dependency resolved to some path containing '/'. That can still pass iflibssl/libcryptoresolve to a non-system path (e.g., a build directory via rpath), which defeats the stated goal of ensuring a distro-linked OpenSSL. Tighten the check to require a system library prefix (e.g.,/lib*or/usr/lib*).
.filter(|line| line.contains(lib))
.any(|line| match line.split_once("=>") {
Some((_, target)) => target.contains('/'),
None => false,
});
flowey/flowey_lib_hvlite/src/_jobs/publish_openvmm_gh_release.rs:116
- The comment above
draft: truesays reruns on the same tag will replace draft assets, but the implementation setson_existing: Fail, which will error out instead. Please update the comment to reflect the actual behavior (or change the behavior to match the comment).
// Publish as a draft. Releasing is new enough that a human
// should look at the assembled release before it is public,
// and a draft lets a re-run of the tag replace its assets
// instead of failing.
draft: true,
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:97
- Release notes are currently hard-coded to the placeholder text "TODO", which will end up in the GitHub release on the next version bump. Consider using generated notes (or a real static note) so published releases don't ship with placeholder text.
tag,
title,
files,
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
draft: true,
// This job runs on every push to main, but the tag only
flowey/flowey_lib_hvlite/src/_jobs/check_distro_build.rs:108
- This job is used both for PR gating and in the tag-triggered
release_openvmmpipeline, but it always assembles the archive as0.0.0-devwithtag: None. That means the release pipeline’s “build” job is not actually building the same (versioned) source archive that the publish job will assemble and upload, undermining the stated goal of sharing assembly machinery. Consider deriving the identity fromGITHUB_REF_*when running on a tag (GitHub backend), and falling back to0.0.0-devotherwise.
// A commit under test is not a release, so it is assembled under a
// version that cannot be mistaken for one, with no tag. Everything else
// about the assembly is identical to what the release does.
let openvmm_repo_path = ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:97
notesis currently set to the literal string "TODO", which will end up as the published GitHub release notes for vmgstool. That makes the release metadata unhelpful for consumers and looks accidental now that notes are explicit.
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
flowey/flowey_lib_hvlite/src/assemble_openvmm_source_release.rs:161
- This assembles the
.tar.gzby capturing all ofgzipstdout into memory (.output()?thenfs_err::write). For a source release tarball this can be large and cause avoidable peak memory/disk pressure on CI runners. Prefer compressing the tar in-place (lettinggzipwrite the output file) to keep memory usage bounded.
let source_archive = output_dir.join(identity.archive_name());
let compressed = flowey::shell_cmd!(rt, "gzip -n --best --stdout {source_tar}")
.output()?;
fs_err::write(&source_archive, compressed.stdout)?;
fs_err::remove_file(source_tar)?;
flowey/flowey_lib_hvlite/src/_jobs/publish_openvmm_gh_release.rs:120
- The PR description says rerunning the same release tag should replace draft assets ("a re-run of the same tag replaces its assets rather than failing"), but the implementation currently fails when a release already exists (
on_existing: ...::Fail). Please reconcile the behavior vs. the documented intent (either update the PR description/plan, or change the publish policy/behavior).
// already exists means an earlier attempt got this far, so say
// so rather than reporting success without doing anything.
// Regenerating a draft means deleting it first, which is
// deliberate: assets are never replaced automatically.
on_existing: flowey_lib_common::publish_gh_release::OnExistingRelease::Fail,
e497fc3 to
01151bb
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
flowey/flowey_lib_hvlite/src/assemble_openvmm_source_release.rs:161
gzip -n --best --stdout {source_tar}is executed via.output()and then written back out, which buffers the entire compressed source archive in memory. For a full source tarball this can be tens/hundreds of MB and risks unnecessary memory spikes/OOM on CI runners. Prefer lettinggzipwrite the.gzfile directly and then renaming it into the final asset name.
let source_archive = output_dir.join(identity.archive_name());
let compressed = flowey::shell_cmd!(rt, "gzip -n --best --stdout {source_tar}")
.output()?;
fs_err::write(&source_archive, compressed.stdout)?;
fs_err::remove_file(source_tar)?;
flowey/flowey_lib_hvlite/src/_jobs/publish_vmgstool_gh_release.rs:97
- This sets the GitHub release notes to the literal string "TODO", which will show up on the release page (even for drafts). If the intent is to avoid maintaining notes text for this automated release, consider using
GhReleaseNotes::Generatedso notes are meaningful and not a placeholder.
notes: flowey_lib_common::publish_gh_release::GhReleaseNotes::Text("TODO".into()),
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
flowey/flowey_lib_hvlite/src/assemble_openvmm_source_release.rs:167
gzip ... --stdoutis captured via.output()and then written to disk. That buffers the entire compressed tarball in memory, which can be hundreds of MB and risks OOM on CI runners. Since the archive is already on disk as a tar, it’s cheaper and safer to letgzipwrite its.gzfile directly.
You can name the intermediate .tar so that gzip -n --best <file> produces the final {version}-source.tar.gz in place, avoiding any in-memory buffering.
let prefix = format!("{}/", identity.source_root());
let source_tar = output_dir.join("openvmm-source.tar");
flowey::shell_cmd!(
rt,
"git -c tar.umask=0002 archive --format=tar --output {source_tar} --prefix={prefix} --add-file={metadata_path} HEAD"
)
.run()?;
fs_err::remove_dir_all(&metadata_dir)?;
// `-n` omits the timestamp and original name from the gzip
// header, which is what makes the result reproducible. Do not
// use `git archive --format=tar.gz`: it defers to the
// `tar.tgz.command` config, so reproducibility would depend on
// the machine's git configuration.
let source_archive = output_dir.join(identity.archive_name());
let compressed = flowey::shell_cmd!(rt, "gzip -n --best --stdout {source_tar}")
.output()?;
fs_err::write(&source_archive, compressed.stdout)?;
fs_err::remove_file(source_tar)?;
flowey/flowey_lib_hvlite/src/_jobs/check_distro_build.rs:210
- The PR description says the gate should also assert the built binary’s OpenSSL deps resolve to real system paths (and treat
=> not foundas failure). The current implementation only checksreadelf -dforNEEDEDentries, which will still pass even if the runner can’t actually resolve those libraries at runtime.
Consider keeping the readelf (direct dependency) check, but also running ldd on the built binary and validating that libssl.so and libcrypto.so resolve to absolute paths and are not not found.
// Read the binary's own `NEEDED` entries rather than `ldd`'s
// output: `ldd` reports the whole transitive closure, so it
// would still be satisfied if `openvmm` linked a static
// OpenSSL while some unrelated shared library pulled in the
// system one.
let binary = format!("target/{target}/release/openvmm");
|
It seems like this does more things than it should:
Can we separate these? The second seems very reasonable to me. I think we probably want to bikeshed the first change a bit--unlike for our dependency repos (mu_msvm, openvmm_deps), here I think we want to be more intentional about what creates a release. |
OpenVMM is meant to be built and packaged by Linux distributions from a source archive, which makes that configuration a shipping interface. It is also the one configuration nothing in CI covers: every other build provisions native dependencies through `.packages/`, which a packager cannot use. A change that only resolves through `.packages/` therefore breaks downstream packagers silently. Add a job that does what a packager does, in order: 1. assemble a source archive from the commit under test, plus a `SHA256SUMS` covering it; 2. `sha256sum --check --strict`; 3. unpack outside the repository, so nothing can reach back into the checkout; 4. assert there is no `.git` inside; 5. assert the archive's embedded `.openvmm-release.json` matches what it was assembled as; 6. `cargo build --release --locked -p openvmm` with `PROTOC` and `OPENSSL_NO_VENDOR=1`, matching what a spec file does; 7. assert the binary's own `NEEDED` entries name the system OpenSSL. Building the checkout rather than an archive would let this pass on a tree a packager cannot reproduce, since a packager has no `.git` directory and no untracked files. The archive also has to carry its identity in a file, for the same reason. Step 7 is what keeps the build honest: if something acquired a vendored or static OpenSSL the build would still succeed, but the packaged binary would no longer be one the distribution can service. It reads `readelf -d` rather than `ldd` because `ldd` reports the whole transitive closure, and so would be satisfied by an unrelated library pulling OpenSSL in. Assembly is reproducible -- `git archive` is deterministic for a commit, `gzip -n` omits the timestamp, and `tar.umask` is pinned rather than inherited from the machine. Measured at 5m35s on a GitHub-hosted runner, against an existing 11m x64-linux baseline. Dropping debug info from the release profile and disabling incremental compilation is what keeps it there. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0ba1c0df-faf0-4a0e-b39d-c3eb0e363fce
a4d7537 to
6a923f2
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
flowey/flowey_lib_hvlite/src/assemble_openvmm_source_release.rs:160
gzip -n --stdout ... .output()?buffers the entire compressed tarball in memory before writing it to disk. For a large source tree this can significantly increase peak RAM usage (and risk OOM) even though the result ultimately lives on disk. Prefer lettinggzipwrite its own output file (with-fto allow reruns) and then rename it to the final archive name.
// `-n` omits the timestamp and original name from the gzip
// header, which is what makes the result reproducible. Do not
// use `git archive --format=tar.gz`: it defers to the
// `tar.tgz.command` config, so reproducibility would depend on
// the machine's git configuration.
let source_archive = output_dir.join(identity.archive_name());
let compressed = flowey::shell_cmd!(rt, "gzip -n --best --stdout {source_tar}")
.output()?;
fs_err::write(&source_archive, compressed.stdout)?;
fs_err::remove_file(source_tar)?;
Adds a CI gate that builds
openvmmthe way a Linux distribution package builds it.Split out of the original #4075 at @jstarks' request. The release automation that was here now lives in #4090, left as a draft so the "what should create a release" question can be settled separately.
Why
OpenVMM is meant to be built and packaged by distributions from a source archive, which makes that configuration a shipping interface. It is also the one configuration nothing in CI covers: every other build provisions native dependencies through
.packages/, which a packager cannot use. Every native dependency has to come from a distribution package instead.Without this, a change that only resolves through
.packages/breaks downstream packagers silently, and we find out when someone tries to build it.What it does
Exactly what a packager does, in order:
SHA256SUMScovering itsha256sum --check --strict.gitinside.openvmm-release.jsonmatches what it was assembled ascargo build --release --locked -p openvmmwithPROTOCpointed at the system protoc andOPENSSL_NO_VENDOR=1, matching what a spec file doesNEEDEDentries namelibssl.soandlibcrypto.soIt builds an assembled archive rather than the checkout because building the checkout would let this pass on a tree a packager cannot reproduce — a packager has no
.gitdirectory and no untracked files. That is also why the archive has to carry its identity in a file.Step 7 is what keeps the build honest: if something acquired a vendored or static OpenSSL the build would still succeed, but the packaged binary would no longer be one the distribution can service. It reads
readelf -drather thanldd, becauselddreports the whole transitive closure and so would still be satisfied ifopenvmmlinked a static OpenSSL while an unrelated library pulled the system one in.Validation
Run on Linux against this branch, in a container, on git 2.43.0:
umask 077, and a full clone versus--depth=1. flowey's output was also byte-identical to an independent hand run of the documented command sequence.git archiveon that clone takes 0.166s and captures all 2825 tracked files..gitabsent,Cargo.lockunchanged by--locked, system protoc resolved, and.packages/never created.Cost
5m35s on a GitHub-hosted runner, against the existing 11m x64-linux baseline. Dropping debug info from the release profile and disabling incremental compilation is what keeps it there.