|
|
|
|
@ -45,11 +45,13 @@ import org.springframework.util.StringUtils;
@@ -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 {
@@ -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> loadSboms() { |
|
|
|
|
Map<String, Resource> sboms = new HashMap<>(); |
|
|
|
|
addConfiguredApplicationSbom(sboms); |
|
|
|
|
addAdditionalSboms(sboms); |
|
|
|
|
addAutodetectedSboms(sboms); |
|
|
|
|
return Collections.unmodifiableMap(sboms); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private Map<String, Resource> getSboms() { |
|
|
|
|
Map<String, Resource> result = new HashMap<>(); |
|
|
|
|
addKnownSboms(result); |
|
|
|
|
addAdditionalSboms(result); |
|
|
|
|
return result; |
|
|
|
|
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 {
@@ -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 {
@@ -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 {
@@ -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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|