Distribute desktop applications

View .md

kanject aws distribute carries a .NET desktop project from a local publish tree to downloadable, checksummed release artifacts across macOS, Windows, and Linux. It owns the edition × RID matrix, destination routing, candidate channel, release feed, and byte-identical promotion.

You'll learn
  • Register a desktop matrix and create a working ZIP/TAR archive without writing a packager
  • Prove version, routes, tools, and finished artifacts locally before adding credentials
  • Stage feed-derived candidates to isolated destinations and promote only approved bytes
  • Graduate to DMG, MSI, and DEB with the correct payload-sign → package → container-sign → verify order

Start with a download that works

Distribution reads <Version>, then <VersionPrefix>, from the project or nearest Directory.Build.props; --version is an explicit controlled override. --scaffold-archive creates a checked-in, dependency-free .NET helper and wires packageCommand plus artifactGlobs. Windows cells produce ZIP; macOS/Linux produce permission-preserving TAR.GZ.

bash
# Version the product in its csproj (or nearest Directory.Build.props)# <Version>1.0.0</Version># Register the cross-platform desktop matrix and create a working archivekanject add distributable src/Acme.Studio/Acme.Studio.csproj   --id acme-studio   --rid osx-arm64   --rid win-x64   --rid linux-x64   --self-contained   --scaffold-archive

Route cells to destinations

Destinations live in the stage file under distribution.targets[]. A target selects distributable + edition + RID; exact selectors beat *. Desktop downloads normally go to versioned S3 buckets or GitHub Releases. Package repositories should use kanject packages rather than treating CodeArtifact as a generic file store.

bash
# Add destinations through the guided flowkanject configure distribution   --env prod   --distributable acme-studio# Review the resulting selector → destination mapkanject configure distribution list --env prod

Use the safety ladder

The local path deliberately increases authority one step at a time. The first plan is credential-free. The build-only run executes the real artifact phases but cannot upload or write a ledger. Only after both are green should a candidate job receive destination credentials.

bash
# Readiness: version, routes, packaging, signing, local toolskanject doctor --features# Guaranteed local matrix plan — no credentials or destination callskanject aws distribute   --env prod   --distributable acme-studio   --dry-run --offline# Execute publish → package → verify → checksum, but upload nothingkanject aws distribute   --env prod   --distributable acme-studio   --no-publish
  • doctor --features — version provenance, routes, helper projects, tool availability, and incomplete sign/verify gates.
  • --dry-run --offline — project, version, matrix, selectors, and routes only; candidate numbering is intentionally unavailable offline.
  • --dry-run — adds destination-aware preflight and may require AWS credentials.
  • --no-publish — runs the real artifact path and leaves each cell under .kanject/dist/<id>/<edition>/<rid>/.

Candidate first, stable after approval

distribute init creates or adopts every declared S3 destination, enforces public-access block, SSE-S3, and versioning, and provisions an isolated -rc sibling. Candidate numbering comes from that candidate feed. Promotion is an S3 server-side copy and release-feed flip—not a rebuild.

bash
# Provision/adopt stable and -rc S3 destinationskanject aws distribute init --env prod --dry-runkanject aws distribute init --env prod# Build once and stage the next feed-derived candidatekanject aws distribute   --candidate   --env prod   --distributable acme-studio# After hands-on approval, copy the tested bytes to stablekanject aws distribute promote --env prod

Graduate to native installers

Once the archive path is proven, scaffold the inert release kit. It copies matching-OS starters for DMG (hdiutil), MSI (WiX v5+), and DEB (dpkg-deb), plus macOS notarization, Windows Authenticode, independent verification, a RID router, and a product-specific README. It never changes the manifest or reads credentials.

bash
# Copy inert, auditable DMG/MSI/DEB and signing starterskanject configure distribution scaffold   --distributable acme-studio# Fill the generated release.env TODOs, wire the chosen commands,# then prove each native cell on its matching OS before staging it.kanject aws distribute   --env prod   --distributable acme-studio   --rid <matching-rid>   --no-publish
bash
kanject aws distribute --env prod --distributable acme-studio --rid osx-arm64 --no-publish

Assemble the .app, sign its payload, build/sign the DMG, notarize, staple, then independently verify with Apple tooling on a macOS runner.

powershell
kanject aws distribute --env prod --distributable acme-studio --rid win-x64 --no-publish

Build the MSI with the pinned WiX tool, Authenticode-sign the payload and finished installer, then inspect the signature on a Windows runner.

bash
kanject aws distribute --env prod --distributable acme-studio --rid linux-x64 --no-publish

Build the DEB with explicit ownership, permissions, desktop metadata, and dependencies; inspect its control data and contents before staging.

Recap
  • --scaffold-archive turns a publish tree into a real first download for every declared RID.
  • doctor --features, offline dry-run, and --no-publish prove progressively stronger claims without destination authority.
  • Candidates live in -rc destinations; promote copies approved bytes to stable without rebuilding.
  • Native installers are matching-OS artifacts with explicit application assembly, two-phase signing, and independent verification.
Was this page helpful?