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 */