Repository navigation
Conversation
The run endpoint used to coerce the input during REST sanitization, and then normalize, validate, and coerce it again before the permission check. Now the input is normalized, validated, and coerced once, during sanitization. The permission check uses that input as is. It prepares the input itself only when it is null, because REST sanitization skips absent parameters. Invalid input is now rejected during sanitization, like other invalid REST parameters. The error is reported as `rest_invalid_param`, with the original error in the details. Abilities hidden from REST and requests with the wrong HTTP method are left to the permission check, so they still get a 404 or 405 error. `WP_Ability::execute()` is unchanged. See #66383.
Adds tests that the run endpoint prepares the input once before the permission check, both for input sent with the request and for the schema default. Also adds tests that invalid input does not replace the 404 error for hidden abilities or the 405 error for a wrong HTTP method. See #66383.
|
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: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. Props Bot commandsYou can trigger Props Bot actions by commenting on this PR:
|
Test using WordPress PlaygroundThe 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
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
92c8bce to
7bda122
Compare
jorgefilipecosta
left a comment
There was a problem hiding this comment.
Hi @gziolo,
Thank you for the PR! Besides the unit tests, I tested the endpoint with apiFetch against wp-env everything worked well, the changes look good to me 👍
euvoor
left a comment
There was a problem hiding this comment.
@gziolo I tested #15685 at 0fc0606523 against #15684 at 7bda122c48 and its base 4110c7f0a3. The existing --filter=Abilit suite passes.
I found a normalization regression introduced by #15684. With a filter that appends !, input raw, and a string schema with maxLength: 4, direct execution succeeds with raw!. REST now stores the prepared raw!, then passes it into execute(), which normalizes it again. The resulting raw!! fails validation and returns HTTP 500. Before this change, REST succeeds. This reproduces with GET, POST and DELETE.
Two other cases prepare input twice before the first permission callback:
- Explicit
nullthat remainsnullafter preparation also enters the permission method’s null fallback. - Equal values in JSON and query parameters both trigger preparation because value equality cannot distinguish their sources.
All 18 targeted REST cases pass on the base; 12 fail on both proposal heads. Three additional direct prepare_input() error-propagation checks pass. I haven’t found a separate issue in the helper extraction itself.
Could we preserve normalization behavior through the complete REST execution path and add coverage for these cases before committing?
|
@euvoor @jorgefilipecosta I’ve revised the approach in edbf3ca. Looking back at 7.1, coercion happened only in REST sanitization. Trunk now performs coercion in both the permission callback and The endpoint now skips input sanitization. The permission callback and The public sanitizer shipped in 7.1, so it remains as a deprecated passthrough. Input preparation errors now come directly from the permission callback. Added regression coverage for non-idempotent normalization, explicit null, absent input, duplicate parameter sources, and repeated dispatches. @euvoor, could you rerun your targeted cases against this commit? @jorgefilipecosta, could you re-review the revised flow and deprecation handling? The PR description now reflects the implementation. |
Replaces the normalization lifecycle test with a test that runs the ability directly and checks that a REST run gives the same result. The permission callback and the execution hook must also get the same input. The test no longer counts internal calls, so it does not depend on how many times the permission check runs. Also improves the docs for the deprecated input sanitizer and the run arguments. See #66383.
Replaces the comparison with direct execution by a smaller test. The normalize filter adds a character, and the schema limits the length. So normalizing the input twice fails validation, and the run no longer returns 200. See #66383.
euvoor
left a comment
There was a problem hiding this comment.
Thanks @gziolo. I reran the original 18 targeted cases unchanged against both edbf3ca532 and e1d1e27148. All pass, resolving the 12 previous failures.
I also ran 77 additional authorization, input-handling and compatibility cases on e1d1e27148. Those pass too, including conflicting input sources, permission denials, normalization changing the resource between checks, and redispatching the same request after switching to an unauthorized user.
The existing --filter=Abilit suite passes with 1,851 tests and 6,612 assertions on PHP 8.4, single-site.
This resolves my blocking findings. I found no further blocker in the revised flow. Thanks for addressing these.
…oint The permission callback and `WP_Ability::execute()` already normalize, validate, and coerce input. The `input` argument now sets `sanitize_callback` to `null`, so both receive the original raw input. `sanitize_input_for_ability()` is deprecated and returns its input unchanged. Follow-up to [62674], [65044]. Developed in #15684. Props gziolo, jorgefilipecosta, euvoor, justlevine. Fixes #66383. git-svn-id: https://develop.svn.wordpress.org/trunk@65368 602fd350-edb4-49c9-b593-d223f7449a82
…oint The permission callback and `WP_Ability::execute()` already normalize, validate, and coerce input. The `input` argument now sets `sanitize_callback` to `null`, so both receive the original raw input. `sanitize_input_for_ability()` is deprecated and returns its input unchanged. Follow-up to [62674], [65044]. Developed in WordPress/wordpress-develop#15684. Props gziolo, jorgefilipecosta, euvoor, justlevine. Fixes #66383. Built from https://develop.svn.wordpress.org/trunk@65368 git-svn-id: http://core.svn.wordpress.org/trunk@64507 1a063a9b-81f0-0310-95a4-ce76da25c4cd
What
Remove the REST run endpoint's redundant input sanitization pass. The permission callback and
WP_Ability::execute()each prepare the original request input independently.For a successful request with supplied input, the endpoint previously validated and coerced input during REST sanitization, then repeated preparation for the permission check and execution. The run argument now explicitly sets
sanitize_callback => null, disabling default REST coercion.The resulting flow is:
WP_Ability::execute(), which performs its own preparation and permission check before execution.Preparation in the controller is extracted into a private helper. Request parameters remain unchanged, and no request cache is needed.
WP_Ability::execute()is unchanged.Compatibility and errors
sanitize_input_for_ability()shipped in WordPress 7.1. It remains callable, is deprecated in 7.2, emits a deprecation notice, and returns its input unchanged. It is no longer registered on the endpoint. Direct callers should account for this behavior change.ability_invalid_inputdirectly instead of arest_invalid_paramwrapper.Testing
npm run test:php -- --filter=Abilitpasses: 1,857 tests, 6,687 assertions. Coding standards, PHP compatibility, and PHPStan checks pass too.null, and without input (9 cases). The normalize filter is not idempotent, so normalizing the same input twice fails validation. Each case also puts a different value in the source the HTTP method ignores, and sends the same request twice. The response, the permission callback input, and thewp_ability_invokedinput must match direct execution.Trac ticket: https://core.trac.wordpress.org/ticket/66383
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code, Codex
Model(s): Claude Opus 5.5 (original implementation)
Used for: Implementation, test updates, regression investigation, review fixes, and PR description updates, iterated on with me.
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.