From a94f3251cfb70603ec838ada368587df79350e1d Mon Sep 17 00:00:00 2001 From: Stephan Vock Date: Thu, 21 May 2026 16:29:51 +0100 Subject: [PATCH] FilterLists: only import entries with a valid version constraint --- src/FilterList/FilterListResolver.php | 18 ++++++++++++++++++ tests/FilterList/FilterListResolverTest.php | 14 +++++++++++++- tests/FilterListWorkerTest.php | 2 +- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/FilterList/FilterListResolver.php b/src/FilterList/FilterListResolver.php index 925aa422d..61e732405 100644 --- a/src/FilterList/FilterListResolver.php +++ b/src/FilterList/FilterListResolver.php @@ -13,9 +13,16 @@ namespace App\FilterList; use App\Entity\FilterListEntry; +use Composer\Semver\VersionParser; +use Psr\Log\LoggerInterface; class FilterListResolver { + public function __construct( + private readonly LoggerInterface $logger, + ) { + } + /** * @param array $existingEntries * @param array $remoteEntries @@ -29,9 +36,20 @@ public function resolve(array $existingEntries, array $remoteEntries): array $existingMap[$existing->getPackageName()][$existing->getVersion()] = $existing; } + $versionParser = new VersionParser(); $new = []; $found = []; foreach ($remoteEntries as $remote) { + try { + $versionParser->parseConstraints($remote->version); + } catch (\UnexpectedValueException $e) { + $this->logger->warning('Skipping filter list entry with invalid version constraint', [ + 'entry' => $remote, + 'exception' => $e, + ]); + continue; + } + if (isset($existingMap[$remote->packageName][$remote->version])) { $found[$remote->packageName][$remote->version] = true; continue; diff --git a/tests/FilterList/FilterListResolverTest.php b/tests/FilterList/FilterListResolverTest.php index b2a725285..319015de9 100644 --- a/tests/FilterList/FilterListResolverTest.php +++ b/tests/FilterList/FilterListResolverTest.php @@ -19,6 +19,7 @@ use App\FilterList\RemoteFilterListEntry; use Doctrine\Persistence\Reflection\TypedNoDefaultReflectionProperty; use PHPUnit\Framework\TestCase; +use Psr\Log\NullLogger; class FilterListResolverTest extends TestCase { @@ -26,7 +27,7 @@ class FilterListResolverTest extends TestCase protected function setUp(): void { - $this->resolver = new FilterListResolver(); + $this->resolver = new FilterListResolver(new NullLogger()); } public function testResolveAddNewEntry(): void @@ -115,6 +116,17 @@ public function testResolveRemovesOnlyUnmatchedVersions(): void $this->assertSame([$existing2], $result[1]); } + public function testResolveSkipsRemoteEntriesWithInvalidVersionConstraint(): void + { + $valid = $this->createRemoteFilterListEntry('vendor/good', '1.0.0'); + $invalid = $this->createRemoteFilterListEntry('vendor/bad', 'not-a-valid-constraint!@#'); + + $result = $this->resolver->resolve([], [$valid, $invalid]); + + $this->assertEntry($valid, $result[0]); + $this->assertSame([], $result[1]); + } + private function createRemoteFilterListEntry(string $packageName, string $version): RemoteFilterListEntry { return new RemoteFilterListEntry( diff --git a/tests/FilterListWorkerTest.php b/tests/FilterListWorkerTest.php index 0695b130a..92bd3c785 100644 --- a/tests/FilterListWorkerTest.php +++ b/tests/FilterListWorkerTest.php @@ -59,7 +59,7 @@ protected function setUp(): void $this->urlGenerator = $this->createStub(UrlGeneratorInterface::class); $doctrine = $this->createStub(ManagerRegistry::class); $this->summaryDumper = $this->createMock(FilterListSummaryDumper::class); - $this->worker = new FilterListWorker($this->locker, new NullLogger(), $doctrine, [FilterSources::AIKIDO->value . '-' . FilterLists::MALWARE->value => $this->filterList], new FilterListResolver(), new FilterListEntryUpdateListener($doctrine), $this->mailer, $this->downloadManager, 'test@example.com', $this->urlGenerator, 'packagist.org', $this->summaryDumper); + $this->worker = new FilterListWorker($this->locker, new NullLogger(), $doctrine, [FilterSources::AIKIDO->value . '-' . FilterLists::MALWARE->value => $this->filterList], new FilterListResolver(new NullLogger()), new FilterListEntryUpdateListener($doctrine), $this->mailer, $this->downloadManager, 'test@example.com', $this->urlGenerator, 'packagist.org', $this->summaryDumper); $this->em = $this->createMock(EntityManager::class);