packaging(nix): add a Nix flake for reproducible from-source builds

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 <johnathan@corganlabs.com>
This commit is contained in:
sandwich
2026-06-17 16:36:38 +00:00
committed by Johnathan Corgan
parent 9a9e90a32c
commit 3733349d33
9 changed files with 297 additions and 3 deletions

View File

@@ -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.<system>.fips` output); the systemd/service
integration that the `.deb`/tarball installers provide is handled
through the NixOS configuration instead.
### Changed

View File

@@ -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)

View File

@@ -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:

View File

@@ -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

View File

@@ -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.<system>.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

View File

@@ -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

100
flake.lock generated Normal file
View File

@@ -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
}

128
flake.nix Normal file
View File

@@ -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;
}
);
}

View File

@@ -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.<system>.fips`
output, e.g. `environment.systemPackages = [ fips.packages.${system}.default ];`.
## Shared Assets
`common/` contains assets used across packaging formats: