Add auto-detection for SBOMs in native-image
Closes gh-40630
This commit is contained in:
parent
a66d3d2f00
commit
a7fb3699ee
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue