Repository navigation
Conversation
Maps ericmann/secrets-api#v0.2.1 into the wp-env tests environment with a deterministic test-only WP_SECRETS_KEY, and loads it from the PHPUnit bootstrap when present. Applied by the operator after the dependency was approved; acceptance tests remain for the implementer.
Goal: acceptance tests for Secrets API availability under wp-env. Tests: test_secrets_api_feature_plugin_loaded_for_tests, test_secrets_api_network_round_trip (run, not skipped, both suites). Interpretation: worked on build/2026-09-28 (created by run_start) instead of build/secrets-api-totp. Manual check: none.
Goal: resolve Secrets API symbols in PHPStan; exclude stubs from PHPUnit. Tests: lint and both suites pass.
Goal: sole Secrets API adapter plus test base class. Tests: 18 adapter tests in group secrets, both suites. Interpretation: test class/file named Two_Factor_Secrets_Tests in tests/class-two-factor-secrets-tests.php; PHPCS demands file name match the class for classes not extending a core test case, and a name sorting before class-two-factor-core.php breaks core tests (they register set_auth_cookie hooks in set_up_before_class, which a preceding test class wipes).
…ling Goal: enrolled-but-unavailable providers force fallback or fail closed. Tests: 2 provider base tests, 5 core tests (fallback, fail-closed, keep available, unconfigured, uninstall hook). Interpretation: resolve_fallback_provider_for_user has an optional 4th by-ref arg exposing the raw filter value for error data; fixture loaded via two_factor_providers path instead of bootstrap (Two_Factor_Dummy not loaded at bootstrap).
Goal: route TOTP key storage through Two_Factor_Secrets with verified writes and lazy migration. Tests: 27 tests in Two_Factor_Totp_Secrets_Tests (multisite cross-blog test skipped on single site). Interpretation: test class named Two_Factor_Totp_Secrets_Tests / file class-two-factor-totp-secrets-tests.php to satisfy PHPCS file naming, as in P1-01.
…gression Goal: honour the tri-state secret read everywhere and fire two_factor_secret_unavailable. Tests: 11 tests appended to Two_Factor_Totp_Secrets_Tests including affected-user login regression. Interpretation: unavailable login prompt omits the generic 'Enter the code' line.
Goal: remove TOTP secrets and markers on user deletion and uninstall. Tests: 6 in Two_Factor_Totp_Secrets_Tests, 1 in core uninstall. Interpretation: hooks call wrapper delete_user_secrets_on_user_deletion() (void) since PHPStan rejects bool-returning action callbacks.
Goal: warn admins when migrated secrets are unreachable. Tests: 8 tests in Two_Factor_Totp_Secrets_Tests.
Goal: report TOTP secret storage state in Site Health. Tests: 6 tests in Two_Factor_Totp_Secrets_Tests. Interpretation: API present with no plaintext users is 'good' (provider label) regardless of writability.
Goal: expose TOTP storage and Secrets API status from the CLI. Tests: 9 tests in Tests_Two_Factor_CLI_Command. Interpretation: Two_Factor_Secrets::provider_label() now returns '' whenever is_api_present() is false (including the test seam).
Goal: bulk-migrate plaintext TOTP secrets in bounded batches. Tests: 8 tests in Tests_Two_Factor_CLI_Command.
Goal: reverse migration with confirmation and verification. Tests: 4 provider tests, 5 CLI tests.
Goal: document Secrets API storage, hooks and CLI. Tests: none (docs); lint and both suites green. Interpretation: readme.md has no equivalent sections and is left unchanged; readme.txt keeps its CRLF line endings.
Goal: contributor docs and inline docs match the shipped code. Tests: none (docs); docblock-only PHP hunks (@SInCE 0.18.0).
Goal: ready-to-paste PR body. Tests: none (docs).
Goal: docs match behaviour (undecryptable secret with API present locks out; export needs filter opt-out first). Tests: two behaviour-pinning tests in Two_Factor_Totp_Secrets_Tests. Interpretation: added open question 6 to PR description. Manual check: NOT VERIFIED (human)
When TOTP was turned off in Settings -> Two-Factor the provider class was never loaded, so user deletion left stored secrets behind, the admin notice and Site Health test never registered, and wp two-factor secrets crashed with a missing class. Always load the class and register those hooks statically, without instantiating the provider (which would expose its REST routes while disabled).
Owner
Author
|
Superseded by #2 (clean branch |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Handoff: TOTP secrets in the WordPress Secrets API
build/2026-09-28(the spec namedbuild/secrets-api-totp;foundry_run_startcreated this one and the run stayed on it)8799d03(plan) onfeature/secrets-api-totp5826028(plus this file)Blocked / skipped tasks
None.
Interpretation choices
build/2026-09-28branch instead of creatingbuild/secrets-api-totp. The.wp-env.jsonand bootstrap changes had already been applied by the operator.Two_Factor_Secrets_Tests(filetests/class-two-factor-secrets-tests.php) and, in P2-01,Two_Factor_Totp_Secrets_Tests(filetests/providers/class-two-factor-totp-secrets-tests.php), notTests_Two_Factor_*as the plan said. PHPCS requires the file name to match the class for classes that don't extend a recognised WP test case, and a file sorting beforetests/class-two-factor-core.phpbreaks the core tests (they registerset_auth_cookiehooks inset_up_before_class(), which an earlier test class wipes). Filter parameter is$enabledbecause PHPCS flags$use.resolve_fallback_provider_for_user()has an optional fourth by-reference argument that exposes the raw filter value so the existing error data (fallback_provider) stays byte-for-byte. TheTwo_Factor_Dummy_Unavailablefixture is loaded through thetwo_factor_providersfilter path, nottests/bootstrap.php, becauseTwo_Factor_Dummyis not loaded at bootstrap time.delete_user_totp_key()now returnstrueonly when plaintext, marker and secret are all gone (including when there was nothing to delete).delete_user_secrets_on_user_deletion()instead ofdelete_user_totp_key(), because PHPStan level 5 rejects bool-returning action callbacks. The constructor test asserts the wrapper.goodnaming the provider label, even when writes are disabled; the "migration disabled" message is used only when plaintext remains andcan_write()is false.Two_Factor_Secrets::provider_label()returns''wheneveris_api_present()is false (so the test seam is honoured). Booleans insecrets statusare the strings'true'/'false'.readme.mdhas no equivalent sections and was left unchanged.readme.txtuses CRLF line endings, preserved.⚠️ ASSUMPTIONconfig keysNone introduced. Constants:
SECRET_SLUG = 'totp',AFFECTED_USERS_CACHE_TTL = 300,Two_Factor_CLI_Command::SECRETS_DEFAULT_BATCH_SIZE = 100(none tuned).Manual checks (all NOT VERIFIED (human))
npm install && npm run env startclonesericmann/secrets-apiv0.2.1 into the tests env; CI passes on the WPlatest,7.0-branch,7.1-branchlegs;gh repo set-default --viewshows the fork.class-two-factor-secrets.phpfor any path that could echo or log a revealed value._wp_network_secret_two-factor/totp-<id>option exists with empty_two_factor_totp_keymeta; log in with an app code; deactivate the feature plugin and confirm only other methods are offered, and that the profile shows the reset notice after re-activating withWP_SECRETS_KEYchanged; deleting the user removes the option row.wp two-factor secrets status(and--format=json),migrate --dry-runthenmigrate,status <user>showssecrets-api,exportprompts and--yescompletes,wp help two-factor secretsshows the OPTIONS block.docs/PR-DESCRIPTION.mdand the readme FAQ for tone; confirm CI is green; open the fork PR (basemaster,ericmann/two-factor) if the pipeline did not; rerun the Phase 2 and 3 browser checks on the final commit.For a reviewer who has not seen this code
Two_Factor_Secretsis the only file that may call the Secrets API (enforced by constraints indocs/foundry.json). Secrets are network scope only; a user-meta marker_two_factor_totp_key_networkrecords the owning network.WP_Error).Two_Factor_Core::get_available_providers_for_user()now forces the fallback provider (or ano_available_2fa_methodserror) when the only enrolled providers reportis_enrolled_but_unavailable_for_user(). The regression test istest_login_fails_closed_for_affected_totp_only_user(and its no-fallback variant).two_factor_secrets_api_presentfilter.docs/PR-DESCRIPTION.mdis the ready-to-paste upstream PR body; nothing was opened againstWordPress/two-factor.