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;