From 9dae0503ee9cd32f3816e7faf6796dc27f42e4a7 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Thu, 30 Apr 2026 13:30:14 -0700 Subject: [PATCH] fix(harness): generate SECRETS_ENCRYPTION_KEY per-run instead of hardcoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the hardcoded base64 sentinel (630dd0da) with a per-run generation in up.sh, exported into compose's interpolation environment. Why: - Hardcoding a 32-byte base64 string in the repo, even one labelled "test-only", sets a bad muscle-memory pattern. The next agent or contributor copies the shape into another harness — or worse, into a staging .env — and the test-only sentinel turns into something someone treats as a real key. - Secret scanners flag key-shaped values regardless of the surrounding comment claiming intent. Avoiding the literal entirely sidesteps the false-positive. - A fresh key per harness lifetime more closely mimics prod's per-tenant isolation, exercising the same code paths without any pretense of stable encrypted-data fixtures (which the harness wipes on every ./down.sh anyway). Implementation: - up.sh: `openssl rand -base64 32` if SECRETS_ENCRYPTION_KEY isn't already set in the caller's env. Honoring a pre-set value lets a debug session pin a key for reproducibility (e.g. when investigating encrypted-row corruption). - compose.yml: `${SECRETS_ENCRYPTION_KEY:?…}` makes a misuse loud — running `docker compose up` directly bypassing up.sh fails fast with a clear error pointing at the right entry point, rather than a 100s unhealthy-tenant timeout. Both paths verified via `docker compose config`: - with key exported: value interpolates cleanly - without it: "required variable SECRETS_ENCRYPTION_KEY is missing a value: must be set — run via tests/harness/up.sh, which generates one per run" --- tests/harness/compose.yml | 14 +++++++------- tests/harness/up.sh | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/tests/harness/compose.yml b/tests/harness/compose.yml index 3fe185cc..1a382a6a 100644 --- a/tests/harness/compose.yml +++ b/tests/harness/compose.yml @@ -86,13 +86,13 @@ services: PLATFORM_URL: "http://tenant:8080" MOLECULE_ENV: "production" # SECRETS_ENCRYPTION_KEY is required when MOLECULE_ENV=production — - # crypto.InitStrict() refuses to boot without it ("32 bytes raw or - # base64-encoded"). The harness uses a clearly-test sentinel so the - # production code path is exercised end-to-end (including the - # encrypted-secret reads/writes) without coupling to a real key. - # Value is base64 of the literal string "harness-test-only-not-for-prod!!" - # (exactly 32 bytes). Do NOT copy this to any other environment. - SECRETS_ENCRYPTION_KEY: "aGFybmVzcy10ZXN0LW9ubHktbm90LWZvci1wcm9kISE=" + # crypto.InitStrict() refuses to boot without it. up.sh generates a + # fresh 32-byte key per harness lifetime via `openssl rand -base64 32` + # and exports it into this compose file's interpolation environment. + # The :? sentinel makes the misuse loud — running `docker compose up` + # directly without going through up.sh fails fast with a clear error + # rather than getting a confusing tenant-unhealthy timeout. + SECRETS_ENCRYPTION_KEY: "${SECRETS_ENCRYPTION_KEY:?must be set — run via tests/harness/up.sh, which generates one per run}" # ADMIN_TOKEN flips the platform into strict-auth mode (matches # production's CP-minted token configuration). Seeded value lets # E2E scripts authenticate without going through CP. diff --git a/tests/harness/up.sh b/tests/harness/up.sh index b3c87936..fbc14910 100755 --- a/tests/harness/up.sh +++ b/tests/harness/up.sh @@ -18,6 +18,22 @@ for arg in "$@"; do esac done +# Generate a per-run encryption key. The tenant runs with +# MOLECULE_ENV=production (intentional, to replay prod-shape bugs), and +# crypto.InitStrict() refuses to boot without SECRETS_ENCRYPTION_KEY. +# Generate fresh so: +# - No key-shaped string lives in the repo (avoids muscle-memorying a +# hardcoded value into other places + secret-scanner false positives). +# - Each harness lifetime gets a unique key, mimicking prod's per-tenant +# isolation. Persistence across runs isn't required — the harness DB +# is wiped on every ./down.sh. +# Honor a caller-supplied value if already exported (lets a debug session +# pin a key for reproducibility). +if [ -z "${SECRETS_ENCRYPTION_KEY:-}" ]; then + SECRETS_ENCRYPTION_KEY=$(openssl rand -base64 32) + export SECRETS_ENCRYPTION_KEY +fi + if [ "$REBUILD" = true ]; then docker compose -f compose.yml build --no-cache tenant cp-stub fi