Software Updates¶
Keygate distributes signed application updates: you upload per-platform artifacts grouped into a release, and clients consume standard update feeds or fetch license-gated download URLs. This requires object storage to be configured.
How releases work¶
- A release is a version (e.g.
1.2.0) in a channel (stable,beta,alpha,dev) with one or more per-platform artifacts (darwin-arm64, windows-x64, linux-x64, …). - Atomic publish gate — a release only becomes visible once fully uploaded; half-uploaded releases never leak.
- Yank — instantly withdraw a bad release.
- Ed25519 signing — each product has its own signing key (private key encrypted at rest under AES-256-GCM with an HKDF-derived subkey). Trust is established by the artifact signature, not URL secrecy.
- Server-side SHA-256 — integrity hashes are computed server-side; the client's hash is never trusted.
Uploads use presigned URLs (direct browser→storage, no proxying through Keygate).
Update feeds (public)¶
One publish serves every major updater format — all public, since trust comes from the signature, not secrecy:
| Feed | Format | Endpoint |
|---|---|---|
| Sparkle (macOS) | appcast XML | GET /api/v1/releases/{product_slug}/feed.xml |
| Velopack (Windows) | JSON feed | GET /api/v1/releases/{product_slug}/feed.json |
| Tauri (cross-platform) | manifest | GET /api/v1/releases/{product_slug}/upgrade.json |
Feeds are per-platform and honor the channel fallback chain (a beta user also sees stable). The product's minimum_supported_version is embedded so clients can force-upgrade off builds below the floor.
Feeds are public by design
Genuinely private builds don't belong in these feeds — put them on internal CI/CD distribution (a private bucket, TestFlight, etc.). Because license gating happens at app start via verify, a public update feed never breaks an installed client when a license rotates.
License-gated downloads¶
For manual or gated downloads, POST /license/download returns a short-lived presigned URL:
- Omit
versionto get the latest published release for the channel/platform. - Returns
url,expires_at,version,platform,sha256,file_size.
Support-window enforcement (perpetual fallback)¶
When the license has a support_until, downloads honor it:
- Any release published before
support_untilis always downloadable — forever. - "Latest" resolves to the newest release the support window covers.
- A pinned version newer than the window returns
403 SUPPORT_EXPIRED. - No
support_until= unlimited.
Failure modes: 400 invalid platform/channel · 403 license inactive or SUPPORT_EXPIRED · 404 RELEASE_NOT_FOUND · 410 RELEASE_YANKED · 503 STORAGE_DISABLED.
Object storage¶
S3-compatible — Cloudflare R2, AWS S3, MinIO, anything speaking SigV4. Configure via the STORAGE_* variables and the RELEASE_KEY_ENCRYPTION_KEY master key (which also encrypts license keys at rest). See Configuration.