--- date: 2026-10-01 branch: bugfix/arr-to-plex title: Radarr and Sonarr may now reach Plex on 32400 — the network path only, not the Plex connection itself --- ## What changed Radarr and Sonarr had no route to Plex. The media library lives on NFS (`/mnt/Storage/plex`, the ZFS dataset `Storage/plex` on `${BULK_NFS_SERVER}`), and NFS does not deliver filesystem CRUD notifications, so Plex never learns that an arr has written a new file. Without a push from the arrs, the library only reflects new media when somebody scans it by hand. That is the bug this branch addresses. The fix is one `dependencies:` entry per app, added to the catalog — the source of truth: - to: plex port: 32400 protocol: tcp in both `catalog/radarr.yaml` and `catalog/sonarr.yaml` (these two *are* the arr suite here; `jackett`, `qbittorrent` and `seerr` are different roles and are untouched). The renderer expands each entry into a **pair** of Cilium policies, which is why a three-line catalog change produces 88 lines under `apps/`: | Side | Policy | File | |---|---|---| | egress | `radarr-allow-plex-32400` | `apps/wave-1/radarr.yaml` | | egress | `sonarr-allow-plex-32400` | `apps/wave-1/sonarr.yaml` | | reciprocal ingress | `plex-allow-radarr-32400` | `apps/wave-0/plex.yaml` | | reciprocal ingress | `plex-allow-sonarr-32400` | `apps/wave-0/plex.yaml` | Three commits, and the middle two are worth recording because both were self-inflicted gate failures rather than design changes: - `753c48b` — the catalog edit alone, with `apps/` left unrendered. - `9048c2f` — re-rendered `apps/` from the catalog, which `render==golden` requires. - `58f02fe` — removed 20 trailing spaces on `catalog/radarr.yaml:103`, left behind as comment-alignment padding when the comment moved down to the `port:` line. Sonarr's equivalent line kept its comment in place, which is why only radarr tripped. ## What I verified **The lint failure, root-caused.** Gate run 193 on `9048c2f` failed with `[fail] lint: FAILED -> blocks merge`, and lint was the only failing stage. yamllint emitted 419 findings, but **418 were `line-length`**, which `ci/yamllint.yaml` pins at `level: warning` and which therefore cannot change the exit code. The single error-level finding in the entire repository was: catalog/radarr.yaml 103:13 error trailing spaces (trailing-spaces) `trailing-spaces` inherits the default severity (error), so that one line returned rc 1. After the fix, `git grep -nIE ' +$' -- '*.yaml' '*.yml'` matches nothing repo-wide. **Gate run 195 on `58f02fe`** (read from the job log, not from the status tick): [ ok ] approval-policy: green [ ok ] l0: green [ ok ] gitea-settings: green [ ok ] render-golden: green [ ok ] decisions-log: green [ ok ] l1: green [ ok ] lint: green [fail] MERGE GATE: UNDETERMINED — greenness was NOT ESTABLISHED. [fail] Stages that did not run: spec-immutability The Gitea check reports `success` / "Successful in 1m41s", but the gate's own verdict is **UNDETERMINED (rc 3)**, not PASS. That tick is `gate.yml` tolerating exit 3 for the one stage it documents as unverifiable on this runner (the spec repo is not checked out there). Nothing else produced a 3. **`render==golden` green** on `58f02fe`, so `apps/` is a faithful canonical render of `catalog/` — the four generated policies are not hand-written drift. **DNS egress was already open** and is not a new gap: `apps/wave-1/radarr.yaml` carries an existing allow for port 53 UDP+TCP, so resolving the Plex service name does not need anything added here. **Live branch protection on `main`**, measured against `/api/v1/repos/Home-Network/home-network-k3s-impl/branches/main` rather than assumed: `protected: true`, `user_can_push: false`, `enable_status_check: true`, `status_check_contexts: ['gate / gate (pull_request)']`, `required_approvals: 1`. ## What I did NOT verify **This change does not accomplish what the PR set out to do.** It opens the network path and nothing else. Triggering a library update also requires each arr's *Settings → Connect → Plex Media Server* entry plus a Plex token, and **none of that exists anywhere in `catalog/` or `apps/`** — I grepped both for `plex`, `token` and `connect` and found only NFS paths, a uid and a timezone. Radarr's and Sonarr's config lives on a 5Gi Longhorn PVC mounted at `/config`, so that connection is UI-only state that exists solely on the PVC and never in git, in the same way Crafty's local login does. **Until somebody adds it in each app's UI, Plex still will not see library updates, and this branch will look like it did nothing.** That follow-up is not tracked by any file in this PR. **L2/L3 conformance never ran.** `CLUSTER_AVAILABLE` is unset on the runner, so the eight requirements this diff touches — `R-NET-01`, `R-NET-05`, `R-NET-06`, `R-NET-07`, `R-IDP-02`, `R-IDP-06`, `R-GITOPS-02`, `R-PLAT-02` — are **UNVERIFIED**. That gap is unusually load-bearing here: the entire substance of this change is four CiliumNetworkPolicies, and no test has confirmed that traffic from the `radarr` or `sonarr` namespaces actually reaches `plex:32400`. The green gate proves the offline render subset only. **`spec-immutability` did not run** (`R-TEST-06` not verified), for the documented reason — the sibling spec repo is absent from the runner. **Nothing was checked on the cluster.** I ran no `kubectl`, so I did not confirm that the `plex` Service exposes 32400 as the arrs would address it, that the pod labels the policies select (`app.kubernetes.io/name`, `k8s:io.kubernetes.pod.namespace`) match the running pods, or that Cilium accepted the four new objects. Flux has not applied any of this: the branch is unmerged, so `.status.lastAppliedRevision` does not contain it. **I did not verify Plex's own side** — whether its library-update endpoint on 32400 is the right target for the arrs' notification, or whether Plex requires "Update my library automatically" enabled to act on one. **I am not the approver and did not approve this PR.** `required_approvals: 1` is live, and the only credential on the authoring workstation belongs to the PR's author (`jakman85`), whose own review Gitea does not count. Per CLAUDE.md §1 the merge is a human action regardless.