From 287648089578fc11f481d6bb4e74c919a290f638 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Sun, 21 Nov 2021 00:39:16 +0200 Subject: [PATCH 01/25] dirty crude implementation --- build-conflicts.php | 165 ++++++++++++++---- src/Roave/SecurityAdvisories/Advisory.php | 8 +- .../GetAdvisoriesFromFriendsOfPhp.php | 23 ++- .../GetAdvisoriesFromGithubApi.php | 15 +- src/Roave/SecurityAdvisories/Source.php | 24 +++ 5 files changed, 194 insertions(+), 41 deletions(-) create mode 100644 src/Roave/SecurityAdvisories/Source.php diff --git a/build-conflicts.php b/build-conflicts.php index 6425baeb..daf1b3b9 100644 --- a/build-conflicts.php +++ b/build-conflicts.php @@ -36,6 +36,7 @@ use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromMultipleSources; use Roave\SecurityAdvisories\Rule\RuleProviderFactory; +use function Psl\Type\array_key; use function set_error_handler; use const E_NOTICE; @@ -89,10 +90,11 @@ static function (int $errorCode, string $message = '', string $file = '', int $l $cloneRoaveAdvisories = static function () use ($roaveAdvisoriesRepository, $buildDir): void { Shell\execute('git', ['clone', $roaveAdvisoriesRepository, $buildDir . '/roave-security-advisories']); - Shell\execute( - 'cp', - ['-r', $buildDir . '/roave-security-advisories', $buildDir . '/roave-security-advisories-original'] - ); + // why do we need a copy ? +// Shell\execute( +// 'cp', +// ['-r', $buildDir . '/roave-security-advisories', $buildDir . '/roave-security-advisories-original'] +// ); }; $buildComponents = @@ -160,7 +162,7 @@ static function (array $components): array { Shell\execute('cp', [$sourceComposerJsonPath, $targetComposerJsonPath]); }; - $commitComposerJson = static function (string $composerJsonPath): void { + $commitComposerJson = static function (string $composerJsonPath, array $addedAdvisories): void { $originalHash = Shell\execute( 'git', ['rev-parse', 'HEAD'], @@ -178,20 +180,46 @@ static function (array $components): array { $message .= "\n" . Str\format( 'Original commit: "%s"', - 'https://github.com/FriendsOfPHP/security-advisories/commit/' . $originalHash + 'https://github.com/FriendsOfPHP/security-advisories/commit/' . $originalHash, ); - try { - Shell\execute('git', ['diff-index', '--quiet', 'HEAD'], $workingDirectory); - } catch (Shell\Exception\FailedExecutionException) { - Shell\execute('git', ['commit', '-m', $message], $workingDirectory); + if (count($addedAdvisories) > 0) { + $message .= "\n\nAdded advisories:"; + + foreach ($addedAdvisories as $advisory) { + $message .= "\n" . Str\format( + ' Package name: "%s"', + $advisory->package->packageName, + ); + $message .= "\n" . Str\format( + ' Summary: "%s"', + $advisory->source->summary, + ); + $message .= "\n" . Str\format( + ' URI: "%s"', + $advisory->source->uri, + ); + $message .= "\n"; + } + + $message .= "\n"; } + + print $message; + + + +// try { +// Shell\execute('git', ['diff-index', '--quiet', 'HEAD'], $workingDirectory); +// } catch (Shell\Exception\FailedExecutionException) { +// Shell\execute('git', ['commit', '-m', $message], $workingDirectory); +// } }; // cleanup: - $cleanBuildDir(); - $cloneAdvisories(); - $cloneRoaveAdvisories(); +// $cleanBuildDir(); +// $cloneAdvisories(); +// $cloneRoaveAdvisories(); $getAdvisories = new GetAdvisoriesAdvisoryRuleDecorator( (new GetAdvisoriesFromMultipleSources( @@ -204,24 +232,99 @@ static function (array $components): array { (new RuleProviderFactory())(), ); - // actual work: - $writeJson( - $buildConflictsJson( - $baseComposerJson, - $buildConflicts( - $buildComponents( - $getAdvisories() - ) - ) - ), - __DIR__ . '/build/composer.json' - ); - $validateComposerJson(__DIR__ . '/build/composer.json'); +// echo "iterating"; +// +// foreach ($getAdvisories() as $val ) { +// var_dump($val); +// } +// sleep(10); +// echo "Iterating"; +// - $copyGeneratedComposerJson( - __DIR__ . '/build/composer.json', - __DIR__ . '/build/roave-security-advisories/composer.json' - ); - $commitComposerJson(__DIR__ . '/build/roave-security-advisories/composer.json'); + $a = file_get_contents( __DIR__ . '/build/roave-security-advisories/composer.json'); + $foo = json_decode($a, true); + $prevConflicts = $foo['conflict']; + $oldConflictPackages = array_keys($prevConflicts); + + + $addedAdvisories = []; + foreach ($getAdvisories() as $val ) { + if (!in_array($val->package->packageName, $oldConflictPackages, true)) { + $addedAdvisories[] = $val; + } + } + + + + +// + + + // actual work: +// $writeJson( +// $buildConflictsJson( +// $baseComposerJson, +// $buildConflicts( +// $buildComponents( +// $getAdvisories() +// ) +// ) +// ), +// __DIR__ . '/build/composer.json' +// ); +// +// $validateComposerJson(__DIR__ . '/build/composer.json'); + +// $copyGeneratedComposerJson( +// __DIR__ . '/build/composer.json', +// __DIR__ . '/build/roave-security-advisories/composer.json' +// ); + + +// $a = file_get_contents( __DIR__ . '/build/roave-security-advisories/composer.json'); +// $foo = json_decode($a, true); +// $prevConflicts = $foo['conflict']; +//// foreach ($foo['conflict'] as $k => $v ) { +//// printf("%s %s \n", $k, $v); +//// } +// +// echo '----------------------------------------------------------------------------------------------------------'; +// +// $b = file_get_contents( __DIR__ . '/build/composer.json'); +// $bar = json_decode($b, true); +// $currConflicts = $bar['conflict']; +// foreach ($bar['conflict'] as $k => $v ) { +// printf("%s %s \n", $k, $v); +// } + + +// var_dump( array_diff_assoc($prevConflicts, $currConflicts)); +// var_dump(array_diff_key($bar['conflict'], $foo['conflict'])); +// var_dump(array_diff_key($foo['conflict'], $bar['conflict'])); +// var_dump($foo); + + // deleted in current + // "3f/pygmentize": "<1.2", + // updated in current + // "adodb/adodb-php": "<6.20.12", // <----- updated vrom 5. to 6. + + // compare by key against current + // shows what was deleted in current +// var_dump(array_diff_key($prevConflicts, $currConflicts)); + + // now try to get what value was changed in current +// var_dump(array_diff_assoc($prevConflicts, $currConflicts)); + + + + /* + * take two json files + * figure the diff what was deleted, what was appended, what is updated + * for each also show source and content + * + */ + + + $commitComposerJson(__DIR__ . '/build/roave-security-advisories/composer.json', $addedAdvisories);// pass here generated message })(); diff --git a/src/Roave/SecurityAdvisories/Advisory.php b/src/Roave/SecurityAdvisories/Advisory.php index 8d98eb6a..8ac24f48 100644 --- a/src/Roave/SecurityAdvisories/Advisory.php +++ b/src/Roave/SecurityAdvisories/Advisory.php @@ -33,11 +33,14 @@ final class Advisory /** @var list */ private array $branchConstraints; + public Source $source; + /** @param list $branchConstraints */ - private function __construct(PackageName $package, array $branchConstraints) + private function __construct(PackageName $package, array $branchConstraints, Source $source) { $this->package = $package; $this->branchConstraints = $this->sortVersionConstraints($branchConstraints); + $this->source = $source; } /** @@ -70,7 +73,8 @@ static function (array $branchConfig): VersionConstraint { return VersionConstraint::fromString(Str\join(Vec\values($versions), ',')); } - ) + ), + $config['source'], ); } diff --git a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php index d1f8241f..36592a99 100644 --- a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php +++ b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php @@ -32,8 +32,10 @@ use RecursiveIterator; use RecursiveIteratorIterator; use Roave\SecurityAdvisories\Advisory; +use Roave\SecurityAdvisories\Source; use SplFileInfo; use Symfony\Component\Yaml\Yaml; +use function Amp\Iterator\concat; final class GetAdvisoriesFromFriendsOfPhp implements GetAdvisories { @@ -57,12 +59,21 @@ static function (SplFileInfo $advisoryFile): Advisory { $filePath = Type\non_empty_string()->assert($advisoryFile->getRealPath()); $yaml = Filesystem\read_file($filePath); - $definition = Type\shape([ - 'branches' => Type\dict(Type\array_key(), Type\shape([ - 'versions' => Type\union(Type\string(), Type\vec(Type\string())), - ], true)), - 'reference' => Type\string(), - ], true)->assert(Yaml::parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE)); + try { + $definition = Type\shape([ + 'branches' => Type\dict(Type\array_key(), Type\shape([ + 'versions' => Type\union(Type\string(), Type\vec(Type\string())), + ], true)), + 'reference' => Type\string(), + 'title' => Type\string(), + 'link' => Type\string(), + ], true)->assert(Yaml::parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE)); + } catch (\Exception $e) { + $foo = Yaml::parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE); + var_dump($e, $foo); + } + + $definition['source'] = Type\object(Source::class)->assert(Source::New($definition['title'], $definition['link'])); return Advisory::fromArrayData($definition); }, diff --git a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php index bdab7304..47efce06 100644 --- a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php +++ b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php @@ -31,6 +31,7 @@ use Psr\Http\Message\RequestInterface; use Roave\SecurityAdvisories\Advisory; use Roave\SecurityAdvisories\Exception\InvalidPackageName; +use Roave\SecurityAdvisories\Source; final class GetAdvisoriesFromGithubApi implements GetAdvisories { @@ -45,6 +46,9 @@ final class GetAdvisoriesFromGithubApi implements GetAdvisories } advisory { withdrawnAt + ghsaId + permalink + summary } } } @@ -83,7 +87,9 @@ public function __invoke(): Generator $versions = Type\shape([0 => Type\non_empty_string(), 1 => Type\optional(Type\non_empty_string())]) ->assert(Str\split($item['node']['vulnerableVersionRange'], ',')); - if ($item['node']['advisory']['withdrawnAt'] !== null) { + + $advisory = $item['node']['advisory']; + if ($advisory['withdrawnAt'] !== null) { // Skip withdrawn advisories. continue; } @@ -93,6 +99,7 @@ public function __invoke(): Generator [ 'reference' => $item['node']['package']['name'], 'branches' => [['versions' => $versions]], + 'source'=> Source::New($advisory['summary'], $advisory['permalink']) ] ); } catch (InvalidPackageName) { @@ -135,7 +142,10 @@ private function getAdvisories(): iterable 'node' => Type\shape([ 'vulnerableVersionRange' => Type\string(), 'package' => Type\shape(['name' => Type\string()]), - 'advisory' => Type\shape(['withdrawnAt' => Type\nullable(Type\string())]), + 'advisory' => Type\shape([ + 'withdrawnAt' => Type\nullable(Type\string()), + 'permalink' => Type\nullable(Type\string()), + 'summary' => Type\string()]), // this is my title or better rename it to summary as well ]), ])), 'pageInfo' => Type\shape([ @@ -145,6 +155,7 @@ private function getAdvisories(): iterable ]), ]), ])); + $vulnerabilities = $data['data']['securityVulnerabilities']; yield from $vulnerabilities['edges']; diff --git a/src/Roave/SecurityAdvisories/Source.php b/src/Roave/SecurityAdvisories/Source.php new file mode 100644 index 00000000..71ad9965 --- /dev/null +++ b/src/Roave/SecurityAdvisories/Source.php @@ -0,0 +1,24 @@ +summary = $summary; + $this->uri = $uri; + } + + public static function New(string $summary, string $uri): self + { + return new self($summary, $uri); + } +} + + + From b4069af0502e75b02a9bc8f9611db1c629af7c43 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Sun, 21 Nov 2021 21:02:13 +0200 Subject: [PATCH 02/25] stuck with PSL, Psalm and.. everything --- build-conflicts.php | 175 ++++++------------ src/Roave/SecurityAdvisories/Advisory.php | 13 +- .../GetAdvisoriesFromFriendsOfPhp.php | 25 +-- .../GetAdvisoriesFromGithubApi.php | 18 +- src/Roave/SecurityAdvisories/Source.php | 24 ++- 5 files changed, 104 insertions(+), 151 deletions(-) diff --git a/build-conflicts.php b/build-conflicts.php index daf1b3b9..df6808c1 100644 --- a/build-conflicts.php +++ b/build-conflicts.php @@ -36,7 +36,11 @@ use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromMultipleSources; use Roave\SecurityAdvisories\Rule\RuleProviderFactory; -use function Psl\Type\array_key; +use function array_keys; +use function count; +use function file_get_contents; +use function in_array; +use function json_decode; use function set_error_handler; use const E_NOTICE; @@ -90,11 +94,10 @@ static function (int $errorCode, string $message = '', string $file = '', int $l $cloneRoaveAdvisories = static function () use ($roaveAdvisoriesRepository, $buildDir): void { Shell\execute('git', ['clone', $roaveAdvisoriesRepository, $buildDir . '/roave-security-advisories']); - // why do we need a copy ? -// Shell\execute( -// 'cp', -// ['-r', $buildDir . '/roave-security-advisories', $buildDir . '/roave-security-advisories-original'] -// ); + Shell\execute( + 'cp', + ['-r', $buildDir . '/roave-security-advisories', $buildDir . '/roave-security-advisories-original'] + ); }; $buildComponents = @@ -183,23 +186,18 @@ static function (array $components): array { 'https://github.com/FriendsOfPHP/security-advisories/commit/' . $originalHash, ); - if (count($addedAdvisories) > 0) { - $message .= "\n\nAdded advisories:"; + if (count($addedAdvisories) === 0) { + $message .= "\n\nNo new security advisories were added"; + } else { + $message .= "\n\nNew security advisories added:"; foreach ($addedAdvisories as $advisory) { - $message .= "\n" . Str\format( - ' Package name: "%s"', - $advisory->package->packageName, - ); - $message .= "\n" . Str\format( - ' Summary: "%s"', - $advisory->source->summary, - ); - $message .= "\n" . Str\format( - ' URI: "%s"', - $advisory->source->uri, - ); - $message .= "\n"; + $message .= Str\format( + "\n\tPackage name: %s\n\tSummary: %s\n\tURI: %s\n", + $advisory->package->packageName, + $advisory->source->summary, + $advisory->source->uri, + ); } $message .= "\n"; @@ -207,19 +205,17 @@ static function (array $components): array { print $message; - - -// try { -// Shell\execute('git', ['diff-index', '--quiet', 'HEAD'], $workingDirectory); -// } catch (Shell\Exception\FailedExecutionException) { -// Shell\execute('git', ['commit', '-m', $message], $workingDirectory); -// } + try { + Shell\execute('git', ['diff-index', '--quiet', 'HEAD'], $workingDirectory); + } catch (Shell\Exception\FailedExecutionException) { + Shell\execute('git', ['commit', '-m', $message], $workingDirectory); + } }; // cleanup: -// $cleanBuildDir(); -// $cloneAdvisories(); -// $cloneRoaveAdvisories(); + $cleanBuildDir(); + $cloneAdvisories(); + $cloneRoaveAdvisories(); $getAdvisories = new GetAdvisoriesAdvisoryRuleDecorator( (new GetAdvisoriesFromMultipleSources( @@ -232,99 +228,42 @@ static function (array $components): array { (new RuleProviderFactory())(), ); + $prevComposerJSONFileData = file_get_contents(__DIR__ . '/build/roave-security-advisories/composer.json'); + $prevComposerDecodedData = json_decode($prevComposerJSONFileData, true); + $oldConflictPackages = array_keys($prevComposerDecodedData['conflict']); -// echo "iterating"; -// -// foreach ($getAdvisories() as $val ) { -// var_dump($val); -// } -// sleep(10); -// echo "Iterating"; -// - - $a = file_get_contents( __DIR__ . '/build/roave-security-advisories/composer.json'); - $foo = json_decode($a, true); - $prevConflicts = $foo['conflict']; - $oldConflictPackages = array_keys($prevConflicts); - - +// /** @var list $addedAdvisories */ + /** + * @psalm-param $addedAdvisories Advisory + */ $addedAdvisories = []; - foreach ($getAdvisories() as $val ) { - if (!in_array($val->package->packageName, $oldConflictPackages, true)) { - $addedAdvisories[] = $val; + foreach ($getAdvisories() as $advisory) { + if (in_array($advisory->package->packageName, $oldConflictPackages, true)) { + continue; } - } - - - - -// + $addedAdvisories[] = $advisory; + } // actual work: -// $writeJson( -// $buildConflictsJson( -// $baseComposerJson, -// $buildConflicts( -// $buildComponents( -// $getAdvisories() -// ) -// ) -// ), -// __DIR__ . '/build/composer.json' -// ); -// -// $validateComposerJson(__DIR__ . '/build/composer.json'); - -// $copyGeneratedComposerJson( -// __DIR__ . '/build/composer.json', -// __DIR__ . '/build/roave-security-advisories/composer.json' -// ); - - -// $a = file_get_contents( __DIR__ . '/build/roave-security-advisories/composer.json'); -// $foo = json_decode($a, true); -// $prevConflicts = $foo['conflict']; -//// foreach ($foo['conflict'] as $k => $v ) { -//// printf("%s %s \n", $k, $v); -//// } -// -// echo '----------------------------------------------------------------------------------------------------------'; -// -// $b = file_get_contents( __DIR__ . '/build/composer.json'); -// $bar = json_decode($b, true); -// $currConflicts = $bar['conflict']; -// foreach ($bar['conflict'] as $k => $v ) { -// printf("%s %s \n", $k, $v); -// } - - -// var_dump( array_diff_assoc($prevConflicts, $currConflicts)); -// var_dump(array_diff_key($bar['conflict'], $foo['conflict'])); -// var_dump(array_diff_key($foo['conflict'], $bar['conflict'])); -// var_dump($foo); - - // deleted in current - // "3f/pygmentize": "<1.2", - // updated in current - // "adodb/adodb-php": "<6.20.12", // <----- updated vrom 5. to 6. - - // compare by key against current - // shows what was deleted in current -// var_dump(array_diff_key($prevConflicts, $currConflicts)); - - // now try to get what value was changed in current -// var_dump(array_diff_assoc($prevConflicts, $currConflicts)); - - - - /* - * take two json files - * figure the diff what was deleted, what was appended, what is updated - * for each also show source and content - * - */ + $writeJson( + $buildConflictsJson( + $baseComposerJson, + $buildConflicts( + $buildComponents( + $getAdvisories() + ) + ) + ), + __DIR__ . '/build/composer.json' + ); + $validateComposerJson(__DIR__ . '/build/composer.json'); + + $copyGeneratedComposerJson( + __DIR__ . '/build/composer.json', + __DIR__ . '/build/roave-security-advisories/composer.json' + ); - $commitComposerJson(__DIR__ . '/build/roave-security-advisories/composer.json', $addedAdvisories);// pass here generated message + $commitComposerJson(__DIR__ . '/build/roave-security-advisories/composer.json', $addedAdvisories); })(); diff --git a/src/Roave/SecurityAdvisories/Advisory.php b/src/Roave/SecurityAdvisories/Advisory.php index 8ac24f48..382adabb 100644 --- a/src/Roave/SecurityAdvisories/Advisory.php +++ b/src/Roave/SecurityAdvisories/Advisory.php @@ -33,20 +33,25 @@ final class Advisory /** @var list */ private array $branchConstraints; + /** @var Source $source */ public Source $source; - /** @param list $branchConstraints */ + /** + * @param PackageName $package + * @param list $branchConstraints + * @param Source $source + */ private function __construct(PackageName $package, array $branchConstraints, Source $source) { $this->package = $package; $this->branchConstraints = $this->sortVersionConstraints($branchConstraints); - $this->source = $source; + $this->source = $source; } /** * @psalm-param array{ * branches: array}>, - * reference: string + * reference: string, * } $config * * @return Advisory @@ -74,7 +79,7 @@ static function (array $branchConfig): VersionConstraint { return VersionConstraint::fromString(Str\join(Vec\values($versions), ',')); } ), - $config['source'], + Type\object(Source::class)->assert($config['source']), ); } diff --git a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php index 36592a99..7228d91d 100644 --- a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php +++ b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php @@ -35,7 +35,6 @@ use Roave\SecurityAdvisories\Source; use SplFileInfo; use Symfony\Component\Yaml\Yaml; -use function Amp\Iterator\concat; final class GetAdvisoriesFromFriendsOfPhp implements GetAdvisories { @@ -59,21 +58,17 @@ static function (SplFileInfo $advisoryFile): Advisory { $filePath = Type\non_empty_string()->assert($advisoryFile->getRealPath()); $yaml = Filesystem\read_file($filePath); - try { - $definition = Type\shape([ - 'branches' => Type\dict(Type\array_key(), Type\shape([ - 'versions' => Type\union(Type\string(), Type\vec(Type\string())), - ], true)), - 'reference' => Type\string(), - 'title' => Type\string(), - 'link' => Type\string(), - ], true)->assert(Yaml::parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE)); - } catch (\Exception $e) { - $foo = Yaml::parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE); - var_dump($e, $foo); - } + $definition = Type\shape([ + 'branches' => Type\dict(Type\array_key(), Type\shape([ + 'versions' => Type\union(Type\string(), Type\vec(Type\string())), + ], true)), + 'reference' => Type\string(), + 'title' => Type\string(), + 'link' => Type\string(), + ], true)->assert(Yaml::parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE)); - $definition['source'] = Type\object(Source::class)->assert(Source::New($definition['title'], $definition['link'])); + $definition['source'] = + Type\object(Source::class)->assert(Source::new($definition['title'], $definition['link'])); return Advisory::fromArrayData($definition); }, diff --git a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php index 47efce06..8b098b17 100644 --- a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php +++ b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php @@ -87,7 +87,6 @@ public function __invoke(): Generator $versions = Type\shape([0 => Type\non_empty_string(), 1 => Type\optional(Type\non_empty_string())]) ->assert(Str\split($item['node']['vulnerableVersionRange'], ',')); - $advisory = $item['node']['advisory']; if ($advisory['withdrawnAt'] !== null) { // Skip withdrawn advisories. @@ -99,7 +98,7 @@ public function __invoke(): Generator [ 'reference' => $item['node']['package']['name'], 'branches' => [['versions' => $versions]], - 'source'=> Source::New($advisory['summary'], $advisory['permalink']) + 'source' => Source::new($advisory['summary'], $advisory['permalink']), ] ); } catch (InvalidPackageName) { @@ -122,7 +121,11 @@ public function __invoke(): Generator * node: array{ * vulnerableVersionRange: string, * package: array{name: string}, - * advisory: array{withdrawnAt: string|null} + * advisory: array{ + * withdrawnAt: string|null, + * permalink: string, + * summary: string, + * } * } * }> * @@ -133,8 +136,8 @@ private function getAdvisories(): iterable $cursor = ''; do { - $response = $this->client->sendRequest($this->getRequest($cursor)); - $data = Json\typed($response->getBody()->__toString(), Type\shape([ + $response = $this->client->sendRequest($this->getRequest($cursor)); + $data = Json\typed($response->getBody()->__toString(), Type\shape([ 'data' => Type\shape([ 'securityVulnerabilities' => Type\shape([ 'edges' => Type\dict(Type\int(), Type\shape([ @@ -144,8 +147,9 @@ private function getAdvisories(): iterable 'package' => Type\shape(['name' => Type\string()]), 'advisory' => Type\shape([ 'withdrawnAt' => Type\nullable(Type\string()), - 'permalink' => Type\nullable(Type\string()), - 'summary' => Type\string()]), // this is my title or better rename it to summary as well + 'permalink' => Type\string(), + 'summary' => Type\string(), + ]), ]), ])), 'pageInfo' => Type\shape([ diff --git a/src/Roave/SecurityAdvisories/Source.php b/src/Roave/SecurityAdvisories/Source.php index 71ad9965..ec37ad07 100644 --- a/src/Roave/SecurityAdvisories/Source.php +++ b/src/Roave/SecurityAdvisories/Source.php @@ -1,24 +1,34 @@ summary = $summary; - $this->uri = $uri; + $this->uri = $uri; } - public static function New(string $summary, string $uri): self + /** + */ + public static function new(string $summary, string $uri): self { - return new self($summary, $uri); + return new self(Type\non_empty_string()->assert($summary), Type\non_empty_string()->assert($uri)); } } - - - From c21c6d777202799cd9b36fe10744576f85072fa1 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Mon, 22 Nov 2021 21:32:23 +0200 Subject: [PATCH 03/25] friends of php test is fixed --- .../AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php | 3 +-- .../AdvisorySources/GetAdvisoriesFromFriendsOfPhpTest.php | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php index 7228d91d..64466d7e 100644 --- a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php +++ b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php @@ -67,8 +67,7 @@ static function (SplFileInfo $advisoryFile): Advisory { 'link' => Type\string(), ], true)->assert(Yaml::parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE)); - $definition['source'] = - Type\object(Source::class)->assert(Source::new($definition['title'], $definition['link'])); + $definition['source'] = ['summary' => $definition['title'], 'link' => $definition['link']]; return Advisory::fromArrayData($definition); }, diff --git a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhpTest.php b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhpTest.php index 942607b5..070fc8bc 100644 --- a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhpTest.php +++ b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhpTest.php @@ -42,6 +42,10 @@ public function testThatAdvisoriesAreBuiltFromYamlFiles(): void ], ], 'reference' => 'composer://3f/pygmentize', + 'source' => [ + 'summary' => 'Remote Code Execution', + 'link' => 'https://github.com/dedalozzo/pygmentize/issues/1', + ] ]), ], Vec\values($advisories)); } From 6e7fcda68b78b45b2f43f2c7a447eabfbad97908 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Mon, 22 Nov 2021 21:34:59 +0200 Subject: [PATCH 04/25] components fixed --- test/RoaveTest/SecurityAdvisories/ComponentTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/RoaveTest/SecurityAdvisories/ComponentTest.php b/test/RoaveTest/SecurityAdvisories/ComponentTest.php index a879b13c..1291c4bf 100644 --- a/test/RoaveTest/SecurityAdvisories/ComponentTest.php +++ b/test/RoaveTest/SecurityAdvisories/ComponentTest.php @@ -44,6 +44,7 @@ public function testFromMultipleAdvisories(): void 'versions' => ['>=2.0-beta.1.1', '<2.1-beta.1.1'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $advisory2 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -55,6 +56,7 @@ public function testFromMultipleAdvisories(): void 'versions' => ['>=4.0-beta.1.1', '<4.1-beta.1.1'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2); @@ -77,6 +79,7 @@ public function testDeDuplicatesOverlappingAdvisories(): void 'versions' => ['>=2.0', '<2.1'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $advisory2 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -94,6 +97,7 @@ public function testDeDuplicatesOverlappingAdvisories(): void 'versions' => ['>=3.0', '<3.1'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $advisory3 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -103,6 +107,7 @@ public function testDeDuplicatesOverlappingAdvisories(): void 'versions' => ['>=3.0.1', '<3.0.99'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2, $advisory3); @@ -123,6 +128,7 @@ public function testDeDuplicatesOverlappingComplexAdvisories(): void 'versions' => ['>=2.0-rc', '<2.1-p'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $advisory2 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -140,6 +146,7 @@ public function testDeDuplicatesOverlappingComplexAdvisories(): void 'versions' => ['>=3.0-stable.5', '<3.1'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $advisory3 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -149,6 +156,7 @@ public function testDeDuplicatesOverlappingComplexAdvisories(): void 'versions' => ['>=3.0.1', '<3.0.99'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2, $advisory3); @@ -167,6 +175,7 @@ public function testSortAdvisoriesWithRealCase(): void 'versions' => ['>=3.1.0', '<=3.1.9'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $advisory2 = clone $advisory1; $advisory3 = Advisory::fromArrayData([ @@ -179,6 +188,7 @@ public function testSortAdvisoriesWithRealCase(): void 'versions' => ['>=3.1.0', '<3.1.11'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2, $advisory3); @@ -203,11 +213,13 @@ public function testSortComplexAdvisoriesWithRealCase( $advisory1 = Advisory::fromArrayData([ 'reference' => $reference, 'branches' => $advisory1Branches, + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $advisory2 = clone $advisory1; $advisory3 = Advisory::fromArrayData([ 'reference' => $reference, 'branches' => $advisory2Branches, + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2, $advisory3); From 03034c04e87cbfc672428ea91ab71c7e041a014b Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Mon, 22 Nov 2021 21:35:26 +0200 Subject: [PATCH 05/25] advisory tests fixes --- test/RoaveTest/SecurityAdvisories/AdvisoryTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/RoaveTest/SecurityAdvisories/AdvisoryTest.php b/test/RoaveTest/SecurityAdvisories/AdvisoryTest.php index 6ae9cd5e..18e8fc66 100644 --- a/test/RoaveTest/SecurityAdvisories/AdvisoryTest.php +++ b/test/RoaveTest/SecurityAdvisories/AdvisoryTest.php @@ -43,6 +43,7 @@ public function testFromArrayWithValidConfig(): void 'versions' => ['>=2.0', '<2.1'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -67,6 +68,7 @@ public function testFromArrayWithComplexValidConfig(): void 'versions' => ['>=2.0-rc.5', '<2.1-rc.6'], ], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -87,6 +89,7 @@ public function testFromArrayWithStringVersion(): void '1.0.x' => ['versions' => '<1.1'], '2.0.x' => ['versions' => '<2.1'], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -107,6 +110,7 @@ public function testFromArrayWithComplexStringVersion(): void '1.0.x' => ['versions' => '<1.1-beta.0.1'], '2.0.x' => ['versions' => '<2.1-beta.0.1'], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -124,6 +128,7 @@ public function testFromArrayWithWrongPackageName(): void $advisory = Advisory::fromArrayData([ 'reference' => 'composer://foo\bar', 'branches' => [], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -146,6 +151,7 @@ public function testFromArrayGeneratesSortedResult( '2.0.x' => ['versions' => $versionConstraint2], '1.0.x' => ['versions' => $versionConstraint1], ], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); self::assertSame($expected, $advisory->getConstraint()); From 4271453026560d150735c9a536a768a0c0f95d00 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Mon, 22 Nov 2021 21:36:17 +0200 Subject: [PATCH 06/25] multiple sources fix --- .../AdvisorySources/GetAdvisoriesFromMultipleSourcesTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromMultipleSourcesTest.php b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromMultipleSourcesTest.php index 71e70cdb..e768ef07 100644 --- a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromMultipleSourcesTest.php +++ b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromMultipleSourcesTest.php @@ -44,6 +44,7 @@ public function testMultipleAdvisoriesSources(): void Advisory::fromArrayData([ 'reference' => 'test/package', 'branches' => [['versions' => ['<1']]], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]), ], Vec\values($advisories()) @@ -55,6 +56,7 @@ private function getGenerator(): Generator return yield Advisory::fromArrayData([ 'reference' => 'test/package', 'branches' => [['versions' => ['<1']]], + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] ]); } } From f35e7002fe140c1d91abf28db609195da089a9ec Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Mon, 22 Nov 2021 21:46:26 +0200 Subject: [PATCH 07/25] fuck yes! unit tests are no longer broken --- .../GetAdvisoriesFromGithubApiTest.php | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApiTest.php b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApiTest.php index be82c626..8cf61848 100644 --- a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApiTest.php +++ b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApiTest.php @@ -98,10 +98,12 @@ public function testGithubAdvisoriesIsAbleToProduceAdvisories(array $apiResponse Advisory::fromArrayData([ 'reference' => 'enshrined/svg-sanitize', 'branches' => [['versions' => ['> 0.12.0, < 0.12.1 ']]], + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] ]), Advisory::fromArrayData([ 'reference' => 'foo/bar', 'branches' => [['versions' => ['> 1.2.3, < 4.5.6 ']]], + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] ]), ], Vec\values($advisories()) @@ -152,7 +154,9 @@ public function correctResponsesSequenceDataProvider(): array "name": "enshrined/svg-sanitize" }, "advisory": { - "withdrawnAt": null + "withdrawnAt": null, + "summary": "some summary", + "permalink": "https://example.com" } } }, @@ -164,7 +168,9 @@ public function correctResponsesSequenceDataProvider(): array "name": "foo/bar" }, "advisory": { - "withdrawnAt": null + "withdrawnAt": null, + "summary": "some summary", + "permalink": "https://example.com" } } } @@ -222,10 +228,12 @@ public function testWillSkipAdvisoriesWithMalformedNames(ResponseInterface ...$r Advisory::fromArrayData([ 'reference' => 'aa/bb', 'branches' => [['versions' => ['> 0.12.0, < 0.12.1 ']]], + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] ]), Advisory::fromArrayData([ 'reference' => 'dd/ee', 'branches' => [['versions' => ['> 1.2.3, < 4.5.6 ']]], + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] ]), ], Vec\values($advisories()) @@ -250,6 +258,7 @@ public function testWillSkipWithdrawnAdvisories(ResponseInterface ...$responses) Advisory::fromArrayData([ 'reference' => 'aa/bb', 'branches' => [['versions' => ['<= 1.1.0']]], + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] ]), ], Vec\Values($advisories())); } @@ -271,7 +280,9 @@ public function correctResponsesWithInvalidAdvisoryNames(): array "name": "aa/bb" }, "advisory": { - "withdrawnAt": null + "withdrawnAt": null, + "summary": "some summary", + "permalink": "https://example.com" } } }, @@ -283,7 +294,9 @@ public function correctResponsesWithInvalidAdvisoryNames(): array "name": "cc" }, "advisory": { - "withdrawnAt": null + "withdrawnAt": null, + "summary": "some summary", + "permalink": "https://example.com" } } }, @@ -295,7 +308,9 @@ public function correctResponsesWithInvalidAdvisoryNames(): array "name": "dd/ee" }, "advisory": { - "withdrawnAt": null + "withdrawnAt": null, + "summary": "some summary", + "permalink": "https://example.com" } } } @@ -350,7 +365,9 @@ public function responsesWithIncorrectRangesProvider(): array "name": "enshrined/svg-sanitize" }, "advisory": { - "withdrawnAt": null + "withdrawnAt": null, + "summary": "some summary", + "permalink": "https://example.com" } } } @@ -396,7 +413,9 @@ public function correctResponseWithWithdrawnAdvisories(): array "name": "aa/bb" }, "advisory": { - "withdrawnAt": "2021-11-17T15:54:51Z" + "withdrawnAt": "2021-11-17T15:54:51Z", + "summary": "some summary", + "permalink": "https://example.com" } } }, @@ -408,7 +427,9 @@ public function correctResponseWithWithdrawnAdvisories(): array "name": "aa/bb" }, "advisory": { - "withdrawnAt": null + "withdrawnAt": null, + "summary": "some summary", + "permalink": "https://example.com" } } } From a89685bb464a98c5eb49f40dea63180836281e0b Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Mon, 22 Nov 2021 21:46:57 +0200 Subject: [PATCH 08/25] some polishing ftw --- src/Roave/SecurityAdvisories/Advisory.php | 3 ++- .../AdvisorySources/GetAdvisoriesFromGithubApi.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Roave/SecurityAdvisories/Advisory.php b/src/Roave/SecurityAdvisories/Advisory.php index 382adabb..aa551a69 100644 --- a/src/Roave/SecurityAdvisories/Advisory.php +++ b/src/Roave/SecurityAdvisories/Advisory.php @@ -52,6 +52,7 @@ private function __construct(PackageName $package, array $branchConstraints, Sou * @psalm-param array{ * branches: array}>, * reference: string, + * source: array{summary: string, link:string}, * } $config * * @return Advisory @@ -79,7 +80,7 @@ static function (array $branchConfig): VersionConstraint { return VersionConstraint::fromString(Str\join(Vec\values($versions), ',')); } ), - Type\object(Source::class)->assert($config['source']), + Source::new($config['source']['summary'], $config['source']['link']), ); } diff --git a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php index 8b098b17..82f10b72 100644 --- a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php +++ b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php @@ -98,7 +98,7 @@ public function __invoke(): Generator [ 'reference' => $item['node']['package']['name'], 'branches' => [['versions' => $versions]], - 'source' => Source::new($advisory['summary'], $advisory['permalink']), + 'source' => ['summary' => $advisory['summary'], 'link' => $advisory['permalink']], ] ); } catch (InvalidPackageName) { From 3f0c1cbc5e8b327aababe7d2a89fd477c5eee118 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Mon, 22 Nov 2021 22:12:58 +0200 Subject: [PATCH 09/25] phpcs automatic fixes --- src/Roave/SecurityAdvisories/Advisory.php | 3 --- .../GetAdvisoriesFromFriendsOfPhp.php | 1 - .../GetAdvisoriesFromGithubApi.php | 1 - src/Roave/SecurityAdvisories/Source.php | 2 -- .../GetAdvisoriesFromFriendsOfPhpTest.php | 2 +- .../GetAdvisoriesFromGithubApiTest.php | 10 ++++---- .../GetAdvisoriesFromMultipleSourcesTest.php | 4 ++-- .../SecurityAdvisories/AdvisoryTest.php | 12 +++++----- .../SecurityAdvisories/ComponentTest.php | 24 +++++++++---------- 9 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/Roave/SecurityAdvisories/Advisory.php b/src/Roave/SecurityAdvisories/Advisory.php index aa551a69..72048b1d 100644 --- a/src/Roave/SecurityAdvisories/Advisory.php +++ b/src/Roave/SecurityAdvisories/Advisory.php @@ -33,13 +33,10 @@ final class Advisory /** @var list */ private array $branchConstraints; - /** @var Source $source */ public Source $source; /** - * @param PackageName $package * @param list $branchConstraints - * @param Source $source */ private function __construct(PackageName $package, array $branchConstraints, Source $source) { diff --git a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php index 64466d7e..a8bc4cb3 100644 --- a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php +++ b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhp.php @@ -32,7 +32,6 @@ use RecursiveIterator; use RecursiveIteratorIterator; use Roave\SecurityAdvisories\Advisory; -use Roave\SecurityAdvisories\Source; use SplFileInfo; use Symfony\Component\Yaml\Yaml; diff --git a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php index 82f10b72..e5170bc1 100644 --- a/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php +++ b/src/Roave/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApi.php @@ -31,7 +31,6 @@ use Psr\Http\Message\RequestInterface; use Roave\SecurityAdvisories\Advisory; use Roave\SecurityAdvisories\Exception\InvalidPackageName; -use Roave\SecurityAdvisories\Source; final class GetAdvisoriesFromGithubApi implements GetAdvisories { diff --git a/src/Roave/SecurityAdvisories/Source.php b/src/Roave/SecurityAdvisories/Source.php index ec37ad07..89ebf418 100644 --- a/src/Roave/SecurityAdvisories/Source.php +++ b/src/Roave/SecurityAdvisories/Source.php @@ -25,8 +25,6 @@ private function __construct(string $summary, string $uri) $this->uri = $uri; } - /** - */ public static function new(string $summary, string $uri): self { return new self(Type\non_empty_string()->assert($summary), Type\non_empty_string()->assert($uri)); diff --git a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhpTest.php b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhpTest.php index 070fc8bc..5802d187 100644 --- a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhpTest.php +++ b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromFriendsOfPhpTest.php @@ -45,7 +45,7 @@ public function testThatAdvisoriesAreBuiltFromYamlFiles(): void 'source' => [ 'summary' => 'Remote Code Execution', 'link' => 'https://github.com/dedalozzo/pygmentize/issues/1', - ] + ], ]), ], Vec\values($advisories)); } diff --git a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApiTest.php b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApiTest.php index 8cf61848..84146d50 100644 --- a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApiTest.php +++ b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromGithubApiTest.php @@ -98,12 +98,12 @@ public function testGithubAdvisoriesIsAbleToProduceAdvisories(array $apiResponse Advisory::fromArrayData([ 'reference' => 'enshrined/svg-sanitize', 'branches' => [['versions' => ['> 0.12.0, < 0.12.1 ']]], - 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'], ]), Advisory::fromArrayData([ 'reference' => 'foo/bar', 'branches' => [['versions' => ['> 1.2.3, < 4.5.6 ']]], - 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'], ]), ], Vec\values($advisories()) @@ -228,12 +228,12 @@ public function testWillSkipAdvisoriesWithMalformedNames(ResponseInterface ...$r Advisory::fromArrayData([ 'reference' => 'aa/bb', 'branches' => [['versions' => ['> 0.12.0, < 0.12.1 ']]], - 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'], ]), Advisory::fromArrayData([ 'reference' => 'dd/ee', 'branches' => [['versions' => ['> 1.2.3, < 4.5.6 ']]], - 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'], ]), ], Vec\values($advisories()) @@ -258,7 +258,7 @@ public function testWillSkipWithdrawnAdvisories(ResponseInterface ...$responses) Advisory::fromArrayData([ 'reference' => 'aa/bb', 'branches' => [['versions' => ['<= 1.1.0']]], - 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some summary', 'link' => 'https://example.com'], ]), ], Vec\Values($advisories())); } diff --git a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromMultipleSourcesTest.php b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromMultipleSourcesTest.php index e768ef07..11d03e2b 100644 --- a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromMultipleSourcesTest.php +++ b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesFromMultipleSourcesTest.php @@ -44,7 +44,7 @@ public function testMultipleAdvisoriesSources(): void Advisory::fromArrayData([ 'reference' => 'test/package', 'branches' => [['versions' => ['<1']]], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]), ], Vec\values($advisories()) @@ -56,7 +56,7 @@ private function getGenerator(): Generator return yield Advisory::fromArrayData([ 'reference' => 'test/package', 'branches' => [['versions' => ['<1']]], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); } } diff --git a/test/RoaveTest/SecurityAdvisories/AdvisoryTest.php b/test/RoaveTest/SecurityAdvisories/AdvisoryTest.php index 18e8fc66..f517ed43 100644 --- a/test/RoaveTest/SecurityAdvisories/AdvisoryTest.php +++ b/test/RoaveTest/SecurityAdvisories/AdvisoryTest.php @@ -43,7 +43,7 @@ public function testFromArrayWithValidConfig(): void 'versions' => ['>=2.0', '<2.1'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -68,7 +68,7 @@ public function testFromArrayWithComplexValidConfig(): void 'versions' => ['>=2.0-rc.5', '<2.1-rc.6'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -89,7 +89,7 @@ public function testFromArrayWithStringVersion(): void '1.0.x' => ['versions' => '<1.1'], '2.0.x' => ['versions' => '<2.1'], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -110,7 +110,7 @@ public function testFromArrayWithComplexStringVersion(): void '1.0.x' => ['versions' => '<1.1-beta.0.1'], '2.0.x' => ['versions' => '<2.1-beta.0.1'], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -128,7 +128,7 @@ public function testFromArrayWithWrongPackageName(): void $advisory = Advisory::fromArrayData([ 'reference' => 'composer://foo\bar', 'branches' => [], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); self::assertEquals(PackageName::fromName('foo/bar'), $advisory->package); @@ -151,7 +151,7 @@ public function testFromArrayGeneratesSortedResult( '2.0.x' => ['versions' => $versionConstraint2], '1.0.x' => ['versions' => $versionConstraint1], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); self::assertSame($expected, $advisory->getConstraint()); diff --git a/test/RoaveTest/SecurityAdvisories/ComponentTest.php b/test/RoaveTest/SecurityAdvisories/ComponentTest.php index 1291c4bf..8686dd97 100644 --- a/test/RoaveTest/SecurityAdvisories/ComponentTest.php +++ b/test/RoaveTest/SecurityAdvisories/ComponentTest.php @@ -44,7 +44,7 @@ public function testFromMultipleAdvisories(): void 'versions' => ['>=2.0-beta.1.1', '<2.1-beta.1.1'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $advisory2 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -56,7 +56,7 @@ public function testFromMultipleAdvisories(): void 'versions' => ['>=4.0-beta.1.1', '<4.1-beta.1.1'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2); @@ -79,7 +79,7 @@ public function testDeDuplicatesOverlappingAdvisories(): void 'versions' => ['>=2.0', '<2.1'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $advisory2 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -97,7 +97,7 @@ public function testDeDuplicatesOverlappingAdvisories(): void 'versions' => ['>=3.0', '<3.1'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $advisory3 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -107,7 +107,7 @@ public function testDeDuplicatesOverlappingAdvisories(): void 'versions' => ['>=3.0.1', '<3.0.99'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2, $advisory3); @@ -128,7 +128,7 @@ public function testDeDuplicatesOverlappingComplexAdvisories(): void 'versions' => ['>=2.0-rc', '<2.1-p'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $advisory2 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -146,7 +146,7 @@ public function testDeDuplicatesOverlappingComplexAdvisories(): void 'versions' => ['>=3.0-stable.5', '<3.1'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $advisory3 = Advisory::fromArrayData([ 'reference' => 'composer://foo/bar', @@ -156,7 +156,7 @@ public function testDeDuplicatesOverlappingComplexAdvisories(): void 'versions' => ['>=3.0.1', '<3.0.99'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2, $advisory3); @@ -175,7 +175,7 @@ public function testSortAdvisoriesWithRealCase(): void 'versions' => ['>=3.1.0', '<=3.1.9'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $advisory2 = clone $advisory1; $advisory3 = Advisory::fromArrayData([ @@ -188,7 +188,7 @@ public function testSortAdvisoriesWithRealCase(): void 'versions' => ['>=3.1.0', '<3.1.11'], ], ], - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2, $advisory3); @@ -213,13 +213,13 @@ public function testSortComplexAdvisoriesWithRealCase( $advisory1 = Advisory::fromArrayData([ 'reference' => $reference, 'branches' => $advisory1Branches, - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $advisory2 = clone $advisory1; $advisory3 = Advisory::fromArrayData([ 'reference' => $reference, 'branches' => $advisory2Branches, - 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'] + 'source' => ['summary' => 'some vulnerability', 'link' => 'https://example.com'], ]); $component = new Component(PackageName::fromName('foo/bar'), $advisory1, $advisory2, $advisory3); From fcb9dda4f88a144556c07477b455e0244928d8ff Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Mon, 22 Nov 2021 23:08:49 +0200 Subject: [PATCH 10/25] a bit stuck --- build-conflicts.php | 12 ++++++++---- src/Roave/SecurityAdvisories/Advisory.php | 2 ++ src/Roave/SecurityAdvisories/Source.php | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/build-conflicts.php b/build-conflicts.php index df6808c1..3da68789 100644 --- a/build-conflicts.php +++ b/build-conflicts.php @@ -165,6 +165,9 @@ static function (array $components): array { Shell\execute('cp', [$sourceComposerJsonPath, $targetComposerJsonPath]); }; + /** + * @psalm-suppress MixedAssignment + */ $commitComposerJson = static function (string $composerJsonPath, array $addedAdvisories): void { $originalHash = Shell\execute( 'git', @@ -229,13 +232,14 @@ static function (array $components): array { ); $prevComposerJSONFileData = file_get_contents(__DIR__ . '/build/roave-security-advisories/composer.json'); + + /** @var array $prevComposerDecodedData + */ $prevComposerDecodedData = json_decode($prevComposerJSONFileData, true); + + /** @var array $oldConflictPackages */ $oldConflictPackages = array_keys($prevComposerDecodedData['conflict']); -// /** @var list $addedAdvisories */ - /** - * @psalm-param $addedAdvisories Advisory - */ $addedAdvisories = []; foreach ($getAdvisories() as $advisory) { if (in_array($advisory->package->packageName, $oldConflictPackages, true)) { diff --git a/src/Roave/SecurityAdvisories/Advisory.php b/src/Roave/SecurityAdvisories/Advisory.php index 72048b1d..0419c59c 100644 --- a/src/Roave/SecurityAdvisories/Advisory.php +++ b/src/Roave/SecurityAdvisories/Advisory.php @@ -28,11 +28,13 @@ /** @psalm-immutable */ final class Advisory { + /** @var PackageName */ public PackageName $package; /** @var list */ private array $branchConstraints; + /** @var Source */ public Source $source; /** diff --git a/src/Roave/SecurityAdvisories/Source.php b/src/Roave/SecurityAdvisories/Source.php index 89ebf418..998d4909 100644 --- a/src/Roave/SecurityAdvisories/Source.php +++ b/src/Roave/SecurityAdvisories/Source.php @@ -9,10 +9,10 @@ final class Source { - /** @var non-empty-string */ + /** @var non-empty-string $summary */ public string $summary; - /** @var non-empty-string */ + /** @var non-empty-string $uri */ public string $uri; /** From 4cd6eaeac97bf8579f6c8d9618f0c70b9e47025a Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Tue, 14 Dec 2021 23:39:55 +0200 Subject: [PATCH 11/25] deleted bad comment --- src/Roave/SecurityAdvisories/Matchers.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Roave/SecurityAdvisories/Matchers.php b/src/Roave/SecurityAdvisories/Matchers.php index a8df4e87..c74b6633 100644 --- a/src/Roave/SecurityAdvisories/Matchers.php +++ b/src/Roave/SecurityAdvisories/Matchers.php @@ -23,8 +23,6 @@ /** * @see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string * - * @fixme: throw this garbage away and use existing regexp from semver.org - * * @psalm-immutable */ final class Matchers From 08a02eb00d230a042c46b5d361b6c4244d1adec8 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Tue, 4 Jan 2022 22:52:47 +0200 Subject: [PATCH 12/25] crude PoC --- build-conflicts.php | 68 +++++------ src/Roave/SecurityAdvisories/Advisory.php | 2 - src/Roave/SecurityAdvisories/Conflicts.php | 109 ++++++++++++++++++ .../SecurityAdvisories/VersionConstraint.php | 2 +- 4 files changed, 140 insertions(+), 41 deletions(-) create mode 100644 src/Roave/SecurityAdvisories/Conflicts.php diff --git a/build-conflicts.php b/build-conflicts.php index 3da68789..a7e593bb 100644 --- a/build-conflicts.php +++ b/build-conflicts.php @@ -36,11 +36,11 @@ use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromMultipleSources; use Roave\SecurityAdvisories\Rule\RuleProviderFactory; -use function array_keys; -use function count; +use function assert; use function file_get_contents; -use function in_array; +use function is_array; use function json_decode; +use function printf; use function set_error_handler; use const E_NOTICE; @@ -168,7 +168,7 @@ static function (array $components): array { /** * @psalm-suppress MixedAssignment */ - $commitComposerJson = static function (string $composerJsonPath, array $addedAdvisories): void { + $commitComposerJson = static function (string $composerJsonPath, iterable $addedAdvisories): void { $originalHash = Shell\execute( 'git', ['rev-parse', 'HEAD'], @@ -189,24 +189,28 @@ static function (array $components): array { 'https://github.com/FriendsOfPHP/security-advisories/commit/' . $originalHash, ); - if (count($addedAdvisories) === 0) { - $message .= "\n\nNo new security advisories were added"; - } else { - $message .= "\n\nNew security advisories added:"; - - foreach ($addedAdvisories as $advisory) { - $message .= Str\format( - "\n\tPackage name: %s\n\tSummary: %s\n\tURI: %s\n", - $advisory->package->packageName, - $advisory->source->summary, - $advisory->source->uri, - ); - } + $updatedAdvisoriesMessage = ''; + foreach ($addedAdvisories as $advisory) { + $updatedAdvisoriesMessage .= Str\format( + "\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n", + 'Package name', + $advisory->package->packageName, + 'Summary', + $advisory->source->summary, + 'URI', + $advisory->source->uri, + ); + } + + $updatedAdvisoriesMessage .= "\n"; - $message .= "\n"; + if (Str\Grapheme\length($updatedAdvisoriesMessage) === 0) { + $updatedAdvisoriesMessage = "\n\nNo security advisories were updated"; + } else { + $updatedAdvisoriesMessage = "\n\n Security advisories updated:" . $updatedAdvisoriesMessage; } - print $message; + $message .= $updatedAdvisoriesMessage; try { Shell\execute('git', ['diff-index', '--quiet', 'HEAD'], $workingDirectory); @@ -231,24 +235,6 @@ static function (array $components): array { (new RuleProviderFactory())(), ); - $prevComposerJSONFileData = file_get_contents(__DIR__ . '/build/roave-security-advisories/composer.json'); - - /** @var array $prevComposerDecodedData - */ - $prevComposerDecodedData = json_decode($prevComposerJSONFileData, true); - - /** @var array $oldConflictPackages */ - $oldConflictPackages = array_keys($prevComposerDecodedData['conflict']); - - $addedAdvisories = []; - foreach ($getAdvisories() as $advisory) { - if (in_array($advisory->package->packageName, $oldConflictPackages, true)) { - continue; - } - - $addedAdvisories[] = $advisory; - } - // actual work: $writeJson( $buildConflictsJson( @@ -264,10 +250,16 @@ static function (array $components): array { $validateComposerJson(__DIR__ . '/build/composer.json'); + // get updated advisories + $prevComposerJSONFileData = file_get_contents(__DIR__ . '/build/roave-security-advisories/composer.json'); + $prevComposerDecodedData = json_decode($prevComposerJSONFileData, true); + assert(is_array($prevComposerDecodedData)); + $updatedAdvisories = Conflicts::fromArray($prevComposerDecodedData['conflict'])->filterNewAdvisories($getAdvisories()); + $copyGeneratedComposerJson( __DIR__ . '/build/composer.json', __DIR__ . '/build/roave-security-advisories/composer.json' ); - $commitComposerJson(__DIR__ . '/build/roave-security-advisories/composer.json', $addedAdvisories); + $commitComposerJson(__DIR__ . '/build/roave-security-advisories/composer.json', $updatedAdvisories); })(); diff --git a/src/Roave/SecurityAdvisories/Advisory.php b/src/Roave/SecurityAdvisories/Advisory.php index 0419c59c..72048b1d 100644 --- a/src/Roave/SecurityAdvisories/Advisory.php +++ b/src/Roave/SecurityAdvisories/Advisory.php @@ -28,13 +28,11 @@ /** @psalm-immutable */ final class Advisory { - /** @var PackageName */ public PackageName $package; /** @var list */ private array $branchConstraints; - /** @var Source */ public Source $source; /** diff --git a/src/Roave/SecurityAdvisories/Conflicts.php b/src/Roave/SecurityAdvisories/Conflicts.php new file mode 100644 index 00000000..935395eb --- /dev/null +++ b/src/Roave/SecurityAdvisories/Conflicts.php @@ -0,0 +1,109 @@ + $v) { + $packageConstraints = []; + foreach (split($v, '|') as $range) { + $packageConstraints[] = VersionConstraint::fromString($range); + } + + $packageConflicts[$referenceName] = $packageConstraints; + } + + $conflicts = new self(); + $conflicts->conflictsMap = $packageConflicts; + + return $conflicts; + } + + // todo: change naming + public function filterNewAdvisories(iterable $advisories): iterable + { + foreach ($advisories as $newAdvisory) { + $pkgName = $newAdvisory->package->packageName; + + if (! array_key_exists($pkgName, $this->conflictsMap)) { + continue; + } + + if (! $this->isAdvisoryUpdate($newAdvisory, $this->conflictsMap[$pkgName])) { + continue; + } + + yield $newAdvisory; + } + } + + /** + * @param VersionConstraint[] $currentConstraints + */ + private function isAdvisoryUpdate(Advisory $newAdvisory, array $currentConstraints): bool + { + foreach ($newAdvisory->getVersionConstraints() as $newConstraint) { + if (! $this->contains($newConstraint, $currentConstraints)) { + return true; + } + } + + return false; + } + + private function contains(VersionConstraint $newConstraint, $currentConstraints): bool + { + foreach ($currentConstraints as $currConstraint) { + if ($currConstraint->contains($newConstraint)) { + return true; + } + } + + return false; + } +} + +/* + foreach ($getAdvisories() as $newAdvisory) { + $currentAdvisoryConstraints = $currentConstraints[$newAdvisory->package->packageName]; + $newAdvisoryConstraints = $newAdvisory->getVersionConstraints(); + + // now check that new advisory constraints are all included into current advisory constraints + // in other words, check that there is no range expansion OR new ranges added + + $isUpdate = false; + // check every new constr agains all old constraints + foreach ($newAdvisoryConstraints as $newConstraint) { + if ($isExpansion($newConstraint, $currentAdvisoryConstraints)) { + $isUpdate = true; + break; + } + } + + if (! $isUpdate) { + continue; + } + + // this is something new, either completely new range, or extension, or deletion(?) + $updatedAdvisories[] = $newAdvisory; + } + + */ diff --git a/src/Roave/SecurityAdvisories/VersionConstraint.php b/src/Roave/SecurityAdvisories/VersionConstraint.php index 5c5d8b3e..dfe23818 100644 --- a/src/Roave/SecurityAdvisories/VersionConstraint.php +++ b/src/Roave/SecurityAdvisories/VersionConstraint.php @@ -142,7 +142,7 @@ public function mergeWith(self $other): self )); } - private function contains(self $other): bool + public function contains(self $other): bool { return $this->isSimpleRangeString() // cannot compare - too complex :-( && $other->isSimpleRangeString() // cannot compare - too complex :-( From 9431fb9985269451e7187538145d692ee6242134 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Sat, 14 May 2022 23:52:09 +0300 Subject: [PATCH 13/25] constraints map implemented (?) but requires test --- .../SecurityAdvisories/ConstraintsMap.php | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/Roave/SecurityAdvisories/ConstraintsMap.php diff --git a/src/Roave/SecurityAdvisories/ConstraintsMap.php b/src/Roave/SecurityAdvisories/ConstraintsMap.php new file mode 100644 index 00000000..0e96233a --- /dev/null +++ b/src/Roave/SecurityAdvisories/ConstraintsMap.php @@ -0,0 +1,86 @@ + $v) { + $packageConstraints = []; + foreach (split($v, '|') as $range) { + $packageConstraints[] = VersionConstraint::fromString($range); + } + + $packageConflicts[$referenceName] = $packageConstraints; + } + + $conflicts = new self(); + $conflicts->map = $packageConflicts; + + return $conflicts; + } + + // todo: change naming + public function advisoriesDiff(iterable $advisoriesToFilter): array + { + $filteredAdvisories = []; + + /** @var Advisory $advisoryToFilter */ + foreach ($advisoriesToFilter as $advisoryToFilter) { // iterate over new advisories + $pkgNameKey = $advisoryToFilter->package->packageName; + + $isNewAdvisory = !array_key_exists($pkgNameKey, $this->map); + + if ($isNewAdvisory) { + $filteredAdvisories[] = $advisoryToFilter; + continue; + } + + $isUpdateAdvisory = $this->isAdvisoryUpdate($pkgNameKey, $advisoryToFilter); + + if ($isUpdateAdvisory) { + $filteredAdvisories[] = $advisoryToFilter; + } + } + + return $filteredAdvisories; + } + + private function isAdvisoryUpdate(string $pkgNameKey, Advisory $advisoryToCheck): bool + { + $packageConstraints = $this->map[$pkgNameKey]; + + /** @var VersionConstraint $advisoryConstraint */ + foreach ($advisoryToCheck->getVersionConstraints() as $advisoryConstraint) { + $included = false; + /** @var VersionConstraint $pkgConstraint */ + foreach ($packageConstraints as $pkgConstraint) { + + if ($pkgConstraint->equalOrIncludes($advisoryConstraint)) { + $included = true; + break; + } + } + if (!$included) { + return true; + } + } + + return false; + } +} From e3c11e4e2534bb068fde166059102c29a911676d Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Sun, 15 May 2022 01:07:04 +0300 Subject: [PATCH 14/25] test for constraint map --- .../Helper/ConstraintsMapTest.php | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php diff --git a/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php new file mode 100644 index 00000000..6880b71c --- /dev/null +++ b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php @@ -0,0 +1,199 @@ +advisoriesDiff($incomingAdvisory); + + self::assertCount(1, $result); + self::assertEquals($expectedAdvisoryConstraint, $result[0]->getConstraint()); + } + + /** + * @dataProvider sameAdvisoriesDataProvider + */ + public function testAdvisoriesDiffDetectsNonUpdatedAdvisory( + array $data, + array $incomingAdvisory, + string $expectedAdvisoryConstraint + ): void { + $map = ConstraintsMap::fromArray($data['conflict']); + $result = $map->advisoriesDiff($incomingAdvisory); + + self::assertCount(0, $result); + } + + + /** @psalm-return non-empty-list */ + public function newAdvisoriesDataProvider(): array + { + return [ + "existing package but with new version added" => [ + [ + 'conflict' => [ + 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', + ], + ], + [ + Advisory::fromArrayData([ + 'branches' => [ + ['versions' => ['>5']], + ], + 'reference' => 'composer://foo/bar', + ]), + ], + ">5", + ], + "new package " => [ + [ + 'conflict' => [ + 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', + ], + ], + [ + Advisory::fromArrayData([ + 'branches' => [ + ['versions' => ['>1']], + ], + 'reference' => 'composer://test/example', + ]), + ], + ">1", + ], + "advisory with expanded range" => [ + [ + 'conflict' => [ + 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', + ], + ], + [ + Advisory::fromArrayData([ + 'branches' => [ + ['versions' => + ['>=4.13', '<4.13.4'], // just a bit over the edge + ], + ], + 'reference' => 'composer://foo/bar', + ]), + ], + ">=4.13,<4.13.4", + ], + "existing conflict updated with new range" => [ + [ + 'conflict' => [ + 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', + ], + ], + [ + Advisory::fromArrayData([ + 'branches' => [ + ['versions' => + ['>=4.13', '<4.13.3'], + ], + ['versions' => + ['>6'], + ], + ], + 'reference' => 'composer://foo/bar', + ]), + ], + ">=4.13,<4.13.3|>6", + ], + ]; + } + + /** @psalm-return non-empty-list */ + public function sameAdvisoriesDataProvider(): array + { + return [ + "single range equals to already existing range" => [ + [ + 'conflict' => [ + 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', + ], + ], + [ + Advisory::fromArrayData([ + 'branches' => [ + ['versions' => ['>=4,<4.4.56']], + ], + 'reference' => 'composer://foo/bar', + ]), + ], + ">=4,<4.4.56", + ], + "all ranges are fully included" => [ + [ + 'conflict' => [ + 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', + ], + ], + [ + Advisory::fromArrayData([ + 'branches' => [ + ['versions' => ['>=4,<4.4.56']], + ['versions' => ['>=4.5,<4.9.18']], + ['versions' => ['>=4.10,<4.11.7']], + ['versions' => ['>=4.13,<4.13.3']], + ], + 'reference' => 'composer://foo/bar', + ]), + ], + ">=4,<4.4.56", + ], + "smaller single range fully included" => [ + [ + 'conflict' => [ + 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', + ], + ], + [ + Advisory::fromArrayData([ + 'branches' => [ + ['versions' => ['>4.1,<4.2']], + ], + 'reference' => 'composer://foo/bar', + ]), + ], + ">=4,<4.4.56", + ], + ]; + } +} From 0552bf263e4613ab304ebcaef0f6cb26efb9964d Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Sun, 15 May 2022 10:47:45 +0300 Subject: [PATCH 15/25] code sniffer fixes --- .../{ => Helper}/ConstraintsMap.php | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) rename src/Roave/SecurityAdvisories/{ => Helper}/ConstraintsMap.php (51%) diff --git a/src/Roave/SecurityAdvisories/ConstraintsMap.php b/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php similarity index 51% rename from src/Roave/SecurityAdvisories/ConstraintsMap.php rename to src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php index 0e96233a..c612ea92 100644 --- a/src/Roave/SecurityAdvisories/ConstraintsMap.php +++ b/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php @@ -2,49 +2,62 @@ declare(strict_types=1); -namespace Roave\SecurityAdvisories; +namespace Roave\SecurityAdvisories\Helper; + +use Roave\SecurityAdvisories\Advisory; +use Roave\SecurityAdvisories\VersionConstraint; use function array_key_exists; +use function assert; use function Psl\Str\split; final class ConstraintsMap { - /** @var array */ + /** @var array> $map */ private array $map; private function __construct() { } + /** + * @param array> $packageConflictsParsedData + * + * @return ConstraintsMap + */ public static function fromArray(array $packageConflictsParsedData): self { $packageConflicts = []; - foreach ($packageConflictsParsedData as $referenceName => $v) { + foreach ($packageConflictsParsedData as $referenceName => $constraintsString) { $packageConstraints = []; - foreach (split($v, '|') as $range) { + foreach (split($constraintsString, '|') as $range) { $packageConstraints[] = VersionConstraint::fromString($range); } $packageConflicts[$referenceName] = $packageConstraints; } - $conflicts = new self(); + $conflicts = new self(); $conflicts->map = $packageConflicts; return $conflicts; } - // todo: change naming - public function advisoriesDiff(iterable $advisoriesToFilter): array + /** + * @param array $advisoriesToFilter + * + * @return array + */ + public function advisoriesDiff(array $advisoriesToFilter): array { $filteredAdvisories = []; - /** @var Advisory $advisoryToFilter */ - foreach ($advisoriesToFilter as $advisoryToFilter) { // iterate over new advisories + foreach ($advisoriesToFilter as $advisoryToFilter) { + assert($advisoryToFilter instanceof Advisory); $pkgNameKey = $advisoryToFilter->package->packageName; - $isNewAdvisory = !array_key_exists($pkgNameKey, $this->map); + $isNewAdvisory = ! array_key_exists($pkgNameKey, $this->map); if ($isNewAdvisory) { $filteredAdvisories[] = $advisoryToFilter; @@ -53,30 +66,32 @@ public function advisoriesDiff(iterable $advisoriesToFilter): array $isUpdateAdvisory = $this->isAdvisoryUpdate($pkgNameKey, $advisoryToFilter); - if ($isUpdateAdvisory) { - $filteredAdvisories[] = $advisoryToFilter; + if (! $isUpdateAdvisory) { + continue; } + + $filteredAdvisories[] = $advisoryToFilter; } return $filteredAdvisories; } - private function isAdvisoryUpdate(string $pkgNameKey, Advisory $advisoryToCheck): bool + private function isAdvisoryUpdate(string $packageName, Advisory $advisoryToCheck): bool { - $packageConstraints = $this->map[$pkgNameKey]; + $packageConstraints = $this->map[$packageName]; - /** @var VersionConstraint $advisoryConstraint */ foreach ($advisoryToCheck->getVersionConstraints() as $advisoryConstraint) { + assert($advisoryConstraint instanceof VersionConstraint); $included = false; - /** @var VersionConstraint $pkgConstraint */ foreach ($packageConstraints as $pkgConstraint) { - - if ($pkgConstraint->equalOrIncludes($advisoryConstraint)) { + assert($pkgConstraint instanceof VersionConstraint); + if ($pkgConstraint->contains($advisoryConstraint)) { $included = true; break; } } - if (!$included) { + + if (! $included) { return true; } } From 0339ba221d8f102f00ffb87d4c913cb6fc7cd663 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Sun, 15 May 2022 20:43:14 +0300 Subject: [PATCH 16/25] code sniffer satisfied for now --- src/Roave/SecurityAdvisories/Conflicts.php | 109 -------------- .../Helper/ConstraintsMapTest.php | 139 +++++++++--------- 2 files changed, 68 insertions(+), 180 deletions(-) delete mode 100644 src/Roave/SecurityAdvisories/Conflicts.php diff --git a/src/Roave/SecurityAdvisories/Conflicts.php b/src/Roave/SecurityAdvisories/Conflicts.php deleted file mode 100644 index 935395eb..00000000 --- a/src/Roave/SecurityAdvisories/Conflicts.php +++ /dev/null @@ -1,109 +0,0 @@ - $v) { - $packageConstraints = []; - foreach (split($v, '|') as $range) { - $packageConstraints[] = VersionConstraint::fromString($range); - } - - $packageConflicts[$referenceName] = $packageConstraints; - } - - $conflicts = new self(); - $conflicts->conflictsMap = $packageConflicts; - - return $conflicts; - } - - // todo: change naming - public function filterNewAdvisories(iterable $advisories): iterable - { - foreach ($advisories as $newAdvisory) { - $pkgName = $newAdvisory->package->packageName; - - if (! array_key_exists($pkgName, $this->conflictsMap)) { - continue; - } - - if (! $this->isAdvisoryUpdate($newAdvisory, $this->conflictsMap[$pkgName])) { - continue; - } - - yield $newAdvisory; - } - } - - /** - * @param VersionConstraint[] $currentConstraints - */ - private function isAdvisoryUpdate(Advisory $newAdvisory, array $currentConstraints): bool - { - foreach ($newAdvisory->getVersionConstraints() as $newConstraint) { - if (! $this->contains($newConstraint, $currentConstraints)) { - return true; - } - } - - return false; - } - - private function contains(VersionConstraint $newConstraint, $currentConstraints): bool - { - foreach ($currentConstraints as $currConstraint) { - if ($currConstraint->contains($newConstraint)) { - return true; - } - } - - return false; - } -} - -/* - foreach ($getAdvisories() as $newAdvisory) { - $currentAdvisoryConstraints = $currentConstraints[$newAdvisory->package->packageName]; - $newAdvisoryConstraints = $newAdvisory->getVersionConstraints(); - - // now check that new advisory constraints are all included into current advisory constraints - // in other words, check that there is no range expansion OR new ranges added - - $isUpdate = false; - // check every new constr agains all old constraints - foreach ($newAdvisoryConstraints as $newConstraint) { - if ($isExpansion($newConstraint, $currentAdvisoryConstraints)) { - $isUpdate = true; - break; - } - } - - if (! $isUpdate) { - continue; - } - - // this is something new, either completely new range, or extension, or deletion(?) - $updatedAdvisories[] = $newAdvisory; - } - - */ diff --git a/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php index 6880b71c..1451aee8 100644 --- a/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php +++ b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php @@ -32,167 +32,164 @@ final class ConstraintsMapTest extends TestCase { /** + * @param array>> $data + * @param array $incomingAdvisories + * * @dataProvider newAdvisoriesDataProvider */ public function testAdvisoriesDiffDetectsUpdatedAndNewAdvisory( array $data, - array $incomingAdvisory, + array $incomingAdvisories, string $expectedAdvisoryConstraint ): void { - $map = ConstraintsMap::fromArray($data['conflict']); - $result = $map->advisoriesDiff($incomingAdvisory); + $map = ConstraintsMap::fromArray($data['conflict']); + $result = $map->advisoriesDiff($incomingAdvisories); self::assertCount(1, $result); self::assertEquals($expectedAdvisoryConstraint, $result[0]->getConstraint()); } /** + * @param array>> $data + * @param array $incomingAdvisories + * * @dataProvider sameAdvisoriesDataProvider */ public function testAdvisoriesDiffDetectsNonUpdatedAdvisory( array $data, - array $incomingAdvisory, - string $expectedAdvisoryConstraint + array $incomingAdvisories, ): void { - $map = ConstraintsMap::fromArray($data['conflict']); - $result = $map->advisoriesDiff($incomingAdvisory); + $map = ConstraintsMap::fromArray($data['conflict']); + $result = $map->advisoriesDiff($incomingAdvisories); self::assertCount(0, $result); } - - /** @psalm-return non-empty-list */ - public function newAdvisoriesDataProvider(): array + /** + * @return array + */ + public function sameAdvisoriesDataProvider(): array { return [ - "existing package but with new version added" => [ + 'single range equals to already existing range' => [ [ - 'conflict' => [ - 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', - ], + 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>5']], + ['versions' => ['>=4,<4.4.56']], ], 'reference' => 'composer://foo/bar', ]), ], - ">5", + '>=4,<4.4.56', ], - "new package " => [ + 'all ranges are fully included' => [ [ - 'conflict' => [ - 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', - ], + 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>1']], + ['versions' => ['>=4,<4.4.56']], + ['versions' => ['>=4.5,<4.9.18']], + ['versions' => ['>=4.10,<4.11.7']], + ['versions' => ['>=4.13,<4.13.3']], ], - 'reference' => 'composer://test/example', + 'reference' => 'composer://foo/bar', ]), ], - ">1", + '>=4,<4.4.56', ], - "advisory with expanded range" => [ + 'smaller single range fully included' => [ [ - 'conflict' => [ - 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', - ], + 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => - ['>=4.13', '<4.13.4'], // just a bit over the edge - ], + ['versions' => ['>4.1,<4.2']], ], 'reference' => 'composer://foo/bar', ]), ], - ">=4.13,<4.13.4", + '>=4,<4.4.56', ], - "existing conflict updated with new range" => [ + ]; + } + + /** + * @return array + */ + public function newAdvisoriesDataProvider(): array + { + return [ + 'existing package but with new version added' => [ [ - 'conflict' => [ - 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', - ], + 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => - ['>=4.13', '<4.13.3'], - ], - ['versions' => - ['>6'], - ], + ['versions' => ['>5']], ], 'reference' => 'composer://foo/bar', ]), ], - ">=4.13,<4.13.3|>6", + '>5', ], - ]; - } - - /** @psalm-return non-empty-list */ - public function sameAdvisoriesDataProvider(): array - { - return [ - "single range equals to already existing range" => [ + 'new package ' => [ [ - 'conflict' => [ - 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', - ], + 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>=4,<4.4.56']], + ['versions' => ['>1']], ], - 'reference' => 'composer://foo/bar', + 'reference' => 'composer://test/example', ]), ], - ">=4,<4.4.56", + '>1', ], - "all ranges are fully included" => [ + 'advisory with expanded range' => [ [ - 'conflict' => [ - 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', - ], + 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>=4,<4.4.56']], - ['versions' => ['>=4.5,<4.9.18']], - ['versions' => ['>=4.10,<4.11.7']], - ['versions' => ['>=4.13,<4.13.3']], + [ + 'versions' => + ['>=4.13', '<4.13.4'], // just a bit over the edge + ], ], 'reference' => 'composer://foo/bar', ]), ], - ">=4,<4.4.56", + '>=4.13,<4.13.4', ], - "smaller single range fully included" => [ + 'existing conflict updated with new range' => [ [ - 'conflict' => [ - 'foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3', - ], + 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>4.1,<4.2']], + [ + 'versions' => + ['>=4.13', '<4.13.3'], + ], + [ + 'versions' => + ['>6'], + ], ], 'reference' => 'composer://foo/bar', ]), ], - ">=4,<4.4.56", + '>=4.13,<4.13.3|>6', ], ]; } From c528ad85f5959bcf90c1a5e977945c1c375785bd Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Sun, 15 May 2022 20:58:02 +0300 Subject: [PATCH 17/25] build-conflicts changes --- build-conflicts.php | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/build-conflicts.php b/build-conflicts.php index a7e593bb..b12c1609 100644 --- a/build-conflicts.php +++ b/build-conflicts.php @@ -23,7 +23,6 @@ use DateTime; use DateTimeZone; use ErrorException; -use Http\Client\Curl\Client; use Psl\Dict; use Psl\Env; use Psl\Filesystem; @@ -32,16 +31,15 @@ use Psl\Str; use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesAdvisoryRuleDecorator; use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromFriendsOfPhp; -use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromGithubApi; use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromMultipleSources; +use Roave\SecurityAdvisories\Helper\ConstraintsMap; use Roave\SecurityAdvisories\Rule\RuleProviderFactory; -use function assert; use function file_get_contents; -use function is_array; +use function iterator_to_array; use function json_decode; -use function printf; use function set_error_handler; +use function var_dump; use const E_NOTICE; use const E_STRICT; @@ -94,10 +92,6 @@ static function (int $errorCode, string $message = '', string $file = '', int $l $cloneRoaveAdvisories = static function () use ($roaveAdvisoriesRepository, $buildDir): void { Shell\execute('git', ['clone', $roaveAdvisoriesRepository, $buildDir . '/roave-security-advisories']); - Shell\execute( - 'cp', - ['-r', $buildDir . '/roave-security-advisories', $buildDir . '/roave-security-advisories-original'] - ); }; $buildComponents = @@ -168,7 +162,7 @@ static function (array $components): array { /** * @psalm-suppress MixedAssignment */ - $commitComposerJson = static function (string $composerJsonPath, iterable $addedAdvisories): void { + $commitComposerJson = static function (string $composerJsonPath, array $addedAdvisories): void { $originalHash = Shell\execute( 'git', ['rev-parse', 'HEAD'], @@ -192,26 +186,23 @@ static function (array $components): array { $updatedAdvisoriesMessage = ''; foreach ($addedAdvisories as $advisory) { $updatedAdvisoriesMessage .= Str\format( - "\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n", + "\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n", 'Package name', $advisory->package->packageName, 'Summary', $advisory->source->summary, 'URI', $advisory->source->uri, + 'Constraints', + $advisory->getConstraint(), ); } - $updatedAdvisoriesMessage .= "\n"; - - if (Str\Grapheme\length($updatedAdvisoriesMessage) === 0) { - $updatedAdvisoriesMessage = "\n\nNo security advisories were updated"; - } else { + if (Str\Grapheme\length($updatedAdvisoriesMessage) != 0) { $updatedAdvisoriesMessage = "\n\n Security advisories updated:" . $updatedAdvisoriesMessage; + $message .= $updatedAdvisoriesMessage . "\n"; } - $message .= $updatedAdvisoriesMessage; - try { Shell\execute('git', ['diff-index', '--quiet', 'HEAD'], $workingDirectory); } catch (Shell\Exception\FailedExecutionException) { @@ -250,11 +241,10 @@ static function (array $components): array { $validateComposerJson(__DIR__ . '/build/composer.json'); - // get updated advisories $prevComposerJSONFileData = file_get_contents(__DIR__ . '/build/roave-security-advisories/composer.json'); - $prevComposerDecodedData = json_decode($prevComposerJSONFileData, true); - assert(is_array($prevComposerDecodedData)); - $updatedAdvisories = Conflicts::fromArray($prevComposerDecodedData['conflict'])->filterNewAdvisories($getAdvisories()); + $prevComposerDecodedData = json_decode($prevComposerJSONFileData, true); + $currentConstraints = ConstraintsMap::fromArray($prevComposerDecodedData['conflict']); + $updatedAdvisories = $currentConstraints->advisoriesDiff(iterator_to_array($getAdvisories())); $copyGeneratedComposerJson( __DIR__ . '/build/composer.json', From b89a3f49f986629851d4f1b7af9f8c222527056f Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Sun, 15 May 2022 21:02:23 +0300 Subject: [PATCH 18/25] build-conflicts cs fix --- build-conflicts.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build-conflicts.php b/build-conflicts.php index b12c1609..d522150b 100644 --- a/build-conflicts.php +++ b/build-conflicts.php @@ -39,7 +39,6 @@ use function iterator_to_array; use function json_decode; use function set_error_handler; -use function var_dump; use const E_NOTICE; use const E_STRICT; @@ -198,9 +197,9 @@ static function (array $components): array { ); } - if (Str\Grapheme\length($updatedAdvisoriesMessage) != 0) { + if (Str\Grapheme\length($updatedAdvisoriesMessage) !== 0) { $updatedAdvisoriesMessage = "\n\n Security advisories updated:" . $updatedAdvisoriesMessage; - $message .= $updatedAdvisoriesMessage . "\n"; + $message .= $updatedAdvisoriesMessage . "\n"; } try { From 03d5e8de29b87d0d4582c5b2fd8bbad14888c234 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Sun, 15 May 2022 22:40:42 +0300 Subject: [PATCH 19/25] tests are good to go now. Had to add "source" to all Advisory initializations --- .../Rule/RuleProviderFactory.php | 1 + ...GetAdvisoriesAdvisoryRuleDecoratorTest.php | 32 +++++++++++++++++++ .../Helper/ConstraintsMapTest.php | 7 ++++ .../Rule/RuleProviderFactoryTest.php | 3 ++ 4 files changed, 43 insertions(+) diff --git a/src/Roave/SecurityAdvisories/Rule/RuleProviderFactory.php b/src/Roave/SecurityAdvisories/Rule/RuleProviderFactory.php index 8514c2a3..e6f9e48e 100644 --- a/src/Roave/SecurityAdvisories/Rule/RuleProviderFactory.php +++ b/src/Roave/SecurityAdvisories/Rule/RuleProviderFactory.php @@ -47,6 +47,7 @@ static function (Advisory $advisory): Advisory { 'branches' => [ ['versions' => ['<2.17.1']], ], + 'source' => ['summary' => 'summary', 'link' => 'link'], ]); }, ]; diff --git a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesAdvisoryRuleDecoratorTest.php b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesAdvisoryRuleDecoratorTest.php index 34bdab7e..6f7deeb7 100644 --- a/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesAdvisoryRuleDecoratorTest.php +++ b/test/RoaveTest/SecurityAdvisories/AdvisorySources/GetAdvisoriesAdvisoryRuleDecoratorTest.php @@ -57,6 +57,7 @@ static function (Advisory $advisory): Advisory { return Advisory::fromArrayData([ 'reference' => $packageName, 'branches' => [['versions' => ['<1.1']]], + 'source' => ['summary' => 'summary', 'link' => 'link'], ]); }; @@ -74,6 +75,7 @@ static function (Advisory $advisory): Advisory { return Advisory::fromArrayData([ 'reference' => $packageName, 'branches' => [['versions' => ['>=3']]], + 'source' => ['summary' => 'summary', 'link' => 'link'], ]); }; @@ -100,18 +102,21 @@ static function (Advisory $advisory): Advisory { ['versions' => ['>2.2']], ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['<1.1']], // changed by rule ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['>=3']], // changed by rule ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ @@ -119,6 +124,7 @@ static function (Advisory $advisory): Advisory { ['versions' => ['>5']], ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], Vec\values($decoratedAdvisories)); } @@ -163,6 +169,8 @@ static function (Advisory $advisory): Advisory { $config['reference'] = $packageName; $config['branches'] = [['versions' => ['<1.0|>2.0']]]; + $config['source'] = ['summary' => 'summary', 'link' => 'link']; + return Advisory::fromArrayData($config); }; @@ -185,24 +193,28 @@ static function (Advisory $advisory): Advisory { ['versions' => ['>2.2']], ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['<1.0|>2.0']], ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['<2|>4']], ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['>5']], ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], Vec\values($decoratedAdvisories) @@ -232,6 +244,7 @@ static function (Advisory $advisory): Advisory { 'versions' => ['<2.17.1'], // change constraint to <2.17.1 ], ]; + $config['source'] = ['summary' => 'summary', 'link' => 'link']; return Advisory::fromArrayData($config); }; @@ -243,6 +256,7 @@ static function (Advisory $advisory): Advisory { Advisory::fromArrayData([ 'branches' => [['versions' => ['<2.17.2']]], 'reference' => 'composer://laminas/laminas-form', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ); @@ -263,28 +277,33 @@ static function (Advisory $advisory): Advisory { ['versions' => ['>2.2']], ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['<1.2']], ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['<2|>4']], ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['>5']], ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [['versions' => ['<2.17.1']]], 'reference' => 'composer://laminas/laminas-form', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], Vec\values($decoratedAdvisories) @@ -314,6 +333,7 @@ static function (Advisory $advisory): Advisory { 'versions' => ['<2.17.1'], // change constraint to <2.17.1 ], ]; + $config['source'] = ['summary' => 'summary', 'link' => 'link']; return Advisory::fromArrayData($config); }; @@ -329,6 +349,7 @@ static function (Advisory $advisory): Advisory { ], ], 'reference' => 'composer://laminas/laminas-form', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ); $getAdvisories->addAdvisory( @@ -339,6 +360,7 @@ static function (Advisory $advisory): Advisory { ], ], 'reference' => 'composer://laminas/laminas-form', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ); @@ -358,36 +380,42 @@ static function (Advisory $advisory): Advisory { ['versions' => ['>2.2']], ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['<1.2']], ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['<2|>4']], ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['>5']], ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['<2.17.1']], ], 'reference' => 'composer://laminas/laminas-form', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), Advisory::fromArrayData([ 'branches' => [ ['versions' => ['>=3', '<3.0.2']], ], 'reference' => 'composer://laminas/laminas-form', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], Vec\values($decoratedAdvisories)); } @@ -418,6 +446,7 @@ public function __invoke(): Generator ['versions' => ['>2.2']], ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]); yield Advisory::fromArrayData([ @@ -425,6 +454,7 @@ public function __invoke(): Generator ['versions' => ['<1.2']], ], 'reference' => 'composer://3f/pygmentize', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]); yield Advisory::fromArrayData([ @@ -432,6 +462,7 @@ public function __invoke(): Generator ['versions' => ['<2|>4']], ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]); yield Advisory::fromArrayData([ @@ -439,6 +470,7 @@ public function __invoke(): Generator ['versions' => ['>5']], ], 'reference' => 'composer://other/package-name', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]); if (count($this->advisories) === 0) { diff --git a/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php index 1451aee8..4944703f 100644 --- a/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php +++ b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php @@ -81,6 +81,7 @@ public function sameAdvisoriesDataProvider(): array ['versions' => ['>=4,<4.4.56']], ], 'reference' => 'composer://foo/bar', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], '>=4,<4.4.56', @@ -98,6 +99,7 @@ public function sameAdvisoriesDataProvider(): array ['versions' => ['>=4.13,<4.13.3']], ], 'reference' => 'composer://foo/bar', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], '>=4,<4.4.56', @@ -112,6 +114,7 @@ public function sameAdvisoriesDataProvider(): array ['versions' => ['>4.1,<4.2']], ], 'reference' => 'composer://foo/bar', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], '>=4,<4.4.56', @@ -135,6 +138,7 @@ public function newAdvisoriesDataProvider(): array ['versions' => ['>5']], ], 'reference' => 'composer://foo/bar', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], '>5', @@ -149,6 +153,7 @@ public function newAdvisoriesDataProvider(): array ['versions' => ['>1']], ], 'reference' => 'composer://test/example', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], '>1', @@ -166,6 +171,7 @@ public function newAdvisoriesDataProvider(): array ], ], 'reference' => 'composer://foo/bar', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], '>=4.13,<4.13.4', @@ -187,6 +193,7 @@ public function newAdvisoriesDataProvider(): array ], ], 'reference' => 'composer://foo/bar', + 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], '>=4.13,<4.13.3|>6', diff --git a/test/RoaveTest/SecurityAdvisories/Rule/RuleProviderFactoryTest.php b/test/RoaveTest/SecurityAdvisories/Rule/RuleProviderFactoryTest.php index 75bf0bd0..d5c8dba5 100644 --- a/test/RoaveTest/SecurityAdvisories/Rule/RuleProviderFactoryTest.php +++ b/test/RoaveTest/SecurityAdvisories/Rule/RuleProviderFactoryTest.php @@ -56,6 +56,7 @@ public function testProviderProvidesRuleIsApplied(): void $config['branches'] = [ ['versions' => ['<2.17.2']], ]; + $config['source'] = ['summary' => 'summary', 'link' => 'link']; $advisory = Advisory::fromArrayData($config); @@ -87,6 +88,7 @@ public function testProviderProvidesRuleNotAppliedBecauseOfPackageName(): void 'versions' => ['<2.17.2'], ], ]; + $config['source'] = ['summary' => 'summary', 'link' => 'link']; $advisory = Advisory::fromArrayData($config); @@ -118,6 +120,7 @@ public function testProviderProvidesRuleNotAppliedBecauseOfUnexpectedConstraint( 'versions' => ['>3.2'], ], ]; + $config['source'] = ['summary' => 'summary', 'link' => 'link']; $advisory = Advisory::fromArrayData($config); From bb88c3dcbcfc6ce75fee02ffbad7b8a1692da123 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Mon, 16 May 2022 14:35:54 +0300 Subject: [PATCH 20/25] no need for asserts for now --- src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php b/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php index c612ea92..3a7bb9dd 100644 --- a/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php +++ b/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php @@ -8,7 +8,6 @@ use Roave\SecurityAdvisories\VersionConstraint; use function array_key_exists; -use function assert; use function Psl\Str\split; final class ConstraintsMap @@ -54,7 +53,6 @@ public function advisoriesDiff(array $advisoriesToFilter): array $filteredAdvisories = []; foreach ($advisoriesToFilter as $advisoryToFilter) { - assert($advisoryToFilter instanceof Advisory); $pkgNameKey = $advisoryToFilter->package->packageName; $isNewAdvisory = ! array_key_exists($pkgNameKey, $this->map); @@ -81,10 +79,8 @@ private function isAdvisoryUpdate(string $packageName, Advisory $advisoryToCheck $packageConstraints = $this->map[$packageName]; foreach ($advisoryToCheck->getVersionConstraints() as $advisoryConstraint) { - assert($advisoryConstraint instanceof VersionConstraint); $included = false; foreach ($packageConstraints as $pkgConstraint) { - assert($pkgConstraint instanceof VersionConstraint); if ($pkgConstraint->contains($advisoryConstraint)) { $included = true; break; From 72e7e7364c1cce001e138308640c033ad04d9ce8 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Tue, 17 May 2022 23:28:29 +0300 Subject: [PATCH 21/25] build-conflict psalm resolved for now (?) --- build-conflicts.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/build-conflicts.php b/build-conflicts.php index d522150b..3234453a 100644 --- a/build-conflicts.php +++ b/build-conflicts.php @@ -31,6 +31,8 @@ use Psl\Str; use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesAdvisoryRuleDecorator; use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromFriendsOfPhp; +use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromGithubApi; +use Http\Client\Curl\Client; use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromMultipleSources; use Roave\SecurityAdvisories\Helper\ConstraintsMap; use Roave\SecurityAdvisories\Rule\RuleProviderFactory; @@ -158,9 +160,6 @@ static function (array $components): array { Shell\execute('cp', [$sourceComposerJsonPath, $targetComposerJsonPath]); }; - /** - * @psalm-suppress MixedAssignment - */ $commitComposerJson = static function (string $composerJsonPath, array $addedAdvisories): void { $originalHash = Shell\execute( 'git', @@ -183,6 +182,7 @@ static function (array $components): array { ); $updatedAdvisoriesMessage = ''; + /** @var Advisory $advisory */ foreach ($addedAdvisories as $advisory) { $updatedAdvisoriesMessage .= Str\format( "\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n", @@ -193,7 +193,7 @@ static function (array $components): array { 'URI', $advisory->source->uri, 'Constraints', - $advisory->getConstraint(), + $advisory->getConstraint() ?? "", ); } @@ -241,7 +241,8 @@ static function (array $components): array { $validateComposerJson(__DIR__ . '/build/composer.json'); $prevComposerJSONFileData = file_get_contents(__DIR__ . '/build/roave-security-advisories/composer.json'); - $prevComposerDecodedData = json_decode($prevComposerJSONFileData, true); + /** @var array>> $prevComposerDecodedData */ + $prevComposerDecodedData = Json\decode($prevComposerJSONFileData, true); $currentConstraints = ConstraintsMap::fromArray($prevComposerDecodedData['conflict']); $updatedAdvisories = $currentConstraints->advisoriesDiff(iterator_to_array($getAdvisories())); From b8e40fbeb32cb5a5000bad97f7a2db634b95c765 Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Wed, 18 May 2022 00:03:55 +0300 Subject: [PATCH 22/25] psalm fixes --- build-conflicts.php | 14 ++++++-------- .../SecurityAdvisories/Helper/ConstraintsMap.php | 13 +++++++------ .../Helper/ConstraintsMapTest.php | 8 ++++---- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/build-conflicts.php b/build-conflicts.php index 3234453a..fd41d604 100644 --- a/build-conflicts.php +++ b/build-conflicts.php @@ -23,6 +23,7 @@ use DateTime; use DateTimeZone; use ErrorException; +use Http\Client\Curl\Client; use Psl\Dict; use Psl\Env; use Psl\Filesystem; @@ -32,14 +33,12 @@ use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesAdvisoryRuleDecorator; use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromFriendsOfPhp; use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromGithubApi; -use Http\Client\Curl\Client; use Roave\SecurityAdvisories\AdvisorySources\GetAdvisoriesFromMultipleSources; use Roave\SecurityAdvisories\Helper\ConstraintsMap; use Roave\SecurityAdvisories\Rule\RuleProviderFactory; use function file_get_contents; use function iterator_to_array; -use function json_decode; use function set_error_handler; use const E_NOTICE; @@ -182,7 +181,6 @@ static function (array $components): array { ); $updatedAdvisoriesMessage = ''; - /** @var Advisory $advisory */ foreach ($addedAdvisories as $advisory) { $updatedAdvisoriesMessage .= Str\format( "\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n", @@ -193,7 +191,7 @@ static function (array $components): array { 'URI', $advisory->source->uri, 'Constraints', - $advisory->getConstraint() ?? "", + $advisory->getConstraint() ?? '', ); } @@ -241,10 +239,10 @@ static function (array $components): array { $validateComposerJson(__DIR__ . '/build/composer.json'); $prevComposerJSONFileData = file_get_contents(__DIR__ . '/build/roave-security-advisories/composer.json'); - /** @var array>> $prevComposerDecodedData */ - $prevComposerDecodedData = Json\decode($prevComposerJSONFileData, true); - $currentConstraints = ConstraintsMap::fromArray($prevComposerDecodedData['conflict']); - $updatedAdvisories = $currentConstraints->advisoriesDiff(iterator_to_array($getAdvisories())); + /** @var array> $prevComposerDecodedData */ + $prevComposerDecodedData = Json\decode($prevComposerJSONFileData, true); + $currentConstraints = ConstraintsMap::fromArray($prevComposerDecodedData['conflict']); + $updatedAdvisories = $currentConstraints->advisoriesDiff(iterator_to_array($getAdvisories())); $copyGeneratedComposerJson( __DIR__ . '/build/composer.json', diff --git a/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php b/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php index 3a7bb9dd..15495276 100644 --- a/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php +++ b/src/Roave/SecurityAdvisories/Helper/ConstraintsMap.php @@ -15,12 +15,16 @@ final class ConstraintsMap /** @var array> $map */ private array $map; - private function __construct() + /** + * @param array> $conflicts + */ + private function __construct(array $conflicts) { + $this->map = $conflicts; } /** - * @param array> $packageConflictsParsedData + * @param array $packageConflictsParsedData * * @return ConstraintsMap */ @@ -37,10 +41,7 @@ public static function fromArray(array $packageConflictsParsedData): self $packageConflicts[$referenceName] = $packageConstraints; } - $conflicts = new self(); - $conflicts->map = $packageConflicts; - - return $conflicts; + return new self($packageConflicts); } /** diff --git a/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php index 4944703f..aa7ff57e 100644 --- a/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php +++ b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php @@ -32,8 +32,8 @@ final class ConstraintsMapTest extends TestCase { /** - * @param array>> $data - * @param array $incomingAdvisories + * @param array> $data + * @param array $incomingAdvisories * * @dataProvider newAdvisoriesDataProvider */ @@ -50,8 +50,8 @@ public function testAdvisoriesDiffDetectsUpdatedAndNewAdvisory( } /** - * @param array>> $data - * @param array $incomingAdvisories + * @param array> $data + * @param array $incomingAdvisories * * @dataProvider sameAdvisoriesDataProvider */ From 18bd74aabda02a4b188d7f08dd479aa6a1b178eb Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Wed, 18 May 2022 00:42:24 +0300 Subject: [PATCH 23/25] how about now ? --- build-conflicts.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/build-conflicts.php b/build-conflicts.php index fd41d604..b563e916 100644 --- a/build-conflicts.php +++ b/build-conflicts.php @@ -23,6 +23,7 @@ use DateTime; use DateTimeZone; use ErrorException; +use Exception; use Http\Client\Curl\Client; use Psl\Dict; use Psl\Env; @@ -37,6 +38,7 @@ use Roave\SecurityAdvisories\Helper\ConstraintsMap; use Roave\SecurityAdvisories\Rule\RuleProviderFactory; +use function assert; use function file_get_contents; use function iterator_to_array; use function set_error_handler; @@ -159,6 +161,14 @@ static function (array $components): array { Shell\execute('cp', [$sourceComposerJsonPath, $targetComposerJsonPath]); }; + /** + * @param string $composerJsonPath + * @param array $addedAdvisories + * + * @return void + * + * @throws Exception + */ $commitComposerJson = static function (string $composerJsonPath, array $addedAdvisories): void { $originalHash = Shell\execute( 'git', @@ -182,6 +192,7 @@ static function (array $components): array { $updatedAdvisoriesMessage = ''; foreach ($addedAdvisories as $advisory) { + assert($advisory instanceof Advisory); $updatedAdvisoriesMessage .= Str\format( "\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n\t%-15s| %s\n", 'Package name', From 9be960577d37c25fa331bf8f252e776d94a4561c Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Wed, 18 May 2022 17:07:51 +0300 Subject: [PATCH 24/25] remove whitespace coming from github --- src/Roave/SecurityAdvisories/VersionConstraint.php | 2 +- test/RoaveTest/SecurityAdvisories/VersionConstraintTest.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Roave/SecurityAdvisories/VersionConstraint.php b/src/Roave/SecurityAdvisories/VersionConstraint.php index dfe23818..724edd00 100644 --- a/src/Roave/SecurityAdvisories/VersionConstraint.php +++ b/src/Roave/SecurityAdvisories/VersionConstraint.php @@ -33,7 +33,7 @@ private function __construct() */ public static function fromString(string $versionConstraint): self { - $constraintString = $versionConstraint; + $constraintString = Str\replace($versionConstraint, ' ', ''); $instance = new self(); if (Regex\matches($constraintString, Matchers::CLOSED_RANGE_MATCHER)) { diff --git a/test/RoaveTest/SecurityAdvisories/VersionConstraintTest.php b/test/RoaveTest/SecurityAdvisories/VersionConstraintTest.php index 105c5b12..79b2da19 100644 --- a/test/RoaveTest/SecurityAdvisories/VersionConstraintTest.php +++ b/test/RoaveTest/SecurityAdvisories/VersionConstraintTest.php @@ -280,7 +280,7 @@ public function complexRangesProvider(): array ['>1a2b3,<4c5d6'], ['>1-a.2'], ['<1-a.2'], - ['<1-a.2, >1-p.1.2'], + ['<1-a.2,>1-p.1.2'], ['1-beta.2.0|1-rc.1.2.3'], ]; @@ -519,6 +519,7 @@ static function (array $entry) { public function normalizableRangesProvider(): array { $samples = [ + ['= 1.1.1', '=1.1.1'], ['>1.0,<2.0', '>1,<2'], ['>=1.0,<2.0', '>=1,<2'], ['>1.0,<=2.0', '>1,<=2'], @@ -536,6 +537,8 @@ public function normalizableRangesProvider(): array ['<1.0', '<1'], ['<=1.0', '<=1'], ['<=1.0.3.0.5.0-beta.0.5.0.0', '<=1.0.3.0.5-beta.0.5'], + ['>= 6.0.0-RC-1', '>=6.0.0-RC-1'], + ['<= 6.0.0-RC-5', '<=6.0.0-RC-5'], ]; return Dict\associate( From 3638683c3f758d6341505d2d60c4b9a7e44b770a Mon Sep 17 00:00:00 2001 From: Ilya Tribusean Date: Wed, 18 May 2022 17:19:55 +0300 Subject: [PATCH 25/25] for `contains` in VersionConstraint.php lets try to compare complex versions represented as strings --- .../SecurityAdvisories/VersionConstraint.php | 6 + .../Helper/ConstraintsMapTest.php | 105 +++++++++++------- 2 files changed, 71 insertions(+), 40 deletions(-) diff --git a/src/Roave/SecurityAdvisories/VersionConstraint.php b/src/Roave/SecurityAdvisories/VersionConstraint.php index 724edd00..b4b2482e 100644 --- a/src/Roave/SecurityAdvisories/VersionConstraint.php +++ b/src/Roave/SecurityAdvisories/VersionConstraint.php @@ -11,6 +11,8 @@ use Psl\Str; use Psl\Vec; +use function strcmp; + /** * A simple version constraint - naively assumes that it is only about ranges like ">=1.2.3,<4.5.6" * @@ -144,6 +146,10 @@ public function mergeWith(self $other): self public function contains(self $other): bool { + if ($this->constraintString !== null && $other->constraintString !== null) { + return strcmp($this->constraintString, $other->constraintString) === 0; + } + return $this->isSimpleRangeString() // cannot compare - too complex :-( && $other->isSimpleRangeString() // cannot compare - too complex :-( && $this->containsLowerBound($other->lowerBoundary) diff --git a/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php index aa7ff57e..045f0c50 100644 --- a/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php +++ b/test/RoaveTest/SecurityAdvisories/Helper/ConstraintsMapTest.php @@ -55,7 +55,7 @@ public function testAdvisoriesDiffDetectsUpdatedAndNewAdvisory( * * @dataProvider sameAdvisoriesDataProvider */ - public function testAdvisoriesDiffDetectsNonUpdatedAdvisory( + public function testSameAdvisoriesAreFilteredOut( array $data, array $incomingAdvisories, ): void { @@ -68,56 +68,78 @@ public function testAdvisoriesDiffDetectsNonUpdatedAdvisory( /** * @return array */ - public function sameAdvisoriesDataProvider(): array + public function newAdvisoriesDataProvider(): array { return [ - 'single range equals to already existing range' => [ + 'existing package but with new version added' => [ [ 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>=4,<4.4.56']], + ['versions' => ['>5']], ], 'reference' => 'composer://foo/bar', 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], - '>=4,<4.4.56', + '>5', ], - 'all ranges are fully included' => [ + 'new package ' => [ [ 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>=4,<4.4.56']], - ['versions' => ['>=4.5,<4.9.18']], - ['versions' => ['>=4.10,<4.11.7']], - ['versions' => ['>=4.13,<4.13.3']], + ['versions' => ['>1']], + ], + 'reference' => 'composer://test/example', + 'source' => ['summary' => 'summary', 'link' => 'link'], + ]), + ], + '>1', + ], + 'advisory with expanded range' => [ + [ + 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], + ], + [ + Advisory::fromArrayData([ + 'branches' => [ + [ + 'versions' => + ['>=4.13', '<4.13.4'], + ], ], 'reference' => 'composer://foo/bar', 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], - '>=4,<4.4.56', + '>=4.13,<4.13.4', ], - 'smaller single range fully included' => [ + 'existing conflict updated with new range' => [ [ 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>4.1,<4.2']], + [ + 'versions' => + ['>=4.13', '<4.13.3'], + ], + [ + 'versions' => + ['>6'], + ], ], 'reference' => 'composer://foo/bar', 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], - '>=4,<4.4.56', + '>=4.13,<4.13.3|>6', ], ]; } @@ -125,78 +147,81 @@ public function sameAdvisoriesDataProvider(): array /** * @return array */ - public function newAdvisoriesDataProvider(): array + public function sameAdvisoriesDataProvider(): array { return [ - 'existing package but with new version added' => [ + 'single range equals to already existing range' => [ [ 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>5']], + ['versions' => ['>=4,<4.4.56']], ], 'reference' => 'composer://foo/bar', 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], - '>5', ], - 'new package ' => [ + 'all ranges are fully included' => [ [ 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - ['versions' => ['>1']], + ['versions' => ['>=4,<4.4.56']], + ['versions' => ['>=4.5,<4.9.18']], + ['versions' => ['>=4.10,<4.11.7']], + ['versions' => ['>=4.13,<4.13.3']], ], - 'reference' => 'composer://test/example', + 'reference' => 'composer://foo/bar', 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], - '>1', ], - 'advisory with expanded range' => [ + 'smaller single range fully included' => [ [ 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], ], [ Advisory::fromArrayData([ 'branches' => [ - [ - 'versions' => - ['>=4.13', '<4.13.4'], // just a bit over the edge - ], + ['versions' => ['>4.1,<4.2']], ], 'reference' => 'composer://foo/bar', 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], - '>=4.13,<4.13.4', ], - 'existing conflict updated with new range' => [ + 'complex range with stability flags' => [ [ - 'conflict' => ['foo/bar' => '>=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3'], + 'conflict' => ['snipe/snipe-it' => '<5.4.3|>=6.0.0-RC-1,<=6.0.0-RC-5'], ], [ Advisory::fromArrayData([ 'branches' => [ - [ - 'versions' => - ['>=4.13', '<4.13.3'], - ], - [ - 'versions' => - ['>6'], - ], + ['versions' => ['>=6.0.0-RC-1, <=6.0.0-RC-5']], ], - 'reference' => 'composer://foo/bar', + 'reference' => 'composer://snipe/snipe-it', + 'source' => ['summary' => 'summary', 'link' => 'link'], + ]), + ], + ], + 'a simple ranges and fixed version advisories' => [ + [ + 'conflict' => ['october/cms' => '=1.1.1|=1.0.471|=1.0.469|>=1.0.319,<1.0.469'], + ], + [ + Advisory::fromArrayData([ + 'branches' => [ + ['versions' => ['=1.0.471']], + ], + 'reference' => 'composer://october/cms', 'source' => ['summary' => 'summary', 'link' => 'link'], ]), ], - '>=4.13,<4.13.3|>6', ], ]; }