Security and evidence
Release integrity
Verify signed tags, checksums, attestations and the separation between build and publication authority.Maelys Warden releases use three independent integrity layers:
- a maintainer-signed annotated Git tag authorizes the release;
- per-file SHA-256 checksums detect byte changes after download;
- GitHub artifact attestations provide a keyless Sigstore-signed statement binding each artifact to this repository, workflow and source commit.
A checksum is not a signature. An attestation proves provenance, not that the source or operating-system sandbox is free of vulnerabilities.
Verify an artifact
Download the package and its adjacent .sha256, then run:
sha256sum -c maelys-warden-0.38.0-linux-x86_64.tar.gz.sha256
gh attestation verify maelys-warden-0.38.0-linux-x86_64.tar.gz \
--repo maelys-dev/maelys-wardenOn macOS, replace sha256sum with shasum -a 256 and compare the value in the
checksum file. SHA256SUMS in each GitHub release covers all uploaded
tarballs, including Homebrew bottles, Debian packages and RPM packages.
GitHub displays the verification state of the signed release tag. The release workflow independently queries GitHub's tag-object verification and refuses an unsigned, lightweight or invalid tag before compiling.
Publication separation
The matrix build runs candidate code with read-only repository permission and no publication token. It produces native Linux x86_64, Linux arm64 and macOS arm64 artifacts, then requests provenance attestations through GitHub OIDC.
A final qualification job compiles nothing. After every build and physical gate
passes, it downloads the same-run artifacts, verifies every checksum and the
physical tested-bytes evidence, then writes and attests
release-qualification.json. That manifest binds every candidate byte to the
source commit, canonical future tag, repository, workflow run and run attempt.
The complete directory is uploaded once as release-candidate-vX.Y.Z.
The signed-tag invocation contains no build or VM job. Its separate publish
job locates an unexpired, successful manual qualification for the exact tag
target SHA, downloads only that candidate, verifies its manifest and Sigstore
attestation against refs/heads/main, and rechecks the physical evidence. It
then waits for approval of the protected release environment and is the only
job granted contents: write.
The optional macOS drivers have an additional boundary and a build-once rule:
hosted builders physical Apple Silicon runner qualification
│ │ │
├─ Swift drivers ───────────────┐ │ │
├─ Warden/OCI/Krun packages ────┼──────►│ test extracted bytes │
├─ guest kernel/bundle ─────────┤ │ emit digest evidence ───►│
└─ libkrun Tahoe bottle ────────┘ │ │
└── no compiler/build ─────┘
│
attested candidate │
▼
signed tag on the same SHA ───────────────────────────────► verify + publish
no build, no VMThe macOS 26 Swift compilation starts immediately and runs in parallel with
the guest-kernel build. Packaging downloads those executables rather than
invoking Swift again. The Krun packaging job links against the exact Sequoia
bottle produced by the bottle matrix. The physical macOS 26 runner downloads
the exact Warden Tahoe bottle, Containerization, Krun, OCI-tools, guest-kernel
and Tahoe libkrun archives, extracts or installs them, and runs both VM matrices with
RELEASE_PREBUILT=1. That mode has no Swift, C-link, materializer-build or
packaging prerequisite.
The physical host is pre-provisioned with the materializer's Homebrew runtime libraries. A release checks their presence but never installs or upgrades them; this removes network access and package-manager compilation from the physical critical path. Only the two exact local bottle archives under test are installed during the job.
The intended critical path is therefore one Swift build followed by the physical VM matrix, not their sum repeated several times. The release target is under 35 minutes on the project runner; the physical job has a 30-minute hard timeout and the Swift build a separate 30-minute timeout. A timeout is a release failure, never authorization to omit the physical proof.
Pre-tag release qualification
The full graph must be exercised from main before creating a tag:
gh workflow run release.yml --repo maelys-dev/maelys-warden --ref mainA manual dispatch is structurally a qualification. It admits only main, uses
the commit SHA as the immutable Homebrew source ref, embeds the canonical future
vX.Y.Z release URL, and runs the package, bottle and physical tested-bytes
gates. It then seals and attests the only candidate the matching tag is allowed
to publish. The publish job is unreachable; the protected release
environment is never entered and no GitHub release or tag is created.
The timing report contains machine-readable JSON and a Markdown table for every
completed candidate job. The workflow fails and emits no release candidate if
any gate failed. After success, scripts/cut-release.sh creates the signed tag
on that exact SHA. The tag workflow searches for the successful qualification
and fails closed if its candidate is missing, expired, from another SHA, or
from another run attempt.
Pipeline time is a correctness property
Cheap admission runs before any build runner: workflow topology, Python and shell syntax, version coherence, and the release audit must pass first. CI then classifies the changed paths without a third-party filtering action. Generic documentation, workflow and shell changes do not rebuild the Linux guest bundle, guest kernel, Krun/OCI package, or either Swift driver. Changes to a driver, guest source, kernel configuration, or their exact build scripts remain conservatively connected to every artifact they affect.
The Apple service driver and direct Containerization driver are separate DAG
nodes. They compile in parallel and have independent SwiftPM caches whose keys
contain the macOS/architecture tuple, Swift toolchain identity, Package.swift,
the complete resolved dependency pins, and the driver source digest. A pin or
toolchain change cannot reuse an old
dependency closure; a source change may reuse only incremental state from the
same pins. Both jobs still run their normal verification target after restore.
CI warms these default-branch caches and the pre-tag qualification consumes the
same keys. A qualification never path-skips an artifact: it builds or exactly
restores and revalidates every publication candidate, then the physical runner
tests those exact bytes without rebuilding. Tag promotion consumes only the
sealed candidate and therefore cannot accidentally turn a cache miss into a
second build.
After the VM gates pass, physical-release-evidence.json records the SHA-256
and size of every tested publication candidate and the SHA-256 of the
executables actually run. The runner attests that evidence through GitHub
OIDC; publish refuses an asset whose bytes differ from it. The repository
audit also rejects a workflow that reintroduces --build-from-source, driver
compilation or repackaging in the physical job, lets qualification reach
publication, or makes signed-tag promotion depend on any build or VM job.
Sequoia and Tahoe runners independently build and attest the Warden headless libkrun bottles. A Linux arm64 runner separately builds and reproducibility-checks the complete Warden-owned Linux/arm64 guest bundle. The Krun signature carries the Hypervisor and dynamic-library-validation entitlements. No Apple signing identity or release secret is required. Checksums, the maintainer-signed Git tag and GitHub provenance attestations provide the release-integrity layers; neither driver claims a Developer ID identity or Apple notarization.
Homebrew publication
The GitHub release and Homebrew tap remain separate authority boundaries. After every release asset exists, the maintainer runs one transaction:
scripts/update-homebrew-tap.sh v0.36.0The script downloads every release input, verifies its adjacent checksum and
GitHub/Sigstore attestation, cross-checks bottle JSON against bottle bytes,
clones the tap once, renders all seven formulas, runs brew style, creates one
signed commit and pushes once. It therefore never exposes users to a tap in
which, for example,
the driver was updated but its guest kernel or OCI tools were not. The older
per-formula scripts remain implementation utilities, not the release path.
Cross-repository publication is not delegated to GITHUB_TOKEN: automatic tap
updates require a separately scoped credential, which is intentionally absent
until it is configured explicitly.
Package scope
Warden ships a standalone CLI, product SDKs and static C libraries, headers and pkg-config metadata. Linux therefore has separate runtime and development packages:
libmaelys-warden-dev_<version>_amd64.debor_arm64.deb;maelys-warden-devel-<version>-1.x86_64.rpmor.aarch64.rpm.maelys-warden_<version>_amd64.debor_arm64.deb;maelys-warden-<version>-1.x86_64.rpmor.aarch64.rpm.
The platform tarballs install the same SDK under /usr/local. Homebrew installs
project-built Sequoia/Tahoe bottles of the signed source through
maelys-dev/homebrew-tap, with a source build retained as fallback. Optional MCP Runtime
and maelys-sandbox-policy adapters are source integrations in the current development
line and are not silently bundled into the core binary packages.
Apple Silicon additionally receives:
maelys-warden-apple-container-driver-<version>-macos-arm64.tar.gz;- a dedicated
maelys-warden-apple-container-driverHomebrew formula consuming that prebuilt release asset rather than invoking Swift locally; maelys-warden-oci-tools-<version>-macos-arm64.tar.gz, containing the common OCI materializer and Warden-owned Linux/arm64 guest bundle;maelys-warden-guest-kernel-<version>-linux-arm64.tar.gz, containing the common raw guest kernel, its config and its provenance manifest;maelys-warden-containerization-driver-<version>-macos-arm64.tar.gz, containing only the direct prebuilt driver and its attestation manifest;maelys-warden-krun-driver-<version>-macos-arm64.tar.gz, containing the signed host driver and arequirements.jsonmanifest which binds the shared OCI tools by digest rather than copying them;maelys-warden-libkrun-1.19.4_1.arm64_{sequoia,tahoe}.bottle.tar.gz, the headless upstream libkrun closure built with featuresblk,external-kernel-only;- a dedicated
maelys-warden-krun-driverformula depending on Warden's headless libkrun bottle without libkrunfw rather than copying dylibs. - dedicated
maelys-warden-oci-tools, guest-kernel and direct-driver formulas; Homebrew owns each installed path from exactly one formula.