Skip to content

Secrets API: Fix Site Health reports and key advice that locks stored secrets - #14847

Open
mpeshev wants to merge 3 commits into
WordPress:trunkfrom
mpeshev:secrets-site-health-fixes
Open

mpeshev wants to merge 3 commits into
WordPress:trunkfrom
mpeshev:secrets-site-health-fixes

Conversation

@mpeshev

@mpeshev mpeshev commented Oct 25, 2026 •

Copy link
Copy Markdown

Follow-up to [64337]. Three problems in the new Secrets API Site Health tests, one commit each:

  1. A broken or unreachable backend reads as healthy. The undecryptable and rotation tests turned the WP_Error from wp_list_secrets() into an empty result ("All secrets can be decrypted"), and the key source test matched "broken" in a translated string, so on translated sites a broken drop-in was reported as "using a dedicated key".
  2. Provider drop-ins got the wrong advice. With a secrets.php that replaces the provider (a host KMS or vault), the key source test described the unused default keyring and recommended WP_SECRETS_KEY.
  3. The key advice locked stored secrets. Sites without WP_SECRETS_KEY were told to define one "with a value from wp secret generate-key", a command that is not in core or WP-CLI. Doing so after any secret is stored makes every secret unreadable and blocks new ones (the root key stays wrapped with the old site key; rotate_site_key() has no caller), while Site Health reported the new key as good. Now a key that cannot unwrap the root key is critical, a dedicated key is recommended only before secrets exist, and once they do, Site Health warns that changing the key or salts makes them unreadable.

Trac ticket: https://core.trac.wordpress.org/ticket/66380

Testing

  • 7 new or updated tests in tests/phpunit/tests/secrets/siteHealth.php; all fail on trunk and pass with the patch.
  • vendor/bin/phpunit --group secrets passes (393 tests).
  • Manual, on 7.2-beta1: store a secret, then define WP_SECRETS_KEY as the trunk advice says. Trunk: the secret becomes unreadable, writes fail, and the key source test says good. With the patch: "Secrets API key does not match the stored secrets" (critical). Removing the constant restores access in both cases.

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5
Used for: finding these issues, drafting the fixes and tests, and running them. I reviewed every line and reproduced the manual steps above.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

🤖 Generated with Claude Code

mpeshev and others added 3 commits October 25, 2026 13:08
…ealth.

Two Site Health tests reported a backend whose secrets cannot be listed as healthy: `wp_secrets_site_health_find_undecryptable()` and `wp_secrets_site_health_count_needing_rotation()` turned the `WP_Error` from `wp_list_secrets()` into an empty result, which read as "All secrets can be decrypted" and "No secrets are pending rotation".

The key source test also detected a broken `secrets.php` drop-in by looking for "broken" in the keyring's description, which is a translated string, so on translated sites a broken drop-in was reported as using a dedicated key.

Return the `WP_Error` from both helpers and report it, and detect the broken keyring by its class.

Follow-up to [64337].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s the provider.

A `secrets.php` drop-in can replace the whole secrets provider, as a host's KMS or vault integration does. Such a provider protects secrets with its own keys, but the key source Site Health test still described the unused default keyring, and recommended defining `WP_SECRETS_KEY`, which that provider never reads.

Report the provider's label instead, with a good status.

Follow-up to [64337].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The key source Site Health test recommended defining `WP_SECRETS_KEY`, or regenerating it, "with a value from `wp secret generate-key`". That command is not part of core or WP-CLI. Following the advice after any secret was stored also makes every stored secret unreadable and blocks saving new ones: the root key stays wrapped with the previous site key, and core has no path that re-wraps it. The key source test then reported the new key as good.

* Report a configured key that cannot unwrap the stored root key as critical, and say that restoring the previous value fixes it.
* Recommend a dedicated key only before any secret is stored. Once secrets exist, warn that changing the key or the salts it derives from makes them unreadable.
* Drop the reference to the WP-CLI command.
* Say in the undecryptable secrets test that restoring the previous key makes the secrets readable again, instead of that there is no way to recover them.

Follow-up to [64337].

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@mpeshev
mpeshev marked this pull request as ready for review October 25, 2026 18:05
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs.

Core Committers: Use this line as a base for the props when committing in SVN:

Props nofearinc.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.


Props Bot commands

You can trigger Props Bot actions by commenting on this PR:

  • @propsbot add <username> to give props to a GitHub user. Requires write access.
  • @propsbot remove <username> to leave a user out of the props. Requires write access.
  • @propsbot refresh to refresh this list. Adding the props-bot label works too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant