From bacd6f419f02a17290424fc19647b9b2527f4309 Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 28 Sep 2026 09:19:12 +0000 Subject: [PATCH] Stop describing dev as the default environment Comments in reqtls and session, and the README Quick Start and deployment checklist, still spoke as if an unset WEBHOOKER_ENVIRONMENT meant dev. The checklist now asks only that the environment is not dev (unset or prod); the Quick Start describes running from the clone. Model: opus-5-5 --- README.md | 29 +++++++++++++++-------------- internal/reqtls/reqtls.go | 2 +- internal/session/session.go | 4 ++-- internal/session/session_test.go | 4 ++-- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 3b217d6..a66cf2a 100644 --- a/README.md +++ b/README.md @@ -44,9 +44,9 @@ make bootstrap # Run all checks (test, lint, format check) make check -# Run in development mode. DATA_DIR defaults to /var/lib/webhooker in -# every environment, so set it (in .env or the shell) to a writable -# directory when running from a clone. +# Run the server from the clone. DATA_DIR defaults to +# /var/lib/webhooker in every environment, so set it (in .env or the +# shell) to a writable directory. DATA_DIR=./data make dev # Build Docker image @@ -753,17 +753,18 @@ reports. serves the admin login form and the unauthenticated receiver with no TLS at all, and the proxy in front of it changes nothing about that. -2. **Set `WEBHOOKER_ENVIRONMENT=prod`, and make sure the proxy sends - `X-Forwarded-Proto`.** These are two requirements, not one. The - environment setting decides CORS and nothing else: `dev` answers - every origin with `Access-Control-Allow-Origin: *` (without - credentials), which a server-rendered production deployment has no - use for, and `prod` — the default — disables it. Cookie `Secure` - and the strict Origin/Referer mode are **not** tied to it — they - are decided per request from the transport, which behind a proxy - means the `X-Forwarded-Proto` header. The block below sets it; - without it every request is read as plaintext and cookies ship - without `Secure`. See [Configuration](#configuration). +2. **Make sure the environment is not `dev` (leave + `WEBHOOKER_ENVIRONMENT` unset or set it to `prod`), and make sure + the proxy sends `X-Forwarded-Proto`.** These are two requirements, + not one. The environment setting decides CORS and nothing else: + `dev` answers every origin with `Access-Control-Allow-Origin: *` + (without credentials), which a server-rendered production + deployment has no use for, and `prod` — the default — disables it. + Cookie `Secure` and the strict Origin/Referer mode are **not** tied + to it — they are decided per request from the transport, which + behind a proxy means the `X-Forwarded-Proto` header. The block below + sets it; without it every request is read as plaintext and cookies + ship without `Secure`. See [Configuration](#configuration). 3. **Set `TRUSTED_PROXIES` to the proxy's address.** Unset, every rate limiter keys on the connecting peer, which behind a proxy is the proxy on every request: all clients collapse into one global bucket diff --git a/internal/reqtls/reqtls.go b/internal/reqtls/reqtls.go index f1704a4..b9e28b5 100644 --- a/internal/reqtls/reqtls.go +++ b/internal/reqtls/reqtls.go @@ -5,7 +5,7 @@ // several packages, by hand, and the answers disagreed. The session // cookie's Secure attribute was decided at startup from the configured // environment while the CSRF cookie's was decided per-request, so a -// deployment behind a TLS proxy in the default environment emitted one +// deployment behind a TLS proxy in the dev environment emitted one // Secure cookie and one non-Secure cookie on the same response. // Everything kept working, which is exactly why nobody noticed. // diff --git a/internal/session/session.go b/internal/session/session.go index 901568e..97b6664 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -146,8 +146,8 @@ func newStore(key []byte) *sessions.CookieStore { // // This is decided per-request, not once at startup. Deciding it at // startup from the configured environment is what this replaces, and -// it got the DEFAULT posture wrong: "dev" is the environment when -// WEBHOOKER_ENVIRONMENT is unset, so a deployment terminating TLS at a +// it got the DEFAULT posture wrong: "dev" was then the environment when +// WEBHOOKER_ENVIRONMENT was unset, so a deployment terminating TLS at a // proxy without also setting the environment emitted the // authentication cookie with no Secure attribute -- silently, and on // the same response as a CSRF cookie that did have one. diff --git a/internal/session/session_test.go b/internal/session/session_test.go index 962df24..a52ae96 100644 --- a/internal/session/session_test.go +++ b/internal/session/session_test.go @@ -990,8 +990,8 @@ func sessionCookieFrom( // TestSave_SecureFollowsRequestTransport is the regression test for // the defect this replaces: Secure was fixed at startup from the -// configured environment, and "dev" is the environment when -// WEBHOOKER_ENVIRONMENT is unset. A deployment behind a TLS proxy in +// configured environment, and "dev" was then the environment when +// WEBHOOKER_ENVIRONMENT was unset. A deployment behind a TLS proxy in // that DEFAULT posture shipped the authentication cookie with no // Secure attribute and said nothing about it. //