---
last_verified: 2026-05-30
verified_version: 0.1.34
owner: devops
freshness_days: 30
---

# Deployment / Distribution Guide — pvtcoms

> Full rationale: `DESIGN.md` §14.4. Distribution is a real constraint for an anonymous app — plan it early.

## Build targets

| Target | Toolchain | Output |
|--------|-----------|--------|
| Rust core | `cargo build --release` | static lib + UniFFI bindings |
| Android | cargo-ndk → `.so` per ABI + Gradle | APK/AAB |
| Desktop | Tauri 2 (`cargo tauri build`) | Win/Linux/macOS bundles |
| iOS (v2) | xcframework + Xcode | .ipa |

## CI / signing / reproducibility

- **CI**: GitHub Actions — Linux runners for Rust (`build`, `test`, `clippy`, `cargo audit`, `cargo deny`); macOS runners for iOS notarization (v2).
- **Locked toolchains**: `rust-toolchain.toml`, `Cargo.lock` committed, Gradle/SwiftPM pins, containers/Nix where feasible.
- **Reproducible builds** = first-class CI requirement (pin toolchains, strip timestamps/paths, deterministic APKs). F-Droid shows per-app reproducibility status. Bake in from day one — hard to retrofit.
- **Signing**: Android (self-sign for F-Droid / Play signing), Desktop (code-sign all binaries; notarize macOS).
- **Supply chain**: `cargo vet` + `cargo audit` + SBOM/SLSA provenance.

## Distribution channels & the Google constraint ⏰

- **Google Developer Verification (from Sept 2026)** requires every Android app — even sideloaded/F-Droid — to come from a developer with a **verified real legal identity**; F-Droid has said it "would cease to function" as written.
  → **Publish under a named legal entity/foundation** (users stay anonymous; the *publisher* cannot). Keep a self-signed-APK sideload path. Assume F-Droid may break.
- **Apple App Store** (v2): no-phone-number onboarding is permitted; budget for strict privacy-manifest compliance.
- **No-phone-number onboarding is store-allowed** (Session/Threema/Briar prove it).

## Release gate

A **named third-party audit** (Quarkslab/Cure53/Trail of Bits/NCC) of PQ crypto + Tor integration + mailbox protocol is a **release gate** before any public "secure/anonymous" claim. Publish the report.

## Containers, Nix & relay deployment

**Reproducible builds are a trust requirement, and plain Docker is the wrong tool for them** (timestamps, layer ordering,
non-deterministic `apt`/gzip change the digest). For a high-threat AGPL app, users must be able to rebuild the exact binary.

| Thing | Approach |
|---|---|
| **Rust core / client reproducible build** | **Nix flakes** (`flake.lock` pins everything) — hermetic, bit-for-bit; also the pinned dev/CI environment. Recipe: `cargo build --locked` + `SOURCE_DATE_EPOCH` + `trim-paths` + `codegen-units=1` + pinned rustc. Verify with `diffoscope`. |
| **Android APK** | The hard frontier: F-Droid verifies by signature-copying (bytes must match). Pin exact **NDK** (r26/r27), `-trimpath`/`--remap-path-prefix`, fixed build OS. Many NDK apps still don't fully reproduce — budget for it; don't block v1 on bit-for-bit. |
| **CI build/test envs** | Containerized is fine (pin by digest), or Nix. Not the source of release reproducibility. |
| **v2 oblivious relays** (mailbox relay, iOS APNs notification relay) | Hardened containers **or microVMs (Firecracker)** for stronger isolation. **No persistent app logs** (Docker's default json log driver leaks metadata — disable it). Distroless/rootless, read-only FS, `no-new-privileges`, drop all caps, seccomp/apparmor. Ephemeral in-memory queues; encrypted at rest if unavoidable. Split ingress relay from gateway role (OHTTP / RFC 9458 trust split). |
| **Do NOT containerize** | The end-user clients themselves, or the in-app Tor runtime (hurts UX + platform integration). |

Every release artifact ships an **SBOM + signed provenance** (SLSA-style).

## Rollback

Versioned releases (`VERSION` + `version_bump.py`); keep prior signed artifacts; secure update channel with rollback protection (a v2 workstream).
