fix(security): no direct HTTP access to plugin PHP files (audit L2, cheap part)

Every file under src/ exits outside WordPress (defined('ABSPATH') ||
exit; after the use block, so a direct request no longer prints a fatal
error with the server path); divi-convert-fixture.php gets the WP_CLI
guard the other integration scripts have. A unit test keeps both true;
PSR1 side-effects warning excluded for the guard.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
2026-09-26 19:32:12 +02:00
co-authored by Claude Opus 5.5
parent 4d4bf57c9f
commit b24eb6c3e9
185 changed files with 418 additions and 1 deletions
+48
View File
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
/**
* Security audit L2: every PHP file is only executable inside WordPress – a direct HTTP request
* to a file under src/ exits silently instead of printing a fatal error with the server path.
* The integration scripts under tests/Integration run only under WP-CLI.
*/
final class DirectAccessGuardTest extends TestCase
{
public function testEverySourceFileExitsOutsideWordPress(): void
{
$root = dirname(__DIR__, 2);
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root . '/src'));
$checked = 0;
foreach ($files as $file) {
if (! str_ends_with((string) $file, '.php')) {
continue;
}
$checked++;
self::assertMatchesRegularExpression(
"/^defined\\('ABSPATH'\\) \\|\\| exit;$/m",
(string) file_get_contents((string) $file),
substr((string) $file, strlen($root) + 1)
);
}
self::assertGreaterThan(100, $checked);
}
public function testIntegrationScriptsRunOnlyUnderWpCli(): void
{
foreach (glob(dirname(__DIR__) . '/Integration/*.php') ?: [] as $file) {
self::assertStringContainsString(
"defined('WP_CLI') && WP_CLI || exit;",
(string) file_get_contents($file),
basename($file)
);
}
}
}