Files
pl_mail/docs/install
Paul LütznerandClaude Opus 5.5 9c25eae1bf fix(secrets): the JWT keypair lives beside the generated secrets
.env named var/secrets/jwt outright, which is beside the generated
secrets only while APP_SECRETS_FILE keeps its default. The TrueNAS
layouts point it into their data dataset, so there the keypair landed on
each container's own throwaway filesystem: every service generated one
on every start ("Generated the JWT keypair." in the log), and a token
one of them signed would have been refused by the others and by the
next restart. Nothing issues JWTs yet - the Android app pairs into an
app password - so nothing broke, but the promise in the comments that
every service verifies what the others sign did not hold.

- config/bootstrap_generated_secrets.php derives both paths from the
  directory APP_SECRETS_FILE is in, for every PHP process including a
  `docker exec` console. A real environment variable still wins; the
  .env defaults are empty, as for the other derived values. On the
  standard compose the paths are the ones they always were.
- app:secrets:init generates under a lock, rechecked once held, as
  GeneratedSecretsFile::ensure() does. lexik's --skip-if-exists is a
  check followed by two writes, so services starting together could
  leave one's private key beside another's public key - a narrow window
  that seven concurrent runs did not hit in five rounds, and closed now
  rather than left rare: with the lock every round generated exactly
  once and left a matching pair.
- A reset that rotates secrets removes the two key files where they
  are, instead of emptying a fixed var/secrets/jwt.
- The security.yaml note on "the future first-party app" is corrected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 13:07:39 +02:00
..