Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ toc::[]
image::Overview.png[]

1. Create a *Software Bill of Materials* (SBOM) for your source code.
2. Call the *Jenkins Plugin* in your build job to create a component manifest and download the license files.
2. Call the *Jenkins Plugin* in your build job to create a component manifest, to patch the SBOM and download the license files.
You can *configure* several JSON data sources to improve data quality.
3. Add the component manifest and the license files to your delivery package (e.g. ZIP, WAR, MSI).

Expand Down Expand Up @@ -80,6 +80,11 @@ Entries have the following attributes:
| If groupMatch is not set
| Regular expression for the component's name

|purlMatch
| Package URL
| Optional, if groupMatch and nameMatch is not set and patching is in use
| Regular expression for the component's purl

| mappedName
| String
| Optional
Expand Down Expand Up @@ -148,6 +153,18 @@ Here are some examples to illustrate what you can do with it:
}
----

- Patching SBOM licenses > override licenses

[source,json]
----
{
"purl": "pkg:maven\/com\.github\.kenglxn\.qrgen\/.*@2\.6\.0\?type=jar",
"licenses": [
"Apache-2.0"
]
}
----

==== License information
Use this setting to define licenses and URLs with the license texts. The URL needs to point to a JSON file containing an array of entries with the following attributes:
|===
Expand All @@ -170,7 +187,9 @@ Use this setting to define licenses and URLs with the license texts. The URL nee
|===

==== License mapping
Different components often use different names for the same license. You can use this setting to define aliases for licenses. The URL needs to point to a JSON file containing an array of entries with the following attributes:
Different components often use different names for the same license. You can use this setting to define aliases for
licenses. The URL needs to point to a JSON file containing an array of entries with the following attributes:

|===
|Name | Type | Required?| Meaning

Expand All @@ -185,6 +204,19 @@ Different components often use different names for the same license. You can use
|The name of the license in the license information
|===

==== License patching rules URL
The URL where to download the rules for patching BOM licenses. This is a required field when you want to use license
patching.

tbd

==== SPDX licenses URL
The URL where to download the list of supported SPDX licenses. If not set, then a local copy of the
https://github.com/spdx/license-list-data/tree/main/json[SPDX GitHub project] will be used.

==== Resolve license expressions
tbd

=== Create manifest
This build step creates a component manifest file based on an input SBOM and the global configuration.

Expand Down Expand Up @@ -251,6 +283,25 @@ pipeline {
}
----

=== Patch SBOM
This build step patch a SBOM, based on your component manifest configuration and the global configuration.
Goal is, to fix incomplete or incorrect license informations in your SBOM.

[source,groovy,title=Declarative pipeline example]
----
pipeline {
agent any

stages {
stage('Patch BOM') {
steps {
patchBOM inputFile: 'input.bom', outputFile: 'output.bom'
}
}
}
}
----

== CLI tool
You can also run the tool as a standalone CLI tool.
This is especially useful when you want to test out changes to component or license metadata since you do not have to switch back and forth between Jenkins
Expand Down Expand Up @@ -285,6 +336,15 @@ Examples:
----
java -jar license-compliance-tool-cli.jar download-licenses --in=path/to/bom --out=manifest.html
----
* Patch licenses
[source]
----
java -jar license-compliance-tool-cli.jar
patch-sbom
--in=file-path/in.bom
--out=file-path/out.bom
--componentMetadata=https://your.server.url/componentMetadata.json
----
* Get usage help
[source]
----
Expand Down
11 changes: 8 additions & 3 deletions cli/pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<properties>
<picocli.version>4.7.6</picocli.version>
Expand Down Expand Up @@ -37,6 +35,13 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</dependency>

<!-- Other test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
19 changes: 17 additions & 2 deletions cli/src/main/java/de/medavis/lct/cli/ConfigurationOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -21,11 +21,14 @@

import java.net.URL;
import java.util.Optional;

import picocli.CommandLine.Command;
import picocli.CommandLine.Option;

import de.medavis.lct.core.Configuration;

import org.jetbrains.annotations.NotNull;

import static de.medavis.lct.cli.StringToUrlConverter.convert;

@Command
Expand All @@ -38,16 +41,28 @@ class ConfigurationOptions implements Configuration {
@Option(names = {"--licenseMapping", "-lm"})
private String licenseMappingsUrl;

@Option(names = {"--spdxLicenseListUrl", "-sllu"}, description = "URL where to download official supported SPDX licenses. If not set, then local copy will be used")
private String spdxLicenseListUri;

@Override
public Optional<URL> getComponentMetadataUrl() {
return convert(componentMetadataUrl);
}

@Override
public Optional<URL> getLicensesUrl() {
return convert(licensesUrl);
}

@Override
public Optional<URL> getLicenseMappingsUrl() {
return convert(licenseMappingsUrl);
}

@Override
@NotNull
public Optional<URL> getSpdxLicensesUrl() {
return convert(spdxLicenseListUri);
}

}
9 changes: 5 additions & 4 deletions cli/src/main/java/de/medavis/lct/cli/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,21 @@
@Command
class Main {

public Main(String[] args) {
int run(String[] args) {
System.setProperty("org.jboss.logging.provider", "slf4j");

final CommandLine commandLine = new CommandLine(this);
commandLine.addSubcommand(new HelpCommand());
commandLine.addSubcommand(new CreateManifest());
commandLine.addSubcommand(new DownloadLicenses());
commandLine.addSubcommand(new AnalyzeComponents());
System.exit(commandLine.execute(args));
commandLine.addSubcommand(new PatchSBOM());
return commandLine.execute(args);
}

public static void main(String[] args) {
new Main(args);

Main main = new Main();
System.exit(main.run(args));
}

}
59 changes: 59 additions & 0 deletions cli/src/main/java/de/medavis/lct/cli/PatchSBOM.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*-
* #%L
* License Compliance Tool - Command Line Interface
* %%
* Copyright (C) 2022 - 2024 medavis GmbH
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package de.medavis.lct.cli;

import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;

import de.medavis.lct.core.asset.AssetLoader;
import de.medavis.lct.core.license.LicenseLoader;
import de.medavis.lct.core.license.LicenseMappingLoader;
import de.medavis.lct.core.metadata.ComponentMetaDataLoader;
import de.medavis.lct.core.patcher.BomPatcher;

import java.nio.file.Path;
import java.util.concurrent.Callable;

@Command(name = "patch-sbom", description = "Patch SBOM with licenses mapping rules")
public class PatchSBOM implements Callable<Void> {

@Option(names = {"--in", "-i"}, required = true)
private Path inputFile;
@Option(names = {"--out", "-o"}, required = true)
private Path outputFile;
@Mixin
private ConfigurationOptions configurationOptions;

@Override
public Void call() throws Exception {
BomPatcher patcher = new BomPatcher(
new AssetLoader(),
new ComponentMetaDataLoader(),
new LicenseLoader(),
new LicenseMappingLoader(),
configurationOptions);

patcher.patch(inputFile, outputFile);

return null;
}

}
64 changes: 64 additions & 0 deletions cli/src/test/java/de/medavis/lct/cli/JsonPath.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*-
* #%L
* License Compliance Tool - Command Line Interface
* %%
* Copyright (C) 2022 - 2024 medavis GmbH
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package de.medavis.lct.cli;

import com.fasterxml.jackson.databind.JsonNode;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JsonPath {

private static final String REGEX = "(?<name>\\D[a-zA-Z0-9]*)(\\[(?<index>\\d*)\\])?";
private static final Pattern PATTERN = Pattern.compile(REGEX);

private JsonPath() {}

@Nullable
public static JsonNode path(@NotNull JsonNode firstNode, @NotNull String path) {

List<String> items = List.of(path.split("\\."));

JsonNode node = firstNode;

for (String item : items) {
Matcher matcher = PATTERN.matcher(item);
while(matcher.find()) {
String name = matcher.group("name");
node = node.path(name);

String sIndex = matcher.group("index");
if (sIndex != null) {
int index = Integer.parseInt(matcher.group("index"));
node = node.path(index);
if (node == null) {
return null;
}
}
}
}

return node;
}
}
Loading