# Holger — guide (the whole workflow)
> **Class:** `guide` · audience: a techie standing holger up end-to-end.
> The *what* is in [`design.md`](design.md); the *why* in [`reasoning.md`](reasoning.md).
> Per-function how-tos: [`registry-guide`](registry-guide.md) ·
> [`serve-guide`](serve-guide.md) · [`storage-guide`](storage-guide.md) ·
> [`auth-guide`](auth-guide.md) · [`agent-guide`](agent-guide.md) ·
> [`embed-guide`](embed-guide.md).
## f0 — one session, internet-side to airgap
The end-to-end shape of using holger crosses several functions. One pass:
1. **Pack (internet side).** Run the **agent** to pull the packages you need and bundle
them into one signed `.znippy` — see [`agent-guide`](agent-guide.md).
2. **Carry.** Move the `.znippy` across the boundary on USB/optical. No cable crosses.
3. **Serve (secure side).** Point a `Repository` in `holger.ron` at the archive, run
`holger-server`, and stock `cargo`/`pip`/`docker` clients fetch out of it — see
[`serve-guide`](serve-guide.md) and the deploy how-to below.
4. **Lock the door.** Before exposing a write path, turn on auth + RBAC — see
[`auth-guide`](auth-guide.md).
5. **Or embed it.** Instead of a server, link `holger-server-lib` and drive a registry
in-process — see [`embed-guide`](embed-guide.md).
## Deploy holger (Helm or raw k8s / Talos)
### Build the image
```bash
docker build -f distribution/Dockerfile -t holger.rs/nordisk/holger:2.0.0 .
```
Two-stage: `rust:1.96-slim` builder → `distroless/cc-debian12:nonroot` runtime (uid
65532). Entrypoint `holger-server start --config /etc/holger/holger.ron`; exposes 50051
(gRPC) and 8081 (HTTP gateway).
### Option 1 — Helm (recommended)
```bash
# dev: NodePort, 5Gi local-path, no auth, :latest
helm install holger deploy/helm/holger -n holger --create-namespace \
-f deploy/helm/holger/values-dev.yaml
# prod: LoadBalancer + Ingress, 200Gi CSI, OIDC auth, pinned tag
helm install holger deploy/helm/holger -n holger --create-namespace \
-f deploy/helm/holger/values-prod.yaml
```
Key `values.yaml` knobs:
| knob | default | note |
|---|---|---|
| `replicaCount` | `1` | keep at 1 — RWO volume |
| `image.repository` / `image.tag` | `holger.rs/nordisk/holger` (Holger serves its own images) / appVersion | container |
| `service.type` | `ClusterIP` | `NodePort` (dev) / `LoadBalancer` (prod) |
| `service.grpcPort` / `httpPort` | `50051` / `8081` | |
| `storage.size` / `storageClassName` | `50Gi` / `local-path` | override class for prod CSI |
| `auth.enabled` / `auth.mtlsCaCert` | `false` / `""` | mounts the CA secret |
| `ingress.enabled` / `ingress.host` | `false` / `holger.example.com` | HTTP gateway |
| `config.ron` | example `helm-dev` repo | the full RON graph |
### Option 2 — raw manifests
```bash
kubectl apply -f deploy/k8s/
kubectl -n holger wait --for=condition=Ready pod -l app=holger --timeout=120s
```
Applies: `namespace`, `deployment` (1 replica, `Recreate`, readonly rootfs, dropped caps,
probes), `service` (+ `service-nodeport` overlay), `pvc` (50Gi RWO `local-path`),
`configmap` (the `holger.ron`), `secret` (mTLS CA).
### Talos specifics (`deploy/k8s/TALOS.md`)
- **No default StorageClass** — the PVC stays `Pending` until you install
`local-path-provisioner` (dev, needs a machine-config `extraMounts` patch) or a real
CSI (OpenEBS Mayastor / democratic-csi) for prod.
- **No cloud LoadBalancer** — use **MetalLB** (VIP on the LAN) or the **NodePort**
overlay (30051 gRPC / 30081 HTTP on every node).
- **Single replica** — writable repos live on one RWO volume; scale-out needs RWX
storage. Snapshot the PVC for backups.
### Smoke test
```bash
kubectl -n holger port-forward svc/holger 8081:8081 &
curl http://localhost:8081/healthz # → ok
helm repo add dev http://localhost:8081/helm-dev
curl -X POST http://localhost:8081/helm-dev/api/charts --data-binary @mychart-0.1.0.tgz
```
## Install / uninstall holger as a service (systemd, either scope)
```bash
holger-server install add # user unit (no root), state in ~/.holger
sudo holger-server install add # system unit as the `holger` user, /home/holger/.holger
holger-server install status # active?
holger-server install render # dry-run: print the unit that would be written
```
Same lifecycle through the Skidbladnir ship: `holger-server service
{install,start,stop,status,health,uninstall}`.
### Uninstalling — **it nukes the data and keeps the keys**
```bash
holger-server install remove # stop + remove the unit; data KEPT
holger-server install remove --purge # + erase the data. SSH KEY + TOKEN KEPT.
```
`--purge` erases the scope's data tree — archives, audit log, autogen `holger.ron`,
caches, registry state (and in system scope the staged `/usr/local/bin/holger-server`).
It **never** touches:
- `.ssh` — the deploy key registered on your private git remotes,
- a stored `token`,
- the `holger` service account and its `/home/holger` home (system scope), because the
home holds the key and the account owns it.
That is the suite-wide law: *uninstalling the software nukes all data but keeps the ssh
keys.* A reinstall reuses the same identity with nothing to re-register. The purge root
follows the scope actually in use (`~/.holger` vs `/home/holger`), and every delete goes
through `skidbladnir::systemd::guarded_remove_dir_all`, which refuses `.ssh`, a real
user's home, a system directory, and a symlink out of the tree.
To destroy the identity too, ask for it by name:
```bash
holger-server install remove --purge --wipe-identity # DESTROYS the deploy key + token
```
`--wipe-identity` is refused without `--purge`. It is irreversible: the key registered
on the git remotes is gone, and a reinstall generates a **new** key you must register on
every remote before holger can pull again.
The output says which of the two happened — `KEPT : … identity item(s) — byte-intact`
or `DESTROYED : … --wipe-identity` — and a purge that found nothing to erase says so
instead of claiming success.
## Verify holger (the test matrix)
- **UI:** `cargo test -p holger-server-ui --features gui` — view-model + look + robot-UI.
- **CLI/agent:** `cargo test -p holger-agent-cli`.
- **Matrix:** `cargo test -p xtask --test holger_matrix` (light) / `-- --ignored`
(heavy: build + boot the mannequin daemon). Or `nornir test run holger`.
- **Bench:** `nornir bench run holger` (holger vs Nexus vs Artifactory, fair hardware,
over the real package protocol).
See [`testing-guide`](testing-guide.md) for the full grid.