# Distribution

Burrow distribution is split by platform authority.

## Apple

macOS, iOS, and visionOS builds use the Apple app plus NetworkExtension packet
tunnel provider. App Store and TestFlight upload lanes stay separate from build
lanes so signing, export, metadata, and external distribution are visible.

Developer ID signing is moving to a KMS-backed key path. The
`apple-developer-id-application` key in the Burrow `burrow-identity` Google KMS
key ring is non-exportable and can produce a standard Apple CSR through
`Scripts/apple/google-kms-csr.py` or the manual Forgejo
`apple-developer-id-kms-csr.yml` workflow. The active G2 Developer ID
Application certificate is `9JKN6HXBHC`, stored as public material at
`Apple/Certificates/developer-id-application-9JKN6HXBHC.cer`, and expires on
`2031-06-08`.

App Store iOS signing uses the same non-exportable model. The
`apple-ios-distribution` key in the Burrow identity key ring produced the active
`IOS_DISTRIBUTION` certificate `3G42677598`, stored as public material at
`Apple/Certificates/ios-distribution-3G42677598.cer`, and expires on
`2027-06-07`. App Store Connect certificate creation can be driven by
`Scripts/apple/create-asc-certificate.mjs` once a KMS-backed CSR has been
generated.

When `BURROW_IOS_DISTRIBUTION_CERTIFICATE_ID` is set, provisioning-profile sync
pins iOS App Store profiles to that certificate. Existing App Store profiles
with the same name are deleted and recreated if Apple reports that they contain
a different distribution certificate.

Sparkle appcast signing keeps the `sparkle-ed25519` Google KMS key available
for payloads small enough for direct KMS Ed25519 signing, but normal macOS
release archives are larger than Google KMS accepts for direct Ed25519
messages. Those archives are signed directly from the decrypted release
`SPARKLE_EDDSA_KEY_PATH` seed so Sparkle receives the standard
full-archive EdDSA signature it verifies at update time. macOS release builds
embed public EdDSA key
`uugZuJeqvvKd91NZ6F1Fv2cQenUbIG/ZW3L9MuaEz30=` and point Sparkle metadata at
`https://releases.burrow.net/sparkle/appcast.xml`. The appcast signer runs only
when `BURROW_SPARKLE_SIGN_WITH_KMS=true` so unsigned local validation artifacts
do not require Google credentials.

This is not equivalent to the existing `.p12` keychain import path. The current
Xcode packaging lane can still use exportable signing assets, while the
KMS-backed Apple certificates require a follow-up signer integration that can
ask Google KMS to produce code signatures without exporting the private key.

## Android

Android starts with a Kotlin shell and Rust core FFI stub. Full VPN support must
use Android `VpnService`, which means Play Store builds need the VPN service
declaration, clear in-app disclosure, and data-safety review before upload.

## Linux

The GTK app is the desktop UI. For VPN operation, it should talk to a host
daemon or privileged helper that owns TUN, routes, DNS, and firewall state.

Flatpak can package the GUI, but it should not be treated as the privileged data
plane. The preferred Linux shape is:

- native packages install `burrowd`, the systemd unit/socket, D-Bus policy, and
  polkit policy
- the Flatpak GUI talks to the host service over a narrowly named D-Bus API or a
  constrained local daemon socket
- the daemon performs privileged operations only after polkit authorizes the
  user action

A Flatpak build can either:

- connect to a system/user Burrow daemon over a constrained local API
- ask a host-installed helper to start or configure the daemon through a
  reviewed D-Bus policy
- stay as a configuration/status UI when no helper is installed

It should not silently install native packages. PackageKit can be an optional
bootstrap path on distros where the native Burrow daemon package is available,
PackageKit is installed, and the Flatpak has a narrow
`org.freedesktop.PackageKit` system-bus permission. That path is a convenience,
not the baseline, because it is distro-dependent and still requires native
package trust and polkit authorization.

The native repository plan is now:

- `packages.burrow.net/apt` for Debian-family packages
- `packages.burrow.net/rpm/<channel>/<basearch>` for RPM-family packages
- `packages.burrow.net/arch/burrow/<arch>` for pacman binary packages
- `aur.archlinux.org/burrow-git.git` for the Arch source-build package
- a Flatpak repository descriptor for the GTK GUI, paired with the native daemon
- the NixOS flake/module for declarative NixOS installs

Package repository signing is split by repository format. Google Cloud KMS owns
non-exportable RSA signing keys for APT, RPM, pacman, Flatpak, and AUR source
surfaces. The current repository builder signs APT `Release`, RPM `repomd.xml`,
and pacman database/package sidecar signatures through the KMS OpenPGP bridge.
Embedded RPM package signatures and Flatpak OSTree summary signing still need a
dedicated implementation pass before those channels are promoted beyond
staging.

Release artifacts and signed repository trees publish through repo-owned storage
wrappers. Garage is the required S3-compatible primary target; GCS remains the
first backup target through buckets owned by `infra/releases`:
`burrow-net-releases` for build artifacts and `burrow-net-packages` for package
repositories. CI authenticates with Authentik-backed Google Workload Identity
Federation before using Google KMS or `gcloud storage`; no Google
service-account JSON key or rclone transport is part of the release path.

An AppImage may be useful as a portable GUI on distributions without current
Flatpak support, but it has the same daemon boundary as Flatpak. NixOS should
prefer the flake/module path so daemon, policy, and service activation are
declarative.

## F-Droid and Play Store

F-Droid should build from source with reproducible metadata and no proprietary
Play dependencies in the free flavor. Play Store can use the same Rust core but
requires the Play policy path for `VpnService`.

## Flatpak

Flatpak distribution is useful for desktop reach, but the app sandbox does not
grant route, DNS, or TUN authority by itself. Burrow should publish Flatpak only
with clear daemon/helper requirements until a real desktop smoke test proves the
full flow.

Flatpak can start child processes inside its sandbox and can request background
or autostart permission for the Flatpak app. That is not enough for the VPN data
plane. Starting the host daemon belongs to one of these paths:

- systemd socket or D-Bus activation installed by the native package
- explicit D-Bus call to a host helper with narrow permissions and polkit
- PackageKit-assisted native package install where supported
- manual native package install instructions opened from the GUI
