Add auto-detection for SBOMs in native-image

Closes gh-40630
This commit is contained in:
Moritz Halbritter 2024-10-15 13:43:53 +02:00
parent a66d3d2f00
commit a7fb3699ee
1 changed files with 54 additions and 40 deletions

View File

@ -45,11 +45,13 @@ import org.springframework.util.StringUtils;
@ImportRuntimeHints(SbomEndpointRuntimeHints.class)
public class SbomEndpoint {
private static final List<String> DEFAULT_APPLICATION_SBOM_LOCATIONS = List.of("classpath:META-INF/sbom/bom.json",
"classpath:META-INF/sbom/application.cdx.json");
static final String APPLICATION_SBOM_ID = "application";
private static final List<AutodetectedSbom> AUTODETECTED_SBOMS = List.of(
new AutodetectedSbom(APPLICATION_SBOM_ID, "classpath:META-INF/sbom/bom.json", true),
new AutodetectedSbom(APPLICATION_SBOM_ID, "classpath:META-INF/sbom/application.cdx.json", true),
new AutodetectedSbom("native-image", "classpath:META-INF/native-image/sbom.json", false));
private final SbomProperties properties;
private final ResourceLoader resourceLoader;
@ -59,14 +61,26 @@ public class SbomEndpoint {
public SbomEndpoint(SbomProperties properties, ResourceLoader resourceLoader) {
this.properties = properties;
this.resourceLoader = resourceLoader;
this.sboms = Collections.unmodifiableMap(getSboms());
this.sboms = loadSboms();
}
private Map<String, Resource> getSboms() {
Map<String, Resource> result = new HashMap<>();
addKnownSboms(result);
addAdditionalSboms(result);
return result;
private Map<String, Resource> loadSboms() {
Map<String, Resource> sboms = new HashMap<>();
addConfiguredApplicationSbom(sboms);
addAdditionalSboms(sboms);
addAutodetectedSboms(sboms);
return Collections.unmodifiableMap(sboms);
}
private void addConfiguredApplicationSbom(Map<String, Resource> sboms) {
String location = this.properties.getApplication().getLocation();
if (!StringUtils.hasLength(location)) {
return;
}
Resource resource = loadResource(location);
if (resource != null) {
sboms.put(APPLICATION_SBOM_ID, resource);
}
}
private void addAdditionalSboms(Map<String, Resource> result) {
@ -80,34 +94,16 @@ public class SbomEndpoint {
});
}
private void addKnownSboms(Map<String, Resource> result) {
Resource applicationSbom = getApplicationSbom();
if (applicationSbom != null) {
result.put(APPLICATION_SBOM_ID, applicationSbom);
}
}
@ReadOperation
Sboms sboms() {
return new Sboms(new TreeSet<>(this.sboms.keySet()));
}
@ReadOperation
Resource sbom(@Selector String id) {
return this.sboms.get(id);
}
private Resource getApplicationSbom() {
if (StringUtils.hasLength(this.properties.getApplication().getLocation())) {
return loadResource(this.properties.getApplication().getLocation());
}
for (String location : DEFAULT_APPLICATION_SBOM_LOCATIONS) {
Resource resource = this.resourceLoader.getResource(location);
private void addAutodetectedSboms(Map<String, Resource> sboms) {
for (AutodetectedSbom sbom : AUTODETECTED_SBOMS) {
if (sboms.containsKey(sbom.id())) {
continue;
}
Resource resource = this.resourceLoader.getResource(sbom.resource());
if (resource.exists()) {
return resource;
sboms.put(sbom.id(), resource);
}
}
return null;
}
private Resource loadResource(String location) {
@ -125,6 +121,16 @@ public class SbomEndpoint {
throw new IllegalStateException("Resource '%s' doesn't exist and it's not marked optional".formatted(location));
}
@ReadOperation
Sboms sboms() {
return new Sboms(new TreeSet<>(this.sboms.keySet()));
}
@ReadOperation
Resource sbom(@Selector String id) {
return this.sboms.get(id);
}
record Sboms(Collection<String> ids) implements OperationResponseBody {
}
@ -146,18 +152,26 @@ public class SbomEndpoint {
}
}
static class SbomEndpointRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
for (String defaultLocation : DEFAULT_APPLICATION_SBOM_LOCATIONS) {
hints.resources().registerPattern(stripClasspathPrefix(defaultLocation));
private record AutodetectedSbom(String id, String resource, boolean needsHints) {
void registerHintsIfNeeded(RuntimeHints hints) {
if (this.needsHints) {
hints.resources().registerPattern(stripClasspathPrefix(this.resource));
}
}
private String stripClasspathPrefix(String location) {
return location.substring("classpath:".length());
}
}
static class SbomEndpointRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
for (AutodetectedSbom sbom : AUTODETECTED_SBOMS) {
sbom.registerHintsIfNeeded(hints);
}
}
}