Commit 7cb35f1
fix(webapp,helm): require control-plane auth secrets and remove weak bundled-datastore defaults (#57)
* fix(webapp): require control-plane auth secrets
* fix(helm): remove weak default credentials for bundled datastores
Empty the shipped postgres/clickhouse/minio/registry credential defaults so an
unconfigured install fails closed instead of booting with publicly-known
passwords. Add fail-closed validation guards for the bundled (deploy=true)
datastores and feed CI throwaway render-time values so chart linting stays green.
* fix(webapp): reject known-insecure control-plane secret defaults
Add a blocklist refine to PROVIDER_SECRET, COORDINATOR_SECRET and
MANAGED_WORKER_SECRET so the webapp rejects the publicly-known
placeholder strings at boot, matching the value the coordinator already
refuses at startup. Add the three now-required vars to the root
.env.example and align the supervisor MANAGED_WORKER_SECRET example with
the Docker example so local setups authenticate consistently.
* fix(helm): fail closed on missing control-plane secrets and fix datastore guard guidance
Blank the bundled provider/coordinator/managed-worker secret defaults and
add a render-time guard so an unconfigured install fails closed instead of
shipping repo-published tokens, matching the datastore fail-closed pattern.
Require both postgres.auth.postgresPassword and postgres.auth.password, and
point the Postgres/ClickHouse guard messages at the key paths the webapp
actually consumes so operators are not sent to a crash loop. Add placeholder
credentials to values-production-example.yaml and the CI lint values so the
documented install paths still render, and update the README to reflect that
a values file with credentials is now required.
* test(webapp): provide required control-plane secrets in e2e harness
The e2e webapp harness (startTestServer) spawns the production webapp
bundle, which now fails closed when PROVIDER_SECRET / COORDINATOR_SECRET
/ MANAGED_WORKER_SECRET are unset. Supply strong test values (not the
blocklisted known-insecure defaults) so the webapp boots and the
E2E Tests: Webapp check passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(webapp,hosting): fail closed on empty app secrets and stop shipping working ones
Extend the fail-closed convention to the two remaining app secrets and the
Docker Compose self-host path:
- env.server: SESSION_SECRET and MAGIC_LINK_SECRET now require .min(1), so an
empty value fails the schema parse at boot rather than running with an empty
secret (SESSION_SECRET is the JWT signing key) or falling through to the
emailAuth runtime guard.
- hosting/docker/.env.example and apps/supervisor/.env.example: ship the
crypto/auth secrets empty with a short 'generate with openssl rand -hex 16'
comment instead of the previous working public values. A bare
'cp .env.example .env && docker compose up' now fails closed on the first
missing secret; the documented setup already generates all six.
- Tests: cover empty and unset rejection for all five required secrets.
Addresses SEC-387 / GHSA-pqxw-g93w-hj9x (the Docker path the earlier commits
in this PR did not cover).
* fix(webapp,helm): reject published application secret defaults
* fix(helm): reject unsupported bundled datastore secret references
* format
* .env
* feat(helm): auto-generate app and control-plane secrets instead of failing closed
Leave secrets.* empty to have the chart generate a strong value on first install, retained across upgrades via lookup so ENCRYPTION_KEY/SESSION_SECRET are never rotated. Explicit values and existingSecret still win. Removes the now-redundant fail-closed guards for these secrets (the webapp still rejects known-insecure values at startup).
* feat(hosting): add docker generate-secrets.sh to fill self-hosting secrets
Fills empty required secrets in .env with openssl-random values. Safe to re-run: never overwrites an already-set value, so restarts and re-runs don't rotate ENCRYPTION_KEY/SESSION_SECRET. Docs updated to run it during setup.
* ci(helm): lint and render release-helm with ci lint-values
The bundled-datastore passwords are now fail-closed, so a values.yaml-only lint/template render fails. Supply ci/lint-values.yaml like the prerelease workflow already does, keeping the chart release pipeline green.
* feat(webapp): allow opting out of the insecure-default secret blocklist
ALLOW_INSECURE_DEFAULT_SECRETS lets a deployment boot while still using a known-published default it cannot safely rotate yet (e.g. ENCRYPTION_KEY protects existing data, SESSION_SECRET rotation logs everyone out). It only bypasses the known-insecure blocklist; the min-length and 32-byte ENCRYPTION_KEY checks still apply. A loud warning is logged at boot naming any secret still on a published default.
* feat(hosting): auto-generate bundled-datastore passwords for docker self-hosting
Remove the shipped weak defaults for postgres/clickhouse/minio/registry. generate-secrets.sh now fills each datastore password (openssl rand), and for the registry writes a matching bcrypt htpasswd via docker. Connection URLs are derived from the single password var by compose interpolation, so server and client always match; datastore services fail closed with a helpful message if a password is unset. Never clobbers an existing value - use --force to rotate.
* docs(self-hosting): document secret auto-generation, rotation gotchas, and the insecure-default opt-out
Note that generate-secrets.sh also fills the bundled datastore passwords; add ALLOW_INSECURE_DEFAULT_SECRETS to the webapp env list; add a Helm secret generation/rotation section covering upgrade retention, the GitOps regeneration caveat, and the lack of a clean ENCRYPTION_KEY migration.
* feat(helm): auto-generate bundled-datastore passwords
Generate the postgres/clickhouse/minio passwords once into a chart-managed datastore Secret (retained across upgrades via lookup) and point each bundled subchart at it via auth.existingSecret; the webapp reads them back through secretKeyRef and $(VAR) URL interpolation, so server and client always match. The registry password is generated and retained inside secrets.yaml (consumed at render time by htpasswd + dockerconfigjson). Drops the deploy=true datastore password guards - a bare helm install now renders and deploys with strong, unique credentials, and explicit values or an existingSecret still win.
* fix(helm): start the s2 container via args, not command
The s2 image ENTRYPOINT is ["./s2"] with the subcommand/flags as CMD. Setting Kubernetes command overrode the entrypoint and tried to exec "lite" directly, so the pod failed with StartError and realtime streams v2 (the default) never came up. Passing them as args preserves the entrypoint (./s2 lite ...). Verified live in kind: the s2 pod now reaches Running.
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: nicktrn <55853254+nicktrn@users.noreply.github.com>1 parent 3cbbaed commit 7cb35f1
29 files changed
Lines changed: 602 additions & 111 deletions
File tree
- .github/workflows
- .server-changes
- apps
- supervisor
- webapp
- app
- test
- docs/self-hosting
- env
- hosting
- docker
- registry
- webapp
- k8s/helm
- ci
- templates
- internal-packages/testcontainers/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
| 55 | + | |
| 56 | + | |
56 | 57 | | |
57 | 58 | | |
58 | 59 | | |
59 | 60 | | |
60 | 61 | | |
| 62 | + | |
61 | 63 | | |
62 | 64 | | |
63 | 65 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
| 50 | + | |
| 51 | + | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
54 | 55 | | |
55 | 56 | | |
| 57 | + | |
56 | 58 | | |
57 | 59 | | |
58 | 60 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
5 | | - | |
| 4 | + | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
85 | 85 | | |
86 | 86 | | |
87 | 87 | | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
88 | 111 | | |
89 | 112 | | |
90 | 113 | | |
| |||
188 | 211 | | |
189 | 212 | | |
190 | 213 | | |
191 | | - | |
192 | | - | |
| 214 | + | |
| 215 | + | |
193 | 216 | | |
194 | 217 | | |
195 | 218 | | |
196 | 219 | | |
197 | 220 | | |
198 | | - | |
| 221 | + | |
| 222 | + | |
199 | 223 | | |
200 | 224 | | |
201 | 225 | | |
| |||
684 | 708 | | |
685 | 709 | | |
686 | 710 | | |
687 | | - | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
688 | 716 | | |
689 | 717 | | |
690 | 718 | | |
| |||
2113 | 2141 | | |
2114 | 2142 | | |
2115 | 2143 | | |
| 2144 | + | |
| 2145 | + | |
| 2146 | + | |
| 2147 | + | |
| 2148 | + | |
| 2149 | + | |
| 2150 | + | |
| 2151 | + | |
| 2152 | + | |
| 2153 | + | |
| 2154 | + | |
| 2155 | + | |
| 2156 | + | |
| 2157 | + | |
| 2158 | + | |
| 2159 | + | |
| 2160 | + | |
| 2161 | + | |
| 2162 | + | |
| 2163 | + | |
| 2164 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
13 | 16 | | |
14 | 17 | | |
15 | 18 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
16 | 19 | | |
17 | 20 | | |
18 | 21 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
82 | 86 | | |
83 | 87 | | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
84 | 95 | | |
85 | 96 | | |
86 | 97 | | |
| |||
130 | 141 | | |
131 | 142 | | |
132 | 143 | | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
133 | 151 | | |
134 | 152 | | |
135 | 153 | | |
| |||
0 commit comments