crates/wg-appliance-core/Cargo.toml
[package]
name = "wg-appliance-core"
version = "0.1.8" # HubRelay::isolate_peers + RelayVerdict.dropped_isolated (HOL-WGDS)
edition = "2021"
description = "The ONE userspace WireGuard data plane of the nordisk appliance fleet: x25519 key handling + keygen, a wg-quick INI tokenizer, a /dev/net/tun device, a boringtun packet pump (encapsulate/decapsulate/timers, AllowedIPs longest-prefix routing) that runs in ONE thread and needs NO wireguard kernel module — and the appliance identity CEREMONY: load-or-mint the keypair at a path (idempotent, fail-closed, 0600), the one canonical identity line every product prints, and the hub.conf dialect (one [Peer], public data only). Consumed by tunnr's wg-appliance PID-1 payload, gunnar's OS-less appliance, and holger's appliance tiers. Carries no product config schema and no address writer: each consumer keeps its own declared config surface and its own netlink/ioctl writer."
license = "MIT OR Apache-2.0"
repository = "https://git.gunnar.rs/nordisk/edda"
keywords = ["wireguard", "boringtun", "tun", "appliance", "userspace"]
categories = ["network-programming"]
exclude = ["/.nornir/"]
[dependencies]
# The Noise state machine + x25519, re-exported. This is the whole reason the
# appliance needs no `CONFIG_WIREGUARD`: the data plane is linked INTO the
# binary. `default-features = false` compiles out boringtun's own `device`
# (socket2 + thiserror + its event loop) — this crate owns the socket loop,
# because the loop is where the two consumers' shapes differ.
boringtun = { version = "0.7.1", default-features = false }
# Constant-time base64, for the one string in this crate that is a SECRET. The
# ordinary `base64` crate is already in the graph (boringtun requires it) and
# was deliberately not used for keys: a private key decoded by a table lookup
# leaks its bytes through the cache.
base64ct = { version = "1", features = ["alloc"] }
# `OsRng` — the `getrandom(2)` syscall, NOT `/dev/urandom`. An OS-less appliance
# may have no `/dev` mounted at all when keys are minted, and a keygen that
# silently fell back to a weak source would hand a fleet one identity. Already
# in the graph: boringtun depends on the same version with the same feature.
# Stays on rand_core 0.6 (2026-10-02, W3 crypto bump): `StaticSecret` is boringtun's
# re-exported x25519-dalek 2, and boringtun 0.7.1 (newest) requires rand_core 0.6 —
# its RNG must satisfy THAT trait. Move with boringtun.
rand_core = { version = "0.6.4", features = ["getrandom"] }
# The tun ioctls, the poll(2) the pump blocks in, and the raw fd read/write.
# `libc` is already in the graph (boringtun depends on it), so this is free.
libc = "0.2"
# Erase key material rather than leaving it in freed heap and stack. Every type
# in this crate that OWNS a private key or a preshared key zeroes it on drop;
# `Zeroizing` covers the parse-time intermediates that used to be dropped
# verbatim. Already in the graph at 1.9.0 — `x25519-dalek`, which boringtun
# pulls, depends on it — so this adds an EDGE, not a crate.
zeroize = { version = "1", features = ["alloc"] }
# Names the peer on boringtun's own timer lines (`HANDSHAKE(REKEY_TIMEOUT)`,
# `CONNECTION_EXPIRED(…)`), which name none: the pump enters a span per peer.
# Already in the graph (boringtun logs through it), so this adds an EDGE.
tracing = "0.1"
[features]
# The shipping surface. `hubfixture` is ON by default so that every existing
# consumer (korp-installer's deploy-test panel, holger's xtask fleet proof)
# keeps compiling unchanged; a PAYLOAD turns it off with
# `default-features = false`, which is the whole point of the split.
default = ["hubfixture"]
# **A test responder, compiled into whatever links it.** [`crate::hubfixture`]
# mints a keypair at runtime and binds `0.0.0.0` on a UDP port. It is the "other
# end of the wire" a proof stands up for itself, and it has no business in an
# appliance image. It used to be an unconditional module and the only thing
# keeping it out of `wg-init` was the linker dropping code nothing called —
# which is an optimisation, not a posture: a `pub` item in a `pub` module is
# reachable by name from any consumer that types it, and `--emit=obj` /
# `-C lto=off` / a `dylib` build keep it. A cargo feature is the decision
# written down.
hubfixture = []
# **The container-form ceremony robot** ([`crate::robot`]). It spawns `podman`
# or `docker` and drives an appliance image, so it is a TEST tool and has no
# place in a runtime build. Not in `default`: only tests and test callers turn
# it on (gunnar-server's `appliance_container_robot` runs with
# `--features container-robot,wg-appliance-core/robot`). This crate's own unit
# tests compile it through `cfg(test)`. (A28 L14, 2026-10-25.)
robot = []