fail2ban required a non-existent intrusion-prevention capability (unassignable on any node) → now requires firewall, which it actually needs to manage bans.
7 tool-runtime modules (plex, bazarr, ombi, home-assistant, nzbget, qbittorrent, umami) whose mesh-<mod> sidecar crash-looped for a missing app credential the manifest never wired → each now declares the credential as an operator-provided own-secret, mounts it read-only into the runtime, and the client reads it from the MESH_*_FILE path (falling back to the old env so nothing regresses), the cloudflare-dns pattern. The operator supplies it with secret accept <node> <module> <name> --from <file>. These are deployable now (they still need a real app token to go green — correct, not a lab thing).
photos (ships a stub app image) and mailu (needs its full Mailu config env + API-token enablement) are deeper conversion jobs, not credential wiring — deferred/tracked. All modules tsc-clean.
Three fixes the whole-mesh dry-run surfaced:
- **fail2ban** required a non-existent `intrusion-prevention` capability (unassignable on any node) → now requires `firewall`, which it actually needs to manage bans.
- **7 tool-runtime modules** (plex, bazarr, ombi, home-assistant, nzbget, qbittorrent, umami) whose `mesh-<mod>` sidecar crash-looped for a missing app credential the manifest never wired → each now declares the credential as an operator-provided `own-secret`, mounts it read-only into the runtime, and the client reads it from the `MESH_*_FILE` path (falling back to the old env so nothing regresses), the cloudflare-dns pattern. The operator supplies it with `secret accept <node> <module> <name> --from <file>`. These are deployable now (they still need a real app token to go green — correct, not a lab thing).
photos (ships a stub app image) and mailu (needs its full Mailu config env + API-token enablement) are deeper conversion jobs, not credential wiring — deferred/tracked. All modules tsc-clean.
The whole-mesh dry-run found fail2ban unassignable on every node: it declared
`capabilities: ["intrusion-prevention"]`, which mesh-host has no detector for
(its detectors are container-runtime, package-manager, service-manager,
firewall, overlay, graphical-session, seat, privileged). intrusion-prevention
is what fail2ban PROVIDES, not a host capability it needs. It bans via
iptables/ufw, so it needs `firewall` — the same capability the firewall module
declares. The `the-intrusion-prevention` claim (node-exclusive) is unchanged.
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
The six modules that run a mesh-<mod> tool-runtime sidecar read an app
credential from an env var the manifest never provided, so the sidecar
crash-looped in the whole-mesh dry-run (e.g. "no Plex token — set
MESH_PLEX_TOKEN"). These are operator-set app secrets, so deliver them the
same way cloudflare-dns delivers its API token: an own-secret file mounted
read-only, with a MESH_<APP>_*_FILE env pointing at the mount, and the
runtime code preferring that file (falling back to the existing env so
nothing regresses).
- plex: own-secret token -> /run/secrets/token, MESH_PLEX_TOKEN_FILE
- bazarr: own-secret api-key -> /run/secrets/api-key, MESH_BAZARR_API_KEY_FILE
- ombi: own-secret api-key -> /run/secrets/api-key, MESH_OMBI_API_KEY_FILE
- home-assistant: own-secret token -> /run/secrets/token, MESH_HOMEASSISTANT_TOKEN_FILE
- nzbget: own-secret password -> /run/secrets/password, MESH_NZBGET_PASSWORD_FILE (URL stays plain env)
- qbittorrent: own-secret password -> /run/secrets/password, MESH_QBITTORRENT_PASSWORD_FILE (URL stays plain env)
The operator now completes each with `secret accept <node> <module> <name> --from <file>`.
tsc passes for all six.
The whole-mesh dry-run found umami's runtime crash-looping "admin password is
not set": its `admin` own-secret is mounted at /run/secrets/admin, but the
client read the bare env UMAMI_ADMIN_PASSWORD, which nothing sets. Same shape as
the six tool-runtime credential fixes — read the mounted file first
(MESH_UMAMI_ADMIN_PASSWORD_FILE), falling back to the env. (photos and mailu
remain deeper conversion jobs — a stub app image and a full Mailu config env —
not credential-wiring, tracked separately.)
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Three fixes the whole-mesh dry-run surfaced:
intrusion-preventioncapability (unassignable on any node) → now requiresfirewall, which it actually needs to manage bans.mesh-<mod>sidecar crash-looped for a missing app credential the manifest never wired → each now declares the credential as an operator-providedown-secret, mounts it read-only into the runtime, and the client reads it from theMESH_*_FILEpath (falling back to the old env so nothing regresses), the cloudflare-dns pattern. The operator supplies it withsecret accept <node> <module> <name> --from <file>. These are deployable now (they still need a real app token to go green — correct, not a lab thing).photos (ships a stub app image) and mailu (needs its full Mailu config env + API-token enablement) are deeper conversion jobs, not credential wiring — deferred/tracked. All modules tsc-clean.
firewallcapability, not the non-existentintrusion-prevention75fb16bbfb