This commit is contained in:
Javier Casares 2026-06-08 12:52:03 +00:00
commit 693e5ae2e6
8 changed files with 0 additions and 283 deletions

View file

@ -1 +0,0 @@
{"version":1,"defects":[],"times":{"Test_Plugin_Headers::plugin_file_exists":0.002,"Test_Plugin_Headers::plugin_name_header_is_present":0.001,"Test_Plugin_Headers::version_header_is_present_and_valid":0,"Test_Plugin_Headers::requires_at_least_header_is_present":0,"Test_Plugin_Headers::requires_php_header_is_present":0,"Test_Plugin_Headers::text_domain_matches_plugin_slug":0,"Test_Plugin_Headers::license_header_is_gpl3":0,"Test_Plugin_Headers::author_header_is_present":0,"Test_Plugin_Headers::readme_file_exists":0,"Test_Plugin_Headers::readme_has_stable_tag":0,"Test_Plugin_Headers::readme_has_requires_at_least":0,"Test_Plugin_Headers::readme_has_requires_php":0,"Test_Plugin_Headers::readme_has_license":0,"Test_Plugin_Headers::stable_tag_matches_plugin_version":0,"Test_Plugin_Headers::requires_at_least_is_consistent":0,"Test_Plugin_Headers::requires_php_is_consistent":0,"Test_Plugin_Headers::license_is_consistent":0}}

View file

@ -1,59 +0,0 @@
# Changelog
All notable changes to Documentation Markdown are documented in this file.
For the WordPress.orgformatted changelog, see [`changelog.txt`](changelog.txt).
## [1.1.1] — 2026-06-08
### Security
- CommonMark: disabled raw HTML passthrough (`html_input: strip`, `allow_unsafe_links: false`) — prevents stored XSS if an upstream repository is compromised
- Plugin settings option now stored with `autoload = false` — encrypted GitHub token no longer loaded on every WordPress request
- Replaced `serialize()` with `wp_json_encode()` in updater HMAC cache signature (eliminates object-injection risk surface)
- Added strict base64 length validation in `robotstxt_docmd_decrypt_token()` before IV extraction
- Added `base64_decode()` strict return-value check in `robotstxt_docmd_get_file_content()`
### Fixed
- Admin notices now display results for all operations (mapping created/updated/deleted, sync complete, error messages); previously only "Settings saved" appeared
- `wp_update_post()` return value now checked during sync — silent failures previously reported as success
- Wrong textdomain `'robotstxt-smtp'` in updater class corrected to `'robotstxt-documentation-markdown'`
### Changed
- `robotstxt-updater.php` renamed to `class-robotstxt-updater.php` (WordPress file-naming convention)
- `Requires PHP` header corrected to `8.0` (real minimum confirmed by PHPCompatibility scan — union types, `str_starts_with()`, `str_contains()`, `mixed` type are the binding constraints; no 8.1/8.2-specific features used)
### Developer / Infrastructure
- Added `composer.json` with full `require-dev` tooling (PHPCS, PHPStan 2.x, PHPUnit 9.6, PHPCompatibility 10.0.0-alpha2, wp-compat, yoast/phpunit-polyfills)
- Added `phpstan.neon` (level 9), `.phpcs.xml` (WordPress standards), `bin/deploy.sh`, `phpunit.xml.dist`
- 17 PHPUnit plugin header tests added (`tests/PluginHeadersTest.php`)
- Added `docs/known-issues.md` and `docs/db-migrations.md`
- `class-robotstxt-updater.php`: PHPCS 0 errors, PHPStan level 9 0 errors
- PHPCompatibility updated to 10.0.0-alpha2 (PHP 8.x feature detection)
## [1.1.0] — 2026-03-28
### Security
- Patched CVE-2026-33347 and CVE-2026-30838 (league/commonmark updated to 2.8.2)
### Changed
- Access level changed from `manage_options` (administrator) to `edit_pages` (editor)
### Fixed
- PHPStan level 9 compliance: zero errors across all plugin files
- `target_order` (menu_order) field now saved and applied end-to-end
- Type-safety improvements for all WordPress API returns
- Token decryption `false` return handled correctly
- Uninstall data cleanup narrows mixed option return before array access
## [1.0.0] — 2026-01-26
### Added
- Initial release: GitHub → WordPress Markdown sync
- Encrypted GitHub token storage (AES-256-CBC)
- Custom Post Type `robotstxt_map` for mapping management
- Automatic cron sync (hourly, twice daily, daily)
- Manual on-demand sync via admin interface
- Markdown to HTML via CommonMark (league/commonmark)
- Multi-repository support
- Debug tools (visible when `WP_DEBUG` enabled)
- Full i18n support (es_ES bundled)

View file

@ -1,90 +0,0 @@
# Pre-Deploy AI Security Audit — v1.1.1
**Date:** 2026-06-08
**Plugin:** Documentation Markdown (by ROBOTSTXT)
**Version:** 1.1.0 → 1.1.1
**Auditor:** Claude Sonnet (Senior WordPress Plugin Security Auditor role)
**Scope:** Full codebase (all 7 PHP plugin files)
---
## Executive Summary
**Overall status: CONDITIONAL PASS → PASS (after fixes applied)**
All [CRITICAL] findings were resolved before tagging. No SQL injection, no CSRF gaps, no direct object reference, no privilege escalation vectors found. Access is gated behind `edit_pages` throughout with both UI-level and execution-level checks.
**Security risk: Low** (after fixes)
**Version recommendation: stable**
---
## Findings Resolved Before Release
### [CRITICAL → FIXED] Finding 011 — CommonMark raw HTML passthrough
**File:** `robotstxt-documentation-markdown-map.php:296`
**Problem:** CommonMark's default config allows raw HTML blocks from Markdown. A compromised upstream GitHub repository could inject `<script>`, `<iframe>`, or event handlers into synced WordPress post content.
**Fix applied:** `html_input => 'strip'`, `allow_unsafe_links => false` in `CommonMarkConverter` config.
### [WARNING → FIXED] Finding 002 — base64 decode without length validation
**File:** `robotstxt-documentation-markdown-functions.php:55`
**Problem:** `base64_decode()` result not length-checked before `substr()` IV extraction. Tampered options could cause silent decryption failures or short-IV oracle scenarios.
**Fix applied:** Added `false === $decoded || strlen($decoded) <= $iv_length` guard.
### [WARNING → FIXED] Finding 008 — Settings option autoloaded
**File:** `robotstxt-documentation-markdown.php:72, 1164`
**Problem:** Encrypted GitHub token loaded with every WordPress request via autoload.
**Fix applied:** `add_option(..., '', false)` and `update_option(..., false)`.
### [WARNING → FIXED] Finding 018 — `wp_update_post()` return unchecked
**File:** `robotstxt-documentation-markdown-map.php:324`
**Problem:** Sync silently reported success even if post update failed.
**Fix applied:** Return value checked; error returned on failure.
### [WARNING → FIXED] Finding 020 — `base64_decode()` unchecked in GitHub fetch
**File:** `robotstxt-documentation-markdown-github.php:289`
**Problem:** Malformed GitHub API response (bad base64) would cause silent empty post.
**Fix applied:** Added `false === $decoded` guard returning `WP_Error`.
### [BUG → FIXED] Admin notices not displayed
**File:** `robotstxt-documentation-markdown.php:908`
**Problem:** Messages for mapping_created, mapping_updated, mapping_deleted, sync_complete, and error parameters were redirected to URL but never rendered.
**Fix applied:** Complete message map added to `robotstxt_docmd_render_admin_notices()`.
---
## Findings Deferred to Future Release
| ID | Severity | Description | Target |
|----|----------|-------------|--------|
| 001 | WARNING | Token key derivation should use HKDF instead of raw `wp_salt()` — would require token migration | v1.2.0 |
| 003 | WARNING | Debug action nonce/page checks split across two `if` blocks — refactoring risk | v1.2.0 |
| 005 | INFO | `esc_js()` in `onclick` pattern — safe with fixed string but fragile for future edits | v1.2.0 |
| 006 | WARNING | `get_posts(post_type=any, limit=100)` on Add Mapping page — performance on large sites | v1.2.0 |
| 009 | INFO | GitHub API URL: branch/path not `rawurlencode()`d — no current attack vector, defensive hardening | v1.2.0 |
| 010 | INFO | `target_post_type` not validated against registered post types at save | v1.2.0 |
| 013 | INFO | Debug "cached vs fresh" indicator always shows cached after first fetch | v1.2.0 |
| 014 | INFO | Discover page `refresh=1` lacks nonce — forces GitHub API call via CSRF | v1.2.0 |
Deferred findings documented in `docs/known-issues.md`.
---
## Positive Findings (No Action Required)
- All state-changing actions protected with nonces (`wp_nonce_field`, `wp_nonce_url`, `check_admin_referer`, `wp_verify_nonce`)
- Capability checks (`current_user_can('edit_pages')`) applied in both UI rendering and execution logic for all admin pages and handlers
- All `$_POST`/`$_GET` access goes through `robotstxt_docmd_input_string()` / `robotstxt_docmd_input_int()` type-narrowing helpers
- All output escaping at render time (`esc_html`, `esc_attr`, `esc_url`, `esc_js`, `wp_kses_post`)
- All redirects via `wp_safe_redirect()` to `admin_url()` destinations
- No raw SQL; custom SQL (transient cleanup) uses `$wpdb->prepare()` with `$wpdb->esc_like()`
- ABSPATH guard on every PHP file
- No `eval()`, no suspicious `base64_decode()` (documented necessary use for GitHub API decoding), no shell functions
- GitHub token encrypted at rest (AES-256-CBC, key from `wp_salt('auth')`)
- `uninstall.php` uses `WP_UNINSTALL_PLUGIN` guard and respects user data-preservation preference

View file

@ -1,9 +0,0 @@
# Database Migrations
This plugin does **not** create custom database tables. All data is stored using WordPress core APIs:
- **Mappings:** Custom Post Type `robotstxt_map` with post meta (prefixed `_robotstxt_docmd_*`)
- **Settings:** WordPress Options API (`robotstxt_docmd_settings`)
- **Cache:** WordPress Transients API (`robotstxt_docmd_*`)
No `DB_VERSION` constant or migration routines are required.

View file

@ -1,113 +0,0 @@
# Pre-Deploy Checklist — Version 1.1.1
**Date:** 2026-06-08
**Plugin:** Documentation Markdown (by ROBOTSTXT)
**Version:** 1.1.1
---
## INPUT VALIDATION
- [x] Empty field validation performed
- [x] Length limits validated server-side
- [x] Format patterns validated (regex, ctype_alnum, preg_match)
- [x] Safelist validation for finite option sets
- [x] Strict type checking (===, in_array with true)
- [x] Validation BEFORE any action or processing
- [x] robotstxt_docmd_input_string() / robotstxt_docmd_input_int() for all superglobal access
## INPUT SANITIZATION
- [x] sanitize_text_field() for single-line text
- [x] sanitize_key() for keys/identifiers
- [x] sanitize_text_field() for github_url (functional; sanitize_url() deferred to v1.2.0 — known-issues.md)
- [x] wp_unslash() before sanitizing superglobals
## OUTPUT ESCAPING
- [x] esc_html() for HTML element content
- [x] esc_attr() for HTML attributes
- [x] esc_url() for all URLs
- [x] esc_js() for inline JavaScript (delete confirm)
- [x] esc_html__(), esc_attr_e() combined i18n+escape functions
- [x] Numeric variables: absint(), (int)
- [x] wp_kses_post() for debug details and status badges
- [x] Escaping at output time, not before storage
## CSRF PROTECTION
- [x] wp_nonce_field() on all forms (save_mapping, save_settings)
- [x] wp_nonce_url() for action URLs (sync, delete)
- [x] check_admin_referer() for all GET state-changing actions
- [x] wp_verify_nonce() in save handlers and updater cache clear
- [x] Nonce action strings are specific (include mapping_id)
- [x] Nonces NOT used for authorization
## DATABASE SECURITY
- [x] $wpdb->prepare() for all custom SQL (transient cleanup)
- [x] $wpdb->esc_like() for LIKE patterns
- [x] WordPress API functions for CPT and post meta
- [x] No $_POST/$_GET interpolation in queries
## CAPABILITY CHECKS
- [x] current_user_can('edit_pages') on every admin page render
- [x] current_user_can('edit_pages') in every handler
- [x] current_user_can('update_plugins') in updater cache clear
- [x] Capability checks in UI rendering (wp_die if no permission)
- [x] Capability checks in execution logic
## FILE OPERATIONS
- [x] ABSPATH guard on every PHP file
- [x] base64_decode() strict with length validation (fixed in 1.1.1)
- [x] No user file uploads managed by this plugin
## DANGEROUS FUNCTIONS
- [x] No eval()
- [x] base64_decode() only for GitHub API content decode (documented necessity)
- [x] No system(), exec(), shell_exec(), passthru()
- [x] No unserialize() — serialize() replaced with wp_json_encode() in 1.1.1
## CODE QUALITY & STANDARDS
- [x] PHPCS: 0 errors, 0 warnings — 7 files, no exclusions
- [x] PHPStan level 9: 0 errors — 7 files, no exclusions
- [x] PHPCompatibility 10.0.0-alpha2: 0 errors (PHP 8.08.5)
- [x] Requires PHP: 8.0 (real minimum confirmed by PHPCompatibility scan)
- [x] All i18n strings use textdomain 'robotstxt-documentation-markdown'
- [x] phpDoc on all public functions/methods/hooks
## TESTING
- [x] PHPUnit: 17/17 tests OK (plugin header tests)
- [x] Stable tag 1.1.1 = Version 1.1.1 = ROBOTSTXT_DOCMD_VERSION = update.json version ✓
## VERSIONING & DOCUMENTATION
- [x] Plugin header: Version: 1.1.1
- [x] ROBOTSTXT_DOCMD_VERSION constant: '1.1.1'
- [x] CHANGELOG.md updated
- [x] changelog.txt updated (WP.org format)
- [x] readme.txt: Stable tag 1.1.1, Requires PHP 8.0, Tested up to 7.1
- [x] update.json: version 1.1.1, requires_php 8.0, tested 7.1
- [x] README.md — no new external dependencies added
## DATABASE & UNINSTALL
- [x] uninstall.php exists and respects data preservation option
- [x] No custom DB tables — documented in docs/db-migrations.md
- [x] Settings stored with autoload=false (fixed in 1.1.1)
## AI AUDIT
- [x] Pre-deploy AI audit executed on full codebase
- [x] All [CRITICAL] findings resolved (Finding 011: CommonMark html_input:strip)
- [x] [WARNING] findings deferred documented in docs/known-issues.md
- [x] Audit report: docs/audit-pre-deploy-1.1.1.md
- [x] Executive summary: PASS
- [x] Security risk: Low
## BUILD & ARTIFACT
- [x] deploy.sh executed manually — artifact generated
- [x] ZIP excludes dev files (composer.json, phpstan.neon, .phpcs.xml, tests/, docs/, bin/, AGENTS.md, CLAUDE.md)
- [x] Production vendor/ included (no require-dev packages)
- [x] *.po files excluded (only .mo bundled)
---
## DEPLOY AUTHORIZATION
- All [CRITICAL] items resolved: **YES**
- Executive summary: **PASS**
- Security risk: **Low**
- Manual approval: **YES**

View file

@ -1,11 +0,0 @@
# Known Issues
This file documents [WARNING]-level findings from pre-deploy audits that have been deferred to future releases.
## Active deferred issues
_None._
---
*For resolved issues see CHANGELOG.md. For [CRITICAL] findings see pre-deploy audit reports in this directory.*

Binary file not shown.