diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93ce7d1..15a4783 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -123,11 +123,26 @@ jobs: validate-test-fixtures: name: Validate Test Fixtures runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout code uses: actions/checkout@v4 + - name: Install dependencies + run: sudo apt-get update && sudo apt-get install -y jq + + - name: Environment snapshot + run: | + echo "=== CI Environment Diagnostic ===" + echo "OS: $(uname -a)" + echo "Shell: $SHELL ($BASH_VERSION)" + echo "jq: $(command -v jq && jq --version || echo 'NOT INSTALLED')" + echo "perl: $(perl -v | head -2)" + echo "grep: $(grep --version | head -1)" + echo "=================================" + - name: Make scripts executable run: | chmod +x ./dist/bin/check-performance.sh @@ -136,7 +151,7 @@ jobs: - name: Run automated fixture tests run: | echo "Running automated fixture validation..." - ./dist/tests/run-fixture-tests.sh + cd dist && ./tests/run-fixture-tests.sh - name: Test antipatterns detection (legacy check) run: | diff --git a/.github/workflows/example-caller.yml b/.github/workflows/example-caller.yml deleted file mode 100644 index 3aa6caf..0000000 --- a/.github/workflows/example-caller.yml +++ /dev/null @@ -1,80 +0,0 @@ -# Example: How to call the reusable WP Performance workflow from your plugin -# Version: 1.0.1 -# -# โ ๏ธ THIS IS AN EXAMPLE/TEMPLATE FILE - NOT AN ACTIVE WORKFLOW -# -# This file is for DOCUMENTATION purposes only. -# Copy this file to your plugin's .github/workflows/ directory and customize. -# Rename to something like "ci.yml" or "performance.yml" -# -# DO NOT activate this workflow in the wp-code-check repository itself! -# The active workflow for this repo is ci.yml - -name: CI - Performance Checks (EXAMPLE - DO NOT USE) - -# TRIGGERS DISABLED - This is a template file that will never run automatically -# When using in your own plugin, replace the 'on:' section below with real triggers -on: - workflow_dispatch: # Only manual trigger - prevents automatic runs - inputs: - note: - description: 'This is a template file. Copy to your plugin repo to use.' - required: false - default: 'See README for usage instructions' - -# EXAMPLE TRIGGERS (uncomment and customize when using in your plugin): -# -# on: -# push: -# branches: [main, development] -# pull_request: -# branches: [main] - -jobs: - # Option 1: Call the reusable workflow from the central repo - # Uncomment and update the repository reference when published - # - # performance: - # uses: neochrome/automated-wp-code-testing/.github/workflows/wp-performance.yml@main - # with: - # paths: 'includes/ src/' - # php-version: '8.2' - # fail-on-warning: false - - # Option 2: Run checks directly (for standalone use) - performance-standalone: - name: Performance Checks (Standalone) - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Run Performance Checks - run: | - # Run the local check script if available - if [ -f "./bin/check-performance.sh" ]; then - chmod +x ./bin/check-performance.sh - ./bin/check-performance.sh --paths "." --strict - else - echo "No local check script found. Running inline checks..." - - # Inline grep checks (same as reusable workflow) - FAILED=0 - - echo "๐ Checking for unbounded queries..." - if grep -rn --include="*.php" --exclude-dir=vendor --exclude-dir=node_modules \ - -e "posts_per_page[[:space:]]*=>[[:space:]]*-1" \ - -e "numberposts[[:space:]]*=>[[:space:]]*-1" \ - -e "nopaging[[:space:]]*=>[[:space:]]*true" .; then - echo "::error::Found unbounded query patterns!" - FAILED=1 - fi - - if [ "$FAILED" = "1" ]; then - exit 1 - fi - - echo "โ All checks passed!" - fi - diff --git a/.gitignore b/.gitignore index e1d6535..5dae01a 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,12 @@ dist/tests/irl/* !dist/tests/irl/_AI_AUDIT_INSTRUCTIONS.md !dist/tests/irl/.gitkeep +# Auto-generated pattern library files (regenerated on every scan) +# These files are auto-generated by pattern-library-manager.sh +# and change with every scan due to timestamp updates +dist/PATTERN-LIBRARY.json +dist/PATTERN-LIBRARY.md + # ============================================ # DEVELOPMENT & TESTING # ============================================ diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..e29745a --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +engine-strict=true + diff --git a/CHANGELOG.md b/CHANGELOG.md index 363ee06..8d1e7ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,356 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.3.3] - 2026-01-13 + +### Added +- **MCP (Model Context Protocol) Support - Tier 1** - AI assistants can now directly access scan results + - **MCP Server** (`dist/bin/mcp-server.js`) - Node.js server exposing scan results as MCP resources + - **Resources Exposed:** + - `wpcc://latest-scan` - Most recent JSON scan log + - `wpcc://latest-report` - Most recent HTML report + - `wpcc://scan/{scan-id}` - Individual scans by timestamp ID + - **Supported AI Tools:** + - Claude Desktop (macOS, Windows) + - Cline (VS Code extension) + - Any MCP-compatible AI assistant + - **Features:** + - Automatic discovery of last 10 scans + - JSON and HTML resource types + - Error handling for missing scans + - Stdio transport (standard MCP) + - **Files Added:** + - `dist/bin/mcp-server.js` (227 lines) - MCP server implementation + - `package.json` - Node.js dependencies (`@modelcontextprotocol/sdk`) + - `PROJECT/1-INBOX/PROJECT-MCP.md` (538 lines) - Comprehensive MCP documentation + - **Impact:** AI assistants can now read scan results without manual copy/paste, enabling automated triage and fix suggestions + +### Changed +- **README.md** - Added MCP Protocol Support section with: + - Quick start guide for Claude Desktop configuration + - Developer guide for AI agents using MCP + - AI agent instructions for analyzing scan results + - Links to comprehensive MCP documentation +- **MARKETING.md** - Added MCP protocol support to comparison table + - WP Code Check: โ MCP support + - PHPCS, PHPStan, Psalm: โ No MCP support + - Differentiates WP Code Check as AI-first tool + +### Technical Details +- **MCP Version:** 1.0.0 (Tier 1 - Basic Resources) +- **Node.js Requirement:** >=18.0.0 +- **Dependencies:** `@modelcontextprotocol/sdk` ^0.5.0 +- **Protocol:** stdio transport (standard MCP) +- **Performance:** <100ms startup, <50ms resource reads +- **Memory:** ~30MB (Node.js + SDK) + +### Roadmap +- **Tier 2 (Planned):** Interactive tools (`scan_wordpress_code`, `filter_findings`) +- **Tier 3 (Planned):** Real-time streaming, prompts, dynamic resources + +## [1.3.2] - 2026-01-13 + +### Added +- **GitHub Issue Creation Tool** (`dist/bin/create-github-issue.sh`) + - Automatically create GitHub issues from scan results with AI triage data + - Interactive preview before creating issues + - Supports both `--repo owner/repo` flag and template-based repo detection + - Generates clean, actionable issues with: + - Scan metadata (plugin/theme name, version, scanner version) + - Confirmed issues section with checkboxes + - Needs review section with confidence levels + - Links to full HTML and JSON reports + - Requires GitHub CLI (`gh`) installed and authenticated + - Uses `--body-file` for reliable issue creation with large bodies + +### Changed +- **README.md**: Added GitHub Issue Creator to tools table and usage documentation +- **Template Support**: Templates now support optional `GITHUB_REPO` field for automated issue creation +- **GitHub Issue Footer**: Changed from broken relative links to local file paths in code blocks for better usability +- **GitHub Issue Creator**: Made `GITHUB_REPO` truly optional - script will generate issue body without creating the issue if no repo is specified +- **Issue Persistence**: When no GitHub repo is specified, issue bodies are now saved to `dist/issues/GH-issue-{SCAN_ID}.md` for manual copy/paste to GitHub or project management apps +- **AI Instructions**: Updated `dist/TEMPLATES/_AI_INSTRUCTIONS.md` with complete Phase 3 (GitHub Issue Creation) workflow documentation + +## [1.3.1] - 2026-01-12 + +### Fixed +- **Phase 2.1: Critical Quality Improvements** + - **Issue #2 (Suppression)**: Removed aggressive suppression logic + - Findings with guards+sanitizers now emit as LOW severity (not suppressed) + - Prevents false negatives from heuristic misattribution + - Still provides context signals for manual triage + - **Issue #4 (user_can)**: Removed `user_can()` from guard detection + - `user_can($user_id, 'cap')` checks OTHER users, not current request + - Reduces false confidence from non-guard capability checks + - Only `current_user_can()` is now detected as a guard + - **Issue #1 (Function Scope)**: Implemented function-scoped guard detection + - Guards now scoped to same function using `get_function_scope_range()` + - Guards must appear BEFORE the superglobal access (not after) + - Prevents branch misattribution (guards in different if/else) + - Prevents cross-function misattribution + - **Issue #3 (Taint Propagation)**: Added basic variable sanitization tracking + - Detects sanitized variable assignments: `$x = sanitize_text_field($_POST['x'])` + - Tracks sanitized variables within function scope + - Detects two-step sanitization: `$x = $_POST['x']; $x = sanitize($x);` + - Reduces false positives for common safe patterns + - **Issue #5 (Test Coverage)**: Added comprehensive test fixtures + - `phase2-branch-misattribution.php`: Tests guards in different branches/functions + - `phase2-sanitizer-multiline.php`: Tests multi-line sanitization patterns + - `verify-phase2.1-improvements.sh`: Automated verification script + +### Changed +- **Library Version**: Updated `false-positive-filters.sh` to v1.3.0 + - Added `get_function_scope_range()` helper function + - Enhanced `detect_guards()` with function scoping + - Added `is_variable_sanitized()` for taint propagation + - Fixed variable scope issues (explicit local declarations) + +### Technical Details +- **Function Scope Detection**: Uses brace counting to find function boundaries +- **Guard Detection**: Scans backward within function, stops at access line +- **Variable Tracking**: Matches assignment patterns with sanitizer functions +- **Limitations Documented**: Heuristic-based, not full PHP parser + +## [1.3.0] - 2026-01-12 + +### Added +- **Phase 2: Context Signals (Guards + Sanitizers)** + - **Guard Detection**: Automatically detects security guards near superglobal access + - Detects nonce checks: `wp_verify_nonce()`, `check_ajax_referer()`, `check_admin_referer()` + - Detects capability checks: `current_user_can()`, `user_can()` + - Scans 20 lines backward from finding to detect guards + - Guards are included in JSON output as array: `"guards":["wp_verify_nonce","current_user_can"]` + - **Sanitizer Detection**: Automatically detects sanitizers wrapping superglobal reads + - Detects `sanitize_*` functions: `sanitize_text_field()`, `sanitize_email()`, `sanitize_key()`, `sanitize_url()` + - Detects `esc_*` functions: `esc_url_raw()`, `esc_url()`, `esc_html()`, `esc_attr()` + - Detects type casters: `absint()`, `intval()`, `floatval()` + - Detects slashing functions: `wp_unslash()`, `stripslashes_deep()` + - Detects WooCommerce sanitizer: `wc_clean()` + - Sanitizers are included in JSON output as array: `"sanitizers":["sanitize_text_field","absint"]` + - **SQL Safety Detection**: Distinguishes safe literal SQL from unsafe concatenated SQL + - Safe literal SQL (only wpdb identifiers): Downgraded to LOW/MEDIUM (best-practice) + - Unsafe concatenated SQL (user input): Remains HIGH/CRITICAL (security) + - Detects superglobal concatenation: `$_GET`, `$_POST`, `$_REQUEST`, `$_COOKIE` + - Detects variable concatenation vs safe wpdb identifiers + - **New Helper Functions** (in `dist/bin/lib/false-positive-filters.sh` v1.2.0) + - `detect_guards()`: Scans backward to find security guards + - `detect_sanitizers()`: Analyzes code for sanitization functions + - `detect_sql_safety()`: Determines if SQL is safe literal or potentially tainted + +### Changed +- **Enhanced JSON Output Schema** + - All findings now include `"guards":[]` and `"sanitizers":[]` arrays + - Provides context for faster triage and prioritization + - Enables automated risk assessment based on protective measures +- **Intelligent Severity Downgrading** + - **Guards only**: Severity downgraded one level (e.g., HIGH โ MEDIUM) + - **Sanitizers only**: Severity downgraded one level (e.g., HIGH โ MEDIUM) + - **Guards + Sanitizers**: Finding suppressed (fully protected) + - **Safe literal SQL**: Downgraded to LOW/MEDIUM with "(literal SQL - best practice)" note + - **No guards/sanitizers**: Original severity maintained +- **Improved Triage Messages** + - Findings include context notes: "(has guards: wp_verify_nonce)" + - Findings include context notes: "(has sanitizers: sanitize_text_field)" + - SQL findings include: "(literal SQL - best practice)" for safe queries +- **Updated `add_json_finding()` Function** + - Now accepts optional 8th parameter: `guards` (space-separated list) + - Now accepts optional 9th parameter: `sanitizers` (space-separated list) + - Backward compatible: existing calls work without modification + +### Fixed +- **Removed `local` keyword from loop contexts** (bash compatibility) + - Fixed "local: can only be used in a function" errors + - Variables in while loops no longer use `local` keyword +- **Improved superglobal detection accuracy** + - Guards and sanitizers now properly detected and reported + - Fully protected code (guards + sanitizers) no longer flagged + - Context-aware severity adjustment reduces false positive noise + +### Testing +- **Created Phase 2 Test Fixtures** + - `dist/tests/fixtures/phase2-guards-detection.php`: Tests guard detection (nonce, capability checks) + - `dist/tests/fixtures/phase2-wpdb-safety.php`: Tests SQL safety detection (literal vs concatenated) +- **Created Phase 2 Verification Script** + - `dist/tests/verify-phase2-context-signals.sh`: Automated testing for Phase 2 features + - Verifies guards array in JSON output + - Verifies sanitizers array in JSON output + - Verifies SQL safety detection and severity downgrading + +### Known Limitations (Phase 2.1 Improvements Required) + +โ ๏ธ **IMPORTANT:** Phase 2 provides valuable context signals but has limitations that require refinement: + +1. **Guard Misattribution Risk**: Window-based detection may attribute guards to unrelated access (different branch/function) +2. **Suppression Too Aggressive**: Suppressing findings when guards+sanitizers detected risks false negatives +3. **Single-Line Sanitizer Detection**: Misses multi-line patterns like `$x = sanitize_text_field($_GET['x']); use($x);` +4. **user_can() Overcounting**: May count non-guard uses; needs conditional context detection +5. **Limited Branch Coverage**: Test fixtures don't cover all branch misattribution cases + +**Recommendation for v1.3.0:** Use guard/sanitizer arrays in JSON output for manual triage. Consider disabling automatic severity downgrading until Phase 2.1 improvements are complete. See `PROJECT/1-INBOX/PHASE2-QUALITY-IMPROVEMENTS.md` for improvement plan. + +## [1.2.4] - 2026-01-12 + +### Added +- **Phase 1 Improvements: Enhanced False Positive Filtering** + - **Improved `is_line_in_comment()` function** (now in shared library) + - Added string literal detection to ignore `/* */` inside quotes + - Increased backscan window from 50 to 100 lines (catches larger docblocks) + - Added inline comment detection for same-line `/* comment */` patterns + - Filters out string content before counting comment markers + - **Improved `is_html_or_rest_config()` function** (now in shared library) + - Tightened HTML form pattern: `