Skip to content

[GR-64832] [GR-64725] Gracefully handle '--enable-sbom' in CE builds #11191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion docs/reference-manual/native-image/BuildOutput.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ The storage formats include: `embed`, which embeds the SBOM in the binary; `clas
The SBOM feature is enabled by default and defaults to the `embed` option.
When embedded, the SBOM size is displayed.
The number of components is always displayed.
The SBOM feature can be disabled with `--enable-sbom=false`.
The SBOM feature can be disabled by using `--enable-sbom=false` on the command line.

Unassociated types are displayed when certain types (such as classes, interfaces, or annotations) cannot be linked to an SBOM component.
If these types contain vulnerabilities, SBOM scanning will not detect them.
Expand Down
2 changes: 1 addition & 1 deletion docs/security/SBOM.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The SBOM is compressed to limit the SBOM's impact on the native executable size.
The compressed size is typically less than 1/10,000 of the overall image size.
The SBOM is stored in the `gzip` format with the exported `sbom` symbol referencing its start address and the `sbom_length` symbol referencing its size.

The SBOM feature can be disabled with `--enable-sbom=false`.
The SBOM feature can be disabled by using `--enable-sbom=false` on the command line.

## Extracting SBOM Contents

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.hosted.sbom;

import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.option.APIOption;
import com.oracle.svm.core.option.AccumulatingLocatableMultiOptionValue;
import com.oracle.svm.core.option.HostedOptionKey;

import jdk.graal.compiler.options.Option;
import jdk.graal.compiler.options.OptionStability;
import jdk.graal.compiler.options.OptionType;

/**
* The Software Bill of Materials (SBOM) feature is only available for Oracle GraalVM. The purpose
* of this package is to display a helpful error message if the SBOM feature is activated with
* GraalVM Community Edition.
*/
@AutomaticallyRegisteredFeature
public class SBOMFeature implements InternalFeature {
protected static final String sbomResourceLocation = "META-INF/native-image/sbom.json";

public static final class Options {
public static final String name = "--enable-sbom";
@APIOption(name = name, defaultValue = "") //
@Option(help = "Assemble a Software Bill of Materials (SBOM) for the executable or shared library based on the results from the static analysis " +
" (only available in Oracle GraalVM). Comma-separated list can contain " +
"'" + SBOMValues.StorageOption.embed + "' to store the SBOM in data sections of the binary, " +
"'" + SBOMValues.StorageOption.export + "' to save the SBOM in the output directory, " +
"'" + SBOMValues.StorageOption.classpath + "' to include the SBOM as a Java resource on the classpath at '" + sbomResourceLocation + "', " +
"'" + SBOMValues.strict + "' to abort the build if any type (such as a class, interface, or annotation) cannot be matched to an SBOM component, " +
"'" + SBOMValues.cyclonedxFormat + "' (the only format currently supported), and '" + SBOMValues.classLevel + "' to include class-level " +
"metadata. The default in Oracle Oracle GraalVM is to embed an SBOM: '" + name + "=" + SBOMValues.StorageOption.embed + "'. " +
"To disable the SBOM feature, use '" + name + "=" + SBOMValues.disableSBOM + "' on the command line.", type = OptionType.User, stability = OptionStability.STABLE) //
public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> IncludeSBOM = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter(),
(options) -> SBOMValueValidator.getInstance().validateSBOMValues(options));
}

@Override
public void afterRegistration(AfterRegistrationAccess access) {
ImageSingletons.add(SBOMValueValidator.class, new UnsupportedSBOMValueValidator());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.hosted.sbom;

import java.util.List;
import java.util.stream.Stream;

import org.graalvm.nativeimage.ImageSingletons;

import com.oracle.svm.core.option.LocatableMultiOptionValue;
import com.oracle.svm.core.util.UserError;

import jdk.graal.compiler.options.OptionKey;

/**
* Validates the values passed to '--enable-sbom'.
*/
public abstract class SBOMValueValidator {
public abstract void validateSBOMValues(OptionKey<?> optionKey);

static SBOMValueValidator getInstance() {
return ImageSingletons.lookup(SBOMValueValidator.class);
}

/**
* Aborts execution if the SBOM feature is deactivated from non-command-line sources like
* 'native-image.properties'. Native Image only supports subtractive option usage from the CLI.
*/
protected static void abortIfSBOMDisabledFromOtherThanCommandLine() {
var optionalFalseOrigin = getNonCommandLikeOriginStream()
.filter(v -> v.value().equals(SBOMValues.disableSBOM))
.findFirst();
if (optionalFalseOrigin.isPresent()) {
List<String> nonCommandLineValues = getNonCommandLikeOriginStream()
.map(LocatableMultiOptionValue.ValueWithOrigin::value)
.toList();
String message = String.format("Value '%s' for option '%s' can only be used on the command line with 'native-image'. Found non-command-line option '%s=%s' from %s.",
SBOMValues.disableSBOM, SBOMFeature.Options.name, SBOMFeature.Options.name, String.join(",", nonCommandLineValues), optionalFalseOrigin.get().origin());
throw UserError.abort(message);
}
}

private static Stream<LocatableMultiOptionValue.ValueWithOrigin<String>> getNonCommandLikeOriginStream() {
return SBOMFeature.Options.IncludeSBOM.getValue().getValuesWithOrigins()
.filter(v -> !v.origin().commandLineLike());
}

protected static boolean isLastValueNotDisable() {
var lastOrigin = SBOMFeature.Options.IncludeSBOM.getValue().lastValueWithOrigin();
return lastOrigin.map(v -> !v.value().equals(SBOMValues.disableSBOM))
.orElse(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.hosted.sbom;

import java.util.Set;

/**
* Defines the available values for the SBOM feature. See {@link SBOMFeature.Options} for more
* information about the individual values.
* <p>
* Note: the only supported SBOM value for GraalVM Community Edition is
* {@link SBOMValues#disableSBOM}.
*/
public class SBOMValues {
public static final String cyclonedxFormat = "cyclonedx";
/**
* The SBOM feature is disabled by passing '--enable-sbom=false'.
*/
public static final String disableSBOM = "false";
public static final String strict = "strict";
/**
* If set, then the classes, fields, constructors, and methods that are used in the image are
* collected and included in the SBOM.
*/
public static final String classLevel = "class-level";

public static final class StorageOption {
public static final String embed = "embed";
public static final String export = "export";
public static final String classpath = "classpath";
public static final Set<String> supportedStorageValues = Set.of(embed, export, classpath);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.hosted.sbom;

import java.util.List;

import com.oracle.svm.core.util.UserError;

import jdk.graal.compiler.options.OptionKey;

/**
* Value validator for '--enable-sbom' that aborts execution if the SBOM feature is activated.
*/
final class UnsupportedSBOMValueValidator extends SBOMValueValidator {
@Override
public void validateSBOMValues(OptionKey<?> optionKey) {
List<String> values = SBOMFeature.Options.IncludeSBOM.getValue().values();
if (values.isEmpty()) {
return;
}

SBOMValueValidator.abortIfSBOMDisabledFromOtherThanCommandLine();
abortIfLastOriginDoesNotDisableSBOM();
}

private static void abortIfLastOriginDoesNotDisableSBOM() {
if (isLastValueNotDisable()) {
String message = String.format("""
The SBOM feature is only available in Oracle GraalVM. \
Upgrade to Oracle GraalVM or disable the SBOM feature by omitting '%s' or \
by making sure '%s=%s' is last on the command line.
""", SBOMFeature.Options.name, SBOMFeature.Options.name, SBOMValues.disableSBOM);
UserError.abort(message);
}
}
}
Loading