diff --git a/.composer-require-checker.json b/.composer-require-checker.json index 8cd5883f..12b803ad 100644 --- a/.composer-require-checker.json +++ b/.composer-require-checker.json @@ -9,6 +9,7 @@ "Composer\\Package\\PackageInterface", "Composer\\Package\\RootPackage", "Composer\\Package\\RootPackageInterface", + "Composer\\PartialComposer", "Composer\\Plugin\\Capability\\CommandProvider", "Composer\\Plugin\\Capable", "Composer\\Plugin\\PluginInterface", diff --git a/HISTORY.md b/HISTORY.md index 73970731..1e586d2b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file. * Support for CycloneDX Spec v1.4 (via [#250]) * SBOM results * might have `metadata.timestamp` populated ([#112] via [#250]) + * might have `metadata.tools.tool.eexternalReferences` populated ([#171] via [#250]) * might have `component.author` populated ([#261] via [#250]) * CLI * New option `omit` (via [#250]) @@ -37,6 +38,7 @@ All notable changes to this project will be documented in this file. [#128]: https://github.com/CycloneDX/cyclonedx-php-composer/issues/128 [#153]: https://github.com/CycloneDX/cyclonedx-php-composer/issues/153 [#154]: https://github.com/CycloneDX/cyclonedx-php-composer/issues/154 +[#171]: https://github.com/CycloneDX/cyclonedx-php-composer/issues/171 [#250]: https://github.com/CycloneDX/cyclonedx-php-composer/pull/250 [#261]: https://github.com/CycloneDX/cyclonedx-php-composer/issues/261 diff --git a/demo/devReq/results/bom.1.4.json b/demo/devReq/results/bom.1.4.json index 3e0fa9a1..2b3b6ffc 100644 --- a/demo/devReq/results/bom.1.4.json +++ b/demo/devReq/results/bom.1.4.json @@ -8,7 +8,24 @@ { "vendor": "cyclonedx", "name": "cyclonedx-php-composer", - "version": "in-dev" + "version": "in-dev", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/#readme", + "comment": "as detected from composer manifest \"homepage\"" + }, + { + "type": "issue-tracker", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/issues", + "comment": "as detected from composer manifest 'support.issues'" + }, + { + "type": "vcs", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/", + "comment": "as detected from composer manifest 'support.source'" + } + ] } ], "component": { diff --git a/demo/devReq/results/bom.1.4.xml b/demo/devReq/results/bom.1.4.xml index 2d0522e1..746c1ed1 100644 --- a/demo/devReq/results/bom.1.4.xml +++ b/demo/devReq/results/bom.1.4.xml @@ -6,6 +6,20 @@ + + + + + + + + + + + + + + diff --git a/demo/laravel-7.12.0/results/bom.1.4.json b/demo/laravel-7.12.0/results/bom.1.4.json index c82da11a..964cd7bb 100644 --- a/demo/laravel-7.12.0/results/bom.1.4.json +++ b/demo/laravel-7.12.0/results/bom.1.4.json @@ -8,7 +8,24 @@ { "vendor": "cyclonedx", "name": "cyclonedx-php-composer", - "version": "in-dev" + "version": "in-dev", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/#readme", + "comment": "as detected from composer manifest \"homepage\"" + }, + { + "type": "issue-tracker", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/issues", + "comment": "as detected from composer manifest 'support.issues'" + }, + { + "type": "vcs", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/", + "comment": "as detected from composer manifest 'support.source'" + } + ] } ], "component": { diff --git a/demo/laravel-7.12.0/results/bom.1.4.xml b/demo/laravel-7.12.0/results/bom.1.4.xml index 67628b92..cd291614 100644 --- a/demo/laravel-7.12.0/results/bom.1.4.xml +++ b/demo/laravel-7.12.0/results/bom.1.4.xml @@ -6,6 +6,20 @@ + + + + + + + + + + + + + + diff --git a/demo/local/results/bom.1.4.json b/demo/local/results/bom.1.4.json index c89324c4..af00210b 100644 --- a/demo/local/results/bom.1.4.json +++ b/demo/local/results/bom.1.4.json @@ -8,7 +8,24 @@ { "vendor": "cyclonedx", "name": "cyclonedx-php-composer", - "version": "in-dev" + "version": "in-dev", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/#readme", + "comment": "as detected from composer manifest \"homepage\"" + }, + { + "type": "issue-tracker", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/issues", + "comment": "as detected from composer manifest 'support.issues'" + }, + { + "type": "vcs", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/", + "comment": "as detected from composer manifest 'support.source'" + } + ] } ], "component": { diff --git a/demo/local/results/bom.1.4.xml b/demo/local/results/bom.1.4.xml index a21d4a7d..47f69bfd 100644 --- a/demo/local/results/bom.1.4.xml +++ b/demo/local/results/bom.1.4.xml @@ -6,6 +6,20 @@ + + + + + + + + + + + + + + diff --git a/demo/symfony/example-results/bom.json b/demo/symfony/example-results/bom.json index 2cf1751d..c219a351 100644 --- a/demo/symfony/example-results/bom.json +++ b/demo/symfony/example-results/bom.json @@ -4,12 +4,29 @@ "specVersion": "1.4", "version": 1, "metadata": { - "timestamp": "2022-12-10T10:14:40Z", + "timestamp": "2022-12-10T11:03:53Z", "tools": [ { "vendor": "cyclonedx", "name": "cyclonedx-php-composer", - "version": "4.0.0-beta.0" + "version": "4.0.0-beta.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/#readme", + "comment": "as detected from composer manifest \"homepage\"" + }, + { + "type": "issue-tracker", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/issues", + "comment": "as detected from composer manifest 'support.issues'" + }, + { + "type": "vcs", + "url": "https://github.com/CycloneDX/cyclonedx-php-composer/", + "comment": "as detected from composer manifest 'support.source'" + } + ] } ], "component": { diff --git a/demo/symfony/example-results/bom.xml b/demo/symfony/example-results/bom.xml index df091c01..9844f10d 100644 --- a/demo/symfony/example-results/bom.xml +++ b/demo/symfony/example-results/bom.xml @@ -1,12 +1,26 @@ - + + + + + + + + + + + + + + + diff --git a/src/Builder.php b/src/Builder.php index c02df0f5..89edbdf8 100644 --- a/src/Builder.php +++ b/src/Builder.php @@ -35,7 +35,6 @@ use Generator; use PackageUrl\PackageUrl; use RuntimeException; -use stdClass; /** * @internal @@ -283,44 +282,9 @@ private function createExternalReferencesFromPackage(CompletePackageInterface $p } /** - * @psalm-param null|non-empty-string $versionOverride - * * @psalm-suppress MissingThrowsDocblock */ - public function createThisTool(?string $versionOverride): Models\Tool - { - // TODO load from actual package ... if available and locked - // use $this->createToolFromPackage() - - /** @var stdClass */ - $thisPackageManifest = json_decode(file_get_contents(__DIR__.'/../composer.json'), false, 512, \JSON_THROW_ON_ERROR); - - $thisPackageManifest->version = $versionOverride - ?? trim(file_get_contents(__DIR__.'/../semver.txt')); - - return $this->createToolFromManifest($thisPackageManifest); - } - - private function createToolFromManifest(stdClass $package): Models\Tool - { - \assert(\is_string($package->name)); - \assert(null === $package->version || \is_string($package->version)); - - [$group, $name] = $this->getGroupAndName($package->name); - - $tool = new Models\Tool(); - $tool->setName($name); - $tool->setVendor($group); - $tool->setVersion($package->version); - $tool->getExternalReferences()->addItems(); - - return $tool; - } - - /** - * @psalm-suppress MissingThrowsDocblock - */ - private function createToolFromPackage(PackageInterface $package): Models\Tool + public function createToolFromPackage(PackageInterface $package): Models\Tool { [$group, $name] = $this->getGroupAndName($package->getName()); $distUrl = $package->getDistUrl(); @@ -331,7 +295,11 @@ private function createToolFromPackage(PackageInterface $package): Models\Tool $tool->setName($name); $tool->setVendor($group); $tool->setVersion($package->getFullPrettyVersion()); - $tool->getExternalReferences()->addItems(); + if ($package instanceof CompletePackageInterface) { + $tool->getExternalReferences()->addItems( + ...iterator_to_array($this->createExternalReferencesFromPackage($package)) + ); + } if ($distUrl) { $tool->getExternalReferences()->addItems( new Models\ExternalReference( diff --git a/src/MakeBom/Command.php b/src/MakeBom/Command.php index 584d9774..924e3589 100644 --- a/src/MakeBom/Command.php +++ b/src/MakeBom/Command.php @@ -118,18 +118,29 @@ private function generateBom(IOInterface $io, Spec $spec): string $this->options->mainComponentVersion, ); - $composer = (new ComposerFactory())->createComposer($io, $this->options->composerFile, fullLoad: true); + $subjectComposer = (new ComposerFactory())->createComposer($io, $this->options->composerFile, fullLoad: true); /** @psalm-suppress RedundantConditionGivenDocblockType -- as with lowest-compatible dependencies this is needed */ - \assert($composer instanceof \Composer\Composer); - $bom = $builder->createBomFromComposer($composer); - unset($composer); + \assert($subjectComposer instanceof \Composer\Composer); + $bom = $builder->createBomFromComposer($subjectComposer); + unset($subjectComposer); if (!$this->options->outputReproducible) { $bom->getMetadata()->setTimestamp(new DateTime()); } + + $selfComposer = (new ComposerFactory())->createComposer($io, __DIR__.'/../../composer.json', + fullLoad: false, disablePlugins: true, disableScripts: true); + /** @psalm-suppress RedundantConditionGivenDocblockType -- as with lowest-compatible dependencies this is needed */ + \assert($selfComposer instanceof \Composer\PartialComposer); $bom->getMetadata()->getTools()->addItems( - $builder->createThisTool($this->options->getToolVersionOverride()) + $builder->createToolFromPackage( + $selfComposer->getPackage() + )->setVersion( + $this->options->getToolVersionOverride() + ?? trim(file_get_contents(__DIR__.'/../../semver.txt') + )) ); + unset($selfComposer); $io->writeError('serialize BOM...', verbosity: IOInterface::VERBOSE); /** @var Serialization\Serializer */