Skip to content

Commit

Permalink
Add p2-aware model converter for CycloneDX SBOM generation
Browse files Browse the repository at this point in the history
  • Loading branch information
ptziegler committed Dec 14, 2023
1 parent aa29626 commit 6b7db61
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 0 deletions.
1 change: 1 addition & 0 deletions tycho-extras/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<module>target-platform-validation-plugin</module>
<module>tycho-pomless</module>
<module>tycho-dependency-tools-plugin</module>
<module>tycho-sbom</module>
</modules>

<dependencyManagement>
Expand Down
8 changes: 8 additions & 0 deletions tycho-extras/tycho-sbom/.settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=17
55 changes: 55 additions & 0 deletions tycho-extras/tycho-sbom/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.tycho.extras</groupId>
<artifactId>tycho-extras</artifactId>
<version>5.0.0-SNAPSHOT</version>
</parent>
<artifactId>tycho-sbom</artifactId>
<name>Tycho SBOM model extension</name>

<dependencies>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>p2-maven-plugin</artifactId>
<version>${project.version}</version>
<type>maven-plugin</type>
</dependency>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-versions-plugin</artifactId>
<version>${project.version}</version>
<type>maven-plugin</type>
</dependency>

<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-component-annotations</artifactId>
</dependency>

<dependency>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>2.7.10</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*******************************************************************************
* Copyright (c) 2023 Patrick Ziegler and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Patrick Ziegler - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.sbom;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Set;

import org.apache.maven.RepositoryUtils;
import org.apache.maven.artifact.Artifact;
import org.codehaus.plexus.component.annotations.Component;
import org.cyclonedx.maven.DefaultModelConverter;
import org.cyclonedx.maven.ModelConverter;
import org.eclipse.equinox.p2.metadata.IArtifactKey;
import org.eclipse.tycho.ArtifactKey;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.DefaultArtifactKey;
import org.eclipse.tycho.core.resolver.target.ArtifactTypeHelper;
import org.eclipse.tycho.versions.engine.Versions;

/**
* Custom implementation of the CycloneDX model converter with support for both
* Maven and p2 artifacts. The generated PURL is usually of the form:
*
* <pre>
* pkg:/p2/&lt;id&gt;@&lt;version&gt;?classifier=&lt;classifier&gt;&amp;location=&lt;download-url&gt;
* </pre>
*
* This converter can be used with the {@code cyclonedx-maven-plugin} by adding
* it as a dependency as follows:
*
* <pre>
* &lt;plugin>
* &lt;groupId&gt;org.cyclonedx&lt;/groupId&gt;
* &lt;artifactId&gt;cyclonedx-maven-plugin&lt;/artifactId&gt;
* &lt;dependencies&gt;
* &lt;dependency&gt;
* &lt;groupId&gt;org.eclipse.tycho.extras&lt;/groupId&gt;
* &lt;artifactId&gt;tycho-sbom&lt;/artifactId&gt;
* &lt;/dependency&gt;
* &lt;/dependencies&gt;
* &lt;/plugin&gt;
* </pre>
*/
@Component(role = ModelConverter.class, hint = "p2")
public class P2ModelConverter extends DefaultModelConverter {
private static final Set<String> SUPPORTED_TYPES = Set.of(ArtifactType.TYPE_BUNDLE_FRAGMENT,
ArtifactType.TYPE_ECLIPSE_PLUGIN, ArtifactType.TYPE_ECLIPSE_FEATURE);

@Override
public String generatePackageUrl(Artifact artifact) {
if (SUPPORTED_TYPES.contains(artifact.getType())) {
return generateP2PackageUrl(artifact, true, true);
}
return super.generatePackageUrl(artifact);
}

@Override
public String generatePackageUrl(org.eclipse.aether.artifact.Artifact artifact) {
return generatePackageUrl(RepositoryUtils.toArtifact(artifact));
}

@Override
public String generateVersionlessPackageUrl(Artifact artifact) {
if (SUPPORTED_TYPES.contains(artifact.getType())) {
return generateP2PackageUrl(artifact, false, true);
}
return super.generateVersionlessPackageUrl(artifact);
}

@Override
public String generateVersionlessPackageUrl(org.eclipse.aether.artifact.Artifact artifact) {
return generateVersionlessPackageUrl(RepositoryUtils.toArtifact(artifact));
}

@Override
public String generateClassifierlessPackageUrl(org.eclipse.aether.artifact.Artifact artifact) {
Artifact mavenArtifact = RepositoryUtils.toArtifact(artifact);
if (SUPPORTED_TYPES.contains(mavenArtifact.getType())) {
return generateP2PackageUrl(mavenArtifact, true, false);
}
return super.generateClassifierlessPackageUrl(artifact);
}

private String generateP2PackageUrl(Artifact artifact, boolean withVersion, boolean withClassifier) {
// TODO Resolve "artifact" and use e.g. TychoProjectManager w/ proper qualifier
ArtifactKey artifactKey = new DefaultArtifactKey(artifact.getType(), artifact.getArtifactId(),
Versions.toCanonicalVersion(artifact.getVersion()));
IArtifactKey p2artifactKey = ArtifactTypeHelper.toP2ArtifactKey(artifactKey);
// TODO Try to find p2 location
String location = "unknown";
if (artifact.getFile() != null) {
location = artifact.getFile().toURI().toString();
}
if (artifact.getDownloadUrl() != null) {
location = artifact.getDownloadUrl();
}
String encodedLocation = URLEncoder.encode(location, StandardCharsets.UTF_8);
//
StringBuilder builder = new StringBuilder();
builder.append("pkg:p2/");
builder.append(p2artifactKey.getId());
if (withVersion) {
builder.append('@');
builder.append(p2artifactKey.getVersion());
}
builder.append('?');
if (withClassifier) {
builder.append("classifier=");
builder.append(p2artifactKey.getClassifier());
builder.append('&');
}
builder.append("location=");
builder.append(encodedLocation);
return builder.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<component-set>
<components>
<component>
<role>org.cyclonedx.maven.ModelConverter</role>
<hint>p2</hint>
<implementation>org.eclipse.tycho.sbom.P2ModelConverter</implementation>
</component>
</components>
</component-set>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*******************************************************************************
* Copyright (c) 2023 Patrick Ziegler and others.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Patrick Ziegler - initial API and implementation
*******************************************************************************/
package org.eclipse.tycho.sbom;

import static org.junit.Assert.assertEquals;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.cyclonedx.maven.ModelConverter;
import org.eclipse.tycho.ArtifactType;
import org.eclipse.tycho.p2maven.repository.EclipsePluginArtifactHandler;
import org.junit.Before;
import org.junit.Test;

public class P2ModelConverterTest {
private Artifact artifact;
private ModelConverter modelConverter;

@Before
public void setUp() {
artifact = new DefaultArtifact("p2.eclipse.plugin", "org.eclipse.platform", "4.30.0.v20231201-0110", "compile",
ArtifactType.TYPE_ECLIPSE_PLUGIN, null, new EclipsePluginArtifactHandler());
artifact.setDownloadUrl(
"https://download.eclipse.org/releases/2023-12/202312061001/plugins/org.eclipse.platform_4.30.0.v20231201-0110.jar");
modelConverter = new P2ModelConverter();
}

@Test
public void testGeneratePackageUrl() {
String purl = modelConverter.generatePackageUrl(artifact);
String location = URLEncoder.encode(artifact.getDownloadUrl(), StandardCharsets.UTF_8);
assertEquals(purl,
"pkg:p2/[email protected]?classifier=osgi.bundle&location=" + location);
}

@Test
public void testGeneratePackageUrlWithoutVersion() {
String purl = modelConverter.generateVersionlessPackageUrl(artifact);
String location = URLEncoder.encode(artifact.getDownloadUrl(), StandardCharsets.UTF_8);
assertEquals(purl, "pkg:p2/org.eclipse.platform?classifier=osgi.bundle&location=" + location);
}
}

0 comments on commit 6b7db61

Please sign in to comment.