Skip to content

Release Pipeline

A platform-neutral dataflow for producing installable application releases without flattening platform-specific trust and repository rules. The central invariant is: build each target from an immutable source identity, transform it in an auditable order, then promote the same verified bytes.

Last reviewed: July 12, 2026

The model

text
source tag

target-matrix binaries

per-target stage trees

archives / bundles / native packages

sign → notarize where required → staple where supported

final checksums + SBOM + provenance

immutable release host

repository/store/community-index metadata

channel promotion (candidate → stable), never rebuild

Each arrow is a provenance boundary. Cross-platform orchestrators automate different subsets: cargo-dist, GoReleaser, JReleaser, dotnet-releaser, and electron-builder span matrix builds through publication; CPack, fpm/nfpm, cargo-packager, Briefcase, cx_Freeze, jpackage, and swift-bundler concentrate on stage/package construction; Velopack and Conveyor extend identity into updater feeds. None makes the target platform's signing or repository policy disappear.

1. Source tag: the immutable intent

The release begins from a signed or otherwise protected source identity, normally a SemVer tag. The tag selects source, version, and release notes; workflow inputs may select a channel but must not silently change payload contents. The release job should reject a dirty tree, unexpected branch, missing tag, duplicate version, or tag/version mismatch before consuming signing credentials (Sparkles baseline, cargo-dist, GoReleaser).

For Sparkles today, annotated vX.Y.Z tags are the sole package version; pushing a tag can make it visible to code.dlang.org independently of GitHub Release publication. That irreversibility is a current fact, not a recommendation (Sparkles baseline).

2. Target-matrix binaries

Compile one binary set per supported target tuple, recording at least:

  • source tag and commit digest;
  • compiler/linker and SDK identity;
  • target architecture, OS, ABI, minimum OS/libc baseline;
  • feature/configuration flags and dependency lock digest;
  • test results associated with the same commit.

A matrix row is not yet a distributable artifact. A Linux binary may bind to too-new glibc; a Windows executable may need adjacent DLLs and Authenticode; a macOS binary may need universal slices, rewritten load commands, entitlements, and nested signatures (platform gotchas, Linux native, WiX/MSI, macOS bundles, macOS signing).

Cross-compilation is valid only where the compiler, packager, verifier, and signer support it. Prefer native hosted runners for final Windows and macOS artifacts until an explicit reproducible cross-host path is demonstrated (comparison).

3. Per-target stage trees

Normalize binaries into a declared stage-tree schema before generating formats. A CLI stage might contain bin/, license/notices, completions, and man pages; GUI stages add icons, desktop metadata, frameworks, resources, and launchers. Make the stage tree an inspectable CI artifact and validate:

  • only expected files are present;
  • executable modes and symlinks are correct;
  • runtime library resolution closes over the intended bundle/system boundary;
  • licenses/notices accompany redistributed dependencies;
  • metadata identity/version/architecture match the source tag;
  • smoke tests run from the stage, outside the build directory.

This separates payload correctness from format generators. AppDir, .app, CMake install trees, and Electron/Python application directories instantiate the same concept (linuxdeploy/appimagetool, macOS bundles, CPack, electron-builder, Briefcase, cx_Freeze).

4. Packages and bundles

Fan each validated stage into only the formats justified by a user/channel need:

Run format-native inspection before signing (dpkg-deb, RPM query/verify tools, MSI validation, MSIX tooling, codesign structure inspection). Installation tests must use clean disposable VMs/containers and cover install, launch, upgrade, and uninstall where the format promises them. This survey does not claim those tests have been run for Sparkles (Sparkles baseline).

5. Sign, notarize, staple

Trust operations are ordered from inner code to outer delivery object:

  1. sign leaf executables/libraries/helpers where the platform requires;
  2. sign the enclosing bundle/package/installer;
  3. submit supported Apple artifacts for notarization;
  4. staple the accepted ticket to supported objects;
  5. verify signatures and policy from a fresh target host.

Windows Authenticode/MSIX and Apple Developer ID are separate credential systems; Linux repository metadata uses repository keys and should not be conflated with executable code signing (WiX/MSI, MSIX, macOS signing, Linux repositories). Signing secrets should be unavailable to pull requests and untrusted build steps. Where practical, isolate signing from compilation and accept only digest-addressed inputs.

Because signing and stapling can change bytes, any checksum or SBOM tied to the final artifact must be emitted after them. An SBOM describing the unsigned stage may still be useful, but its relationship to the signed container must be recorded explicitly (concepts).

6. Final checksums, SBOM, and provenance

For every final artifact, emit a manifest containing filename, media/format, target, size, cryptographic digest, source tag/commit, and signing status. Add:

  • an SPDX or CycloneDX SBOM for shipped components;
  • provenance identifying builder/workflow and source/material digests;
  • detached signatures or attestations where the delivery client understands them;
  • a machine-readable release manifest used by downstream index generation.

The release manifest should be generated from actual bytes, not duplicated handwritten configuration. cargo-dist, GoReleaser, and JReleaser illustrate orchestrators growing from archive production toward checksums, attestations/SBOMs, and publisher integrations; exact support and defaults belong to their deep-dives.

IMPORTANT

A checksum posted next to an artifact on the same compromised origin is an integrity aid, not independent publisher authentication. Repository signatures, code signatures, and provenance answer different trust questions (concepts § signing layers).

7. Immutable release host

Upload by digest/version and reject replacement. The host is the canonical origin for community catalogs that reference URLs and hashes: winget, Scoop, Homebrew casks/formulae, and Chocolatey packaging all become fragile if an asset at a stable URL mutates (winget, scoop, homebrew, chocolatey).

Publication should be idempotent: rerunning may verify or fill a missing asset but must not overwrite a different digest for the same version. GitHub Release, object storage, and package repositories require different APIs; orchestrators can coordinate them but cannot supply immutability if the host allows destructive replacement (GoReleaser, JReleaser).

8. Package indexes and repositories

Generate channel metadata from the immutable release manifest:

  • APT/RPM/pacman repositories index package identity, architecture, version, dependencies, path, size, and hashes, then sign repository metadata (Linux repositories);
  • Flatpak/Snap publish repository/store-native refs, assertions, and channels (Flatpak, Snap);
  • winget, Chocolatey, Scoop, and Homebrew add ecosystem-specific manifests/recipes that reference or rebuild from upstream artifacts (winget, chocolatey, scoop, homebrew);
  • Velopack/Conveyor produce updater metadata whose identity, channel, signature, and rollout semantics become part of the application contract (Velopack, Conveyor).

Treat index publication as a separate, reviewable job with least-privilege credentials. A package index should consume final artifact digests rather than trigger a second build.

9. Promotion and rollback

A candidate release passes installation/upgrade smoke tests before its existing digest is made visible in stable. Promotion should update signed metadata or channel pointers, not recompile or repackage. Record the prior channel state so metadata can be rolled back when the client model permits; never “fix” a published version by replacing its bytes. Flatpak refs, Snap channels, package-repository suites, and updater feeds provide concrete channel mechanisms (Flatpak, Snap, Linux repositories, Velopack).

Pipeline acceptance matrix

GateEvidence requiredFailure stops
Sourceprotected tag/commit, clean version mappingall downstream work
Binarytarget metadata, tests, dependency/load auditstage creation
Stageinventory, launch smoke test, noticespackaging
Packagenative inspection + clean-host install/upgrade/uninstallsigning/publication
Trustsignature verification; Apple acceptance + staple verificationchecksums/publication
Supply chainfinal digest manifest, SBOM, provenancestable publication
Hostimmutable upload confirmed by read-back digestindex generation
Indexschema/policy validation + signaturepromotion
Promotioncandidate smoke results and explicit approvalstable channel

This is a recommended validation model derived from the surveyed systems, not current Sparkles behavior. The incremental adoption path is in recommendations.

Sources

  • Shared definitions and primary specifications: concepts.
  • Format mechanics: artifact formats and the linked format deep-dives.
  • Current repository behavior: Sparkles baseline.
  • Tool-specific automation claims: the linked deep-dives, pinned to local source commits.