Skip to content
Merged
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
17 changes: 11 additions & 6 deletions client/src/main/java/dev/snowdrop/buildpack/BuilderImage.java
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,19 @@ private ImageReference getRunImageFromMetadataJSON() throws BuildpackException {

// if caller did not set runImage, and metadata is absent, error.
if(ri==null){
throw new Exception("No runImage specified, and builderImage is missing metadata declaration");
throw new Exception("No runImage specified, and builderImage is missing metadata declaration :: "+this.metadataJson);
}

// remap docker.io references back to docker.io
// if (ri.startsWith("index.docker.io/")) {
// ri = ri.substring("index.docker.io/".length());
// ri = "docker.io/" + ri;
// }
//first observed with ubi9 builder, stack/runImage/image is empty string
//image is present in the images array, so fallback to that.
if(ri.trim().isEmpty()){
//fallback to looking for runImage in the images array..
String fbImg = JsonUtils.getValue(root, "images/0/image");
if(fbImg==null || fbImg.trim().isEmpty()){
throw new Exception("No runImage specified, and builderImage is missing metadata declaration :: (fbImage:"+fbImg+") "+this.metadataJson);
}
ri = fbImg;
}

return new ImageReference(ri);
} catch (Exception e) {
Expand Down
15 changes: 12 additions & 3 deletions client/src/main/java/dev/snowdrop/buildpack/utils/JsonUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,23 @@ public static String getValue(JsonNode root, String path) {
path = path.substring(1);
}
String[] parts = path.split("/");
JsonNode next = root.get(parts[0]);
JsonNode next = null;
if(!root.isArray()){
next = root.get(parts[0]);
}else{
try{
next = root.get(Integer.parseInt(parts[0]));
}catch(NumberFormatException nfe){
throw new IllegalArgumentException("Invalid path, expected array index but got: "+parts[0]+" for path: "+path);
}
}
if (next != null && parts.length > 1) {
return getValue(next, path.substring(path.indexOf("/") + 1));
}
if (next == null) {
return null;
}
return next.asText();
}
return next.asText();
}
public static List<String> getArray(JsonNode root, String path) {
if (path.startsWith("/")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;

import java.util.List;
Expand Down Expand Up @@ -60,4 +62,54 @@ void testJsonUtils() {
fail(e);
}
}

@Test
void testGetValueArrayIndexTraversal() throws Exception {
// JSON with nested arrays: /name/0/thing/2/name style paths
String json = "{\"items\":[{\"name\":\"first\",\"tags\":[\"a\",\"b\",\"c\"]},{\"name\":\"second\",\"tags\":[\"x\",\"y\",\"z\"]}]}";

ObjectMapper om = new ObjectMapper();
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode root = om.readTree(json);

// Access object field then array index then field
String name = JsonUtils.getValue(root, "items/0/name");
assertEquals("first", name);

String secondName = JsonUtils.getValue(root, "/items/1/name");
assertEquals("second", secondName);

// Access object field then array index then array index (nested arrays)
String tag = JsonUtils.getValue(root, "items/0/tags/2");
assertEquals("c", tag);

String lastTag = JsonUtils.getValue(root, "/items/1/tags/0");
assertEquals("x", lastTag);
}

@Test
void testGetValueArrayIndexOutOfBounds() throws Exception {
String json = "{\"items\":[{\"name\":\"only\"}]}";

ObjectMapper om = new ObjectMapper();
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode root = om.readTree(json);

// Out-of-bounds index returns null
String val = JsonUtils.getValue(root, "items/5/name");
assertNull(val);
}

@Test
void testGetValueArrayNonNumericIndexThrows() throws Exception {
String json = "{\"items\":[{\"name\":\"only\"}]}";

ObjectMapper om = new ObjectMapper();
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode root = om.readTree(json);

// Non-numeric path segment against an array should throw
assertThrows(IllegalArgumentException.class, () ->
JsonUtils.getValue(root, "items/notANumber/name"));
}
}
Loading