Repository navigation
feat(free,#326): add a local protection report - #338
Conversation
Read blocked attempts from the perimeter denial log and active grant budget from the existing grants table. No new table and no change to denial or grant enforcement.
Plugin Check rejects fopen and fclose. The report now uses the filesystem API and does not load a log past the byte cap.
|
Plugin Check failed on The reader no longer calls The adapter / redirection-adapter failure in the same run ( |
|
QA verdict: BLOCKED at Mergeable, not behind, GitHub merge state BLOCKED. Scope is a local Protection screen. Head Do not merge until admin, jobs, journal, and undo finish on this exact SHA. |
Scope
Adds a read-only Protection report under Products → Protection, next to Bulk Prices and Grants. Fixes nothing in the perimeter or the grant store. Does not close #326.
Invariant / Current Spec Reference
Denial and grant enforcement are unchanged.
Perimeter_GuardandPerimeter_Audit_Log::record()were not edited. Grant writes were not edited. Version, Stable tag, and the 0.3.0 tag were not bumped.readme.txtanddocs/marketing/**were not edited.Relevant Canonical CC-* Tests (
docs/test-plan.md)No legacy CC-* experiment ID. New hermetic test:
php wordpress/tests/admin/protection-report-unit.php.What Changed
Protection_Report_Queryreads two existing stores.Protection_Report_Adminrenders the window (7/30/90), blocked-attempt counts by the surfaces the denial log actually stores, active grants (used, reserved, remaining, expiry), and recent refusal rows (time, actor id and display name, surface, product id, reason code).Grant_Admin::can_mutate()(manage_woocommerceandedit_products).No new table
The issue guessed a
writeleash_perimeter_*table. That table does not exist.Perimeter refusals are append-only JSON lines written by
Perimeter_Audit_LogwhenWP_DEBUG_LOGis enabled. Each line storestimestamp,code,where,actor,object_id,kind, anddetail. The surface iswhere(rest,product_save,variation_save,product_set_stock,variation_set_stock,update_product_stock_query,update_post_metadata,add_post_metadata,delete_post_metadata,pre_trash_post,pre_delete_post).writeleash_grant_auditcannot answer "denials by surface". It has no surface column, and perimeter refusals are not inserted there. Active budget and expiry already live onwriteleash_grants(budget_max,budget_consumed,budget_reserved,expires_at,status,restriction_removed_at). Those two stores answer the report, so no table was added.detailandrouteare dropped at parse time. REST lines store the actor user id inobject_id; the screen says so. Other surfaces store the product id.The empty state says what appears after a restricted account is used. If
WP_DEBUG_LOGis off, the screen says refusals are not recorded yet.Security Impact
Read-only. No
wp_remote_,curl_, orfile_get_contents. No telemetry. Prepared SQL only (%ifor the grants table). Actor display is user id plus display name, not email or login. A restricted account's direct product write is still denied by the existing guard; this screen only reads the line the guard already asked the audit log to append.PostgreSQL Semantics Considered
Not applicable. This screen reads the WordPress debug log and the existing MySQL/MariaDB grant table. No PostgreSQL behavior is claimed.
Adversarial / Bypass Testing
php wordpress/tests/admin/protection-report-unit.phpResult:
#326 protection report unit: PASS (143 assertions). The run covers the empty state, 7/30/90 windows, surface reconciliation, pagination caps, grant budget remaining (including a non-negative floor), expired/revoked/removed grants, and a fixture log whosedetailandroutedo not survive parsing. The source assertion checks both new classes forwp_remote_,curl_,file_get_contents, andhttp:///https://.bash .github/ci/pr-fast.shon141d439598890e7b446f111b0f6ae7c2ac602df1:#133 PR_FAST PASS.Limitations / Unknowns
WP_DEBUG_LOGis enabled, and the audit log stops appending at 5 MB. The report cannot count a refusal that was never written.object_idis the actor id because that is whatPerimeter_Guard::rest_pre_dispatch()logs. This PR does not change that call.Out-of-Scope Work Explicitly Not Included
PUBLIC-PAYLOAD.mdrecords the new read-only screen because the package inventory requires it.