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

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


The following commit(s) were added to refs/heads/main by this push:
     new 8ad18065b44d CAMEL-26916: camel-yaml-dsl-validator - an insecure 
opt-in that can be set on the component keeps its default when reading the body 
(#29808)
8ad18065b44d is described below

commit 8ad18065b44d2490757fef7c9a013b69209c0b46
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Nov 13 11:02:37 2026 +0100

    CAMEL-26916: camel-yaml-dsl-validator - an insecure opt-in that can be set 
on the component keeps its default when reading the body (#29808)
    
    The YAML validator treated a body type that depends on an option the route 
does not set, but that can be set on the component, as not known, and said 
nothing. For the insecure opt-ins (security insecure:ssl, 
insecure:serialization or insecure:dev) that made it go quiet where it should 
not: pulsar (allowJavaSerializedObject), jms/activemq/activemq6/amqp 
(transferExchange, objectMessageEnabled), sjms/sjms2 (objectMessageEnabled), 
mina (transferExchange, objectCodecPattern), netty (trans [...]
    
    Such an option is off unless turned on, and one turned on for the whole 
component is reported by the security policy at startup, so 
CatalogBodyTypes.componentSide() no longer counts it as "can be set elsewhere": 
it keeps its default unless the route sets it.
    
    - BodyTypeResolver documents it on the hidden parameter, and 
body-types.adoc states the rule.
    - TextBodyFlowTest expects the pulsar finding again (dropped by #29807), 
and testTheBodyOfAnInsecureOptIn checks that a route leaving 
allowJavaSerializedObject alone is reported and one turning it on is not.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../user-manual/modules/ROOT/pages/body-types.adoc |  5 ++-
 .../camel/dsl/yaml/validator/CatalogBodyTypes.java | 13 ++++++-
 .../camel/dsl/yaml/validator/TextBodyFlowTest.java | 43 +++++++++++++++++++---
 .../camel/tooling/model/BodyTypeResolver.java      |  3 +-
 4 files changed, 55 insertions(+), 9 deletions(-)

diff --git a/docs/user-manual/modules/ROOT/pages/body-types.adoc 
b/docs/user-manual/modules/ROOT/pages/body-types.adoc
index 7a6eb96450d2..291bef09072b 100644
--- a/docs/user-manual/modules/ROOT/pages/body-types.adoc
+++ b/docs/user-manual/modules/ROOT/pages/body-types.adoc
@@ -432,7 +432,10 @@ option, but it can be set elsewhere: not known.
 the model the step uses (the language of its expression, its data format, its 
endpoint, or the data type transformer
 of its `toType`), with the options of that model. `steps` is the body the 
steps of the EIP end with.
 . *An option the side names whose value is not known before the route runs* (a 
`+{{placeholder}}+` or a `+${expression}+`),
-or an option the step does not set but that can be set elsewhere, such as on 
the component: not known.
+or an option the step does not set but that can be set elsewhere, such as on 
the component: not known. An insecure
+opt-in (its `security` is `insecure:ssl`, `insecure:serialization` or 
`insecure:dev`, such as `allowJavaSerializedObject`)
+is not such an option: it keeps its default when the step does not set it, as 
one turned on for the whole component is
+reported by the xref:security-policy.adoc[security policy] at startup.
 . *An option of `dependsOn` the step sets:* the `byOption` entry for that 
value says the body. When it has a
 `javaTypeOption` the step sets, the body is an object of that class. Without 
such an entry: not known.
 . *The `javaTypeOption` of the side, when the step sets it:* an object of the 
class it names, or null. It wins over the
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java
index 6f6bcdf0275a..d4c5b7cc6a23 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java
@@ -255,7 +255,11 @@ final class CatalogBodyTypes {
         }
         Set<String> configurable = new HashSet<>();
         for (BaseOptionModel option : model.getComponentOptions()) {
-            configurable.add(option.getName());
+            // an insecure option (allowJavaSerializedObject, 
transferExchange) is an opt-in: it keeps its default when
+            // the step does not set it, as one turned on for the whole 
component is reported by the security policy
+            if (!isInsecure(option)) {
+                configurable.add(option.getName());
+            }
         }
         Map<String, String> set = values(node != null && node.isObject() ? 
node.get("parameters") : null);
         String text = node != null && node.isString() ? node.asString()
@@ -299,6 +303,13 @@ final class CatalogBodyTypes {
         }
     }
 
+    /**
+     * Whether the option is one of the insecure opt-ins: security 
insecure:ssl, insecure:serialization or insecure:dev.
+     */
+    private static boolean isInsecure(BaseOptionModel option) {
+        return option.getSecurity() != null && 
option.getSecurity().startsWith("insecure:");
+    }
+
     /**
      * What a side says for the options a step sets, by the rule the tools 
share (BodyTypeResolver of the tooling
      * model); null when it is not known for the step.
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
index 286374536237..13d37bd6b07f 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
@@ -1430,10 +1430,10 @@ public class TextBodyFlowTest {
 
     @Test
     public void testTheBodyOfMessaging() {
-        // the paho consumer gives bytes, so a field read needs an unmarshal; 
smtp sends what converts to text, so
-        // parsed data must be marshalled first, and so must the reply of a 
nats consumer that answers (InOut); the
-        // converter of spring-rabbitmq and the allowJavaSerializedObject 
option of pulsar may be set on the component,
-        // and an imap mail may be text, a stream or a multipart, which say 
nothing
+        // the paho consumer gives bytes, so a field read needs an unmarshal; 
pulsar and smtp send what converts to
+        // bytes or text, so parsed data must be marshalled first, and so must 
the reply of a nats consumer that answers
+        // (InOut); the converter of spring-rabbitmq may be set on the 
component, and an imap mail may be text, a stream
+        // or a multipart, which say nothing
         String yaml = """
                 - route:
                     id: mqtt
@@ -1502,10 +1502,10 @@ public class TextBodyFlowTest {
                             name: id
                             simple: ${body[id]}
                 """;
-        assertThat(lines(yaml)).hasSize(3).anySatisfy(m -> assertThat(m)
+        assertThat(lines(yaml)).hasSize(4).anySatisfy(m -> assertThat(m)
                 .contains("route mqtt: simple reads a field of the body 
(${body[id]})")
                 .contains("the paho consumer gives it as bytes"))
-                .noneSatisfy(m -> assertThat(m).contains("route publish:"))
+                .anySatisfy(m -> assertThat(m).contains("to: pulsar needs the 
body as text, bytes, a stream or a file"))
                 .anySatisfy(m -> assertThat(m)
                         .contains("route service:")
                         .contains("the body at the end of the route is the 
reply to the nats request"))
@@ -1513,6 +1513,37 @@ public class TextBodyFlowTest {
                         .contains("route mail: to: smtp needs the body as 
text, bytes, a stream or a file"));
     }
 
+    @Test
+    public void testTheBodyOfAnInsecureOptIn() {
+        // allowJavaSerializedObject of pulsar can be set on the component, 
but it is an insecure opt-in: it keeps its
+        // default (off) when the route does not set it, so parsed data must 
be marshalled first; a route that turns it
+        // on sends any body, which says nothing
+        String yaml = """
+                - route:
+                    id: publish
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: pulsar:persistent://public/default/orders
+                - route:
+                    id: legacy
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: 
pulsar:persistent://public/default/orders?allowJavaSerializedObject=true
+                """;
+        assertThat(lines(yaml)).hasSize(1).first().asString()
+                .contains("route publish: to: pulsar needs the body as text, 
bytes, a stream or a file");
+    }
+
     @Test
     public void testTheBodyOfMoreComponents() {
         // ssh runs the body as a command and gives its output as a stream, 
and so does its consumer; spring-redis keeps
diff --git 
a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/BodyTypeResolver.java
 
b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/BodyTypeResolver.java
index 0a45b58ff7ec..34cef6604c23 100644
--- 
a/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/BodyTypeResolver.java
+++ 
b/tooling/camel-tooling-model/src/main/java/org/apache/camel/tooling/model/BodyTypeResolver.java
@@ -73,7 +73,8 @@ public final class BodyTypeResolver {
      * @param  options the options the step sets, by name: the endpoint uri, 
the parameters or the options of a data
      *                 format
      * @param  hidden  the options that can be set elsewhere when the step 
does not set them, such as the options of the
-     *                 component
+     *                 component; not the insecure opt-ins 
(allowJavaSerializedObject), which keep their default unless
+     *                 the step sets them
      * @return         the body, or null when it is not known for the step
      */
     public static Resolved resolve(BodyTypeModel side, Map<String, String> 
options, Set<String> hidden) {

Reply via email to