|
14 | 14 | # variable rc3+ uses inside DATABASE_URL. Either way, the bundled |
15 | 15 | # value can't drift behind the stack and Doctrine picks the right |
16 | 16 | # SQL dialect. |
17 | | -# - ./jwt/{private,public}.pem: wiped if present, because rotating |
18 | | -# JWT_PASSPHRASE orphans whatever keypair the previous install |
19 | | -# generated. `task install`'s `lexik:jwt:generate-keypair |
20 | | -# --skip-if-exists` then regenerates fresh against the new |
21 | | -# passphrase. Skipping this wipe lets the runtime fail login with |
22 | | -# "Unable to create a signed JWT from the given configuration" |
23 | | -# (auth succeeds, signing fails). |
| 17 | +# - ./jwt/{private,public}.pem: left ALONE. This script never deletes |
| 18 | +# operator key material — a wipe here is invisible to upgrade paths |
| 19 | +# that don't run `task install` (e.g. clone -> v3 via `task up`), |
| 20 | +# stranding them with no keypair. Instead, when a fresh .env.symfony |
| 21 | +# rotates JWT_PASSPHRASE, we warn that any existing keypair no longer |
| 22 | +# matches; `task jwt:ensure` (run by `task install`, and available |
| 23 | +# standalone) validates the keypair and regenerates only on mismatch. |
24 | 24 | # |
25 | 25 | # This is the single bootstrap entry point. `task install` / `task up` / |
26 | 26 | # `task update` precondition on `.env.symfony` existing — running this is |
@@ -105,31 +105,24 @@ rm -f .env.symfony.bak |
105 | 105 |
|
106 | 106 | # JWT_PASSPHRASE was just rotated to a fresh random value. Any pre- |
107 | 107 | # existing keypair at ./jwt/{private,public}.pem was encrypted with |
108 | | -# whatever passphrase preceded this run — it's now orphaned and |
109 | | -# `task install`'s `lexik:jwt:generate-keypair --skip-if-exists` |
110 | | -# won't notice the mismatch, so login would 500 with "Unable to |
111 | | -# create a signed JWT from the given configuration." (auth succeeds, |
112 | | -# JWT signing fails). Wipe the orphans here; `task install` |
113 | | -# regenerates fresh against the new passphrase. |
114 | | -# |
115 | | -# Route the rm through a transient alpine container: the keypair is |
116 | | -# written by the os2display container's UID 1042 `deploy` user, so |
117 | | -# on Linux hosts a host-side `rm` fails with "Permission denied" |
118 | | -# unless the operator runs as UID 1042 or has sudo. Docker Desktop |
119 | | -# (macOS/Windows) brokers ownership at the VM boundary, so a host |
120 | | -# `rm` would work there — but the container path is portable. |
121 | | -JWT_WIPED="" |
| 108 | +# whatever passphrase preceded this run, so it no longer matches. We do |
| 109 | +# NOT delete it here — `task jwt:ensure` (run by `task install`) validates |
| 110 | +# the keypair against the passphrase and regenerates only on mismatch, so |
| 111 | +# the fix works whether or not `task install` is the next step. Just flag |
| 112 | +# the orphan so the operator isn't surprised. |
| 113 | +JWT_ORPHANED="" |
122 | 114 | if [ -f jwt/private.pem ] || [ -f jwt/public.pem ]; then |
123 | | - docker run --rm -v "$PWD/jwt:/jwt" alpine rm -f /jwt/private.pem /jwt/public.pem |
124 | | - JWT_WIPED="yes" |
| 115 | + JWT_ORPHANED="yes" |
125 | 116 | fi |
126 | 117 |
|
127 | 118 | echo |
128 | 119 | echo ".env.symfony created from $IMAGE." |
129 | 120 | echo " APP_SECRET / JWT_PASSPHRASE: random 32-byte hex (auto-generated)" |
130 | 121 | echo " DATABASE_URL serverVersion: ${MARIADB_TAG}-MariaDB (matched to compose pin)" |
131 | | -if [ -n "$JWT_WIPED" ]; then |
132 | | - echo " ./jwt/*.pem: wiped (orphaned by rotated JWT_PASSPHRASE)" |
| 122 | +if [ -n "$JWT_ORPHANED" ]; then |
| 123 | + echo " ./jwt/*.pem: kept, but no longer match the rotated" |
| 124 | + echo " JWT_PASSPHRASE — 'task jwt:ensure' (run by" |
| 125 | + echo " 'task install') regenerates them on mismatch." |
133 | 126 | fi |
134 | 127 | echo |
135 | 128 | echo "Edit .env.symfony for any ADMIN_*, CLIENT_*, OIDC_*, or DATABASE_URL" |
|
0 commit comments