From e8d6c4a746a99d085157491524c0ab496dccc804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Riemenschneider?= Date: Fri, 2 Aug 2024 12:48:06 +0200 Subject: [PATCH] [#551] Dependency patch resolution: Only allow patches from trusted dependencies --- src/Plugin/Patches.php | 4 ++++ src/Resolver/Dependencies.php | 42 +++++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/Plugin/Patches.php b/src/Plugin/Patches.php index 5b74ca1..55b04f2 100644 --- a/src/Plugin/Patches.php +++ b/src/Plugin/Patches.php @@ -146,6 +146,10 @@ public function activate(Composer $composer, IOInterface $io): void 'type' => 'string', 'default' => 'patches.json', ], + "allow-dependency-patches" => [ + 'type' => 'list', + 'default' => null, + ], "ignore-dependency-patches" => [ 'type' => 'list', 'default' => [], diff --git a/src/Resolver/Dependencies.php b/src/Resolver/Dependencies.php index e7ee835..0e1e512 100644 --- a/src/Resolver/Dependencies.php +++ b/src/Resolver/Dependencies.php @@ -24,21 +24,42 @@ public function resolve(PatchCollection $collection): void return; } - $this->io->write(' - Resolving patches from dependencies.'); - + // Using both config keys, if $allowed_dependencies is set, it takes precedence + $allowed_dependencies = $this->plugin->getConfig('allow-dependency-patches'); $ignored_dependencies = $this->plugin->getConfig('ignore-dependency-patches'); + // First check, if we do allow dependency patches at all. + if ($allowed_dependencies === []) { + $this->io->write(' - No patches from dependencies are allowed.'); + return; + } + + $this->io->write(' - Resolving patches from dependencies.'); + $lockdata = $locker->getLockData(); foreach ($lockdata['packages'] as $p) { - // If we're supposed to skip gathering patches from a dependency, do that. - if (in_array($p['name'], $ignored_dependencies)) { - continue; + $allowed = in_array($p['name'], $allowed_dependencies ?? []); + $ignored = in_array($p['name'], $ignored_dependencies); + + // Allowed dependencies is not set in composer.json, and we're not + // supposed to skip gathering patches from this dependency + if (is_null($allowed_dependencies) && !$ignored) { + $this->lookForPatches($p, $collection); } - // Find patches in the composer.json for dependencies. - if (!isset($p['extra']) || !isset($p['extra']['patches'])) { - continue; + // Allowed dependencies are set, act only on allowed, if they're not + // ignored also. + if ($allowed && !$ignored) { + $this->lookForPatches($p, $collection); } + } + } + + private function lookForPatches(array $p, PatchCollection $collection): void + { + + // Find patches in the composer.json for dependencies. + if (isset($p['extra']['patches'])) { foreach ($this->findPatchesInJson($p['extra']['patches']) as $package => $patches) { foreach ($patches as $patch) { $patch->extra['provenance'] = "dependency:" . $package; @@ -47,8 +68,11 @@ public function resolve(PatchCollection $collection): void $collection->addPatch($patch); } } + } - // TODO: Also find patches in a configured patches.json for the dependency. + // Find patches in a patch-file for dependencies. + if (isset($p['extra']['composer-patches']['patches-file'])) { + // @todo Handle patch files. } } }