Files
Crussell/backend/run-prod-tag-tests.sh
popertots f9e8385d5a fix: auth/2FA security — stdout-log code delivery is dev/test-only, production fails closed until email/SMS; verification-code hashing, lockout recovery, sabredav fail-closed
- TWO_FACTOR_ALLOW_LOG_DELIVERY production opt-in REMOVED: plaintext codes are written to the stdout log ([2FA]/[VERIFY]) only in dev/test builds as a local DEV ONLY feature while email/SMS delivery (P6) is implemented. Production builds have no delivery channel and code issuance fails closed (503) under any configuration — no silent log-based code leak
- verification/2FA codes hashed at rest (HMAC-SHA256 via TWO_FACTOR_PEPPER, CHAR(64)); [VERIFY] dev log relay; per-user brute-force budget; password_reset purpose clears lockout for self-service recovery; dummy-bcrypt on login no-user path kills timing oracle
- sabredav weak-password list + entropy gate; .env.example ships fail-closed DAV_ADMIN_PASSWORD
- delete-account re-auth (current_password + fresh 2FA code when enforced)
- prod-tag suite (run-prod-tag-tests.sh) compiles and runs the production 2FA issuance gate: production ALWAYS reports no delivery channel and refuses issuance after the pepper check
- startup_checks_test SNAPSHOT_ENC_KEY values built at runtime so gitleaks sees no secret-shaped literals
- env-docs parity updated (flag removed, 38 vars)
2026-08-22 00:34:50 +01:00

53 lines
2.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# run-prod-tag-tests.sh — compiles and runs the PRODUCTION-ONLY 2FA tests.
#
# WHY: the fail-closed 2FA issuance/delivery branches live in
# handlers/user/twofa_prod.go, which is `//go:build !dev && !test`. The two
# documented CI test matrices — "test,dev" and "test,!dev" — BOTH set the
# `test` tag, so twofa_prod.go never compiles under either, and the dev/test
# variant (twofa_dev.go, `dev || test`) is always the compiled function. The
# production security default — no TWO_FACTOR_PEPPER → refuse issuance, no
# delivery channel → 503 — is therefore unreachable under both matrices.
#
# This script runs `go test` with NEITHER the `dev` NOR the `test` tag
# (`-tags "!dev,!test"`), the ONLY build configuration where twofa_prod.go
# compiles AND twofaProdVariant reports the real prod functions are live, so
# the assertions in twofa_prod_test.go actually execute instead of skipping.
#
# Note on `-tags "test,!dev"`: CI's "prod" matrix uses that tag set for
# vet/staticcheck/gosec (source-level checks), but for TESTS it still excludes
# twofa_prod.go (`!test`) and still compiles twofa_dev.go (`test` matches
# `dev || test`) — so it cannot exercise the prod fail-closed branches. The
# genuinely-prod test build is `!dev,!test` only.
#
# Env: GO_TESTING/DAV_SKIP_INIT are set so internal/dav's prod-service init
# (service_prod.go) does not attempt a real Postgres connect at package-load
# time — the CI test jobs set the same vars.
#
# USAGE:
# ./run-prod-tag-tests.sh # run the prod-shape 2FA tests
# ./run-prod-tag-tests.sh -v # pass through extra go test args
#
# Agents and humans: run backend tests through this script (or take the
# lockfile yourself: `flock /tmp/crussell-tests.lock -c '<cmd>'`). The lock
# protects the shared test-DB namespace even though these packages do not
# currently touch the DB — if that ever changes the DB stays safe.
set -u
LOCKFILE="${LOCKFILE:-/tmp/crussell-tests.lock}"
LOCK_TIMEOUT="${LOCK_TIMEOUT:-300}"
cd "$(dirname "$0")"
# GO_TESTING=1: internal/dav prod init skips the real connect (service_prod.go).
# DAV_SKIP_INIT=1: belt-and-braces for the same skip gate.
export GO_TESTING=1
export DAV_SKIP_INIT=1
# handlers/user holds the only prod-only test code (twofa_prod_test.go under
# `!dev`). handlers/payments is included to prove the payments package still
# compiles in a genuinely-prod build (it has no `test && dev` test files, so
# `go test` reports "[no test files]" and exercises the package build only).
exec flock -w "$LOCK_TIMEOUT" "$LOCKFILE" go test -tags "!dev,!test" -count=1 "$@" ./handlers/user/ ./handlers/payments/