Some checks failed
Deploy Application / deploy (push) Has been cancelled
117 lines
4.0 KiB
PHP
117 lines
4.0 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
/**
|
||
* Dependency Security Checker
|
||
*
|
||
* Checks Composer dependencies for known security vulnerabilities
|
||
* Uses the Packagist Security Advisories database
|
||
*/
|
||
|
||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||
|
||
use App\Framework\Composer\Services\ComposerLockReader;
|
||
|
||
final class DependencySecurityChecker
|
||
{
|
||
private const SECURITY_ADVISORIES_URL = 'https://packagist.org/api/security-advisories/';
|
||
|
||
public function __construct(
|
||
private readonly ComposerLockReader $lockReader
|
||
) {
|
||
}
|
||
|
||
public function checkDependencies(): array
|
||
{
|
||
$basePath = __DIR__ . '/../..';
|
||
$composerLock = $this->lockReader->readFromProjectRoot($basePath);
|
||
$packages = $composerLock->getPackagesWithType();
|
||
|
||
echo "🔍 Checking " . count($packages) . " dependencies for security vulnerabilities...\n\n";
|
||
|
||
$vulnerabilities = [];
|
||
|
||
foreach ($packages as $package) {
|
||
$advisories = $this->checkPackage($package['name'], $package['version']);
|
||
|
||
if (!empty($advisories)) {
|
||
$vulnerabilities[$package['name']] = [
|
||
'version' => $package['version'],
|
||
'advisories' => $advisories
|
||
];
|
||
}
|
||
}
|
||
|
||
return $vulnerabilities;
|
||
}
|
||
|
||
public function printReport(array $vulnerabilities): void
|
||
{
|
||
if (empty($vulnerabilities)) {
|
||
echo "✅ No known security vulnerabilities found in dependencies!\n";
|
||
return;
|
||
}
|
||
|
||
echo "🚨 Found " . count($vulnerabilities) . " packages with security advisories:\n\n";
|
||
|
||
foreach ($vulnerabilities as $package => $data) {
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
||
echo "📦 {$package}\n";
|
||
echo " Current Version: {$data['version']}\n";
|
||
echo " Vulnerabilities:\n";
|
||
|
||
foreach ($data['advisories'] as $advisory) {
|
||
echo "\n";
|
||
echo " • {$advisory['title']}\n";
|
||
echo " Severity: {$advisory['severity']}\n";
|
||
echo " Affected: {$advisory['affected_versions']}\n";
|
||
echo " Fixed in: {$advisory['fixed_versions']}\n";
|
||
echo " Link: {$advisory['link']}\n";
|
||
}
|
||
|
||
echo "\n";
|
||
}
|
||
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
||
echo "\n⚠️ RECOMMENDATION: Update vulnerable packages immediately!\n";
|
||
}
|
||
|
||
|
||
private function checkPackage(string $name, string $version): array
|
||
{
|
||
// Note: This is a placeholder implementation
|
||
// In a production environment, you would:
|
||
// 1. Query the FriendsOfPHP/security-advisories database
|
||
// 2. Use the Packagist API
|
||
// 3. Or integrate with local-php-security-checker
|
||
|
||
// For now, we'll provide a manual check message
|
||
static $firstRun = true;
|
||
|
||
if ($firstRun) {
|
||
echo "ℹ️ For real-time vulnerability scanning, use:\n";
|
||
echo " - local-php-security-checker: https://github.com/fabpot/local-php-security-checker\n";
|
||
echo " - Composer audit: composer audit\n";
|
||
echo " - GitHub Dependabot: Enable in repository settings\n\n";
|
||
$firstRun = false;
|
||
}
|
||
|
||
// Placeholder: In production, this would return actual advisories
|
||
return [];
|
||
}
|
||
}
|
||
|
||
// Run the checker
|
||
try {
|
||
$lockReader = new ComposerLockReader();
|
||
$checker = new DependencySecurityChecker($lockReader);
|
||
$vulnerabilities = $checker->checkDependencies();
|
||
$checker->printReport($vulnerabilities);
|
||
|
||
exit(empty($vulnerabilities) ? 0 : 1);
|
||
} catch (\Exception $e) {
|
||
echo "❌ Error: {$e->getMessage()}\n";
|
||
exit(2);
|
||
}
|