feat(music-assistant): PO token server for YouTube Music provider #1451

Merged
k.renner merged 1 commits from feat/ma-youtube-music-po-token-v2 into main 2026-10-26 09:05:42 +00:00
Member

Adds a bgutil PO token server next to Music Assistant so MA's YouTube Music provider can stream tracks with no local copy (MA prefers the local file when it has one).

  • kubernetes/apps/music-assistant/po-token-server.yaml: Deployment (non-root uid 1000, drop ALL, RuntimeDefault seccomp), ClusterIP Service on :4416, pod-scoped CNP: ingress only from the MA pod on 4416 plus kubelet probes; egress to DNS and world:443 only (the server is unauthenticated). Egress uses world:443 rather than toFQDNs because the full set of Google endpoints BotGuard needs isn't documented.
  • Image automation bgutil-pot-provider: bare-semver tags (node flavor), range 2.x. MA 2.10.7 pip installs bgutil-ytdlp-pot-provider unpinned at runtime (2.0.2 on PyPI today), so the server has to stay on the same major. The MA docs' "1.2.1" predates the 2.x plugin line.

Manual step after merge (can't be automated): MA UI → Settings → Providers → add YouTube Music with a Premium account cookie and PO token server URL http://po-token-server.music-assistant.svc.cluster.local:4416. The cookie expires periodically and must then be re-entered.

Verified: kubectl kustomize renders both apps/music-assistant and infrastructure/image-automation on current main.

🤖 Generated with Claude Code

Adds a bgutil PO token server next to Music Assistant so MA's YouTube Music provider can stream tracks with no local copy (MA prefers the local file when it has one). - `kubernetes/apps/music-assistant/po-token-server.yaml`: Deployment (non-root uid 1000, drop ALL, RuntimeDefault seccomp), ClusterIP Service on :4416, pod-scoped CNP: ingress only from the MA pod on 4416 plus kubelet probes; egress to DNS and world:443 only (the server is unauthenticated). Egress uses world:443 rather than toFQDNs because the full set of Google endpoints BotGuard needs isn't documented. - Image automation `bgutil-pot-provider`: bare-semver tags (node flavor), range `2.x`. MA 2.10.7 `pip install`s `bgutil-ytdlp-pot-provider` unpinned at runtime (2.0.2 on PyPI today), so the server has to stay on the same major. The MA docs' "1.2.1" predates the 2.x plugin line. **Manual step after merge (can't be automated):** MA UI → Settings → Providers → add YouTube Music with a Premium account cookie and PO token server URL `http://po-token-server.music-assistant.svc.cluster.local:4416`. The cookie expires periodically and must then be re-entered. Verified: `kubectl kustomize` renders both `apps/music-assistant` and `infrastructure/image-automation` on current main. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude-bot added 1 commit 2026-10-26 09:03:06 +00:00
feat(music-assistant): add PO token server for YouTube Music provider
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
96ea510143
MA's YouTube Music provider needs a bgutil PO token server; MA installs
the matching yt-dlp plugin unpinned from PyPI (2.0.2 today), so the
server tracks 2.x via image automation. The MA docs' "1.2.1" predates
the 2.x plugin line.

Reachable only from the MA pod; egress limited to DNS and world:443.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
review-bot left a comment
Member

🤖 Automated review — model claude-opus-5-5, commit 96ea51014393696fad95728e9efb596d380778a0.

Automated review by the review-bot: it approves only when it found nothing red or yellow, and a human still merges. Push new commits to get a fresh review.


Summary

This PR adds a bgutil PO token server (Deployment, ClusterIP Service on :4416 and a pod-scoped CiliumNetworkPolicy) to the music-assistant namespace so Music Assistant's YouTube Music provider can stream. It also enrols the server's image in Flux image automation (2.x, bare-semver filter). The manifests are consistent with the repo:

  • The CNP's ingress selector matches MA's pod label (app.kubernetes.io/name: music-assistant, deployment.yaml).
  • MA's default route stays on eth0 (the sbr NAD), so the ClusterIP is reachable.
  • No policy restricts MA's own egress (#1432 left music-assistant out of scope; there is no music-assistant-ns.yaml).
  • The image-automation files follow the README's process.

GitHub reports the PR as mergeable. Since the PR base cb697e2, main has only gained the CoreDNS change (#1450), which touches none of these files. No other PR or code adds a PO token server.

⚪ Unverified

  • Image tag and flavour. I could not check that docker.io/brainicism/bgutil-ytdlp-pot-provider:2.0.2 exists, or that bare-semver tags are the node build. Both claims rest only on the PR body. The music-assistant Flux Kustomization runs with wait: true and timeout: 30m (kubernetes/clusters/homelab/music-assistant.yaml). A bad tag would leave that Kustomization not-Ready, although MA itself keeps running.
  • Non-root runtime and health endpoint. po-token-server.yaml:24-29 forces uid/gid 1000 and drops ALL capabilities, and the probes hit GET /ping (po-token-server.yaml:38-51). I could not check the upstream image's user, whether its working directory is writable by uid 1000, or that /ping exists. If any of these is wrong, the pod crash-loops or never becomes Ready, with the same Kustomization effect as above.
  • Plugin version. The claim that MA 2.10.x pip installs bgutil-ytdlp-pot-provider unpinned at runtime decides whether 2.x is the right range. It is external behaviour I could not check. MA on main is now 2.10.8 (deployment.yaml), not 2.10.7 as the PR body says.

🟡 Suggestions

  • CNP location. kubernetes/apps/music-assistant/po-token-server.yaml:73-114 puts the CiliumNetworkPolicy in the app directory. Every other hand-written CNP lives in kubernetes/infrastructure/network-policies/<ns>-ns.yaml and is listed in that directory's kustomization.yaml (navidrome, kuma-sync, review-bot, etc.). The only in-app CNPs are the ones authentik-gate-sync generates. Moving it to a new music-assistant-ns.yaml keeps policy review in one place, and the later per-workload egress audit of music-assistant that #1432 deferred will find it there.
  • World egress includes the LAN. po-token-server.yaml:108-114 allows toEntities: world on 443. #1432 describes world in this cluster as "internet + LAN". This third-party image is now auto-bumped across a whole major with no human in the loop, so the pod can reach every HTTPS service on the LAN (UDM, etc.). The PR explains why it didn't use toFQDNs. A middle ground would be toCIDRSet with 0.0.0.0/0 / ::/0 and except the RFC1918/ULA ranges, or FQDN patterns for *.google.com / *.youtube.com / *.googlevideo.com. Either keeps the "unknown Google endpoints" flexibility without reaching into the LAN.

🟢 Nits

  • The PR body says MA 2.10.7; main runs 2.10.8.
  • Nothing monitors the new server (no KumaMonitor, no alert). A broken token server only shows up as YouTube Music playback failures in MA.

Tests

The repo validates manifests in CI (ci-manifests-test), which was still pending on the head sha when I checked. The PR says it ran kubectl kustomize on both kustomizations, which is the expected check for a manifest-only change. There is no unit-test surface here. After merge, check:

  • the pod becomes Ready under uid 1000;
  • hubble observe --verdict DROPPED -n music-assistant shows no drops between MA and po-token-server:4416, or from the server to Google;
  • the ImagePolicy resolves to a bare 2.x.y tag.

Recommendation

Looks reasonable — no blocking issues; comments above are optional.

🤖 **Automated review** — model `claude-opus-5-5`, commit `96ea51014393696fad95728e9efb596d380778a0`. > Automated review by the `review-bot`: it approves only when it found nothing red or yellow, and a human still merges. Push new commits to get a fresh review. --- ## Summary This PR adds a bgutil PO token server (Deployment, ClusterIP Service on :4416 and a pod-scoped CiliumNetworkPolicy) to the `music-assistant` namespace so Music Assistant's YouTube Music provider can stream. It also enrols the server's image in Flux image automation (`2.x`, bare-semver filter). The manifests are consistent with the repo: - The CNP's ingress selector matches MA's pod label (`app.kubernetes.io/name: music-assistant`, `deployment.yaml`). - MA's default route stays on eth0 (the `sbr` NAD), so the ClusterIP is reachable. - No policy restricts MA's own egress (#1432 left `music-assistant` out of scope; there is no `music-assistant-ns.yaml`). - The image-automation files follow the README's process. GitHub reports the PR as mergeable. Since the PR base `cb697e2`, main has only gained the CoreDNS change (#1450), which touches none of these files. No other PR or code adds a PO token server. ## ⚪ Unverified - **Image tag and flavour.** I could not check that `docker.io/brainicism/bgutil-ytdlp-pot-provider:2.0.2` exists, or that bare-semver tags are the node build. Both claims rest only on the PR body. The `music-assistant` Flux Kustomization runs with `wait: true` and `timeout: 30m` (`kubernetes/clusters/homelab/music-assistant.yaml`). A bad tag would leave that Kustomization not-Ready, although MA itself keeps running. - **Non-root runtime and health endpoint.** `po-token-server.yaml:24-29` forces uid/gid 1000 and drops ALL capabilities, and the probes hit `GET /ping` (`po-token-server.yaml:38-51`). I could not check the upstream image's user, whether its working directory is writable by uid 1000, or that `/ping` exists. If any of these is wrong, the pod crash-loops or never becomes Ready, with the same Kustomization effect as above. - **Plugin version.** The claim that MA 2.10.x `pip install`s `bgutil-ytdlp-pot-provider` unpinned at runtime decides whether `2.x` is the right range. It is external behaviour I could not check. MA on main is now 2.10.8 (`deployment.yaml`), not 2.10.7 as the PR body says. ## 🟡 Suggestions - **CNP location.** `kubernetes/apps/music-assistant/po-token-server.yaml:73-114` puts the CiliumNetworkPolicy in the app directory. Every other hand-written CNP lives in `kubernetes/infrastructure/network-policies/<ns>-ns.yaml` and is listed in that directory's `kustomization.yaml` (navidrome, kuma-sync, review-bot, etc.). The only in-app CNPs are the ones authentik-gate-sync generates. Moving it to a new `music-assistant-ns.yaml` keeps policy review in one place, and the later per-workload egress audit of `music-assistant` that #1432 deferred will find it there. - **World egress includes the LAN.** `po-token-server.yaml:108-114` allows `toEntities: world` on 443. #1432 describes `world` in this cluster as "internet + LAN". This third-party image is now auto-bumped across a whole major with no human in the loop, so the pod can reach every HTTPS service on the LAN (UDM, etc.). The PR explains why it didn't use `toFQDNs`. A middle ground would be `toCIDRSet` with `0.0.0.0/0` / `::/0` and `except` the RFC1918/ULA ranges, or FQDN patterns for `*.google.com` / `*.youtube.com` / `*.googlevideo.com`. Either keeps the "unknown Google endpoints" flexibility without reaching into the LAN. ## 🟢 Nits - The PR body says MA 2.10.7; main runs 2.10.8. - Nothing monitors the new server (no KumaMonitor, no alert). A broken token server only shows up as YouTube Music playback failures in MA. ## Tests The repo validates manifests in CI (`ci-manifests-test`), which was still pending on the head sha when I checked. The PR says it ran `kubectl kustomize` on both kustomizations, which is the expected check for a manifest-only change. There is no unit-test surface here. After merge, check: - the pod becomes Ready under uid 1000; - `hubble observe --verdict DROPPED -n music-assistant` shows no drops between MA and `po-token-server:4416`, or from the server to Google; - the ImagePolicy resolves to a bare `2.x.y` tag. ## Recommendation Looks reasonable — no blocking issues; comments above are optional. <!-- pr-review:sha=96ea51014393696fad95728e9efb596d380778a0 -->
k.renner merged commit 439e4b4b83 into main 2026-10-26 09:05:42 +00:00
Sign in to join this conversation.