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

nordisk/holger

docs/v2/01-what-holger-is.md

1. What Holger is

Holger is a secure artifact gateway. It takes packages from the internet, checks them once, and serves only what passed to the build systems of a site that may have no network at all.

Holger runs in two setups. In both, the internet side is the same: the Holger server pulls from the sources named in holger.ron (PyPI, npm, Maven, crates.io, OCI, Go, APK; build feature online), and every package walks the intake repositories incoming → quarantine → approved → production: it is verified, scanned in a sandbox and approved by people (chapter 5). holger-ui is the console for the approvals. The two setups differ in how the approved packages reach the site.

Setup A: fetch

Setup B: one-way

The RON's domain: "<label>" names which side a Holger is on: it is printed by start and the CLI verbs, sent as X-Holger-Domain on every answer, and shown in the console's top bar.

Two modes: Upstream (Fetch) and CDS (one-way)

Every downstream runs in one of two modes, chosen by boundary: in its RON (server/lib/src/boundary.rs, enum Boundary). Upstream (Fetch) is Setup A. CDS (one-way, a cross-domain solution) is Setup B. Parts that exist only on the HOL-CDS-4 branch (heimdall-allin/cds4, not yet on main) are marked "(with HOL-CDS-4)".

Upstream (Fetch) CDS (one-way)
RON boundary: Fetch boundary: OneWay (the default)
Talks to the internet Yes, but only to the hosts each source declares in its RON, and only from inside a fetch job (with HOL-CDS-4). Without HOL-CDS-4, it dials only its one upstream Holger. Never. Nothing dials and nothing is sent back.
How packages come in Through the fetch worker holger-fetch-worker, one HTTP exchange per Heimdall job (with HOL-CDS-4). Holger resolves the declared names itself and hands the job its set of host + IP:port peers; Heimdall's broker connects only those. The job sends the host name as TLS SNI and checks the certificate against the name, never the IP. It never follows a redirect: the target goes back to Holger, which checks it against the source's hosts and starts a new job. Code: server/fetch-worker/src/lib.rs, server/lib/src/job_runner/fetch.rs. Tests: server/fetch-worker/tests/fetch_jobs.rs, real_sources.rs (real PyPI and crates.io), fetch_under_heimdall.rs. Signed bundles from the inbox also work, as in CDS. Signed bundles (.holger.znippy), carried through a USB stick or a diode into <data>/bundle.inbox. Each one is opened only inside the verify-bundle job (server/lib/src/job_runner/verify_bundle.rs). Tests in server/lib/tests/bundle_import_runs_in_a_job.rs: a_good_bundle_imports_through_the_verify_bundle_job, the_server_never_opens_the_bundle_file.
Outbound client in the server None. Test (server/cli/tests/one_way_ships_no_client.rs): the_fetching_build_links_no_client_crate_beyond_the_one_way_build. The fetch code lives only in the worker, and no server build links it: no_server_build_links_the_fetch_worker_which_is_its_own_build (with HOL-CDS-4). Two exceptions are named in the tests: the gRPC channel of RemoteHolger (paired sync, row below) and, with paired, edda estate-clock's signed-time request to the front. None. Tests (same file): the_one_way_downstream_links_no_client_and_no_fetch_code, the_one_way_appliance_links_no_client_no_dialer_and_no_pairing.
Compiled into the build cargo install holger-downstream --features fetch. This adds server-lib fetch: the mirror, RemoteHolger and the sync pull. Medium row downstream-fetch-musl (.nornir/build-variants.toml) adds fetch, downstream-wg and paired. With HOL-CDS-4 it also adds heimdall, and the medium ships the fetch worker's rootfs (holger-recipe/tests/fetch_worker_media.rs: only_the_fetching_medium_ships_the_fetch_worker). cargo install holger-downstream. Server-lib is built without fetch, so the mirror, RemoteHolger and the sync pull are not compiled at all. Appliance row downstream-musl adds pid1, and with HOL-CDS-4 also heimdall (the_one_way_appliance_under_heimdall_links_no_client_and_no_fetch_job). The fetch worker is never on its medium.
Paired sync over WireGuard (RemoteHolger) Applies with downstream-wg: udp/51830 with a pre-shared key, to its ONE upstream Holger. RemoteHolger is in server/lib/src/object.rs, behind fetch. Test: fetch_is_what_adds_the_fetch_code_and_the_tunnel. Never. There is no fetch, no WireGuard dialer and no pairing in the build (the_one_way_appliance_links_no_client_no_dialer_and_no_pairing).

The internet-side holger server built with online is not a downstream and is outside this table. Today it still pulls through an in-process client (server/lib/src/upstream_rust.rs). Moving that pull onto the fetch job is open work.

The formats

The default build serves twelve formats:

format feature
raw (any file) fmt-raw
Rust (cargo) fmt-rust
npm fmt-npm
Maven fmt-maven
Python (PEP 503 / PEP 691) fmt-python
Docker / OCI fmt-docker
Go modules fmt-go
Helm fmt-helm
deb fmt-deb
rpm fmt-rpm
znippy package fmt-znippy
Build Thing fmt-build-thing

NuGet, gems, conda and Composer are opt-in, with all-formats. The downstream (holger-downstream) serves the same twelve.

The products

product what it is where
holger the server: intake chain, scanners, approvals, the formats, export server/cli, bin holger
holger-downstream the on-prem downstream: import signed bundles from its inbox (one-way, the default), or also fetch them (--features fetch); verify, serve holger-downstream/, a thin crate over server/cli
holger-ui the web console; it only calls the server and draws crates/holger-ui in nordisk/holger-ui
holger-cli the command-line tool: console actions over gRPC, the airgap bundle, the verifier, the courier holger-cli/

Each is one crate (cargo install <product>), and each names the extras all-formats, online, federation and full.

An estate (front, main, twin, sold through the ONE box) is built by the Build Thing (chapter 7, chapter 9).

Moved from v1

Still in v1