Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

holger-estate-front/Cargo.toml

# **holger-estate-front — vm1 of holger's estate: holger's OWN front program.**
#
# Owner 2026-09-27, verbatim: "i SAID follow the pattern gunnar has for vm1 vm2
# vm3 regarding installer etc. NOT BECOME gunnar!!". So this is gunnar's PATTERN
# (vm1 = one program, PID 1 of its own medium: the installer's view of it, the
# WireGuard relay, the twin's certification, the ONE monetize's SoldEstate
# client, the web face with its own certificate, the console, the repository
# route) built from holger + the SHARED nordisk crates only. ZERO dependency on
# the gunnar repository — no gunnar crate, no gunnar checkout, no gunnar medium
# (guarded: tests/no_gunnar_in_the_graph.rs).
#
# | piece | from |
# |---|---|
# | the installer's view of vm1 (`Vm`, kind front), the verdict | Skidbladnir `nordisk-pairing::frontside` |
# | the relay, the web face (ACME, certificates, hand-over, callbacks), the repository route | edda `estate-front` |
# | PID 1 (network, reaper, SIGTERM) | edda `appliance-pid1` |
# | the twin's certification (state machine) | Skidbladnir `nordisk-twin::certify` — holger's `Boxes` over holger's own AdminService (src/certify.rs) |
# | the ONE monetize's SoldEstate client (material, upgrade, update) | monetize-estate-side `sold_door` (feature `metered`); NO monetize runs here (G16) |
# | the update step, the metadata seed reader | Skidbladnir `nordisk-pairing::frontside::update`, `nordisk-pairing::seed::metadata` |
# | the console | holger-ui `holger-ui-server` (the thin server: bundle + pass-through) |
#
# ## Why its own workspace
#
# The open holger must contain no money code (`open_build_speaks_no_money`),
# and the root workspace resolves from its own siblings without a monetize or
# holger-ui checkout. A path dependency is resolved for the WHOLE workspace at
# `cargo metadata`, so this crate is `exclude`d from the root (like `holger-rs`)
# with a lock of its own; the recipe builds it with `manifest_dir`.
[package]
name = "holger-estate-front"
version = "3.0.0"
edition = "2021"
license = "MIT OR Apache-2.0"
publish = false
description = "vm1 of holger's estate: holger's own front program, PID 1 of the holger-front-installer-metered medium — the installer's view of the front, the estate's WireGuard relay, the twin certified by holger's own AdminService, the bare monetize with its plugin door, the web face with its own certificate, holger's console and the repository route to the primary. Built from holger and the shared nordisk crates only."

[workspace]

[features]
default = ["console"]
# holger's console (holger-ui's thin server: the built bundle embedded and a
# pass-through to the primary's gRPC-web and passkey doors) on :443.
console = ["dep:holger-ui-server"]
# The paid front (`holger-front-installer-metered`): NO monetize runs here (G16,
# ONE monetize). It calls the ONE monetize's `SoldEstate` door, signed by the
# estate's client key (open monetize crates only: monetize-proto, monetize-embed;
# never monetize-impl), and relays the ONE monetize's door and key to the boxes.
# The open front links no money code.
#
# A lost main or twin is re-admitted by this front (src/recharge.rs): the kept installer
# material and the re-admission are nordisk-pairing's (`kept`, `installer-wireguard`). A
# re-admitted main is filled by the ONE recharge lane (nordisk-twin `recharge`): the ONE box's
# pulled `recharge_from_twin` order, or this front itself when the estate fed `repair_auto =
# true` (src/autofill.rs, Gunnar's front autofill, lane G11).
# `holger-ui-server?/metered`: the console's paid half (the sign-up, welcome and order pages, the
# pay link and the buy routes) exists only here; an open front's console serves none (A28 M13).
metered = ["dep:monetize-estate-side", "dep:monetize-site-buy", "nordisk-pairing/kept", "nordisk-pairing/installer-wireguard", "dep:ureq", "holger-ui-server?/metered"]
# **DEV-NARRATE** (owner 2026-10-19, Gunnar's dev media for Holger): vm1's boot log, SEALED to
# the installer's key over udp/51822 from the moment the NIC has an address
# (the holger-dev-narrate crate, Skidbladnir `nordisk_narrate::boxside`). Only the
# `estate-front-musl-metered-narrate` row names it; the medium's option defaults it OFF.
# **holger.rs's public face** (TASKS-12 S-6, the owner's SLIM and AIRGAP rules,
# 2026-10-25): robots.txt, the sitemap, llms.txt and the front page's head tags,
# holger-ui's `holger-public-site` crate (no HTTP client), mounted by the console
# under its own `public-site`. OFF by default; ON in the front's payload row.
public-site = ["console", "holger-ui-server?/public-site"]
dev-narrate = ["holger-dev-narrate/dev-narrate"]

[[bin]]
name = "holger-estate-front"
path = "src/main.rs"

[dependencies]
# `stderr-capture`: fd 2 into the boot log, so every eprintln! line reaches the log door.
# `mesh-probe` and `front-renew` (P4c, A28 M11): the front's mesh probe and its paired-link
# renewal are nordisk-pairing's, off there by default; this front runs both as before (the
# probe only `wg_only`, the renewal once the installer fed it).
nordisk-pairing = { path = "../../Skidbladnir/crates/installer/nordisk-pairing", version = "0.5.26", features = ["wireguard", "stderr-capture", "frontside-update", "mesh-probe", "front-renew"] }
nordisk-twin = { path = "../../Skidbladnir/crates/installer/nordisk-twin", version = "0.1.2" }
# The STAGE lines and DEV-NARRATE's start, shared with holger-server (A28 L12). Its sender
# (nordisk-narrate) exists only under `dev-narrate`: absent from every release row.
holger-dev-narrate = { path = "../server/dev-narrate", version = "3.0.0" }
# `acme` (estate-front 0.1.5, A32-11): estate-front's ACME client is a default-off feature
# now (the airgap default links none); Holger's front takes its certificate from Let's Encrypt,
# so it names it, and nothing changes for Holger.
estate-front = { path = "../../edda/crates/estate-front", version = "0.3.0", features = ["acme"] }
# The provider :443 is served with (`tls()`, edda `Hooks::tls`, lane WG-PSK): Skidbladnir's
# pqtls (X25519MLKEM768 first). Already in the graph through estate-front.
rustls = { version = "0.23", default-features = false, features = ["ring", "std"] }
# The estate's clock (edda estate-clock): the front
# keeps its own clock (`fetch` + `adjust`) and serves signed time to the boxes.
estate-clock = { path = "../../edda/crates/estate-clock", version = "0.1.1", features = ["fetch", "adjust"] }
appliance-pid1 = { path = "../../edda/crates/appliance-pid1", version = "0.1.8", features = ["dhcp", "runtime"] }
wg-appliance-core = { path = "../../edda/crates/wg-appliance-core", version = "0.1.5" }
# The downstreams' rules (lane HOL-WGDS): `via`, the hub port's packet rule, the sync door's call rule.
holger-downstream-rules = { path = "../server/downstream", version = "3.1.1" }
hyper-util = { version = "0.1", default-features = false, features = ["client-legacy", "http1", "http2", "tokio"] }
holger-ui-server = { path = "../../holger-ui/crates/holger-ui-server", version = "3.0.0", optional = true }
# **The ONE monetize's `SoldEstate` client** (feature `metered`; P4a): monetize-estate-side's
# `sold_door`, shared with Gunnar's front (T16) — the door from the feed, every call signed by
# the estate's client key, the update step's `Shop`. Open crates only (monetize-proto and
# monetize-embed beneath it); never monetize-impl.
monetize-estate-side = { path = "../../monetize/crates/monetize-estate-side", version = "0.3.0", default-features = false, features = ["sold-door"], optional = true }
# **The buy flow on the site** (A12, owner 2026-10-23): Gunnar's buy doors, shared in monetize's
# OPEN crate; this front supplies Holger's provider (`src/buy.rs`). Never monetize-impl.
monetize-site-buy = { path = "../../monetize/crates/monetize-site-buy", optional = true }
# jera jobs: the renewal of every paired link (src/renew.rs, every build), the sold
# front's duties (src/sold.rs, `metered`) and the mesh probe's looks (src/mesh_probe.rs, lane W9).
jera = { path = "../../edda/crates/jera", default-features = false }
# **The live update** (L20): the front's own A/B slot (holger-live over korp `live`). The update
# step itself (the release app proven before it is staged: its sha256, its blake3 pin) is
# nordisk-pairing's `frontside::update` since P4a.
holger-live = { path = "../estate/holger-live", features = ["jobs"] }
# The console key's bearer (`console_key`: blake3 `derive_key`).
blake3 = "1"
# The console key's x25519 (A7 row 14, `console_key`): boringtun's re-export of x25519-dalek 2, the
# same crate the WireGuard plane (wg-appliance-core) already links.
boringtun = { version = "0.7.1", default-features = false }
# The release object's GET (feature `metered`): ureq on rustls + ring + webpki-roots, as
# nordisk-pairing's own client.
ureq = { version = "3", default-features = false, features = ["rustls"], optional = true }
serde_json = "1"
tokio = { version = "1", features = ["rt-multi-thread", "macros", "net", "time", "sync", "io-util"] }
tonic = { version = "0.14", default-features = false, features = ["transport", "codegen"] }
tonic-prost = "0.14"
prost = "0.14"
axum = { version = "0.8", default-features = false, features = ["tokio", "http1", "http2"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt", "env-filter", "ansi"] }
anyhow = "1"
# toml 0.8 -> 1.1 (2026-10-03, finish-bump). Every call site here reads or writes a
# whole FILE through `toml::from_str` / `toml::to_string` into a typed struct or a
# `toml::Value` document (certify.rs, console.rs, tests/no_gunnar_in_the_graph.rs) —
# none uses `.parse::<toml::Value>()`, which in 1.x parses ONE value, not a document.
toml = "1.1"
serde = { version = "1", features = ["derive"] }

[build-dependencies]
protox = "0.9"
tonic-prost-build = "0.14"

[dev-dependencies]
# `tests/shop_pairing_contract.rs`: the ONE shop's Holger install feed is what this front and
# its boxes read. The shop's own crates, dev-only: nothing of the shop ships in the front.
monetize-shop-pairing = { path = "../../monetize/crates/monetize-shop-pairing" }
# Holger's own facts (its contract with the shop and its sale proof, v2.0 P3): what the shop's
# pairing speaks for a sold Holger is read off them.
holger-monetize-guest = { path = "../crates/holger-monetize-guest" }
monetize-server = { path = "../../monetize/crates/monetize-server" }
# `tests/holgers_site_runs_the_shared_buy_flow.rs`: the shared buy flow's fake ONE box and fake
# Stripe (monetize-site-buy `testkit`), behind Holger's own provider. Dev-only.
monetize-site-buy = { path = "../../monetize/crates/monetize-site-buy", features = ["testkit"] }
# The first login on a local rig (tests/the_people_are_holgers.rs): a soft
# authenticator for the person's key.
nornir-auth-webauthn = { version = "0.1.2", features = ["test-support"] }
estate-front = { path = "../../edda/crates/estate-front", version = "0.3.0", features = ["test-support"] }
tempfile = "3"
# tests/the_relay_answers_each_box_fed_as_the_shop_feeds.rs: a box's handshake shaped by its
# real plan, against the real relay (lane D14). Already in the graph through wg-appliance-core.
boringtun = { version = "0.7.1", default-features = false }
# Two REAL holgers for the certification test (tests/the_front_certifies_the_twin_over_mtls.rs).
# With the estate (the twin over mutual TLS is server-lib `estate` since H2's estate cut):
# the front is an estate component; holger-recipe `estate_edges_name_the_estate` holds it.
# `jobs` + `sandbox-off`: tests/estate_links_say_https_through_the_front.rs (HOL-DOCFIND), a
# primary with pull-through sources behind the front.
holger-server-lib = { path = "../server/lib", features = ["estate", "jobs", "sandbox-off"] }
# The thin client, through the front's repository route (lane B3).
holger-cli = { path = "../holger-cli" }
tower = { version = "0.5", features = ["util"] }
http = "1"
rustls = { version = "0.23", default-features = false, features = ["ring", "std"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["ring"] }
tokio = { version = "1", features = ["io-util"] }

# ★ DEV media only (lane N1, 2026-10-20, Gunnar's `[profile.dev-media]`): the `…-narrate`
# rows — the TEST estates' media, never a release — build with this. Release's
# optimisation level without the whole-program passes; its own profile is also what gives
# a `…-narrate` row its OWN artifact path (target/<triple>/dev-media/), so it never emits
# the binary its base release row emits.
[profile.dev-media]
inherits = "release"
lto = false
codegen-units = 16

# ── THE ESTATE'S SIBLING PATCHES (B7): this workspace builds the siblings from their
# checkouts beside holger, as `.cargo/estate-siblings.toml` names them (paths rebased to
# this directory; `xtask/tests/lone_clone.rs` holds the two equal). The root takes none.
[patch.crates-io]
appliance-grow = { path = "../../edda/crates/appliance-grow" }
appliance-pid1 = { path = "../../edda/crates/appliance-pid1" }
disk-snapshot = { path = "../../edda/crates/disk-snapshot" }
draupnir = { path = "../../draupnir" }
edda-admit = { path = "../../edda/crates/admit" }
estate-clock = { path = "../../edda/crates/estate-clock" }
facett-app = { path = "../../facett/facett-app" }
facett-core = { path = "../../facett/facett-core" }
facett-syschart = { path = "../../facett/facett-syschart" }
facett-table = { path = "../../facett/facett-table" }
guest-host = { path = "../../edda/crates/guest-host" }
jera = { path = "../../edda/crates/jera" }
korp-installer = { path = "../../tunnr/crates/korp-installer" }
modgunn = { path = "../../modgunn" }
monetize-embed = { path = "../../monetize/crates/monetize-embed" }
monetize-estate-side = { path = "../../monetize/crates/monetize-estate-side" }
monetize-mail = { path = "../../monetize/crates/monetize-mail" }
monetize-product = { path = "../../monetize/crates/monetize-product" }
monetize-product-guest = { path = "../../monetize/crates/monetize-product-guest" }
monetize-proto = { path = "../../monetize/crates/monetize-proto" }
nordisk-narrate = { path = "../../Skidbladnir/crates/installer/nordisk-narrate" }
nordisk-pairing = { path = "../../Skidbladnir/crates/installer/nordisk-pairing" }
nordisk-twin = { path = "../../Skidbladnir/crates/installer/nordisk-twin" }
nornir-auth-oidc = { path = "../../edda/crates/nornir-auth-oidc" }
nornir-auth-policy = { path = "../../edda/crates/nornir-auth-policy" }
nornir-auth-webauthn = { path = "../../edda/crates/nornir-auth-webauthn" }
nornir-identity = { path = "../../edda/crates/nornir-identity" }
nornir-identity-session = { path = "../../edda/crates/nornir-identity-session" }
nornir-bench = { path = "../../edda/crates/nornir-bench" }
nornir-build-thing = { path = "../../edda/crates/nornir-build-thing" }
nornir-escape = { path = "../../edda/crates/nornir-escape" }
nornir-feature-graph = { path = "../../edda/crates/nornir-feature-graph" }
nornir-gate = { path = "../../edda/crates/nornir-gate" }
nornir-hash = { path = "../../edda/crates/nornir-hash" }
nornir-service = { path = "../../edda/crates/nornir-service" }
nornir-testmatrix = { path = "../../edda/crates/nornir-testmatrix" }
nornir-vault = { path = "../../edda/crates/nornir-vault" }
nornir-xtask-support = { path = "../../edda/crates/nornir-xtask-support" }
plugin-door-wire = { path = "../../Skidbladnir/crates/installer/plugin-door-wire" }
skidbladnir = { path = "../../Skidbladnir" }
skidbladnir-systemd = { path = "../../Skidbladnir/crates/skidbladnir-systemd" }
wg-appliance-core = { path = "../../edda/crates/wg-appliance-core" }