Files
Crussell/backend/handlers/user/twofa_prod_test.go
T
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

78 lines
4.1 KiB
Go

//go:build !dev
package user
// Tests for the PRODUCTION 2FA issuance gate (twofa_prod.go).
//
// LIMITATION (documented — M17): twofa_prod.go is compiled only in a genuine
// production build (`!dev && !test`). Under BOTH required test runs — the
// "test,dev" run and the "test,!dev" prod-shape run — the dev/test variant
// (twofa_dev.go, build tag `dev || test`) is the compiled function and its
// fail-closed branches (no TWO_FACTOR_PEPPER → refuse; no delivery channel →
// 503) are unreachable. These tests compile in every `!dev` build and run
// their assertions ONLY when the prod variant marker reports the real prod
// functions are live; under the test tag they skip with the same documented
// rationale the payments package uses (twofa_delivery_prod_test.go).
//
// CLOSING THE GAP: run-prod-tag-tests.sh (backend/) runs `go test -tags
// "!dev,!test" ./handlers/user/` — the ONLY build configuration where
// twofa_prod.go compiles AND twofaProdVariant is true, so the assertions below
// actually execute there. The `if !twofaProdVariant { t.Skip(...) }` guards
// MUST stay: under the CI "test,!dev" matrix the dev/test variants are still
// the compiled functions (the `test` tag matches `dev || test`), so without
// the guards those runs would FAIL rather than skip.
//
// DELIVERY POSTURE (current): stdout-log delivery of 2FA codes is a
// DEV/TEST-ONLY local feature. A production build has NO delivery channel of
// any kind — email/SMS is not wired yet (P6) and there is deliberately no
// production opt-in to log delivery — so code issuance fails closed
// unconditionally (after the pepper check) and twoFADeliveryAvailable is
// always false.
import (
"os"
"testing"
)
// TestTwoFAEnsureIssueAllowed_ProdPredicate pins the production issuance gate:
// it fails closed without TWO_FACTOR_PEPPER (an unsalted digest in the 1M code
// space would be offline-brute-forceable) and, with the pepper set, STILL fails
// closed because a production build has no delivery channel (email/SMS unwired,
// stdout-log delivery is dev/test-only) — issuance can never succeed until a
// real transport lands.
func TestTwoFAEnsureIssueAllowed_ProdPredicate(t *testing.T) {
if !twofaProdVariant {
t.Skip("twoFAEnsureIssueAllowed() is the dev/test build's always-allowed variant (twofa_dev.go, `dev || test`); the prod fail-closed branches are unreachable under the test tag — see the file header for the documented limitation")
}
os.Unsetenv(twoFAPepperEnv)
if err := twoFAEnsureIssueAllowed(); err == nil {
t.Error("expected issuance refused without TWO_FACTOR_PEPPER in a production build")
} else if err.Error() != "TWO_FACTOR_PEPPER is not set; refusing to issue a 2FA code (an unsalted digest would be offline-brute-forceable)" {
t.Errorf("expected the pepper-required error without the pepper, got %v", err)
}
// With the pepper set, a production build STILL refuses: there is no
// delivery channel (email/SMS unwired, P6; stdout-log delivery is a
// dev/test-only local feature and there is no production opt-in).
os.Setenv(twoFAPepperEnv, "test-pepper")
if err := twoFAEnsureIssueAllowed(); err == nil {
t.Error("expected issuance refused in a production build with no delivery channel (email/SMS unwired, log delivery dev/test-only)")
} else if err != errTwoFADeliveryUnavailable {
t.Errorf("expected errTwoFADeliveryUnavailable with no channel, got %v", err)
}
}
// TestTwoFADeliveryAvailable_ProdPredicate pins the production delivery
// predicate: a production build ALWAYS reports no delivery channel — stdout-log
// delivery is a dev/test-only local feature, never a production channel.
func TestTwoFADeliveryAvailable_ProdPredicate(t *testing.T) {
if !twofaProdVariant {
t.Skip("twoFADeliveryAvailable() is the dev/test build's trivially-true variant (twofa_dev.go, `dev || test`); the always-false production predicate is unreachable under the test tag — see the file header for the documented limitation")
}
if twoFADeliveryAvailable() {
t.Error("a production build must ALWAYS report NO 2FA delivery channel (email/SMS unwired; stdout-log delivery is dev/test-only)")
}
}