//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)") } }