From c65a9f1fee12cb8068f119185fc0a89f59c15770 Mon Sep 17 00:00:00 2001 From: rorts Date: Wed, 17 Jan 2024 13:46:44 +0100 Subject: [PATCH] Generate externalRefs with PURL --- .../java/org/spdx/maven/CreateSpdxMojo.java | 15 ++- .../utils/SpdxDependencyInformation.java | 13 ++- .../spdx/maven/utils/SpdxDocumentBuilder.java | 8 +- .../maven/utils/SpdxExternalRefBuilder.java | 40 +++++++ .../java/org/spdx/maven/TestSpdxMojo.java | 61 +++++++++- .../json-pom-generate-purl.xml | 109 ++++++++++++++++++ .../json-pom-use-artifact.xml | 4 +- .../unit/spdx-maven-plugin-test/json-pom.xml | 4 +- .../pom-with-no-contributors.xml | 4 +- .../unit/spdx-maven-plugin-test/pom.xml | 4 +- .../unit/spdx-maven-plugin-test/uri-pom.xml | 4 +- 11 files changed, 244 insertions(+), 22 deletions(-) create mode 100644 src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java create mode 100644 src/test/resources/unit/spdx-maven-plugin-test/json-pom-generate-purl.xml diff --git a/src/main/java/org/spdx/maven/CreateSpdxMojo.java b/src/main/java/org/spdx/maven/CreateSpdxMojo.java index 87c4f58..d645f61 100644 --- a/src/main/java/org/spdx/maven/CreateSpdxMojo.java +++ b/src/main/java/org/spdx/maven/CreateSpdxMojo.java @@ -478,9 +478,16 @@ public class CreateSpdxMojo extends AbstractMojo * If true, use ${project.groupId}:${artifactId} as the SPDX package name. * Otherwise, ${project.name} will be used */ - @Parameter + @Parameter( property = "spdx.useArtifactID" ) private boolean useArtifactID; + /** + * If true, adds an external reference to every package with category "PACKAGE-MANAGER", type "purl" + * and locator "pkg:maven/${project.groupId}/${project.artifactId}@${project.version}". + */ + @Parameter( property = "spdx.generatePurls" ) + private boolean generatePurls; + public void execute() throws MojoExecutionException { if ( skip ) @@ -608,7 +615,7 @@ private SpdxDocumentBuilder initSpdxDocumentBuilder( OutputFormat outputFormatEn spdxDocumentNamespace = spdxDocumentNamespace.replace( " ", "%20" ); } URI namespaceUri = new URI( spdxDocumentNamespace ); - builder = new SpdxDocumentBuilder( spdxFile, namespaceUri, + builder = new SpdxDocumentBuilder( mavenProject, generatePurls, spdxFile, namespaceUri, this.matchLicensesOnCrossReferenceUrls, outputFormatEnum ); } catch ( SpdxBuilderException e ) @@ -652,7 +659,7 @@ private SpdxDependencyInformation getSpdxDependencyInformation( Set de SpdxDocumentBuilder builder, boolean useArtifactID ) throws LicenseMapperException, InvalidSPDXAnalysisException { - SpdxDependencyInformation retval = new SpdxDependencyInformation( builder.getLicenseManager(), builder.getSpdxDoc(), createExternalRefs ); + SpdxDependencyInformation retval = new SpdxDependencyInformation( builder.getLicenseManager(), builder.getSpdxDoc(), createExternalRefs, generatePurls ); if ( dependencies != null ) { for ( Artifact dependency : dependencies ) @@ -798,7 +805,7 @@ private void logIncludedDirectories( List includedDirectories ) } /** - * @param container SPDX Document containing any extracted license infos + * @param spdxDoc SPDX Document containing any extracted license infos * @return default file information from the plugin parameters * @throws MojoExecutionException */ diff --git a/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java b/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java index d9f3ae8..c0a0445 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java +++ b/src/main/java/org/spdx/maven/utils/SpdxDependencyInformation.java @@ -58,7 +58,9 @@ import org.spdx.library.SpdxInvalidIdException; import org.spdx.library.model.Checksum; import org.spdx.library.model.ExternalDocumentRef; +import org.spdx.library.model.ExternalRef; import org.spdx.library.model.ExternalSpdxElement; +import org.spdx.library.model.ReferenceType; import org.spdx.library.model.Relationship; import org.spdx.library.model.SpdxDocument; import org.spdx.library.model.SpdxElement; @@ -66,6 +68,7 @@ import org.spdx.library.model.enumerations.AnnotationType; import org.spdx.library.model.enumerations.ChecksumAlgorithm; import org.spdx.library.model.enumerations.Purpose; +import org.spdx.library.model.enumerations.ReferenceCategory; import org.spdx.library.model.enumerations.RelationshipType; import org.spdx.library.model.license.AnyLicenseInfo; import org.spdx.library.model.license.SpdxNoAssertionLicense; @@ -153,16 +156,18 @@ public RelationshipType getRelationshipType() private LicenseManager licenseManager; private SpdxDocument spdxDoc; private boolean createExternalRefs = false; + private boolean generatePurls = false; DateFormat format = new SimpleDateFormat( SpdxConstants.SPDX_DATE_FORMAT ); /** */ public SpdxDependencyInformation( LicenseManager licenseManager, - SpdxDocument spdxDoc, boolean createExternalRefs ) + SpdxDocument spdxDoc, boolean createExternalRefs, boolean generatePurls ) { this.licenseManager = licenseManager; this.spdxDoc = spdxDoc; this.createExternalRefs = createExternalRefs; + this.generatePurls = generatePurls; } /** @@ -360,6 +365,11 @@ private SpdxElement createSpdxPackage( Artifact artifact, .setComment( "This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file." ) .setVersionInfo( artifact.getBaseVersion() ) .setFilesAnalyzed( false ) +<<<<<<< Updated upstream +======= + .setDownloadLocation( "NOASSERTION" ) + .setExternalRefs( SpdxExternalRefBuilder.getDefaultExternalRefs( spdxDoc, generatePurls, mavenProject ) ) +>>>>>>> Stashed changes .build(); return pkg; } @@ -668,6 +678,7 @@ private SpdxPackage createSpdxPackage( MavenProject project, boolean useArtifact packageName, new SpdxNoAssertionLicense(), copyright, declaredLicense ) .setDownloadLocation( downloadLocation ) .setFilesAnalyzed( false ) + .setExternalRefs( SpdxExternalRefBuilder.getDefaultExternalRefs( spdxDoc, generatePurls, project ) ) .build(); if ( project.getVersion() != null ) { diff --git a/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java index cbab038..c477982 100644 --- a/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java +++ b/src/main/java/org/spdx/maven/utils/SpdxDocumentBuilder.java @@ -31,6 +31,7 @@ import java.util.Set; import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; import org.apache.maven.shared.model.fileset.FileSet; import org.spdx.jacksonstore.MultiFormatStore; @@ -80,6 +81,8 @@ public class SpdxDocumentBuilder //TODO: Map the SPDX document to the Maven build artifacts DateFormat format = new SimpleDateFormat( SpdxConstants.SPDX_DATE_FORMAT ); + private MavenProject project; + private boolean generatePurls; private SpdxDocument spdxDoc; private SpdxPackage projectPackage; private LicenseManager licenseManager; @@ -98,9 +101,11 @@ public class SpdxDocumentBuilder * @throws SpdxBuilderException * @throws LicenseMapperException */ - public SpdxDocumentBuilder( File spdxFile, URI spdxDocumentNamespace, + public SpdxDocumentBuilder( MavenProject project, boolean generatePurls, File spdxFile, URI spdxDocumentNamespace, boolean useStdLicenseSourceUrls, OutputFormat outputFormat ) throws SpdxBuilderException, LicenseMapperException { + this.project = project; + this.generatePurls = generatePurls; this.spdxFile = spdxFile; if ( spdxDocumentNamespace == null ) @@ -336,6 +341,7 @@ private SpdxPackage createSpdxPackage( SpdxProjectInformation projectInformation .setDownloadLocation( downloadUrl ) .setPackageVerificationCode( nullPackageVerificationCode ) .setPrimaryPurpose( projectInformation.getPrimaryPurpose() ) + .setExternalRefs( SpdxExternalRefBuilder.getDefaultExternalRefs( spdxDoc, generatePurls, project ) ) .build(); } catch ( InvalidSPDXAnalysisException e ) diff --git a/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java b/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java new file mode 100644 index 0000000..20f5467 --- /dev/null +++ b/src/main/java/org/spdx/maven/utils/SpdxExternalRefBuilder.java @@ -0,0 +1,40 @@ +package org.spdx.maven.utils; + +import java.util.Collection; +import java.util.List; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.project.MavenProject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spdx.library.InvalidSPDXAnalysisException; +import org.spdx.library.model.ExternalRef; +import org.spdx.library.model.ReferenceType; +import org.spdx.library.model.SpdxDocument; +import org.spdx.library.model.enumerations.ReferenceCategory; + +public class SpdxExternalRefBuilder +{ + + private static final Logger LOG = LoggerFactory.getLogger( SpdxExternalRefBuilder.class ); + + public static Collection getDefaultExternalRefs( SpdxDocument spdxDoc, boolean generatePurls, MavenProject project ) { + ExternalRef generatedPurlExternalRef = generatePurls ? generatePurlExternalRef( spdxDoc, project ) : null; + return generatedPurlExternalRef == null ? List.of() : List.of(generatedPurlExternalRef); + } + + private static ExternalRef generatePurlExternalRef( SpdxDocument spdxDoc, MavenProject project ) + { + try + { + String purl = "pkg:maven/" + project.getGroupId() + "/" + project.getArtifactId() + "@" + project.getVersion(); + return spdxDoc.createExternalRef( ReferenceCategory.PACKAGE_MANAGER, new ReferenceType("http://spdx.org/rdf/references/purl"), + purl, null ); + } + catch (InvalidSPDXAnalysisException e) + { + LOG.warn( "Invalid reference type \"purl\" for generated purl external ref"); + return null; + } + } + +} diff --git a/src/test/java/org/spdx/maven/TestSpdxMojo.java b/src/test/java/org/spdx/maven/TestSpdxMojo.java index d2ecc00..c9d0a24 100644 --- a/src/test/java/org/spdx/maven/TestSpdxMojo.java +++ b/src/test/java/org/spdx/maven/TestSpdxMojo.java @@ -14,11 +14,13 @@ import org.junit.After; import org.junit.AfterClass; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.spdx.jacksonstore.MultiFormatStore; import org.spdx.jacksonstore.MultiFormatStore.Format; import org.spdx.library.ModelCopyManager; import org.spdx.library.model.ExternalRef; +import org.spdx.library.model.ReferenceType; import org.spdx.library.model.SpdxDocument; import org.spdx.library.model.SpdxElement; import org.spdx.library.model.SpdxFile; @@ -77,7 +79,7 @@ public void testExecute() throws Exception assertTrue( spdxFile.exists() ); // Test output artifact file is created File artifactFile = getTestFile( - "target/test-classes/unit/spdx-maven-plugin-test/spdx maven plugin test.spdx.rdf.xml" ); + "target/test-classes/unit/spdx-maven-plugin-test/spdx-maven-plugin-test.spdx.rdf.xml" ); assertTrue( artifactFile.exists() ); ISerializableModelStore modelStore = new RdfStore(); ModelCopyManager copyManager = new ModelCopyManager(); @@ -321,7 +323,7 @@ public void testExecuteUseArtfactId() throws Exception assertTrue( spdxFile.exists() ); // Test output artifact file is created File artifactFile = getTestFile( - "target/test-classes/unit/spdx-maven-plugin-test/spdx maven plugin test.spdx.json" ); + "target/test-classes/unit/spdx-maven-plugin-test/spdx-maven-plugin-test.spdx.json" ); assertTrue( artifactFile.exists() ); ISerializableModelStore modelStore = new MultiFormatStore( new InMemSpdxStore(), Format.JSON ); ModelCopyManager copyManager = new ModelCopyManager(); @@ -431,7 +433,7 @@ else if ( creator.equals( "Person: Creator2" ) ) assertTrue( described instanceof SpdxPackage ); SpdxPackage pkg = (SpdxPackage) described; // name - assertEquals( "org.spdx:spdx maven plugin test", pkg.getName().get() ); + assertEquals( "org.spdx:spdx-maven-plugin-test", pkg.getName().get() ); // packageAnnotations assertEquals( 1, pkg.getAnnotations().size() ); org.spdx.library.model.Annotation annotation = pkg.getAnnotations().toArray( new org.spdx.library.model.Annotation [pkg.getAnnotations().size()] )[0]; @@ -567,7 +569,7 @@ public void testExecuteJson() throws Exception assertTrue( spdxFile.exists() ); // Test output artifact file is created File artifactFile = getTestFile( - "target/test-classes/unit/spdx-maven-plugin-test/spdx maven plugin test.spdx.json" ); + "target/test-classes/unit/spdx-maven-plugin-test/spdx-maven-plugin-test.spdx.json" ); assertTrue( artifactFile.exists() ); ISerializableModelStore modelStore = new MultiFormatStore( new InMemSpdxStore(), Format.JSON ); ModelCopyManager copyManager = new ModelCopyManager(); @@ -850,7 +852,7 @@ public void testExecuteUriNotUrl() throws Exception assertTrue( spdxFile.exists() ); // Test output artifact file is created File artifactFile = getTestFile( - "target/test-classes/unit/spdx-maven-plugin-test/spdx maven plugin test.spdx.rdf.xml" ); + "target/test-classes/unit/spdx-maven-plugin-test/spdx-maven-plugin-test.spdx.rdf.xml" ); assertTrue( artifactFile.exists() ); ISerializableModelStore modelStore = new RdfStore(); ModelCopyManager copyManager = new ModelCopyManager(); @@ -883,7 +885,7 @@ public void testExecuteNoContributors() throws Exception assertTrue( spdxFile.exists() ); // Test output artifact file is created File artifactFile = getTestFile( - "target/test-classes/unit/spdx-maven-plugin-test/spdx maven plugin test.spdx.rdf.xml" ); + "target/test-classes/unit/spdx-maven-plugin-test/spdx-maven-plugin-test.spdx.rdf.xml" ); assertTrue( artifactFile.exists() ); ISerializableModelStore modelStore = new RdfStore(); ModelCopyManager copyManager = new ModelCopyManager(); @@ -1110,4 +1112,51 @@ else if ( externalRefs[0].getReferenceCategory().equals( assertEquals( fileWithSnippet, snippets.get( 1 ).getSnippetFromFile().getId() ); //TODO Test dependencies } + + @Test + public void testExecuteUseGeneratePurls() throws Exception + { + File testPom = new File( getBasedir(), UNIT_TEST_RESOURCE_DIR + "/json-pom-generate-purl.xml" ); + // CreateSpdxMojo mojo = (CreateSpdxMojo) configureMojo( myMojo, "spdx-maven-plugin", testPom ); + // if the below does not work due to a lookup error, run mvn test goal + CreateSpdxMojo mojo = (CreateSpdxMojo) lookupMojo( "createSPDX", testPom ); + assertNotNull( mojo ); + mojo.execute(); + // Test SPDX filename parameter + File spdxFile = new File( getBasedir(), SPDX_JSON_FILE_NAME ); + assertTrue( spdxFile.exists() ); + // Test output artifact file is created + File artifactFile = getTestFile( + "target/test-classes/unit/spdx-maven-plugin-test/spdx-maven-plugin-test.spdx.json" ); + assertTrue( artifactFile.exists() ); + ISerializableModelStore modelStore = new MultiFormatStore( new InMemSpdxStore(), Format.JSON ); + ModelCopyManager copyManager = new ModelCopyManager(); + SpdxDocument result; + String documentUri; + try ( InputStream is = new FileInputStream( artifactFile.getAbsolutePath() ) ) + { + documentUri = modelStore.deSerialize( is, false ); + result = new SpdxDocument( modelStore, documentUri, copyManager, false ); + } + List warnings = result.verify(); + assertEquals( 0, warnings.size() ); + // Test configuration parameters found in the test resources pom.xml file + // Document namespace + assertEquals( "http://spdx.org/documents/spdx%20toolsv2.0%20rc1", result.getDocumentUri() ); + // purls + List packages = new ArrayList<>(); + SpdxModelFactory.getElements( modelStore, documentUri, copyManager, SpdxPackage.class ).forEach( (pkg) -> { + packages.add( (SpdxPackage)pkg ); + }); + for ( SpdxPackage pkg : packages ) { + Collection externalRefs = pkg.getExternalRefs(); + assertNotNull( externalRefs ); + assertFalse( externalRefs.isEmpty() ); + ExternalRef externalRef = pkg.getExternalRefs().stream().findFirst().get(); + assertEquals( externalRef.getReferenceCategory(), ReferenceCategory.PACKAGE_MANAGER ); + assertEquals( externalRef.getReferenceType().getIndividualURI(), "http://spdx.org/rdf/references/purl"); + assertEquals( externalRef.getReferenceLocator(), + "pkg:maven/" + pkg.getName().get().replace(":", "/") + "@" + pkg.getVersionInfo().get() ); + } + } } diff --git a/src/test/resources/unit/spdx-maven-plugin-test/json-pom-generate-purl.xml b/src/test/resources/unit/spdx-maven-plugin-test/json-pom-generate-purl.xml new file mode 100644 index 0000000..053a7c9 --- /dev/null +++ b/src/test/resources/unit/spdx-maven-plugin-test/json-pom-generate-purl.xml @@ -0,0 +1,109 @@ + + 4.0.0 + + org.spdx + spdx-maven-plugin-test + 1.0-SNAPSHOT + jar + Test SPDX Plugin + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + http://spdx.org/tools + + Linux Foundation + http://www.linuxfoundation.org + + + UTF-8 + + + + + junit + junit + 4.13.1 + test + + + + + src + Test + + + resources + false + resources + + **/* + + + + META-INF + false + . + + NOTICE + LICENSE + README.txt + changelog + + + + src + + **/*.java + + + + + + Test + + **/*.java + + + + false + TestFiles + + **/* + + + + + + + org.spdx + spdx-maven-plugin + + + build-spdx + prepare-package + + createSPDX + + + + + + + + target/test-classes/unit/spdx-maven-plugin-test/test.spdx.json + true + JSON + http://spdx.org/documents/spdx%20toolsv2.0%20rc1 + Apache-2.0 + true + + + + + diff --git a/src/test/resources/unit/spdx-maven-plugin-test/json-pom-use-artifact.xml b/src/test/resources/unit/spdx-maven-plugin-test/json-pom-use-artifact.xml index 3074dc1..f54c3a5 100644 --- a/src/test/resources/unit/spdx-maven-plugin-test/json-pom-use-artifact.xml +++ b/src/test/resources/unit/spdx-maven-plugin-test/json-pom-use-artifact.xml @@ -4,7 +4,7 @@ 4.0.0 org.spdx - spdx maven plugin test + spdx-maven-plugin-test 1.0-SNAPSHOT jar Test SPDX Plugin @@ -235,4 +235,4 @@ - \ No newline at end of file + diff --git a/src/test/resources/unit/spdx-maven-plugin-test/json-pom.xml b/src/test/resources/unit/spdx-maven-plugin-test/json-pom.xml index 6b64a1d..a8dd724 100644 --- a/src/test/resources/unit/spdx-maven-plugin-test/json-pom.xml +++ b/src/test/resources/unit/spdx-maven-plugin-test/json-pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.spdx - spdx maven plugin test + spdx-maven-plugin-test 1.0-SNAPSHOT jar Test SPDX Plugin @@ -234,4 +234,4 @@ - \ No newline at end of file + diff --git a/src/test/resources/unit/spdx-maven-plugin-test/pom-with-no-contributors.xml b/src/test/resources/unit/spdx-maven-plugin-test/pom-with-no-contributors.xml index 5be1f98..b6ce64f 100644 --- a/src/test/resources/unit/spdx-maven-plugin-test/pom-with-no-contributors.xml +++ b/src/test/resources/unit/spdx-maven-plugin-test/pom-with-no-contributors.xml @@ -4,7 +4,7 @@ 4.0.0 org.spdx - spdx maven plugin test + spdx-maven-plugin-test 1.0-SNAPSHOT jar Test SPDX Plugin @@ -235,4 +235,4 @@ - \ No newline at end of file + diff --git a/src/test/resources/unit/spdx-maven-plugin-test/pom.xml b/src/test/resources/unit/spdx-maven-plugin-test/pom.xml index f751e84..1efd539 100644 --- a/src/test/resources/unit/spdx-maven-plugin-test/pom.xml +++ b/src/test/resources/unit/spdx-maven-plugin-test/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.spdx - spdx maven plugin test + spdx-maven-plugin-test 1.0-SNAPSHOT jar Test SPDX Plugin @@ -239,4 +239,4 @@ - \ No newline at end of file + diff --git a/src/test/resources/unit/spdx-maven-plugin-test/uri-pom.xml b/src/test/resources/unit/spdx-maven-plugin-test/uri-pom.xml index 3545fba..de9db6f 100644 --- a/src/test/resources/unit/spdx-maven-plugin-test/uri-pom.xml +++ b/src/test/resources/unit/spdx-maven-plugin-test/uri-pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.spdx - spdx maven plugin test + spdx-maven-plugin-test 1.0-SNAPSHOT jar Test SPDX Plugin @@ -239,4 +239,4 @@ - \ No newline at end of file +