zupt/DISTRIBUTION.md
Cristian Cezar Moisés 544a2cd647
Some checks failed
CI / build-and-test (clang) (push) Has been cancelled
CI / build-and-test (gcc) (push) Has been cancelled
CI / strict-warnings (clang, -Wall -Wextra -Wpedantic -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wnull-dereference -O2 -std=c11 -Werror) (push) Has been cancelled
CI / strict-warnings (gcc, -Wall -Wextra -Wpedantic -Wshadow -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wnull-dereference -Wformat-security -Wlogical-op -Wjump-misses-init -Wdouble-promotion -O2 -std=c11 -Werror) (push) Has been cancelled
CI / sanitizers (push) Has been cancelled
CI / pie-hardening (push) Has been cancelled
CI / cross-aarch64 (push) Has been cancelled
CI / dist-reproducibility (push) Has been cancelled
CI / packaging-syntax (push) Has been cancelled
CI / release (push) Has been cancelled
v4.0.0: codec 2.60.4 security release, --pq-box sealed-box mode, F-16 fix
Major release. Highlights:

- Codec: vendored VaptVupt codec moves to canonical 2.60.4 security
  release. Fixes a high-severity OOB heap write in the AVX2 decode fast
  path (reachable on a valid stream sized to exactly content_size, both
  tail variants). Brings CBMC-formally-verified BCJ filters with
  automatic ELF/PE/Mach-O detection. Compressed output stays
  byte-identical (ratio gate Δ 0.00%); wire format unchanged at v1.6.
- New --pq-box sealed-box recipient mode (vendored libpqvaptvupt 0.6.0):
  ML-KEM-768 + X25519 combined via HKDF-SHA256 with domain separation,
  AES-256-CTR + HMAC-SHA256 EtM. Legacy --pq and --pq-sdk stay readable.
- F-16: discloses and fixes a pre-existing data-loss defect in the
  <= 3.8.0 in-tree BCJ encoder. Full back-compat matrix decodes
  byte-exact under 4.0.0; every readable pre-4.0 archive remains readable.

Repository hygiene:
- Sync full 4.0.0 source tree (codec, crypto, SDK, GUI, packaging, tests).
- Remove internal scratch files (PROMPT.md, FORMAL_AUDIT_PROMPT.md)
  and superseded version-specific docs (INTEGRATION_PROTOCOL_2.60.4.md,
  docs/FINDINGS-2.x.md) and a stray test binary.
- Refresh README download/install section to real 4.0.0 release assets;
  bump version badge to 4.0.0.
- Add .gitignore for build outputs (keeps vendored prebuilt libraries).
2026-06-10 18:48:58 -03:00

8.4 KiB

Distributing Zupt

This document describes the upstream packaging recipes shipped under packaging/ and the path from "local source tree" to "package installable on every major Linux distribution and macOS."

Recipes are upstream-maintained but distro-submission-ready. Real submission to AUR / Debian / Fedora / Homebrew / NixOS is operational work outside this repository.

Producing a reproducible source tarball

Every packaging recipe expects an upstream tarball zupt-VERSION.tar.gz produced by the project's make dist target. The tarball is byte-reproducible:

make dist
# → /tmp/zupt-2.4.4.tar.gz
# → sha256: 407d20ef03e5bf857195b99e04843ef3b07357416a4115add1e8aaa2007a769f
# → bytes:  813113

Re-running make dist on the same source tree produces an identical sha256 (verified by tests/test_dist_reproducible.sh, wired into make test). This lets distros pin a stable hash in their recipes.

The reproducibility properties:

  • Files sorted by name (deterministic order across filesystems)
  • mtime fixed to SOURCE_DATE_EPOCH (default 1747699200; override via env)
  • uid/gid pinned to root (0/0) via --owner=0 --group=0 --numeric-owner
  • gzip wrapped with -9n (no embedded timestamp or filename)
  • Source-only — no .o, no built binaries, no .git/ tree
  • Includes the vendored libzuptsdk.so.2.0.0 real file plus its two symlinks (libzuptsdk.so, libzuptsdk.so.2)

To force a specific epoch (for distro release-day pinning):

SOURCE_DATE_EPOCH=1727740800 make dist  # 2024-10-01 UTC

Recipes shipped

Distro / Platform Path Format
Arch Linux packaging/aur/PKGBUILD AUR PKGBUILD
Debian / Ubuntu packaging/debian/ Source package (3.0 (quilt))
Fedora / RHEL packaging/rpm/zupt.spec RPM .spec
macOS packaging/homebrew/zupt.rb Homebrew formula
NixOS / Nix flake packaging/nix/flake.nix Nix flake

All recipes:

  • Install the binary to $PREFIX/bin/zupt (default /usr/bin/zupt)
  • Install the vendored libzuptsdk.so* triple to $PREFIX/lib/zupt/ (the binary uses relative rpath so users don't need LD_LIBRARY_PATH)
  • Install manpage to $PREFIX/share/man/man1/zupt.1.gz
  • Install docs (README, SECURITY, CHANGELOG, AUDIT) to $PREFIX/share/doc/zupt/
  • Run the full upstream regression suite (make test) during build when the distro's package guidelines allow check-phase execution

Arch Linux (AUR)

Maintainer flow:

# 1. Produce the upstream tarball
make dist
# → /tmp/zupt-2.4.4.tar.gz

# 2. Upload to a stable URL (e.g. git.securityops.co releases)

# 3. Update packaging/aur/PKGBUILD:
#    - Set pkgver=2.4.4
#    - Set sha256sums=("$(sha256sum /tmp/zupt-2.4.4.tar.gz | awk '{print $1}')")

# 4. Generate .SRCINFO
cd packaging/aur && makepkg --printsrcinfo > .SRCINFO

# 5. Test locally
makepkg -s

# 6. Push to AUR
git clone ssh://aur@aur.archlinux.org/zupt.git aur-zupt
cp packaging/aur/PKGBUILD packaging/aur/.SRCINFO aur-zupt/
cd aur-zupt && git add -A && git commit -m "v2.4.4" && git push

User install:

yay -S zupt          # or paru, pikaur, etc.

Shell completions (v2.4.7+)

make install automatically installs Bash, zsh, and fish completion files alongside the binary and manpage:

Shell Path
Bash $PREFIX/share/bash-completion/completions/zupt
zsh $PREFIX/share/zsh/site-functions/_zupt
fish $PREFIX/share/fish/vendor_completions.d/zupt.fish

The source files live under completions/ in the project tree. Distros that prefer a different install location should override the relevant paths in their make install invocation; the underlying recipe is straightforward.

For per-user installation without root:

# Bash
cp completions/zupt.bash ~/.local/share/bash-completion/completions/zupt

# zsh (somewhere in $fpath; add the directory to ~/.zshrc if needed)
cp completions/_zupt ~/.zsh/completion/_zupt

# fish
cp completions/zupt.fish ~/.config/fish/completions/zupt.fish

Completions cover every CLI flag the binary actually parses (--kdf, --comment, --comment-file, --pq-sdk, --dedup, etc.) and are validated on every CI run via tests/test_completions_manpage.sh.

Debian / Ubuntu

The packaging/debian/ tree is a Debian source-package layout. Maintainer flow:

# 1. Produce the upstream tarball with the standard Debian
#    orig.tar.gz naming convention:
make dist
cp /tmp/zupt-2.4.4.tar.gz /tmp/zupt_2.4.4.orig.tar.gz

# 2. Unpack and overlay the debian/ tree:
cd /tmp && tar xzf zupt_2.4.4.orig.tar.gz && cd zupt-2.4.4
cp -a /path/to/zupt/packaging/debian ./debian

# 3. Build the source package:
dpkg-buildpackage -S -us -uc       # source-only
dpkg-buildpackage -b -us -uc       # binary

# 4. Lint:
lintian zupt_2.4.4-1_*.deb

# 5. Submit via the standard Debian mentors process:
#    https://mentors.debian.net/intro-maintainers/

User install (after the package lands in Debian unstable / Ubuntu):

sudo apt install zupt

Fedora / RHEL / CentOS

# 1. Produce the tarball
make dist
cp /tmp/zupt-2.4.4.tar.gz ~/rpmbuild/SOURCES/

# 2. Drop the .spec into the SPECS directory:
cp packaging/rpm/zupt.spec ~/rpmbuild/SPECS/

# 3. Build source + binary RPMs:
cd ~/rpmbuild && rpmbuild -ba SPECS/zupt.spec

# 4. Lint:
rpmlint RPMS/x86_64/zupt-2.4.4-1.fc*.rpm

# 5. Submit via the Fedora new-package review process:
#    https://docs.fedoraproject.org/en-US/package-maintainers/Package_Review_Process/
#    EPEL automatically inherits Fedora packages.

User install (after the package lands in Fedora / EPEL):

sudo dnf install zupt                 # Fedora
sudo dnf install epel-release zupt    # RHEL/CentOS via EPEL

macOS (Homebrew)

# 1. Produce the tarball and upload to a stable release URL.

# 2. Update packaging/homebrew/zupt.rb:
#    - Set url to the release URL
#    - Set sha256 to the upstream tarball sha256

# 3. Test locally:
brew install --build-from-source ./packaging/homebrew/zupt.rb
brew test zupt
brew audit --strict --online zupt

# 4. Submit to homebrew-core (preferred, requires popularity threshold):
#    https://docs.brew.sh/Adding-Software-to-Homebrew
#
#    OR host in your own tap:
#    https://docs.brew.sh/How-to-Create-and-Maintain-a-Tap

User install (after submission lands):

brew install zupt
# OR from a custom tap:
brew install cristiancmoises/tap/zupt

NixOS / Nix flake

# 1. Build directly from the flake (no central submission needed):
nix build github:cristiancmoises/zupt#zupt
nix run github:cristiancmoises/zupt#zupt -- version

# 2. To consume from another flake:
#    inputs.zupt.url = "github:cristiancmoises/zupt?ref=v2.4.4";
#    packages.x86_64-linux.default = inputs.zupt.packages.x86_64-linux.zupt;

# 3. To submit to nixpkgs (https://github.com/NixOS/nixpkgs):
#    - Adapt packaging/nix/flake.nix's `zupt` derivation into a
#      pkgs/by-name/zu/zupt/package.nix using fetchurl and a hash.
#    - Follow the nixpkgs contribution guide:
#      https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md

Submitting upstream — checklist

Before pushing any recipe to a distro repository:

  • make dist produces a reproducible tarball (verified by tests/test_dist_reproducible.sh on every make test)
  • The tarball is uploaded to a stable, immutable URL
  • The recipe's checksum field is updated to match sha256sum /tmp/zupt-VERSION.tar.gz
  • The recipe builds and tests pass in a clean chroot/container
  • The CHANGELOG mentions distro-relevant changes since the last release
  • The license metadata is correct (AGPL-3.0-or-later for Zupt core; GPL-3.0-or-later for the vendored VaptVupt codec)

Security posture for downstream

Every packaging recipe runs make test during build (check() for AUR, override_dh_auto_test for Debian, %check for RPM, checkPhase for Nix, test block for Homebrew). The suite includes:

  • F-06: 2 000 HMAC tamper trials, 0 silent accepts required
  • F-08: top-MAC header/footer integrity-trailer regression
  • F-09: 1 827-position exhaustive byte sweep on PQ-SDK archive, 0 silent accepts required
  • F-10..F-12: KDF default, auth-fail message, encrypted comments
  • dist reproducibility: make dist byte-identical across two runs

A build that doesn't pass make test will fail at distro check time — the recipes don't paper over regressions.