From 65bb6e7833c281310f0fcef5b5c77a5415930aee Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:15:17 +0100 Subject: [PATCH] fix: bounded config fixes for the PHP CI gates Keeps the library PHP (defensive PHP-security tooling). Config-only fixes: - composer.json: add autoload.files for src/WordPress/Adapter.php so the aegis_* WordPress-adapter functions are loaded (PSR-4 only autoloads classes, never free functions). - Adapter.php: move the aegis_* helpers to the GLOBAL namespace (was PhpAegis\WordPress). They are WordPress-style globals invoked unqualified (aegis_html(...)) and rely on PHP's global-function fallback; namespaced, the ~20 functions were unresolvable from the test namespaces. 'use' imports retained so the underlying class refs still resolve. - .php-cs-fixer.dist.php: fix invalid v3 config (exit 16): drop bogus 'no_eval' (no such fixer) and rename 'no_unneeded_curly_braces' -> 'no_unneeded_braces'. - php-lint.yml Security Pattern Check: add \b word boundaries so curl_exec() no longer matches \bexec\(, and anchor the backtick check + exclude quoted-string contexts so the library's own escaped backtick char in its Turtle/URI validators is not flagged. Verified statically (no PHP runtime in env): composer.json is valid JSON; new security-pattern regexes produce zero matches on src/ while still catching a bare exec(. composer.lock and the PHPStan L9 baseline still require a PHP runtime (see PR notes). Co-Authored-By: Claude Opus 4.8 --- .github/workflows/php-lint.yml | 16 ++++++++++++---- .php-cs-fixer.dist.php | 3 +-- composer.json | 5 ++++- src/WordPress/Adapter.php | 6 +++++- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.github/workflows/php-lint.yml b/.github/workflows/php-lint.yml index 0787e93..9a94bb9 100644 --- a/.github/workflows/php-lint.yml +++ b/.github/workflows/php-lint.yml @@ -177,8 +177,11 @@ jobs: run: | FOUND=0 - # Dangerous execution functions - DANGEROUS=$(grep -rEn 'eval\s*\(|exec\s*\(|system\s*\(|passthru\s*\(|shell_exec\s*\(|proc_open\s*\(|popen\s*\(' \ + # Dangerous execution functions. + # Word boundaries (\b) are required so legitimate functions whose + # names merely END in a dangerous token are not flagged, e.g. + # curl_exec() (HTTP, not command execution) must NOT match \bexec\(. + DANGEROUS=$(grep -rEn '\beval\s*\(|\bexec\s*\(|\bsystem\s*\(|\bpassthru\s*\(|\bshell_exec\s*\(|\bproc_open\s*\(|\bpopen\s*\(' \ --include="*.php" src/ 2>/dev/null || true) if [ -n "$DANGEROUS" ]; then echo "::error::Dangerous execution functions found:" @@ -186,8 +189,13 @@ jobs: FOUND=1 fi - # Backtick execution - BACKTICKS=$(grep -rEn '`[^`]*\$' --include="*.php" src/ 2>/dev/null || true) + # Backtick (shell) execution with variable interpolation. + # Anchor on the OPENING backtick of a shell-exec operator, then drop + # lines where the backtick is a literal character inside a quoted + # string/regex (this security library escapes the backtick char in + # its Turtle/URI validators, which is legitimate, not shell exec). + BACKTICKS=$(grep -rEn '(=|\(|\breturn\b|\becho\b)\s*`[^`]*\$[^`]*`' --include="*.php" src/ 2>/dev/null \ + | grep -vE "['\"][^'\"]*\`" || true) if [ -n "$BACKTICKS" ]; then echo "::error::Backtick execution with variables found:" echo "$BACKTICKS" diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index f7052b5..2ace148 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -71,7 +71,7 @@ // Control structures 'no_unneeded_control_parentheses' => true, - 'no_unneeded_curly_braces' => true, + 'no_unneeded_braces' => true, 'yoda_style' => [ 'equal' => false, 'identical' => false, @@ -205,7 +205,6 @@ ], // Security-conscious rules - 'no_eval' => true, // Warn about eval() usage 'random_api_migration' => true, // Use random_int/random_bytes 'native_function_invocation' => [ 'include' => ['@compiler_optimized'], diff --git a/composer.json b/composer.json index 4f0180c..58f726f 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,10 @@ "autoload": { "psr-4": { "PhpAegis\\": "src/" - } + }, + "files": [ + "src/WordPress/Adapter.php" + ] }, "autoload-dev": { "psr-4": { diff --git a/src/WordPress/Adapter.php b/src/WordPress/Adapter.php index 5ee06f2..da016be 100644 --- a/src/WordPress/Adapter.php +++ b/src/WordPress/Adapter.php @@ -7,7 +7,11 @@ declare(strict_types=1); -namespace PhpAegis\WordPress; +// NOTE: These WordPress-style helpers live in the GLOBAL namespace on purpose, +// mirroring WordPress's own global functions (esc_html(), esc_attr(), ...). +// Callers invoke them unqualified (aegis_html(...)) and rely on PHP's global +// function fallback, so they must not be namespaced. The `use` imports below +// keep the underlying class references (Sanitizer::html, etc.) resolvable. use PhpAegis\Validator; use PhpAegis\Sanitizer;