Skip to content

docs(media): the tier has no secrets file by decision, and the handover says where Jellyfin's admin lives (#528) - #546

Merged
Gerrrt merged 1 commit into
mainfrom
gerrrt/media-stack-secrets-886896
Sep 19, 2026
Merged

Gerrrt merged 1 commit into
mainfrom
gerrrt/media-stack-secrets-886896

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Sep 19, 2026

Copy link
Copy Markdown
Owner

stacks/media was the one tier with no secrets/<stack>.example.yaml and no .sops.yaml rule. #528 asked whether that is a gap or a decision, and for successor-handover.md to say where the media admin lives. This records the decision: no secrets file, on purpose, beside the Home Assistant exception in docs/security.md § Secrets.

Why no file

  • Nothing a file held could reach the container. Jellyfin's admin is created by its own setup wizard and kept as a hash in jellyfin.db inside jellyfin-config. No environment variable or rendered file is a way to hand it in. Audiobookshelf (Media tier: Audiobookshelf #140) and Navidrome (Media tier: Navidrome #141) create their first user the same way, so the exception is the tier's, not Jellyfin's.
  • The host cannot hold the tier's key. make secrets-init STACK=media has to run on the stack's host (bootstrap.sh refuses elsewhere), and smaug runs TrueNAS with neither make nor sops. A media rule would stay a placeholder forever or hold the estate's key, which is the inversion ADR-0020's per-stack rules exist to prevent.
  • A successor needs no password. Jellyfin's Forgot Password, from an address it counts as local, writes a PIN file into the config volume; the login page takes the PIN. The read command is in stacks/media/README.md and in the handover, which now lists Jellyfin's admin and TrueNAS's own web-UI admin under what the repository does not hold.

The alternative, a vault-style secrets/media.sops.yaml encrypted to the estate's recipients, was considered and declined: it renders nothing, the tooling cannot create it on prometheus, and it adds an ADR-0024 proof obligation for a credential the host it protects cannot use.

What changed

  • docs/security.md — the decision, what protects the credential, and what would retire the exception (a media service taking a credential from outside).
  • docs/runbooks/successor-handover.md — the two admins under "what it does not hold", the reset flow, and a stacks/media row under "safe to stop".
  • stacks/media/README.md — a section on where the admin lives, why there is no secrets file, and the way back in without the password.
  • .sops.yaml — a comment saying there is no media rule on purpose, so the next reader does not add one.
  • stacks/media/compose.yaml, .env.example — name the decision where they said "stacks/media has no secrets file: Jellyfin's admin credential lives only in a password manager #528's" (the headers themselves were brought up to date by Buy and build the NAS, smaug, on CasaBonita (ADR-0016, ADR-0040) #413's commit on main).
  • README.md, secrets/README.md — one line each.

No ADR: this applies ADR-0035's class and ADR-0020's rule. Nothing deploys and nothing on smaug changes.

Verified

make validate green in this worktree on the second run. The first run failed observability: promtool check config once and its own diagnostic rerun printed SUCCESS with only the expected file_sd warnings — the known local promtool flake, on files this branch does not touch. check_sops_rules.py still maps secrets/media.sops.yaml to the catch-all and passes, which is the point of the .sops.yaml comment.

Adjacent, not fixed here

scripts/backup-volumes.sh has no jellyfin-config sentinel while stacks/media/README.md says the volume is backed up by it. That belongs to #484.

Closes #528
Refs #138 #140 #141 #484

🤖 Generated with Claude Code

…er says where Jellyfin's admin lives (#528)

stacks/media was the one tier with no secrets/<stack>.example.yaml and no
.sops.yaml rule, and #528 asked whether that is a gap or a decision. It is a
decision, for three reasons written into docs/security.md beside the Home
Assistant exception it belongs with:

- Jellyfin's admin is created by its own setup wizard and kept as a hash in
  jellyfin.db inside jellyfin-config. No environment variable or rendered
  file could hand it in, so a value in a secrets file would reach nothing.
  Audiobookshelf (#140) and Navidrome (#141) create their first user the
  same way.
- `make secrets-init STACK=media` has to run on the stack's host, and smaug
  runs TrueNAS with neither make nor sops. A media rule would stay a
  placeholder forever or hold the estate's key, which is the inversion
  ADR-0020's per-stack rules exist to prevent.
- The successor's way in is host access plus Jellyfin's own Forgot Password
  flow, which writes a PIN file into the config volume from a LAN client.
  That needs no password at all, so successor-handover.md now lists the
  Jellyfin and TrueNAS admins under what the repository does not hold, with
  the reset command.

.sops.yaml gains a comment saying there is no media rule on purpose, so the
next reader does not add one and land a future file on the estate's key.
The compose header and .env.example, which #413's commit had already brought
up to date with the 2026-09-19 deploy, now name the decision where they said
"#528's". The README layout tree and secrets/README.md name the exception in
one line each.

Not changed here: scripts/backup-volumes.sh has no jellyfin-config sentinel
while stacks/media/README.md says the volume is backed up by it. That is
#484's.

Refs #138 #140 #141 #484

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Gerrrt
Gerrrt merged commit f6fa5d0 into main Sep 19, 2026
3 checks passed
@Gerrrt
Gerrrt deleted the gerrrt/media-stack-secrets-886896 branch September 19, 2026 22:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stacks/media has no secrets file: Jellyfin's admin credential lives only in a password manager

1 participant