This is an automated email from the ASF dual-hosted git repository.

luigidemasi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-kit.git

commit 80f57109bd3d20c90deec53c6f4e3e0a81d0e818
Author: Jinal Sarvaiya <[email protected]>
AuthorDate: Fri Nov 6 14:39:10 2026 +0000

    fix #100: fail-closed on malformed inline JSON and array-wrapped envelopes
---
 .../camel/kit/ship/controller/ShipStageResult.java | 19 +++++++++-
 .../kit/ship/controller/ShipStageResultTest.java   | 44 ++++++++++++++++++++++
 2 files changed, 61 insertions(+), 2 deletions(-)

diff --git 
a/kit/camel-kit-core/src/main/java/org/apache/camel/kit/ship/controller/ShipStageResult.java
 
b/kit/camel-kit-core/src/main/java/org/apache/camel/kit/ship/controller/ShipStageResult.java
index 71628e01..614c0bf0 100644
--- 
a/kit/camel-kit-core/src/main/java/org/apache/camel/kit/ship/controller/ShipStageResult.java
+++ 
b/kit/camel-kit-core/src/main/java/org/apache/camel/kit/ship/controller/ShipStageResult.java
@@ -408,11 +408,26 @@ record ShipStageResult(
     }
 
     private static boolean looksLikeEnvelope(String span) {
+        String trimmed = span.trim();
+        if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
+            return false;
+        }
         try {
             JsonNode node = JSON.readTree(span);
-            return node.isObject() && node.has("materialAmbiguity");
-        } catch (JsonProcessingException e) {
+            if (node.isObject()) {
+                return node.has("materialAmbiguity");
+            }
+            if (node.isArray()) {
+                for (JsonNode element : node) {
+                    if (element.isObject() && 
element.has("materialAmbiguity")) {
+                        return true;
+                    }
+                }
+            }
             return false;
+        } catch (JsonProcessingException e) {
+            // fail-closed: unparseable JSON starting with {/[ is suspicious
+            return true;
         }
     }
 
diff --git 
a/kit/camel-kit-core/src/test/java/org/apache/camel/kit/ship/controller/ShipStageResultTest.java
 
b/kit/camel-kit-core/src/test/java/org/apache/camel/kit/ship/controller/ShipStageResultTest.java
index f7d27a63..10f9eea8 100644
--- 
a/kit/camel-kit-core/src/test/java/org/apache/camel/kit/ship/controller/ShipStageResultTest.java
+++ 
b/kit/camel-kit-core/src/test/java/org/apache/camel/kit/ship/controller/ShipStageResultTest.java
@@ -536,6 +536,50 @@ class ShipStageResultTest {
                 "backtick-wrapped correction envelope with escaped key");
     }
 
+    @Test
+    void rejectsInlineBacktickWithDuplicateKey() throws Exception {
+        ObjectNode fenced = result(null, null);
+        ObjectNode bare = result(null, null);
+        bare.put("materialAmbiguity", true);
+        bare.withArray("unansweredQuestions").addObject()
+                .put("question", "Which retry 
limit?").putNull("defaultApplied");
+        String bareJson = JSON.writeValueAsString(bare);
+        String duplicated = bareJson.substring(0, bareJson.length() - 1)
+                            + ",\"materialAmbiguity\":false}";
+        String input = "```json\n" + JSON.writeValueAsString(fenced)
+                       + "\n```\nCorrection: `" + duplicated + "`";
+        assertRejected(Stage.DESIGN, input,
+                "backtick-wrapped duplicate-key correction");
+    }
+
+    @Test
+    void rejectsInlineBacktickWithTrailingDocument() throws Exception {
+        ObjectNode fenced = result(null, null);
+        ObjectNode bare = result(null, null);
+        bare.put("materialAmbiguity", true);
+        bare.withArray("unansweredQuestions").addObject()
+                .put("question", "Which retry 
limit?").putNull("defaultApplied");
+        String bareJson = JSON.writeValueAsString(bare);
+        String trailing = bareJson + bareJson;
+        String input = "```json\n" + JSON.writeValueAsString(fenced)
+                       + "\n```\nCorrection: `" + trailing + "`";
+        assertRejected(Stage.DESIGN, input,
+                "backtick-wrapped trailing-document correction");
+    }
+
+    @Test
+    void rejectsInlineBacktickArrayWrappedCorrection() throws Exception {
+        ObjectNode fenced = result(null, null);
+        ObjectNode bare = result(null, null);
+        bare.put("materialAmbiguity", true);
+        bare.withArray("unansweredQuestions").addObject()
+                .put("question", "Which retry 
limit?").putNull("defaultApplied");
+        String input = "```json\n" + JSON.writeValueAsString(fenced)
+                       + "\n```\nCorrection: `[" + 
JSON.writeValueAsString(bare) + "]`";
+        assertRejected(Stage.DESIGN, input,
+                "backtick-wrapped array-wrapped correction");
+    }
+
     @Test
     void acceptsHarmlessInlineJsonExample() throws Exception {
         ObjectNode valid = result("149-local-controller", null);

Reply via email to