Opened 12 days ago
Last modified 42 minutes ago
#66187 accepted enhancement
Secrets API: encrypted, versioned storage for credentials
| Reported by: | ericmann | Owned by: | whyisjake |
|---|---|---|---|
| Priority: | normal | Milestone: | 7.2 |
| Component: | Security | Version: | |
| Severity: | normal | Keywords: | has-patch has-unit-tests needs-dev-note needs-docs |
| Cc: | Focuses: |
Description
The Secrets API proposal is for a core API that stores credentials such as API keys and tokens encrypted at rest, keeps a previous version for rotation, and lets hosts replace the storage through a secrets.php drop-in. This ticket covers the 7.2 part: the API itself. The admin screen is deferred to 7.3, as the proposal says. The WP-CLI commands stay in the feature plugin for now, since WP-CLI commands ship as WP-CLI packages rather than in core.
The patch is the src/ directory of the feature plugin, copied without changes, plus the wiring the plugin's bootstrap does today. The plugin has been public since 4 September and is at v0.2.0. The documentation, including every place the code departs from the proposal and why, is at secretsapi.dev.
This is also the storage #64789 asks for. The Connectors screen from #64730 keeps AI provider API keys as plaintext options, which are visible on options.php. Stored through this API, they are encrypted under a key that is not in the database, so a database dump or backup no longer exposes them. Moving Connectors onto wp_set_secret() and wp_get_secret() can follow once this lands.
The patch
- The API: 14 new files in
src/wp-includes/.- the public functions
WP_SecretandWP_Secret_Version- the provider, store and keyring interfaces, with their default and fail-closed implementations
- the cipher and the key manager
src/wp-admin/includes/secrets-site-health.phpadds three Site Health tests and a debug-information section.
- Loading:
wp-settings.phploads the API, then loadswp-content/secrets.phpthrough a newwp_load_secrets_dropin()inload.php, just before must-use plugins. - Failing closed: if the drop-in throws, or sets a provider, store or keyring that does not implement its interface, every Secrets API call returns
WP_Errorfor the rest of the request. Nothing falls back to the default provider: a broken drop-in has to read as unreachable, never as "this secret does not exist". See ADR 0007. - Capabilities:
populate_roles_720()grantsmanage_secretsto administrators on install, andupgrade_720()grants it on upgrade.manage_network_secretsjoins the other network capabilities inmap_meta_cap(), so only super admins hold it. - Tests: the plugin's tests for everything in
src/, 371 of them, intests/phpunit/tests/secrets/. They come with provider and keyring conformance suites for hosts that write drop-ins.
Changes and additions beyond the proposal
The proposal names wp_set_secret(), wp_get_secret(), wp_delete_secret(), wp_import_option_as_secret(), WP_Secret, and WP_Secret_Version. Everything below differs from or goes beyond that, and is listed so each item can be reviewed, and rejected, on its own. The reasoning for each is on the linked page.
WP_Secret::reveal()returnsstring|WP_Error, notstring: retrievalwp_retire_secret_version()andwp_list_secrets(): rotation, retrieval- Network scope, which the proposal describes without naming functions:
wp_set_network_secret(),wp_get_network_secret(),wp_delete_network_secret(),wp_retire_network_secret_version(),wp_list_network_secrets(). See network. wp_secrets_validate_name(),wp_secrets_memzero(),wp_using_secrets_dropin(),wp_secrets_provider_is_writable(),wp_secrets_provider_label()- The
wp_secret_changedaction, for auditing, plusWP_Secret::get_name()andWP_Secret::withheld() - The
WP_Secrets_Provider,WP_Secrets_Store, andWP_Secrets_Keyringinterfaces, and their default and fail-closed implementations. The provider replaced the proposal's two-part drop-in contract after hosts on the proposal thread showed it could not describe how they already deploy. See providers and keyrings and ADR 0001. - Constants: ten
WP_SECRETS_ERROR_*codes,WP_SECRETS_RECORD_VERSION,WP_SECRETS_MAX_NAME_LENGTH,WP_SECRETS_CAP_MANAGE, andWP_SECRETS_CAP_MANAGE_NETWORK
The scope page has the complete list.
Testing
- In this branch:
npm run test:php -- --group secretspasses on single site and multisite (371 tests each).tests/phpunit/tests/user/capabilities.phppasses with both capabilities added to its inventory.- The full single-site suite shows no new failures.
- The plugin's CI: PHP 7.4, 8.0 and 8.3, each against WordPress latest and trunk, plus a multisite job and a WP-CLI smoke test on PHP 7.4 and 8.3.
- Drop-in examples: the ones in the plugin's
examples/directory have been run against live AWS KMS and AWS Secrets Manager, against HashiCorp Vault 2.1.1 (including a sealed server), and against OpenBao 2.7.0.
Notes for committers
$wp_db_versionis set to a placeholder, 61900, whichupgrade_720()checks. It needs the real revision number on commit.wp-tests-config-sample.phpships placeholder salts, and the default keyring deliberately refuses to derive a key from them. When the salts are placeholders, the test bootstrap therefore defines a fixedWP_SECRETS_KEYin the main PHPUnit process. The four tests that exercise the salt-based fallback are skipped in that case.- Every new symbol is marked
@since 7.2.0.
Change History (13)
This ticket was mentioned in PR #13759 on WordPress/wordpress-develop by @ericmann.
12 days ago
#1
This ticket was mentioned in Slack in #core by ericmann. View the logs.
8 days ago
This ticket was mentioned in Slack in #core by amykamala. View the logs.
7 days ago
#5
follow-up:
↓ 6
@
7 days ago
@ericmann I wonder if we should put everything in the includes folder into a folder. Just looking at the abilities-api/ai/etc. as an example.
#6
in reply to: ↑ 5
@
43 hours ago
Replying to whyisjake:
@ericmann I wonder if we should put everything in the includes folder into a folder. Just looking at the abilities-api/ai/etc. as an example.
@whyisjake Agreed, and done. Everything now lives in src/wp-includes/secrets/, following the layout abilities-api/ and ai-client/ use. The PR has it as a separate commit, so it reads as 13 renames plus the require paths in wp-settings.php. Nothing else changes.
Only two things stayed where they were:
src/wp-includes/secrets.php, the functions file, stays at the top level next to the folder, the wayabilities-api.phpandai-client.phpdo.src/wp-admin/includes/secrets-site-health.phpstays inwp-admin/includes/.
If you would rather have secrets.php inside the folder too, that is a small change and I am happy to make it. The feature plugin has the same layout as of today, so its src/ and the patch are still identical.
#7
@
42 hours ago
- Keywords needs-dev-note needs-docs added
That sounds good to me. Let's get merged this week.
This ticket was mentioned in Slack in #core by whyisjake. View the logs.
5 hours ago
@westonruter commented on PR #13759:
4 hours ago
#9
I ran PHPStan rule level 10 on the changes in this PR and there were quite a few opportunities for improvement. For the changes in src:
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-admin/includes/schema.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
977 Function populate_roles_720() has no return type specified.
🪪 missingType.return
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-admin/includes/secrets-site-health.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
23 Function wp_secrets_site_health_tests() has parameter $tests with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
23 Function wp_secrets_site_health_tests() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
24 Cannot access offset 'secrets_api_key_source' on mixed.
🪪 offsetAccess.nonOffsetAccessible
29 Cannot access offset 'secrets_api_undecryptable' on mixed.
🪪 offsetAccess.nonOffsetAccessible
34 Cannot access offset 'secrets_api_needs_rotation' on mixed.
🪪 offsetAccess.nonOffsetAccessible
56 Function wp_secrets_site_health_result() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
82 Function wp_secrets_site_health_test_key_source() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
139 Function wp_secrets_site_health_test_undecryptable() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
160 Cannot access offset 'name' on mixed.
🪪 offsetAccess.nonOffsetAccessible
160 Parameter #1 $text of function esc_html expects float|int|string, mixed given.
🪪 argument.type
164 Cannot access offset 'fingerprint' on mixed.
🪪 offsetAccess.nonOffsetAccessible
164 Parameter #1 $text of function esc_html expects float|int|string, mixed given.
🪪 argument.type
191 Function wp_secrets_site_health_find_undecryptable() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
201 Cannot access offset 'name' on mixed.
🪪 offsetAccess.nonOffsetAccessible
201 Cannot access offset 'name' on mixed.
🪪 offsetAccess.nonOffsetAccessible
201 Parameter #1 $name of function wp_get_network_secret expects string, mixed given.
🪪 argument.type
201 Parameter #1 $name of function wp_get_secret expects string, mixed given.
🪪 argument.type
205 Cannot access offset 'name' on mixed.
🪪 offsetAccess.nonOffsetAccessible
206 Cannot access offset 'fingerprint' on mixed.
🪪 offsetAccess.nonOffsetAccessible
221 Function wp_secrets_site_health_test_needs_rotation() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
278 Cannot access offset 'needs_rotation' on mixed.
🪪 offsetAccess.nonOffsetAccessible
298 Function wp_secrets_site_health_debug_info() has parameter $info with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
298 Function wp_secrets_site_health_debug_info() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-admin/includes/upgrade.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
2517 Function upgrade_720() has no return type specified.
🪪 missingType.return
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/load.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
848 Function wp_load_secrets_dropin() has no return type specified.
🪪 missingType.return
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
169 Function wp_secrets_memzero() has no return type specified.
🪪 missingType.return
325 Function _wp_secrets_get_store() should return WP_Secrets_Store but returns mixed.
🪪 return.type
361 Function _wp_secrets_get_key_manager() should return WP_Secrets_Key_Manager but returns mixed.
🪪 return.type
549 Function wp_list_secrets() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
622 Function wp_list_network_secrets() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
655 Function _wp_secrets_get_provider() should return WP_Secrets_Provider but returns mixed.
🪪 return.type
809 Function _wp_secrets_list() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets/class-wp-secret.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
239 Method WP_Secret::__debugInfo() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
308 Method WP_Secret::__unserialize() has parameter $data with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets/class-wp-secrets-broken-store.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
51 Method WP_Secrets_Broken_Store::set() has parameter $record with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets/class-wp-secrets-cipher.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
69 Method WP_Secrets_Cipher::encrypt_value() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
161 Parameter #1 $ciphertext of function sodium_crypto_aead_xchacha20poly1305_ietf_decrypt expects string, mixed given.
🪪 argument.type
163 Parameter #3 $nonce of function sodium_crypto_aead_xchacha20poly1305_ietf_decrypt expects string, mixed given.
🪪 argument.type
175 Parameter #1 $ciphertext of function sodium_crypto_aead_xchacha20poly1305_ietf_decrypt expects string, mixed given.
🪪 argument.type
177 Parameter #3 $nonce of function sodium_crypto_aead_xchacha20poly1305_ietf_decrypt expects string, mixed given.
🪪 argument.type
178 Parameter #4 $key of function sodium_crypto_aead_xchacha20poly1305_ietf_decrypt expects string, string|true given.
🪪 argument.type
181 Parameter #1 $value of function wp_secrets_memzero expects string, string|true given.
🪪 argument.type
190 Method WP_Secrets_Cipher::decrypt_value() should return string|WP_Error but returns string|true.
🪪 return.type
356 Method WP_Secrets_Cipher::decode_record_fields() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets/class-wp-secrets-config-key-provider.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
171 Method WP_Secrets_Config_Key_Provider::unwrap() should return string|WP_Error but returns string|true.
🪪 return.type
183 Parameter #1 $value of method WP_Secrets_Config_Key_Provider::is_canonical_base64_32() expects string, mixed given.
🪪 argument.type
216 Method WP_Secrets_Config_Key_Provider::get_site_key() should return string|WP_Error but returns string|false.
🪪 return.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets/class-wp-secrets-key-manager.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
217 Method WP_Secrets_Key_Manager::get_root_key() should return string|WP_Error but returns string|null.
🪪 return.type
264 Parameter #1 $key_material of method WP_Secrets_Keyring::wrap() expects string, string|null given.
🪪 argument.type
267 Parameter #1 $value of function wp_secrets_memzero expects string, string|null given.
🪪 argument.type
281 Parameter #1 $value of function wp_secrets_memzero expects string, string|null given.
🪪 argument.type
292 Parameter #1 $value of function wp_secrets_memzero expects string, string|null given.
🪪 argument.type
315 Method WP_Secrets_Key_Manager::get_wrapped_root_key() should return string|false but returns mixed.
🪪 return.type
330 Method WP_Secrets_Key_Manager::get_wrapped_root_key() should return string|false but returns mixed.
🪪 return.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets/class-wp-secrets-libsodium-provider.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
174 Method WP_Secrets_Libsodium_Provider::read_prior_record() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
198 Cannot access offset 'fingerprint' on mixed.
🪪 offsetAccess.nonOffsetAccessible
230 Method WP_Secrets_Libsodium_Provider::demote_slot() has parameter $current_slot with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
230 Method WP_Secrets_Libsodium_Provider::demote_slot() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
509 do_action() call for hook "wp_secret_changed" references documentation in "src/wp-includes/secrets.php", but no such file exists in the tree being
analyzed.
🪪 wordpress.hookDocReferenceFileMissing
565 Cannot access offset 'fingerprint' on mixed.
🪪 offsetAccess.nonOffsetAccessible
578 do_action() call for hook "wp_secret_changed" references documentation in "src/wp-includes/secrets.php", but no such file exists in the tree being
analyzed.
🪪 wordpress.hookDocReferenceFileMissing
620 Method WP_Secrets_Libsodium_Provider::list_secrets() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
633 Parameter #1 $haystack of function strpos expects string, mixed given.
🪪 argument.type
637 Parameter #1 $name of method WP_Secrets_Store::get() expects string, mixed given.
🪪 argument.type
643 Cannot access offset 'created' on mixed.
🪪 offsetAccess.nonOffsetAccessible
645 Cannot access offset 'needs_rotation' on mixed.
🪪 offsetAccess.nonOffsetAccessible
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets/class-wp-secrets-option-store.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
52 Method WP_Secrets_Option_Store::get() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
81 Method WP_Secrets_Option_Store::set() has parameter $record with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
160 Method WP_Secrets_Option_Store::list_names() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
164 Binary operation "." between mixed and '%' results in an error.
🪪 binaryOp.invalid
164 Cannot call method esc_like() on mixed.
🪪 method.nonObject
167 Cannot call method get_col() on mixed.
🪪 method.nonObject
168 Cannot call method prepare() on mixed.
🪪 method.nonObject
169 Cannot access property $sitemeta on mixed.
🪪 property.nonObject
169 Part $wpdb->sitemeta (mixed) of encapsed string cannot be cast to string.
🪪 encapsedStringPart.nonString
175 Cannot call method get_col() on mixed.
🪪 method.nonObject
176 Cannot call method prepare() on mixed.
🪪 method.nonObject
177 Cannot access property $options on mixed.
🪪 property.nonObject
177 Part $wpdb->options (mixed) of encapsed string cannot be cast to string.
🪪 encapsedStringPart.nonString
193 Parameter #1 $string of function substr expects string, mixed given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets/interface-wp-secrets-provider.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
173 Method WP_Secrets_Provider::list_secrets() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/secrets/interface-wp-secrets-store.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
38 Method WP_Secrets_Store::get() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
52 Method WP_Secrets_Store::set() has parameter $record with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
76 Method WP_Secrets_Store::list_names() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
[ERROR] Found 85 errors on changed lines (base: trunk)
<details><summary>Errors in <code>tests</code></summary>
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/includes/bootstrap.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
42 Strict comparison using === between 'put your unique…' and 'put your unique…' will always evaluate to true.
🪪 identical.alwaysTrue
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/includes/secrets/class-mock-keyring.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
12 Property Mock_Keyring::$fail_wrap has no type specified.
🪪 missingType.property
13 Property Mock_Keyring::$fail_unwrap has no type specified.
🪪 missingType.property
14 Property Mock_Keyring::$wrap_calls has no type specified.
🪪 missingType.property
15 Property Mock_Keyring::$unwrap_calls has no type specified.
🪪 missingType.property
18 Cannot use ++ on mixed.
🪪 preInc.type
31 Cannot use ++ on mixed.
🪪 preInc.type
88 Method Mock_Keyring::wrap_call_count() should return int but returns mixed.
🪪 return.type
95 Method Mock_Keyring::unwrap_call_count() should return int but returns mixed.
🪪 return.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/includes/secrets/class-mock-store.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
10 Property Mock_Store::$records has no type specified.
🪪 missingType.property
11 Property Mock_Store::$fail has no type specified.
🪪 missingType.property
17 Property Mock_Store::$received_records has no type specified.
🪪 missingType.property
19 Method Mock_Store::get() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
20 Cannot access offset 'get' on mixed.
🪪 offsetAccess.nonOffsetAccessible
26 Method Mock_Store::get() should return array|WP_Error|null but returns mixed.
🪪 return.type
26 Parameter #1 $key of function array_key_exists expects int|string, mixed given.
🪪 argument.type
26 Parameter #2 $search of function array_key_exists expects array, mixed given.
🪪 argument.type
26 Possibly invalid array key type mixed.
🪪 offsetAccess.invalidOffset
29 Method Mock_Store::set() has parameter $record with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
30 Cannot access an offset on mixed.
🪪 offsetAccess.nonOffsetAccessible
32 Cannot access offset 'set' on mixed.
🪪 offsetAccess.nonOffsetAccessible
36 Cannot access offset mixed on mixed.
🪪 offsetAccess.nonOffsetAccessible
42 Cannot access offset 'delete' on mixed.
🪪 offsetAccess.nonOffsetAccessible
46 Cannot access offset mixed on mixed.
🪪 offsetAccess.nonOffsetAccessible
51 Method Mock_Store::list_names() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
52 Cannot access offset 'list' on mixed.
🪪 offsetAccess.nonOffsetAccessible
59 Parameter #1 $input of function array_keys expects array, mixed given.
🪪 argument.type
60 Parameter #1 $haystack of function strpos expects string, int|string given.
🪪 argument.type
61 Parameter #1 $string of function substr expects string, int|string given.
🪪 argument.type
75 Cannot access offset string on mixed.
🪪 offsetAccess.nonOffsetAccessible
87 Method Mock_Store::get_received_records() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
88 Method Mock_Store::get_received_records() should return array but returns mixed.
🪪 return.type
91 Method Mock_Store::key() has no return type specified.
🪪 missingType.return
91 Method Mock_Store::key() has parameter $name with no type specified.
🪪 missingType.parameter
91 Method Mock_Store::key() has parameter $network with no type specified.
🪪 missingType.parameter
92 Binary operation "." between 'network:'|'site:' and mixed results in an error.
🪪 binaryOp.invalid
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/includes/secrets/class-wp-secrets-keyring-conformance.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
29 Method WP_Secrets_Keyring_Conformance::test_wrap_returns_a_non_empty_string_that_unwraps_to_the_same_bytes() has no return type specified.
🪪 missingType.return
49 Method WP_Secrets_Keyring_Conformance::test_two_wraps_of_the_same_bytes_return_different_strings() has no return type specified.
🪪 missingType.return
65 Method WP_Secrets_Keyring_Conformance::test_unwrap_of_garbage_is_a_wp_error() has no return type specified.
🪪 missingType.return
77 Method WP_Secrets_Keyring_Conformance::test_unwrap_of_a_truncated_value_is_a_wp_error() has no return type specified.
🪪 missingType.return
81 Parameter #1 $string of function strlen expects string, string|WP_Error given.
🪪 argument.type
81 Parameter #1 $string of function substr expects string, string|WP_Error given.
🪪 argument.type
91 Method WP_Secrets_Keyring_Conformance::test_unwrap_of_a_value_with_one_flipped_byte_is_a_wp_error() has no return type specified.
🪪 missingType.return
95 Parameter #1 $string of function strlen expects string, string|WP_Error given.
🪪 argument.type
97 Cannot access offset int on string|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
97 Cannot access offset int on string|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
97 Parameter #1 $character of function ord expects string, mixed given.
🪪 argument.type
99 Parameter #1 $wrapped of method WP_Secrets_Keyring::unwrap() expects string, (ArrayAccess&WP_Error)|string given.
🪪 argument.type
106 Method WP_Secrets_Keyring_Conformance::test_get_key_source_returns_a_non_empty_string() has no return type specified.
🪪 missingType.return
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/includes/secrets/class-wp-secrets-provider-conformance.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
53 Method WP_Secrets_Provider_Conformance::require_writable() has no return type specified.
🪪 missingType.return
61 Method WP_Secrets_Provider_Conformance::test_reports_a_non_empty_label() has no return type specified.
🪪 missingType.return
68 Method WP_Secrets_Provider_Conformance::test_reports_a_known_protection_boundary() has no return type specified.
🪪 missingType.return
76 Method WP_Secrets_Provider_Conformance::test_is_writable_returns_a_bool() has no return type specified.
🪪 missingType.return
84 Method WP_Secrets_Provider_Conformance::test_a_read_only_provider_actually_refuses_writes() has no return type specified.
🪪 missingType.return
109 Method WP_Secrets_Provider_Conformance::test_a_name_that_was_never_set_is_null() has no return type specified.
🪪 missingType.return
120 Method WP_Secrets_Provider_Conformance::test_previous_on_a_provider_or_secret_without_history_is_null_not_error() has no return type specified.
🪪 missingType.return
133 Method WP_Secrets_Provider_Conformance::test_deleting_something_absent_is_success() has no return type specified.
🪪 missingType.return
143 Method WP_Secrets_Provider_Conformance::test_retiring_with_no_previous_version_is_success() has no return type specified.
🪪 missingType.return
155 Method WP_Secrets_Provider_Conformance::test_a_stored_value_comes_back_intact() has no return type specified.
🪪 missingType.return
174 Method WP_Secrets_Provider_Conformance::test_a_fingerprint_is_stable_for_the_same_value() has no return type specified.
🪪 missingType.return
181 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
182 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
189 Method WP_Secrets_Provider_Conformance::test_a_deleted_secret_reads_as_absent() has no return type specified.
🪪 missingType.return
202 Method WP_Secrets_Provider_Conformance::test_listing_returns_an_array_or_an_error_and_never_a_value() has no return type specified.
🪪 missingType.return
214 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertStringNotContainsString() expects string, string|false given.
🪪 argument.type
219 Method WP_Secrets_Provider_Conformance::test_listing_includes_a_stored_secret() has no return type specified.
🪪 missingType.return
226 Parameter #1 $input_list of function wp_list_pluck expects array, array|WP_Error given.
🪪 argument.type
236 Method WP_Secrets_Provider_Conformance::test_listing_respects_a_name_prefix() has no return type specified.
🪪 missingType.return
243 Parameter #1 $input_list of function wp_list_pluck expects array, array|WP_Error given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/brokenDropinFallbacks.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
12 Call to method PHPUnit\Framework\Assert::assertInstanceOf() with 'WP_Secrets_Store' and WP_Secrets_Broken_Store will always evaluate to true.
🪪 method.alreadyNarrowedType
42 Call to method PHPUnit\Framework\Assert::assertInstanceOf() with 'WP_Secrets_Keyring' and WP_Secrets_Broken_Keyring will always evaluate to true.
🪪 method.alreadyNarrowedType
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/capabilities.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
30 Call to method PHPUnit\Framework\Assert::assertSame() with 'manage_secrets' and 'manage_secrets' will always evaluate to true.
🪪 method.alreadyNarrowedType
31 Call to method PHPUnit\Framework\Assert::assertSame() with 'manage_network…' and 'manage_network…' will always evaluate to true.
🪪 method.alreadyNarrowedType
35 Cannot call method has_cap() on WP_Role|null.
🪪 method.nonObject
40 Cannot call method has_cap() on WP_Role|null.
🪪 method.nonObject
45 Cannot call method remove_cap() on WP_Role|null.
🪪 method.nonObject
49 Cannot call method has_cap() on WP_Role|null.
🪪 method.nonObject
64 Cannot call method remove_cap() on WP_Role|null.
🪪 method.nonObject
70 Cannot call method has_cap() on WP_Role|null.
🪪 method.nonObject
73 Method Tests_Secrets_Capabilities::data_upgrade_720_gate() has no return type specified.
🪪 missingType.return
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/errorCodes.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
11 Call to method PHPUnit\Framework\Assert::assertSame() with 'secret_decryption…' and 'secret_decryption…' will always evaluate to true.
🪪 method.alreadyNarrowedType
12 Call to method PHPUnit\Framework\Assert::assertSame() with 'secret_key…' and 'secret_key…' will always evaluate to true.
🪪 method.alreadyNarrowedType
13 Call to method PHPUnit\Framework\Assert::assertSame() with 'secret_store…' and 'secret_store…' will always evaluate to true.
🪪 method.alreadyNarrowedType
14 Call to method PHPUnit\Framework\Assert::assertSame() with 'secret_invalid_name' and 'secret_invalid_name' will always evaluate to true.
🪪 method.alreadyNarrowedType
15 Call to method PHPUnit\Framework\Assert::assertSame() with 'secret_invalid_value' and 'secret_invalid_value' will always evaluate to true.
🪪 method.alreadyNarrowedType
16 Call to method PHPUnit\Framework\Assert::assertSame() with 'secret_crypto…' and 'secret_crypto…' will always evaluate to true.
🪪 method.alreadyNarrowedType
17 Call to method PHPUnit\Framework\Assert::assertSame() with 'secret_record…' and 'secret_record…' will always evaluate to true.
🪪 method.alreadyNarrowedType
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/extensionPoints.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
38 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
49 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
61 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
110 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/networkScope.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
28 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
29 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
45 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
68 Parameter #1 $input_list of function wp_list_pluck expects array, array|WP_Error given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/provider.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
22 Method WP_Secrets_Provider@anonymous/tests/secrets/provider.php:17::set() never returns true so it can be removed from the return type.
🪪 return.unusedType
29 Method WP_Secrets_Provider@anonymous/tests/secrets/provider.php:17::delete() never returns true so it can be removed from the return type.
🪪 return.unusedType
37 Method WP_Secrets_Provider@anonymous/tests/secrets/provider.php:17::list_secrets() never returns WP_Error so it can be removed from the return type.
🪪 return.unusedType
37 Method WP_Secrets_Provider@anonymous/tests/secrets/provider.php:17::list_secrets() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
150 Call to method PHPUnit\Framework\Assert::assertNotInstanceOf() with 'WP_Secrets…' and WP_Secrets_Broken_Provider will always evaluate to true.
🪪 method.alreadyNarrowedType
214 Call to method PHPUnit\Framework\Assert::assertNotNull() with WP_Error will always evaluate to true.
🪪 method.alreadyNarrowedType
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/readonlyProviderConformance.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
20 Method WP_Secrets_Provider@anonymous/tests/secrets/readonlyProviderConformance.php:15::set() never returns true so it can be removed from the return type.
🪪 return.unusedType
27 Method WP_Secrets_Provider@anonymous/tests/secrets/readonlyProviderConformance.php:15::delete() never returns true so it can be removed from the return
type.
🪪 return.unusedType
31 Method WP_Secrets_Provider@anonymous/tests/secrets/readonlyProviderConformance.php:15::retire_previous() never returns true so it can be removed from the
return type.
🪪 return.unusedType
35 Method WP_Secrets_Provider@anonymous/tests/secrets/readonlyProviderConformance.php:15::list_secrets() never returns WP_Error so it can be removed from the
return type.
🪪 return.unusedType
35 Method WP_Secrets_Provider@anonymous/tests/secrets/readonlyProviderConformance.php:15::list_secrets() return type has no value type specified in iterable
type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/siteHealth.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
13 Parameter #2 $array of method PHPUnit\Framework\Assert::assertArrayHasKey() expects array|ArrayAccess, mixed given.
🪪 argument.type
17 Argument of an invalid type array|ArrayAccess supplied for foreach, only iterables are supported.
🪪 foreach.nonIterable
18 Cannot access offset 'test' on mixed.
🪪 offsetAccess.nonOffsetAccessible
18 Cannot access offset 'test' on mixed.
🪪 offsetAccess.nonOffsetAccessible
18 Parameter #1 $function_name of function function_exists expects string, mixed given.
🪪 argument.type
18 Part $test['test'] (mixed) of encapsed string cannot be cast to string.
🪪 encapsedStringPart.nonString
25 Parameter #2 $array of method PHPUnit\Framework\Assert::assertArrayHasKey() expects array|ArrayAccess, mixed given.
🪪 argument.type
29 Result of || is always true.
🪪 booleanOr.alwaysTrue
29 Strict comparison using === between 'put your unique…' and 'put your unique…' will always evaluate to true.
🪪 identical.alwaysTrue
29 Strict comparison using === between 'put your unique…' and 'put your unique…' will always evaluate to true.
🪪 identical.alwaysTrue
33 Unreachable statement - code above always terminates.
🪪 deadCode.unreachable
49 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertStringContainsString() expects string, mixed given.
🪪 argument.type
92 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
95 Cannot access offset 'ct' on mixed.
🪪 offsetAccess.nonOffsetAccessible
95 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
101 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertStringContainsString() expects string, mixed given.
🪪 argument.type
102 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertStringContainsString() expects string, mixed given.
🪪 argument.type
109 Cannot access offset 'ct' on mixed.
🪪 offsetAccess.nonOffsetAccessible
109 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
114 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertStringNotContainsString() expects string, mixed given.
🪪 argument.type
132 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertStringContainsString() expects string, mixed given.
🪪 argument.type
141 Cannot access offset 'fields' on mixed.
🪪 offsetAccess.nonOffsetAccessible
143 Parameter #2 $array of method PHPUnit\Framework\Assert::assertArrayHasKey() expects array|ArrayAccess, mixed given.
🪪 argument.type
150 Cannot access offset 'value' on mixed.
🪪 offsetAccess.nonOffsetAccessible
151 Cannot access offset 'value' on mixed.
🪪 offsetAccess.nonOffsetAccessible
152 Cannot access offset 'value' on mixed.
🪪 offsetAccess.nonOffsetAccessible
153 Cannot access offset 'value' on mixed.
🪪 offsetAccess.nonOffsetAccessible
159 Cannot access offset 'dropin_active' on mixed.
🪪 offsetAccess.nonOffsetAccessible
159 Cannot access offset 'fields' on mixed.
🪪 offsetAccess.nonOffsetAccessible
159 Cannot access offset 'value' on mixed.
🪪 offsetAccess.nonOffsetAccessible
169 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertStringNotContainsString() expects string, string|false given.
🪪 argument.type
175 Cannot access offset 'fields' on mixed.
🪪 offsetAccess.nonOffsetAccessible
175 Parameter #2 $array of method PHPUnit\Framework\Assert::assertArrayNotHasKey() expects array|ArrayAccess, mixed given.
🪪 argument.type
191 Cannot access offset 'fields' on mixed.
🪪 offsetAccess.nonOffsetAccessible
191 Parameter #2 $array of method PHPUnit\Framework\Assert::assertArrayNotHasKey() expects array|ArrayAccess, mixed given.
🪪 argument.type
196 Cannot access offset 'fields' on mixed.
🪪 offsetAccess.nonOffsetAccessible
196 Parameter #2 $array of method PHPUnit\Framework\Assert::assertArrayHasKey() expects array|ArrayAccess, mixed given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/threeStateContract.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
103 Result of || is always true.
🪪 booleanOr.alwaysTrue
103 Strict comparison using === between 'put your unique…' and 'put your unique…' will always evaluate to true.
🪪 identical.alwaysTrue
103 Strict comparison using === between 'put your unique…' and 'put your unique…' will always evaluate to true.
🪪 identical.alwaysTrue
107 Unreachable statement - code above always terminates.
🪪 deadCode.unreachable
152 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
152 Cannot access offset 'fingerprint' on mixed.
🪪 offsetAccess.nonOffsetAccessible
169 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
172 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
172 Cannot access offset 'fingerprint' on mixed.
🪪 offsetAccess.nonOffsetAccessible
175 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/versionSlots.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
45 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
49 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
54 Cannot access offset 'created' on mixed.
🪪 offsetAccess.nonOffsetAccessible
54 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
58 Cannot access offset 'created' on mixed.
🪪 offsetAccess.nonOffsetAccessible
58 Cannot access offset 'previous' on mixed.
🪪 offsetAccess.nonOffsetAccessible
69 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
69 Cannot access offset 'needs_rotation' on mixed.
🪪 offsetAccess.nonOffsetAccessible
74 Cannot access offset 'needs_rotation' on mixed.
🪪 offsetAccess.nonOffsetAccessible
74 Cannot access offset 'previous' on mixed.
🪪 offsetAccess.nonOffsetAccessible
86 Cannot access offset 'ct' on mixed.
🪪 offsetAccess.nonOffsetAccessible
86 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
90 Cannot access offset 'ct' on mixed.
🪪 offsetAccess.nonOffsetAccessible
90 Cannot access offset 'previous' on mixed.
🪪 offsetAccess.nonOffsetAccessible
94 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
113 Cannot access offset 'ct' on mixed.
🪪 offsetAccess.nonOffsetAccessible
113 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
117 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
129 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
151 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
166 Cannot use array destructuring on array<int<0, max>|string, mixed>|null.
🪪 offsetAccess.nonArray
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpDeleteSecret.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
29 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
43 Cannot use array destructuring on array<int<0, max>|string, mixed>|null.
🪪 offsetAccess.nonArray
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpImportOptionAsSecret.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
13 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
30 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
30 Cannot access offset 'needs_rotation' on mixed.
🪪 offsetAccess.nonOffsetAccessible
38 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
38 Cannot access offset 'needs_rotation' on mixed.
🪪 offsetAccess.nonOffsetAccessible
81 Cannot use array destructuring on array<int<0, max>|string, mixed>|null.
🪪 offsetAccess.nonArray
98 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
99 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpListSecrets.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
18 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertCount() expects Countable|iterable, array|WP_Error given.
🪪 argument.type
21 Cannot access offset 0 on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
21 Parameter #1 $input of function array_keys expects array, mixed given.
🪪 argument.type
23 Cannot access offset 'name' on mixed.
🪪 offsetAccess.nonOffsetAccessible
23 Cannot access offset 0 on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
35 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertStringNotContainsString() expects string, string|false given.
🪪 argument.type
41 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
44 Cannot access offset 'fingerprint' on mixed.
🪪 offsetAccess.nonOffsetAccessible
44 Cannot access offset 0 on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
50 Cannot access offset 'has_previous' on mixed.
🪪 offsetAccess.nonOffsetAccessible
50 Cannot access offset 0 on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
54 Cannot access offset 0 on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
61 Cannot access offset 'current' on mixed.
🪪 offsetAccess.nonOffsetAccessible
61 Cannot access offset 'needs_rotation' on mixed.
🪪 offsetAccess.nonOffsetAccessible
64 Cannot access offset 'needs_rotation' on mixed.
🪪 offsetAccess.nonOffsetAccessible
64 Cannot access offset 0 on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
71 Parameter #1 $input_list of function wp_list_pluck expects array, array|WP_Error given.
🪪 argument.type
80 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertCount() expects Countable|iterable, array|WP_Error given.
🪪 argument.type
93 Parameter #1 $namespace of function wp_list_secrets expects string, array<int, string> given.
🪪 argument.type
108 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertCount() expects Countable|iterable, array|WP_Error given.
🪪 argument.type
109 Cannot access offset 'name' on mixed.
🪪 offsetAccess.nonOffsetAccessible
109 Cannot access offset 0 on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
110 Cannot access offset 'fingerprint' on mixed.
🪪 offsetAccess.nonOffsetAccessible
110 Cannot access offset 0 on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
111 Cannot access offset 'has_previous' on mixed.
🪪 offsetAccess.nonOffsetAccessible
111 Cannot access offset 0 on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
118 Parameter #1 $input_list of function wp_list_pluck expects array, array|WP_Error given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpSecret.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
21 Method Tests_Secrets_WPSecret::make_secret() has no return type specified.
🪪 missingType.return
38 Cannot call method reveal() on mixed.
🪪 method.nonObject
44 Cannot call method fingerprint() on mixed.
🪪 method.nonObject
50 Cannot call method get_name() on mixed.
🪪 method.nonObject
56 Parameter #2 $value of class WP_Secret constructor expects string, int given.
🪪 argument.type
76 Method Tests_Secrets_WPSecret::test_masking_surfaces_never_contain_the_plaintext() has parameter $callback with no type specified.
🪪 missingType.parameter
79 Trying to invoke mixed but it's not a callable.
🪪 callable.nonCallable
81 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertStringNotContainsString() expects string, mixed given.
🪪 argument.type
84 Method Tests_Secrets_WPSecret::data_masking_surfaces() has no return type specified.
🪪 missingType.return
88 Cannot cast mixed to string.
🪪 cast.string
93 Part $secret (mixed) of encapsed string cannot be cast to string.
🪪 encapsedStringPart.nonString
122 Parameter #1 $message of function error_log expects string, mixed given.
🪪 argument.type
135 Cannot cast mixed to string.
🪪 cast.string
142 Parameter #1 $json of function json_decode expects string, string|false given.
🪪 argument.type
168 Cannot clone non-object variable $secret of type mixed.
🪪 clone.nonObject
168 Expression "clone $secret" on a separate line does not do anything.
🪪 expr.resultUnused
178 Method Tests_Secrets_WPSecret::test_serialization_magic_methods_throw_directly() has parameter $args with no type specified.
🪪 missingType.parameter
178 Method Tests_Secrets_WPSecret::test_serialization_magic_methods_throw_directly() has parameter $method with no type specified.
🪪 missingType.parameter
180 Parameter #1 $objectOrMethod of class ReflectionMethod constructor expects object|string, mixed given.
🪪 argument.type
180 Parameter #2 $method of class ReflectionMethod constructor expects string, mixed given.
🪪 argument.type
187 Parameter #1 $object of method ReflectionMethod::invokeArgs() expects object|null, mixed given.
🪪 argument.type
187 Parameter #2 $args of method ReflectionMethod::invokeArgs() expects array, mixed given.
🪪 argument.type
190 Method Tests_Secrets_WPSecret::data_refusing_magic_methods() has no return type specified.
🪪 missingType.return
201 Parameter #1 $obj of function spl_object_id expects object, mixed given.
🪪 argument.type
208 Parameter #2 $array of method PHPUnit\Framework\Assert::assertArrayHasKey() expects array|ArrayAccess, mixed given.
🪪 argument.type
318 Parameter #3 $reason of static method WP_Secret::withheld() expects WP_Error, string given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpSecretsCipher.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
11 Method Tests_Secrets_WPSecretsCipher::invoke_private() has no return type specified.
🪪 missingType.return
11 Method Tests_Secrets_WPSecretsCipher::invoke_private() has parameter $args with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
11 Method Tests_Secrets_WPSecretsCipher::invoke_private() has parameter $instance with no type specified.
🪪 missingType.parameter
11 Method Tests_Secrets_WPSecretsCipher::invoke_private() has parameter $method with no type specified.
🪪 missingType.parameter
12 Parameter #1 $objectOrMethod of class ReflectionMethod constructor expects object|string, mixed given.
🪪 argument.type
12 Parameter #2 $method of class ReflectionMethod constructor expects string, mixed given.
🪪 argument.type
17 Parameter #1 $object of method ReflectionMethod::invokeArgs() expects object|null, mixed given.
🪪 argument.type
20 Method Tests_Secrets_WPSecretsCipher::master_key() has no return type specified.
🪪 missingType.return
20 Method Tests_Secrets_WPSecretsCipher::master_key() has parameter $byte with no type specified.
🪪 missingType.parameter
21 Parameter #1 $ascii of function chr expects int, mixed given.
🪪 argument.type
26 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
30 Parameter #1 $master_key of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
37 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
39 Parameter #1 $master_key of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
46 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
48 Parameter #1 $master_key of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
56 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
56 Parameter #6 $plaintext of method WP_Secrets_Cipher::encrypt_value() expects string, array given.
🪪 argument.type
65 Method Tests_Secrets_WPSecretsCipher::test_encrypt_rejects_a_bad_master_key() has parameter $bad_key with no type specified.
🪪 missingType.parameter
68 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
74 Method Tests_Secrets_WPSecretsCipher::data_bad_master_keys() has no return type specified.
🪪 missingType.return
86 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
97 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
108 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
119 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
131 Method Tests_Secrets_WPSecretsCipher::test_decrypt_fails_when_context_does_not_match() has parameter $name with no type specified.
🪪 missingType.parameter
131 Method Tests_Secrets_WPSecretsCipher::test_decrypt_fails_when_context_does_not_match() has parameter $scope with no type specified.
🪪 missingType.parameter
131 Method Tests_Secrets_WPSecretsCipher::test_decrypt_fails_when_context_does_not_match() has parameter $site_id with no type specified.
🪪 missingType.parameter
131 Method Tests_Secrets_WPSecretsCipher::test_decrypt_fails_when_context_does_not_match() has parameter $slot with no type specified.
🪪 missingType.parameter
133 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
135 Parameter #1 $master_key of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
135 Parameter #2 $scope of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
135 Parameter #3 $site_id of method WP_Secrets_Cipher::decrypt_value() expects int, mixed given.
🪪 argument.type
135 Parameter #4 $name of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
135 Parameter #5 $slot of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
141 Method Tests_Secrets_WPSecretsCipher::data_mismatched_context() has no return type specified.
🪪 missingType.return
152 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
154 Parameter #1 $master_key of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
163 Method Tests_Secrets_WPSecretsCipher::test_decrypt_fails_when_a_field_is_tampered() has parameter $field with no type specified.
🪪 missingType.parameter
165 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
167 Cannot access offset mixed on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
167 Parameter #1 $str of function base64_decode expects string, mixed given.
🪪 argument.type
167 Possibly invalid array key type mixed.
🪪 offsetAccess.invalidOffset
168 Parameter #1 $string of function strlen expects string, string|false given.
🪪 argument.type
169 Cannot access offset int<-1, max> on string|false.
🪪 offsetAccess.nonOffsetAccessible
169 Cannot access offset int<-1, max> on string|false.
🪪 offsetAccess.nonOffsetAccessible
170 Cannot access offset mixed on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
170 Possibly invalid array key type mixed.
🪪 offsetAccess.invalidOffset
172 Parameter #1 $master_key of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
177 Method Tests_Secrets_WPSecretsCipher::data_tamperable_fields() has no return type specified.
🪪 missingType.return
189 Method Tests_Secrets_WPSecretsCipher::test_decrypt_rejects_a_malformed_record() has parameter $record with no type specified.
🪪 missingType.parameter
192 Parameter #1 $master_key of method WP_Secrets_Cipher::decrypt_value() expects string, mixed given.
🪪 argument.type
198 Method Tests_Secrets_WPSecretsCipher::data_malformed_records() has no return type specified.
🪪 missingType.return
230 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
231 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
233 Cannot access offset 'dk' on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
233 Cannot access offset 'dk' on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
234 Cannot access offset 'ct' on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
234 Cannot access offset 'ct' on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
242 Parameter #1 $master_key of method WP_Secrets_Cipher::encrypt_value() expects string, mixed given.
🪪 argument.type
243 Cannot access offset 'nonce' on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
244 Cannot access offset 'dk_nonce' on array|WP_Error.
🪪 offsetAccess.nonOffsetAccessible
247 Parameter #1 $array of function array_unique expects an array of values castable to string, list given.
🪪 argument.type
254 Parameter #1 $master_key of method WP_Secrets_Cipher::fingerprint() expects string, mixed given.
🪪 argument.type
255 Parameter #1 $master_key of method WP_Secrets_Cipher::fingerprint() expects string, mixed given.
🪪 argument.type
263 Parameter #1 $master_key of method WP_Secrets_Cipher::fingerprint() expects string, mixed given.
🪪 argument.type
264 Parameter #1 $master_key of method WP_Secrets_Cipher::fingerprint() expects string, mixed given.
🪪 argument.type
272 Parameter #1 $master_key of method WP_Secrets_Cipher::fingerprint() expects string, mixed given.
🪪 argument.type
273 Parameter #1 $master_key of method WP_Secrets_Cipher::fingerprint() expects string, mixed given.
🪪 argument.type
289 Parameter #1 $master_key of method WP_Secrets_Cipher::fingerprint() expects string, mixed given.
🪪 argument.type
289 Parameter #2 $plaintext of method WP_Secrets_Cipher::fingerprint() expects string, array given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpSecretsConfigKeyProvider.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
16 Method Tests_Secrets_WPSecretsConfigKeyProvider::invoke_private() has no return type specified.
🪪 missingType.return
16 Method Tests_Secrets_WPSecretsConfigKeyProvider::invoke_private() has parameter $args with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
16 Method Tests_Secrets_WPSecretsConfigKeyProvider::invoke_private() has parameter $instance with no type specified.
🪪 missingType.parameter
16 Method Tests_Secrets_WPSecretsConfigKeyProvider::invoke_private() has parameter $method with no type specified.
🪪 missingType.parameter
17 Parameter #1 $objectOrMethod of class ReflectionMethod constructor expects object|string, mixed given.
🪪 argument.type
17 Parameter #2 $method of class ReflectionMethod constructor expects string, mixed given.
🪪 argument.type
22 Parameter #1 $object of method ReflectionMethod::invokeArgs() expects object|null, mixed given.
🪪 argument.type
26 Call to method PHPUnit\Framework\Assert::assertInstanceOf() with 'WP_Secrets_Keyring' and WP_Secrets_Config_Key_Provider will always evaluate to true.
🪪 method.alreadyNarrowedType
43 Parameter #1 $key_material of method WP_Secrets_Config_Key_Provider::wrap() expects string, int given.
🪪 argument.type
68 Parameter #1 $wrapped of method WP_Secrets_Config_Key_Provider::unwrap() expects string, array given.
🪪 argument.type
96 Parameter #1 $str of function base64_decode expects string, string|WP_Error given.
🪪 argument.type
98 Parameter #1 $string of function strlen expects string, string|false given.
🪪 argument.type
99 Cannot access offset int<-1, max> on string|false.
🪪 offsetAccess.nonOffsetAccessible
99 Cannot access offset int<-1, max> on string|false.
🪪 offsetAccess.nonOffsetAccessible
108 Result of || is always true.
🪪 booleanOr.alwaysTrue
108 Strict comparison using === between 'put your unique…' and 'put your unique…' will always evaluate to true.
🪪 identical.alwaysTrue
108 Strict comparison using === between 'put your unique…' and 'put your unique…' will always evaluate to true.
🪪 identical.alwaysTrue
112 Unreachable statement - code above always terminates.
🪪 deadCode.unreachable
120 Method Tests_Secrets_WPSecretsConfigKeyProvider::test_is_canonical_base64_32() has parameter $expected with no type specified.
🪪 missingType.parameter
120 Method Tests_Secrets_WPSecretsConfigKeyProvider::test_is_canonical_base64_32() has parameter $value with no type specified.
🪪 missingType.parameter
126 Method Tests_Secrets_WPSecretsConfigKeyProvider::data_canonical_base64_32() has no return type specified.
🪪 missingType.return
141 Method Tests_Secrets_WPSecretsConfigKeyProvider::test_are_usable_salt_values() has parameter $expected with no type specified.
🪪 missingType.parameter
141 Method Tests_Secrets_WPSecretsConfigKeyProvider::test_are_usable_salt_values() has parameter $key with no type specified.
🪪 missingType.parameter
141 Method Tests_Secrets_WPSecretsConfigKeyProvider::test_are_usable_salt_values() has parameter $salt with no type specified.
🪪 missingType.parameter
147 Method Tests_Secrets_WPSecretsConfigKeyProvider::data_usable_salt_values() has no return type specified.
🪪 missingType.return
188 Parameter #1 $data of function bin2hex expects string, mixed given.
🪪 argument.type
271 Result of || is always true.
🪪 booleanOr.alwaysTrue
271 Strict comparison using === between 'put your unique…' and 'put your unique…' will always evaluate to true.
🪪 identical.alwaysTrue
271 Strict comparison using === between 'put your unique…' and 'put your unique…' will always evaluate to true.
🪪 identical.alwaysTrue
275 Unreachable statement - code above always terminates.
🪪 deadCode.unreachable
312 Parameter #1 $wrapped of method WP_Secrets_Config_Key_Provider::unwrap() expects string, string|WP_Error given.
🪪 argument.type
313 Parameter #1 $wrapped of method WP_Secrets_Config_Key_Provider::unwrap() expects string, string|WP_Error given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpSecretsKeyManager.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
52 Parameter #4 $key of function sodium_crypto_kdf_derive_from_key expects string, string|WP_Error given.
🪪 argument.type
107 Method Tests_Secrets_WPSecretsKeyManager::test_get_master_key_reports_an_invalid_site_id_as_a_wp_error() has parameter $site_id with no type specified.
🪪 missingType.parameter
112 Parameter #2 $site_id of method WP_Secrets_Key_Manager::get_master_key() expects int|null, mixed given.
🪪 argument.type
118 Method Tests_Secrets_WPSecretsKeyManager::data_invalid_site_ids() has no return type specified.
🪪 missingType.return
196 Parameter #1 $known_string of function hash_equals expects string, string|WP_Error given.
🪪 argument.type
196 Parameter #2 $user_string of function hash_equals expects string, string|WP_Error given.
🪪 argument.type
221 Cannot call method reveal() on WP_Secret|null.
🪪 method.nonObject
271 Method WP_Secrets_Keyring@anonymous/tests/secrets/wpSecretsKeyManager.php:270::wrap() never returns WP_Error so it can be removed from the return type.
🪪 return.unusedType
274 Method WP_Secrets_Keyring@anonymous/tests/secrets/wpSecretsKeyManager.php:270::unwrap() never returns string so it can be removed from the return type.
🪪 return.unusedType
332 Parameter #1 $string of function strlen expects string, string|WP_Error given.
🪪 argument.type
333 Parameter #1 $string of function strlen expects string, string|WP_Error given.
🪪 argument.type
405 Parameter #1 $expected of method PHPUnit\Framework\Assert::assertSame() contains unresolvable type.
🪪 argument.unresolvableType
428 Parameter #1 $value of function wp_secrets_memzero expects string, string|WP_Error given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpSecretsMemzero.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
19 Parameter #1 $value of function wp_secrets_memzero expects string, int given.
🪪 argument.type
41 Call to method PHPUnit\Framework\Assert::assertSame() with 'shared plaintext' and 'shared plaintext' will always evaluate to true.
🪪 method.alreadyNarrowedType
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpSecretsOptionStore.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
9 Method Tests_Secrets_WPSecretsOptionStore::sample_record() has no return type specified.
🪪 missingType.return
24 Call to method PHPUnit\Framework\Assert::assertInstanceOf() with 'WP_Secrets_Store' and WP_Secrets_Option_Store will always evaluate to true.
🪪 method.alreadyNarrowedType
37 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
45 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
52 Parameter #1 $arr1 of function array_merge expects array, mixed given.
🪪 argument.type
54 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
64 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, string given.
🪪 argument.type
83 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
99 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
101 Cannot call method get_var() on mixed.
🪪 method.nonObject
102 Cannot call method prepare() on mixed.
🪪 method.nonObject
103 Cannot access property $options on mixed.
🪪 property.nonObject
103 Part $wpdb->options (mixed) of encapsed string cannot be cast to string.
🪪 encapsedStringPart.nonString
113 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
114 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
118 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertContains() expects iterable, array|WP_Error given.
🪪 argument.type
126 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
128 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertNotContains() expects iterable, array|WP_Error given.
🪪 argument.type
133 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
134 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
136 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertContains() expects iterable, array|WP_Error given.
🪪 argument.type
138 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertContains() expects iterable, array|WP_Error given.
🪪 argument.type
153 Parameter #2 $record of method WP_Secrets_Option_Store::set() expects array, mixed given.
🪪 argument.type
157 Parameter #2 $haystack of method PHPUnit\Framework\Assert::assertContains() expects iterable, array|WP_Error given.
🪪 argument.type
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpSecretsValidateName.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
10 Method Tests_Secrets_WpSecretsValidateName::test_accepts_valid_names() has parameter $name with no type specified.
🪪 missingType.parameter
11 Parameter #1 $name of function wp_secrets_validate_name expects string, mixed given.
🪪 argument.type
14 Method Tests_Secrets_WpSecretsValidateName::data_valid_names() has no return type specified.
🪪 missingType.return
30 Method Tests_Secrets_WpSecretsValidateName::test_rejects_invalid_names() has parameter $name with no type specified.
🪪 missingType.parameter
31 Parameter #1 $name of function wp_secrets_validate_name expects string, mixed given.
🪪 argument.type
45 Method Tests_Secrets_WpSecretsValidateName::test_accepts_an_unnamespaced_name_but_reports_it() has parameter $name with no type specified.
🪪 missingType.parameter
48 Parameter #1 $name of function wp_secrets_validate_name expects string, mixed given.
🪪 argument.type
51 Method Tests_Secrets_WpSecretsValidateName::data_unnamespaced_names() has no return type specified.
🪪 missingType.return
72 Method Tests_Secrets_WpSecretsValidateName::data_invalid_names() has no return type specified.
🪪 missingType.return
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
Line tests/phpunit/tests/secrets/wpSetSecretAndWpGetSecret.php
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
30 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
31 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
71 Parameter #2 $value of function wp_set_secret expects string, array<int, string> given.
🪪 argument.type
79 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
90 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
105 Cannot access property $options on mixed.
🪪 property.nonObject
105 Cannot call method get_results() on mixed.
🪪 method.nonObject
105 Part $wpdb->options (mixed) of encapsed string cannot be cast to string.
🪪 encapsedStringPart.nonString
120 Cannot call method reveal() on WP_Error|WP_Secret|null.
🪪 method.nonObject
154 Cannot call method fingerprint() on WP_Error|WP_Secret|null.
🪪 method.nonObject
168 Cannot use array destructuring on array<int<0, max>|string, mixed>|null.
🪪 offsetAccess.nonArray
207 Argument of an invalid type array<int<0, max>|string, mixed>|null supplied for foreach, only iterables are supported.
🪪 foreach.nonIterable
------ ------------------------------------------------------------------------------------------------------------------------------------------------------------
[ERROR] Found 400 errors on changed lines (base: trunk)
</details>
If you want I can start working on pushing up fixes for these.
#10
follow-up:
↓ 12
@
4 hours ago
A couple of things that I am interested in seeing addressed:
- I would like to hear from the Woo folks on how they would use this and if it is something they think is valuable. (I see one of them is watching this ticket, but it still might be worth reaching out directly)
- How do you think the import and export plugins need to change to support this? Moving a website from one one host to another shouldn't break things.
- Is there any sort of alerting in place for if decryption fails or is the expectation that this is completely on implementors?
#12
in reply to: ↑ 10
@
48 minutes ago
Replying to jorbin:
A couple of things that I am interested in seeing addressed:
...
- How do you think the import and export plugins need to change to support this? Moving a website from one one host to another shouldn't break things.
Export plugins should be able to pull the secrets if they _really_ want to in order to support a migration. But I'd personally advise against that approach as it would effectively write secrets in plain text into an export blob.
A better approach would be for the export plugins to define which secrets need to exist upon import to give the person doing the transfer the opportunity to set them on the new host first.
- Is there any sort of alerting in place for if decryption fails or is the expectation that this is completely on implementors?
This is why decryption failure results in a WP_Error rather than a false to differentiate between "this failed decryption" vs "this secret does not exist." Handling the failure itself would be on the implementors.
@ericmann commented on PR #13759:
42 minutes ago
#13
I ran PHPStan rule level 10 on the changes in this PR and there were quite a few opportunities for improvement. For the changes in
src:
[...]
If you want I can start working on pushing up fixes for these.
I appreciate the callouts sir! I need to get this resolved on the feature plugin as well to keep them in sync, so I'll start working on resolving this all ASAP.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
Adds the Secrets API for 7.2: encrypted, versioned storage for credentials, with a
secrets.phpdrop-in for hosts. The ticket has the full description and the list of additions beyond the proposal. The documentation is at secretsapi.dev.Three commits, meant to be reviewed separately:
src/at v0.2.0, copied unchanged: 14 files insrc/wp-includes/and the Site Health tests.wp-settings.phploads the API, then loadswp-content/secrets.phpthrough a newwp_load_secrets_dropin()inload.php, just before must-use plugins.WP_Errorand never falls back to the default provider.class-wp-site-health.phploads the secrets Site Health tests.populate_roles_720()andupgrade_720()grantmanage_secretsto administrators.manage_network_secretsgoes with the network capabilities inmap_meta_cap().$wp_db_versionis a placeholder, 61900, which needs the real revision on commit.tests/phpunit/tests/secrets/, with helpers intests/phpunit/includes/secrets/, plus the capability inventory.WP_SECRETS_KEYwhenwp-tests-config.phphas the placeholder salts, which the default keyring refuses.Testing:
npm run test:php -- --group secretspasses on single site and multisite.tests/phpunit/tests/user/capabilities.phppasses.Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5.5, Claude Sonnet 5, Claude Fable 5.1
Used for: Most of the code and tests, in the feature plugin and in this port: the API, the core wiring, the test port, and review passes. I directed the design, and the decisions are recorded as ADRs at secretsapi.dev.