diff --git a/src/main/java/io/github/guacsec/trustifyda/image/ImageUtils.java b/src/main/java/io/github/guacsec/trustifyda/image/ImageUtils.java index 30da1baa..0eb173e2 100644 --- a/src/main/java/io/github/guacsec/trustifyda/image/ImageUtils.java +++ b/src/main/java/io/github/guacsec/trustifyda/image/ImageUtils.java @@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; import com.github.packageurl.MalformedPackageURLException; +import io.github.guacsec.trustifyda.logging.LoggersFactory; import io.github.guacsec.trustifyda.tools.Operations; import io.github.guacsec.trustifyda.utils.Environment; import java.io.File; @@ -35,11 +36,14 @@ import java.util.Map; import java.util.Objects; import java.util.function.Supplier; +import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.StreamSupport; public class ImageUtils { + private static final Logger LOG = LoggersFactory.getLogger(ImageUtils.class.getName()); + static final String TRUSTIFY_DA_SYFT_CONFIG_PATH = "TRUSTIFY_DA_SYFT_CONFIG_PATH"; static final String TRUSTIFY_DA_SYFT_IMAGE_SOURCE = "TRUSTIFY_DA_SYFT_IMAGE_SOURCE"; static final String TRUSTIFY_DA_IMAGE_PLATFORM = "TRUSTIFY_DA_IMAGE_PLATFORM"; @@ -281,10 +285,21 @@ static String hostInfo(String engine, String info) { var exec = Operations.getCustomPathOrElse(engine); var cmd = new String[] {exec, "info"}; - var output = Operations.runProcessGetFullOutput(null, cmd, null); + Operations.ProcessExecOutput output; + try { + output = Operations.runProcessGetFullOutput(null, cmd, null); + } catch (RuntimeException e) { + if (e.getCause() instanceof IOException) { + LOG.warning( + String.format( + "Container engine '%s' not available: %s", exec, e.getCause().getMessage())); + return ""; + } + throw e; + } if (output.getOutput().isEmpty() && (!output.getError().isEmpty() || output.getExitCode() != 0)) { - throw new RuntimeException(output.getError()); + return ""; } return output diff --git a/src/test/java/io/github/guacsec/trustifyda/image/ImageUtilsTest.java b/src/test/java/io/github/guacsec/trustifyda/image/ImageUtilsTest.java index 12838309..115331dc 100644 --- a/src/test/java/io/github/guacsec/trustifyda/image/ImageUtilsTest.java +++ b/src/test/java/io/github/guacsec/trustifyda/image/ImageUtilsTest.java @@ -27,6 +27,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.AdditionalMatchers.aryEq; @@ -549,9 +550,29 @@ void test_host_info_no_docker_path() { isNull(), aryEq(new String[] {"docker", "info"}), isNull())) .thenReturn(output); - var exception = + var result = ImageUtils.hostInfo("docker", "info"); + assertEquals("", result); + } + } + + @Test + void test_host_info_other_runtime_exceptions_propagate() { + try (MockedStatic mock = Mockito.mockStatic(Operations.class)) { + RuntimeException expected = new RuntimeException("non-io-error"); + + mock.when(() -> Operations.getCustomPathOrElse(eq("docker"))).thenReturn("docker"); + + mock.when(() -> Operations.getExecutable(eq("docker"), any())).thenReturn("docker"); + + mock.when( + () -> + Operations.runProcessGetFullOutput( + isNull(), aryEq(new String[] {"docker", "info"}), isNull())) + .thenThrow(expected); + + RuntimeException thrown = assertThrows(RuntimeException.class, () -> ImageUtils.hostInfo("docker", "info")); - assertEquals("test-error", exception.getMessage()); + assertSame(expected, thrown); } }