Distribute desktop applications
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.
- 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.
# 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.
# 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.
# 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.
# 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.
# 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 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.
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.
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.
--scaffold-archiveturns a publish tree into a real first download for every declared RID.doctor --features, offline dry-run, and--no-publishprove progressively stronger claims without destination authority.- Candidates live in
-rcdestinations;promotecopies approved bytes to stable without rebuilding. - Native installers are matching-OS artifacts with explicit application assembly, two-phase signing, and independent verification.