From 3733349d33ac89d02df85609aedebf3181d3ec08 Mon Sep 17 00:00:00 2001 From: sandwich Date: Wed, 17 Jun 2026 16:36:38 +0000 Subject: [PATCH] packaging(nix): add a Nix flake for reproducible from-source builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a flake that builds all four binaries (fips, fipsctl, fips-gateway, fipstop) on Linux and macOS, pinning the exact toolchain from rust-toolchain.toml (1.94.1 + rustfmt/clippy) via fenix so Nix builds match CI and the AUR/Debian packaging. Wire up the build-time native deps the source tree needs: pkg-config and bindgenHook (libclang) for the rustables/libdbus-sys bindgen step, and dbus for bluer's BLE support. autoPatchelfHook rewrites the binary RPATHs so the daemon resolves libdbus-1.so.3 and libgcc_s.so.1 from the Nix store at runtime — without it `fips` fails to load on NixOS, which has no global /usr/lib. Outputs: packages.{default,fips}, apps for each binary, checks.fips, and a devShell with the pinned toolchain plus cargo-edit. Tests are skipped in the package build since they exercise TUN devices, raw sockets, and mDNS that aren't available in the sandbox, mirroring the AUR/Debian packaging. Verified end-to-end in a pure Nix store (nixos/nix container): nix build, nix flake check, and running all four binaries succeed against the committed flake.lock. Documented across the install and developer docs: a Nix / NixOS section in packaging/README.md, the from-source guide in docs/getting-started.md (noting the flake produces binaries only, with NixOS system integration through the system configuration rather than the installer), the CHANGELOG, README, CONTRIBUTING, and the v0.4.0 release notes. Co-authored-by: Johnathan Corgan --- CHANGELOG.md | 12 +++ CONTRIBUTING.md | 4 + README.md | 12 ++- RELEASE-NOTES.md | 3 + docs/getting-started.md | 17 ++++ docs/releases/release-notes-v0.4.0.md | 3 + flake.lock | 100 ++++++++++++++++++++ flake.nix | 128 ++++++++++++++++++++++++++ packaging/README.md | 21 +++++ 9 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/CHANGELOG.md b/CHANGELOG.md index 90def49..472af98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 (`LimitNOFILE` drop-in) and OpenWrt (procd `nofile`) procedures to raise the limit, and how to verify the per-peer ratio stays bounded. Linked from the how-to index. +- Nix flake (`flake.nix` at the project root) for reproducible + from-source builds on Nix/NixOS. Builds all four binaries (`fips`, + `fipsctl`, `fips-gateway`, `fipstop`), pins the exact toolchain from + `rust-toolchain.toml` via fenix, and wires the build-time native + dependencies (`libclang` for `bindgen`, plus `dbus` and `pkg-config`), + so it needs no host setup beyond Nix with flakes enabled. Flake inputs + are lock-pinned (`flake.lock` committed) for reproducibility, and the + flake exposes `nix build`, `nix run`, a `nix develop` dev shell with the + pinned toolchain, and `nix flake check`. The flake produces binaries + (and a NixOS `packages..fips` output); the systemd/service + integration that the `.deb`/tarball installers provide is handled + through the NixOS configuration instead. ### Changed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e813a7..ed94fae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,6 +42,10 @@ and fail without it. BLE-capable builds additionally need `bluez`, `libdbus-1-dev`, and `pkg-config` installed; the default build picks up BLE if those are present and skips it cleanly if not. +On Nix, `nix develop` provides the pinned toolchain and all of these +build prerequisites without any manual install; see the Nix / NixOS +section of [packaging/README.md](packaging/README.md). + For multi-node integration runs, Docker is required. The harness under [testing/](testing/) starts containerized topologies and exercises real mesh behavior; see [testing/README.md](testing/README.md) diff --git a/README.md b/README.md index 66c3d61..788cad7 100644 --- a/README.md +++ b/README.md @@ -98,9 +98,9 @@ This installs the daemon, CLI tools (`fipsctl`, `fipstop`), the optional `fips-gateway` service, systemd units, and a default `/etc/fips/fips.yaml` you can edit before starting. -For macOS, Windows, OpenWrt, the systemd tarball, or a from-source -build, see [docs/getting-started.md](docs/getting-started.md) for -the full multi-platform installation guide. +For macOS, Windows, OpenWrt, the systemd tarball, a Nix flake, or a +from-source build, see [docs/getting-started.md](docs/getting-started.md) +for the full multi-platform installation guide. To join a live mesh and reach your first peer, follow the new-user tutorial progression starting at @@ -143,6 +143,12 @@ Nym (mixnet) transport builds on all desktop platforms. The OpenWrt availability on the target; it will flip to ✅ only if confirmed buildable there. +Alternatively, the repo ships a [Nix flake](flake.nix): `nix develop` +drops you into a shell with the pinned toolchain and every build +prerequisite (libclang, dbus, pkg-config) already provided, and +`nix build .#fips` builds all four binaries with no host setup. See the +Nix / NixOS section of [packaging/README.md](packaging/README.md). + ## Documentation `docs/` is organised by reader purpose: diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 0d62767..46e42a6 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -257,6 +257,9 @@ Operator-actionable items moving from v0.3.0 to v0.4.0: - **From source**: `cargo build --release` from a checkout of the v0.4.0 tag (Rust 1.94.1 per `rust-toolchain.toml`; `libclang-dev` is a required Linux build prerequisite). +- **Nix / NixOS**: `nix build .#fips` from a checkout of the v0.4.0 tag + builds the binaries from source with the pinned toolchain and no manual + prerequisites (see the Nix section of `packaging/README.md`). The full per-commit changelog lives in [`CHANGELOG.md`](../../CHANGELOG.md). Issues and discussion at diff --git a/docs/getting-started.md b/docs/getting-started.md index f7e4152..8dc2d5b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -88,6 +88,23 @@ See [packaging/README.md](../packaging/README.md) for per-format build details, cross-target options, and the full `make` target list. +### With Nix (flake) + +On Nix/NixOS, a [flake](../flake.nix) at the project root builds the +binaries from source with the pinned toolchain and no manual +prerequisite install: + +```sh +nix build .#fips # all four binaries, into ./result/bin +nix develop # dev shell with the toolchain + build deps +``` + +This path produces binaries only — it does not run the installer, so +there are no systemd units, no `fips` group, and no default `fips.yaml`. +On NixOS, wire the daemon in through your system configuration using the +flake's `packages..fips` output instead. See the Nix / NixOS +section of [packaging/README.md](../packaging/README.md). + ## What's installed and running Here's what the installer leaves on your machine, what's diff --git a/docs/releases/release-notes-v0.4.0.md b/docs/releases/release-notes-v0.4.0.md index 0d62767..46e42a6 100644 --- a/docs/releases/release-notes-v0.4.0.md +++ b/docs/releases/release-notes-v0.4.0.md @@ -257,6 +257,9 @@ Operator-actionable items moving from v0.3.0 to v0.4.0: - **From source**: `cargo build --release` from a checkout of the v0.4.0 tag (Rust 1.94.1 per `rust-toolchain.toml`; `libclang-dev` is a required Linux build prerequisite). +- **Nix / NixOS**: `nix build .#fips` from a checkout of the v0.4.0 tag + builds the binaries from source with the pinned toolchain and no manual + prerequisites (see the Nix section of `packaging/README.md`). The full per-commit changelog lives in [`CHANGELOG.md`](../../CHANGELOG.md). Issues and discussion at diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..0ec4b36 --- /dev/null +++ b/flake.lock @@ -0,0 +1,100 @@ +{ + "nodes": { + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1781527054, + "narHash": "sha256-1fX9ev2Fh5QoKQ41G9dYutjo5j/jywu6tZse5Eb1Ck4=", + "owner": "nix-community", + "repo": "fenix", + "rev": "8c2e51dffefc040a21975da7abf6f252c8c9b783", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1781074563, + "narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "fenix": "fenix", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1781453968, + "narHash": "sha256-+V3nK4pCngbmgyVGXY6Kkrlevp4ocPkJJLf2aqwkDNA=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "cc272809a173c2c11d0e479d639c811c1eacf049", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..b760c32 --- /dev/null +++ b/flake.nix @@ -0,0 +1,128 @@ +{ + description = "FIPS — a distributed, decentralized network routing protocol for mesh nodes connecting over arbitrary transports"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + fenix, + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + pkgs = import nixpkgs { inherit system; }; + + # Honor the toolchain the repo pins in rust-toolchain.toml + # (channel 1.94.1 + rustfmt, clippy) so Nix builds match CI and the + # AUR/Debian packaging exactly, including the edition-2024 frontend. + rustToolchain = fenix.packages.${system}.fromToolchainFile { + file = ./rust-toolchain.toml; + sha256 = "sha256-zC8E38iDVJ1oPIzCqTk/Ujo9+9kx9dXq7wAwPMpkpg0="; + }; + + rustPlatform = pkgs.makeRustPlatform { + cargo = rustToolchain; + rustc = rustToolchain; + }; + + cargoToml = pkgs.lib.importTOML ./Cargo.toml; + + # libdbus-sys (pulled in transitively by `bluer`, Linux/glibc only) + # runs `bindgen` against the system D-Bus headers at build time. + nativeBuildInputs = [ + pkgs.pkg-config + rustPlatform.bindgenHook # sets LIBCLANG_PATH + clang for bindgen + ]; + + buildInputs = pkgs.lib.optionals pkgs.stdenv.isLinux [ + pkgs.dbus # libdbus-1.so.3, linked via bluer→libdbus-sys + pkgs.stdenv.cc.cc.lib # libgcc_s.so.1, needed by every Rust binary + ]; + + fips = rustPlatform.buildRustPackage { + pname = "fips"; + version = cargoToml.package.version; + + src = pkgs.lib.cleanSourceWith { + src = ./.; + # Drop the build dir and the usual editor/VCS noise so the source + # hash is stable and unrelated edits don't trigger rebuilds. + filter = + path: type: + (pkgs.lib.cleanSourceFilter path type) && (baseNameOf path != "target"); + }; + + cargoLock.lockFile = ./Cargo.lock; + + inherit buildInputs; + + # autoPatchelfHook rewrites the RPATH of the built binaries so the + # daemon finds libdbus-1.so.3 (linked via bluer→libdbus-sys) in the + # Nix store at runtime — without it the `fips` binary fails to load + # on NixOS where there is no global /usr/lib. + nativeBuildInputs = + nativeBuildInputs ++ pkgs.lib.optionals pkgs.stdenv.isLinux [ pkgs.autoPatchelfHook ]; + + # The test suite exercises TUN devices, raw sockets and mDNS, none of + # which exist in the build sandbox. The AUR/Debian packaging likewise + # ships the release binaries without running the integration tests + # here, so keep the package build hermetic and skip them. + doCheck = false; + + meta = { + description = cargoToml.package.description; + homepage = cargoToml.package.homepage; + license = pkgs.lib.licenses.mit; + mainProgram = "fips"; + platforms = pkgs.lib.platforms.linux ++ pkgs.lib.platforms.darwin; + }; + }; + + mkApp = name: { + type = "app"; + program = "${fips}/bin/${name}"; + meta.description = "Run the ${name} binary from the FIPS package"; + }; + in + { + packages = { + default = fips; + fips = fips; + }; + + apps = { + default = mkApp "fips"; + fips = mkApp "fips"; + fipsctl = mkApp "fipsctl"; + fips-gateway = mkApp "fips-gateway"; + fipstop = mkApp "fipstop"; + }; + + # `nix flake check` builds the package (and thus validates the flake on + # the current system). + checks.fips = fips; + + devShells.default = pkgs.mkShell { + inherit buildInputs; + nativeBuildInputs = nativeBuildInputs ++ [ + rustToolchain + pkgs.cargo-edit + ]; + # Point rust-analyzer at the matching std sources. + RUST_SRC_PATH = "${rustToolchain}/lib/rustlib/src/rust/library"; + }; + + formatter = pkgs.nixfmt; + } + ); +} diff --git a/packaging/README.md b/packaging/README.md index d5d9644..045fee4 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -177,6 +177,27 @@ yay -S fips # release build from latest tag See [aur/README.md](aur/README.md) for AUR publication instructions and maintainer guide. +### Nix / NixOS (flake) + +A [flake](../flake.nix) at the project root builds all four binaries +(`fips`, `fipsctl`, `fips-gateway`, `fipstop`) from source. It pins the +exact toolchain from `rust-toolchain.toml` via +[fenix](https://github.com/nix-community/fenix) and wires up the +build-time native dependencies (`libclang` for `bindgen`, plus `dbus` +and `pkg-config` for BLE), so it needs no system setup beyond Nix with +flakes enabled. + +```sh +nix build .#fips # build the package (all four binaries) +nix run .#fips -- --help # run a binary directly +nix run .#fipsctl -- status +nix develop # dev shell with the pinned toolchain + cargo-edit +nix flake check # build + validate the flake +``` + +Add to a NixOS configuration via the flake's `packages..fips` +output, e.g. `environment.systemPackages = [ fips.packages.${system}.default ];`. + ## Shared Assets `common/` contains assets used across packaging formats: