Protect abilities: register status, threats, and Account Protection via Registrar#48737
Protect abilities: register status, threats, and Account Protection via Registrar#48737enejb wants to merge 1 commit into
Conversation
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 🔴 Action required: Please include detailed testing steps, explaining how to test your change, like so: 🔴 Action required: We would recommend that you add a section to the PR description to specify whether this PR includes any changes to data or privacy, like so: Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! |
Code Coverage SummaryCoverage changed in 1 file.
1 file is newly checked for coverage.
|
Summary
Registers the first slice of Jetpack Protect abilities with the WordPress Abilities API, following the plan in the Abilities Everywhere project (§2.3 plugin-core abilities surface). The class extends the shared
Registrarbase fromautomattic/jetpack-wp-abilities, so thejetpack_wp_abilities_enabledgate, late-load fallback, and per-ability allow-list filter all come for free.This v1 surface is read-only plus one declarative state-setter. Destructive writes (
fix-threat,ignore-threat,request-scan) are deliberately deferred to a follow-up — they need careful per-id capability scoping that the read paths don't.Abilities registered
jetpack-protect/get-status{ has_plan, last_scan: { timestamp, status, threats_found }, threat_counts: { total, fixable, critical }, scan_in_progress }jetpack-protect/list-threats[{ id, signature, title, description, severity, type, fixable, ignored, first_detected, source }], withseverity(critical/high/medium/low) andtype(core/plugin/theme/file) filters;per_pagecapped at 100jetpack-protect/get-threatid(consolidated-read pattern: unknown id →[], notWP_Error); addsrecommended_actionjetpack-protect/get-account-protection-status{ enabled, supported, last_event, attempt_count_24h, blocked_count_24h }(event/count fields are placeholder-shaped; tracked for the follow-up)jetpack-protect/set-account-protection{ enabled, changed }— idempotent toggle of the Account Protection moduleCapability matching
All five abilities gate on
current_user_can( 'manage_options' ), matching the existing capability on every route inprojects/plugins/protect/src/class-rest-controller.phpand the/statusroute inprojects/packages/protect-status/src/class-rest-controller.php. No new caps invented.Wiring
Case C (plugin-core ability — the REST surface lives in the plugin itself, not in a module).
Protect_Abilities::init()is called fromJetpack_Protect::init()after the legacyREST_Controller::init(). The Registrar handles thejetpack_wp_abilities_enabledgate internally — no extraapply_filtersat the call site.Test coverage
projects/plugins/protect/tests/php/abilities/Protect_Abilities_Test.php(41 tests, 125 assertions):per_pagecap == 100.Protect_Abilities_Test_Stubthat overrides the protected seams (fetch_status,fetch_account_protection_settings,account_protection,has_required_plan).get-threatwith unknown id returns[](notWP_Error).set-account-protectionidempotency: desired==current →changed=false, no call toenable()/disable().'0'-style string id accepted; non-booleanenabledrejected with distinct error code.Test plan
cd projects/plugins/protect && composer phpunit -- --filter Protect_Abilities_Testpasses (currently 41/41).jetpack_wp_abilities_enabledtrue on a Protect-connected site and confirm the 5 slugs appear inwp_get_abilities()//wp-json/wp-abilities/v1/abilities.jetpack-protect/get-statuswith admin auth and confirm the 4-key shape.jetpack-protect/list-threatswith{ severity: 'critical' }and confirm filter applies.jetpack-protect/set-account-protectiontwice with the sameenabledvalue — second call returnschanged=false.