From efe6e44883cccc5320a361b0c26c698ab4f925c0 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Thu, 4 Jan 2024 10:55:59 +0100 Subject: [PATCH] Perform audit on Composer and its dependencies during diagnose, fixes #11216 (#11761) --- src/Composer/Command/DiagnoseCommand.php | 56 +++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/src/Composer/Command/DiagnoseCommand.php b/src/Composer/Command/DiagnoseCommand.php index d1b4fbee5..7d41bf554 100644 --- a/src/Composer/Command/DiagnoseCommand.php +++ b/src/Composer/Command/DiagnoseCommand.php @@ -12,14 +12,23 @@ namespace Composer\Command; +use Composer\Advisory\Auditor; use Composer\Composer; use Composer\Factory; use Composer\Config; use Composer\Downloader\TransportException; +use Composer\IO\BufferIO; +use Composer\Json\JsonFile; +use Composer\Package\RootPackage; +use Composer\Package\Version\VersionParser; use Composer\Pcre\Preg; +use Composer\Repository\ComposerRepository; +use Composer\Repository\FilesystemRepository; use Composer\Repository\PlatformRepository; use Composer\Plugin\CommandEvent; use Composer\Plugin\PluginEvents; +use Composer\Repository\RepositorySet; +use Composer\Repository\RootPackageRepository; use Composer\Util\ConfigValidator; use Composer\Util\Git; use Composer\Util\IniHelper; @@ -153,10 +162,13 @@ EOT $io->write('Checking pubkeys: ', false); $this->outputResult($this->checkPubKeys($config)); - $io->write('Checking composer version: ', false); + $io->write('Checking Composer version: ', false); $this->outputResult($this->checkVersion($config)); } + $io->write('Checking Composer and its dependencies for vulnerabilities: ', false); + $this->outputResult($this->checkComposerAudit($config)); + $io->write(sprintf('Composer version: %s', Composer::getVersion())); $platformOverrides = $config->get('platform') ?: []; @@ -438,6 +450,48 @@ EOT return true; } + /** + * @return string|true + */ + private function checkComposerAudit(Config $config) + { + $result = $this->checkConnectivityAndComposerNetworkHttpEnablement(); + if ($result !== true) { + return $result; + } + + $auditor = new Auditor(); + $repoSet = new RepositorySet(); + $installedJson = new JsonFile(__DIR__ . '/../../../vendor/composer/installed.json'); + if (!$installedJson->exists()) { + return 'Could not find Composer\'s installed.json, this must be a non-standard Composer installation.'; + } + + $localRepo = new FilesystemRepository($installedJson); + $version = Composer::getVersion(); + $packages = $localRepo->getCanonicalPackages(); + if ($version !== '@package_version@') { + $versionParser = new VersionParser(); + $normalizedVersion = $versionParser->normalize($version); + $rootPkg = new RootPackage('composer/composer', $normalizedVersion, $version); + $packages[] = $rootPkg; + } + $repoSet->addRepository(new ComposerRepository(['type' => 'composer', 'url' => 'https://packagist.org'], new NullIO(), $config, $this->httpDownloader)); + + try { + $io = new BufferIO(); + $result = $auditor->audit($io, $repoSet, $packages, Auditor::FORMAT_TABLE, true, [], Auditor::ABANDONED_IGNORE); + } catch (\Throwable $e) { + return 'Failed performing audit: '.$e->getMessage().''; + } + + if ($result > 0) { + return 'Audit found some issues:' . PHP_EOL . $io->getOutput(); + } + + return true; + } + private function getCurlVersion(): string { if (extension_loaded('curl')) {