You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by "oscerd (via GitHub)" <gi...@apache.org> on 2026/09/22 10:07:16 UTC

[PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

oscerd opened a new pull request, #26737:
URL: https://github.com/apache/camel/pull/26737

   This aligns how `DoclingProducer` handles the path-bearing values it forwards to the docling CLI.
   
   Input file paths are normalized and, when `inputBaseDirectory` is set, confined to that directory; custom CLI argument values are normalized via `validatePathSafety`. The `CamelDoclingOutputFilePath` header, by contrast, was passed straight to the `--output` flag with no normalization and no containment option.
   
   This PR:
   
   - adds an optional `outputBaseDirectory` endpoint option mirroring `inputBaseDirectory`;
   - normalizes the `CamelDoclingOutputFilePath` header and, when `outputBaseDirectory` is set, confines it to that directory (values resolving outside — including absolute paths — are rejected);
   - documents the option and behavior in the component docs and the 4.23 upgrade guide;
   - adds `DoclingOutputPathValidationTest`.
   
   Both `inputBaseDirectory` and `outputBaseDirectory` are unset by default, so existing routes are unaffected.
   
   JIRA: https://issues.apache.org/jira/browse/CAMEL-24894
   
   _Claude Code on behalf of oscerd_
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "gnodet-bot (via GitHub)" <gi...@apache.org>.
gnodet-bot commented on code in PR #26737:
URL: https://github.com/apache/camel/pull/26737#discussion_r4070627545


##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc:
##########
@@ -714,6 +714,13 @@ It is unset by default, which keeps the previous behaviour of accepting any path
 Additionally, a local input path that does not exist is now reported as a `File not found` `IOException`
 before Docling is invoked. Previously the size check silently skipped a path that resolved to nothing and
 the failure surfaced later, from the Docling process or API call.
+
+The `CamelDoclingOutputFilePath` header, which selects the CLI output directory, is now normalized before it
+is passed to Docling, and a new `outputBaseDirectory` option confines it the same way `inputBaseDirectory`
+confines input paths. Both are unset by default, which keeps the previous behaviour of using the header value
+as given. When `outputBaseDirectory` is set, an output path that resolves outside it - including an absolute

Review Comment:
   âš ī¸ **Inaccurate:** normalization is applied unconditionally — when `outputBaseDirectory` is unset _and_ the header is set, `resolveWithinOutputBaseDirectory` still calls `Paths.get(outputPath).normalize()`. The raw header value is no longer passed verbatim. Only the jail check is gated behind the option; the normalization step runs regardless.
   
   Suggestion:
   
   ```suggestion
   confines input paths. Both are unset by default; when `outputBaseDirectory` is absent the header value is
   normalized (lexically — `..` components are resolved) but otherwise used as given.
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #26737:
URL: https://github.com/apache/camel/pull/26737#issuecomment-5774686976

   :star2: Thank you for your contribution to the Apache Camel project! :star2:
     :robot: CI automation will test this PR automatically.
   
     :camel: Apache Camel Committers, please review the following items:
   
     * First-time contributors **require MANUAL approval** for the GitHub Actions to run
     * You can use the command `/component-test (camel-)component-name1 (camel-)component-name2..` to request a test from the test bot although they are normally detected and executed by CI.
     * You can label PRs using `skip-tests` and `test-dependents` to fine-tune the checks executed by this PR.
     * Build and test logs are available in the summary page. **Only** [Apache Camel committers](https://camel.apache.org/community/team/#committers) have access to the summary.
     
     :warning: Be careful when sharing logs. Review their contents before sharing them publicly.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on code in PR #26737:
URL: https://github.com/apache/camel/pull/26737#discussion_r4070902196


##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc:
##########
@@ -714,6 +714,13 @@ It is unset by default, which keeps the previous behaviour of accepting any path
 Additionally, a local input path that does not exist is now reported as a `File not found` `IOException`
 before Docling is invoked. Previously the size check silently skipped a path that resolved to nothing and
 the failure surfaced later, from the Docling process or API call.
+
+The `CamelDoclingOutputFilePath` header, which selects the CLI output directory, is now normalized before it
+is passed to Docling, and a new `outputBaseDirectory` option confines it the same way `inputBaseDirectory`
+confines input paths. Both are unset by default, which keeps the previous behaviour of using the header value
+as given. When `outputBaseDirectory` is set, an output path that resolves outside it - including an absolute

Review Comment:
   Good catch — normalization is unconditional; only the base-directory jail is gated behind `outputBaseDirectory`. Reworded the upgrade guide and the component doc accordingly (the value is normalized lexically, otherwise used as given, when the option is unset). Also folded in the componentdsl `Regen` commit — thanks.
   
   _Claude Code on behalf of oscerd_



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on code in PR #26737:
URL: https://github.com/apache/camel/pull/26737#discussion_r4082117119


##########
components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingProducer.java:
##########
@@ -2277,17 +2278,41 @@ private void addLayoutArguments(List<String> command) {
         }
     }
 
-    private void addOutputDirectoryArguments(List<String> command, Exchange exchange, String outputDirectory) {
+    private void addOutputDirectoryArguments(List<String> command, Exchange exchange, String outputDirectory)
+            throws IOException {
         String outputPath = exchange.getIn().getHeader(DoclingHeaders.OUTPUT_FILE_PATH, String.class);
+        command.add("--output");
         if (outputPath != null) {
-            command.add("--output");
-            command.add(outputPath);
+            // the header is caller-provided, so it gets the same normalization and optional base-directory
+            // containment as input paths do, instead of reaching the CLI verbatim
+            command.add(resolveWithinOutputBaseDirectory(outputPath).toString());
         } else {
-            command.add("--output");
             command.add(outputDirectory);
         }
     }
 
+    /**
+     * Normalizes the given output directory and, when {@code outputBaseDirectory} is configured, verifies that it stays
+     * inside that directory. Mirrors {@link #resolveWithinInputBaseDirectory(String)} so that the output directory
+     * carried by the {@link DoclingHeaders#OUTPUT_FILE_PATH} header receives the same treatment as input paths.
+     */
+    private Path resolveWithinOutputBaseDirectory(String outputPath) throws IOException {
+        String base = configuration.getOutputBaseDirectory();
+        if (base == null || base.isEmpty()) {
+            // no directory restriction: normalize lexically only, and leave relative paths relative so that they keep
+            // resolving the way they did before - against the CLI working directory, when one is set
+            return Paths.get(outputPath).normalize();

Review Comment:
   Added `outputPathIsNormalizedInTheBuiltCommand`: it builds the command via `buildDoclingCommand` and asserts `out/./sub/../x` reaches `--output` as `out/x`, pinning the documented normalization for the default (no-`outputBaseDirectory`) branch rather than relying on the failure message.
   
   _Claude Code on behalf of oscerd_



##########
components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingProducer.java:
##########
@@ -2277,17 +2278,41 @@ private void addLayoutArguments(List<String> command) {
         }
     }
 
-    private void addOutputDirectoryArguments(List<String> command, Exchange exchange, String outputDirectory) {
+    private void addOutputDirectoryArguments(List<String> command, Exchange exchange, String outputDirectory)
+            throws IOException {
         String outputPath = exchange.getIn().getHeader(DoclingHeaders.OUTPUT_FILE_PATH, String.class);
+        command.add("--output");
         if (outputPath != null) {
-            command.add("--output");
-            command.add(outputPath);
+            // the header is caller-provided, so it gets the same normalization and optional base-directory
+            // containment as input paths do, instead of reaching the CLI verbatim
+            command.add(resolveWithinOutputBaseDirectory(outputPath).toString());
         } else {
-            command.add("--output");
             command.add(outputDirectory);
         }
     }
 
+    /**
+     * Normalizes the given output directory and, when {@code outputBaseDirectory} is configured, verifies that it stays
+     * inside that directory. Mirrors {@link #resolveWithinInputBaseDirectory(String)} so that the output directory
+     * carried by the {@link DoclingHeaders#OUTPUT_FILE_PATH} header receives the same treatment as input paths.
+     */
+    private Path resolveWithinOutputBaseDirectory(String outputPath) throws IOException {
+        String base = configuration.getOutputBaseDirectory();
+        if (base == null || base.isEmpty()) {
+            // no directory restriction: normalize lexically only, and leave relative paths relative so that they keep
+            // resolving the way they did before - against the CLI working directory, when one is set
+            return Paths.get(outputPath).normalize();
+        }
+        Path baseDir = Paths.get(base).toAbsolutePath().normalize();
+        // resolve relative paths against the base directory itself, so that the path checked here is exactly the path
+        // used downstream regardless of the process working directory; an absolute header value that escapes is rejected
+        Path path = baseDir.resolve(Paths.get(outputPath)).normalize();
+        if (!path.startsWith(baseDir)) {

Review Comment:
   Agreed, no code change — it deliberately mirrors `resolveWithinInputBaseDirectory`, and `toRealPath()` would change semantics for not-yet-existing output directories. Added the caveat that containment is lexical and does not resolve symbolic links to the `outputBaseDirectory` option description, the helper javadoc, and the component docs.
   
   _Claude Code on behalf of oscerd_



##########
components/camel-ai/camel-docling/src/test/java/org/apache/camel/component/docling/DoclingOutputPathValidationTest.java:
##########
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.docling;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * Tests that the {@code CamelDoclingOutputFilePath} header is normalized and, when {@code outputBaseDirectory} is
+ * configured, confined to that directory before it reaches the docling CLI {@code --output} flag, consistently with how
+ * input paths honour {@code inputBaseDirectory}.
+ */
+class DoclingOutputPathValidationTest extends CamelTestSupport {
+
+    private static final String CONTENT = "just some document text";
+
+    @TempDir
+    Path tempDir;
+
+    // ------------------------------------------------------- no outputBaseDirectory
+
+    @Test
+    void outputPathWithoutBaseDirectoryIsAllowed() {
+        // no restriction is configured: the header is normalized only and passes through, so the run fails later on the
+        // absent docling binary rather than on a containment check
+        assertThatThrownBy(() -> template.requestBodyAndHeader("direct:default", CONTENT,
+                DoclingHeaders.OUTPUT_FILE_PATH, tempDir.resolve("out").toString()))
+                .isInstanceOf(CamelExecutionException.class)
+                .cause()
+                .hasMessageNotContaining("outputBaseDirectory");
+    }
+
+    // ------------------------------------------------------ outputBaseDirectory jail
+
+    @Test
+    void outputPathInsideOutputBaseDirectoryIsAccepted() throws Exception {
+        String inside = baseDir().resolve("out").toString();
+
+        // the docling binary is absent so execution still fails, but it must not fail on the jail check
+        assertThatThrownBy(() -> template.requestBodyAndHeader("direct:jailed", CONTENT,
+                DoclingHeaders.OUTPUT_FILE_PATH, inside))
+                .isInstanceOf(CamelExecutionException.class)
+                .cause()
+                .hasMessageNotContaining("outputBaseDirectory");
+    }
+
+    @Test
+    void outputPathOutsideOutputBaseDirectoryIsRejected() throws Exception {
+        baseDir();
+        String outside = tempDir.resolve("outside").toString();
+
+        assertThatThrownBy(() -> template.requestBodyAndHeader("direct:jailed", CONTENT,
+                DoclingHeaders.OUTPUT_FILE_PATH, outside))
+                .isInstanceOf(CamelExecutionException.class)
+                .cause()
+                .isInstanceOf(IOException.class)
+                .hasMessageContaining("outputBaseDirectory");
+    }
+
+    @Test
+    void absoluteOutputPathOutsideOutputBaseDirectoryIsRejected() throws Exception {
+        baseDir();
+
+        // an absolute header value ignores the base directory when resolved, so it must be rejected as escaping
+        assertThatThrownBy(() -> template.requestBodyAndHeader("direct:jailed", CONTENT,
+                DoclingHeaders.OUTPUT_FILE_PATH, "/var/www/html/uploads"))
+                .isInstanceOf(CamelExecutionException.class)
+                .cause()
+                .isInstanceOf(IOException.class)
+                .hasMessageContaining("outputBaseDirectory");
+    }
+
+    @Test
+    void traversalOutOfOutputBaseDirectoryIsRejected() throws Exception {

Review Comment:
   Right — `@TempDir` hands out absolute paths, so the old value hit the absolute branch. Switched `traversalOutOfOutputBaseDirectoryIsRejected` to a genuinely relative `"../outside"`, which now exercises the `baseDir.resolve(...)` + `normalize()` path.
   
   _Claude Code on behalf of oscerd_



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "davsclaus (via GitHub)" <gi...@apache.org>.
davsclaus commented on code in PR #26737:
URL: https://github.com/apache/camel/pull/26737#discussion_r4071659731


##########
components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingProducer.java:
##########
@@ -2277,17 +2278,41 @@ private void addLayoutArguments(List<String> command) {
         }
     }
 
-    private void addOutputDirectoryArguments(List<String> command, Exchange exchange, String outputDirectory) {
+    private void addOutputDirectoryArguments(List<String> command, Exchange exchange, String outputDirectory)
+            throws IOException {
         String outputPath = exchange.getIn().getHeader(DoclingHeaders.OUTPUT_FILE_PATH, String.class);
+        command.add("--output");
         if (outputPath != null) {
-            command.add("--output");
-            command.add(outputPath);
+            // the header is caller-provided, so it gets the same normalization and optional base-directory
+            // containment as input paths do, instead of reaching the CLI verbatim
+            command.add(resolveWithinOutputBaseDirectory(outputPath).toString());
         } else {
-            command.add("--output");
             command.add(outputDirectory);
         }
     }
 
+    /**
+     * Normalizes the given output directory and, when {@code outputBaseDirectory} is configured, verifies that it stays
+     * inside that directory. Mirrors {@link #resolveWithinInputBaseDirectory(String)} so that the output directory
+     * carried by the {@link DoclingHeaders#OUTPUT_FILE_PATH} header receives the same treatment as input paths.
+     */
+    private Path resolveWithinOutputBaseDirectory(String outputPath) throws IOException {
+        String base = configuration.getOutputBaseDirectory();
+        if (base == null || base.isEmpty()) {
+            // no directory restriction: normalize lexically only, and leave relative paths relative so that they keep
+            // resolving the way they did before - against the CLI working directory, when one is set
+            return Paths.get(outputPath).normalize();
+        }
+        Path baseDir = Paths.get(base).toAbsolutePath().normalize();
+        // resolve relative paths against the base directory itself, so that the path checked here is exactly the path
+        // used downstream regardless of the process working directory; an absolute header value that escapes is rejected
+        Path path = baseDir.resolve(Paths.get(outputPath)).normalize();
+        if (!path.startsWith(baseDir)) {

Review Comment:
   🟡 `normalize()` is lexical, so this containment check does not resolve symlinks: a symlink inside `outputBaseDirectory` pointing outside it passes.
   
   That matches `resolveWithinInputBaseDirectory` exactly, so consistency — the stated goal of the PR — is preserved, and switching to `toRealPath()` would change semantics for paths that don't exist yet, which is the normal case for an output directory. So I'm not suggesting a code change; just a sentence in the `outputBaseDirectory` javadoc and/or the option description, so operators don't read the option as a stronger boundary than it is.



##########
components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingProducer.java:
##########
@@ -2277,17 +2278,41 @@ private void addLayoutArguments(List<String> command) {
         }
     }
 
-    private void addOutputDirectoryArguments(List<String> command, Exchange exchange, String outputDirectory) {
+    private void addOutputDirectoryArguments(List<String> command, Exchange exchange, String outputDirectory)
+            throws IOException {
         String outputPath = exchange.getIn().getHeader(DoclingHeaders.OUTPUT_FILE_PATH, String.class);
+        command.add("--output");
         if (outputPath != null) {
-            command.add("--output");
-            command.add(outputPath);
+            // the header is caller-provided, so it gets the same normalization and optional base-directory
+            // containment as input paths do, instead of reaching the CLI verbatim
+            command.add(resolveWithinOutputBaseDirectory(outputPath).toString());
         } else {
-            command.add("--output");
             command.add(outputDirectory);
         }
     }
 
+    /**
+     * Normalizes the given output directory and, when {@code outputBaseDirectory} is configured, verifies that it stays
+     * inside that directory. Mirrors {@link #resolveWithinInputBaseDirectory(String)} so that the output directory
+     * carried by the {@link DoclingHeaders#OUTPUT_FILE_PATH} header receives the same treatment as input paths.
+     */
+    private Path resolveWithinOutputBaseDirectory(String outputPath) throws IOException {
+        String base = configuration.getOutputBaseDirectory();
+        if (base == null || base.isEmpty()) {
+            // no directory restriction: normalize lexically only, and leave relative paths relative so that they keep
+            // resolving the way they did before - against the CLI working directory, when one is set
+            return Paths.get(outputPath).normalize();

Review Comment:
   🟠 This is the branch the upgrade guide leads with — "the header is now normalized lexically (redundant separators and `.`/`..` segments are resolved) before it is passed to Docling" — and it is the case most existing routes will hit, since `outputBaseDirectory` is unset by default. But no test asserts what actually reaches `--output`.
   
   The two "accepted" tests only assert `hasMessageNotContaining("outputBaseDirectory")`, which passes for any failure that happens not to mention the option — including a failure caused by normalization going wrong. A test that captures the built command and checks, say, `out/./sub/../x` → `out/x` would pin the documented behaviour down.



##########
components/camel-ai/camel-docling/src/test/java/org/apache/camel/component/docling/DoclingOutputPathValidationTest.java:
##########
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.docling;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * Tests that the {@code CamelDoclingOutputFilePath} header is normalized and, when {@code outputBaseDirectory} is
+ * configured, confined to that directory before it reaches the docling CLI {@code --output} flag, consistently with how
+ * input paths honour {@code inputBaseDirectory}.
+ */
+class DoclingOutputPathValidationTest extends CamelTestSupport {
+
+    private static final String CONTENT = "just some document text";
+
+    @TempDir
+    Path tempDir;
+
+    // ------------------------------------------------------- no outputBaseDirectory
+
+    @Test
+    void outputPathWithoutBaseDirectoryIsAllowed() {
+        // no restriction is configured: the header is normalized only and passes through, so the run fails later on the
+        // absent docling binary rather than on a containment check
+        assertThatThrownBy(() -> template.requestBodyAndHeader("direct:default", CONTENT,
+                DoclingHeaders.OUTPUT_FILE_PATH, tempDir.resolve("out").toString()))
+                .isInstanceOf(CamelExecutionException.class)
+                .cause()
+                .hasMessageNotContaining("outputBaseDirectory");
+    }
+
+    // ------------------------------------------------------ outputBaseDirectory jail
+
+    @Test
+    void outputPathInsideOutputBaseDirectoryIsAccepted() throws Exception {
+        String inside = baseDir().resolve("out").toString();
+
+        // the docling binary is absent so execution still fails, but it must not fail on the jail check
+        assertThatThrownBy(() -> template.requestBodyAndHeader("direct:jailed", CONTENT,
+                DoclingHeaders.OUTPUT_FILE_PATH, inside))
+                .isInstanceOf(CamelExecutionException.class)
+                .cause()
+                .hasMessageNotContaining("outputBaseDirectory");
+    }
+
+    @Test
+    void outputPathOutsideOutputBaseDirectoryIsRejected() throws Exception {
+        baseDir();
+        String outside = tempDir.resolve("outside").toString();
+
+        assertThatThrownBy(() -> template.requestBodyAndHeader("direct:jailed", CONTENT,
+                DoclingHeaders.OUTPUT_FILE_PATH, outside))
+                .isInstanceOf(CamelExecutionException.class)
+                .cause()
+                .isInstanceOf(IOException.class)
+                .hasMessageContaining("outputBaseDirectory");
+    }
+
+    @Test
+    void absoluteOutputPathOutsideOutputBaseDirectoryIsRejected() throws Exception {
+        baseDir();
+
+        // an absolute header value ignores the base directory when resolved, so it must be rejected as escaping
+        assertThatThrownBy(() -> template.requestBodyAndHeader("direct:jailed", CONTENT,
+                DoclingHeaders.OUTPUT_FILE_PATH, "/var/www/html/uploads"))
+                .isInstanceOf(CamelExecutionException.class)
+                .cause()
+                .isInstanceOf(IOException.class)
+                .hasMessageContaining("outputBaseDirectory");
+    }
+
+    @Test
+    void traversalOutOfOutputBaseDirectoryIsRejected() throws Exception {

Review Comment:
   🟡 `baseDir().resolve("..").resolve("outside")` is already an absolute path (`@TempDir` hands out absolute paths), so this exercises the same branch as `absoluteOutputPathOutsideOutputBaseDirectoryIsRejected` above rather than the relative-traversal one it's named for.
   
   A genuinely relative value — `"../outside"` — would cover the `baseDir.resolve(...)` + `normalize()` path that nothing else reaches.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "gnodet (via GitHub)" <gi...@apache.org>.
gnodet commented on PR #26737:
URL: https://github.com/apache/camel/pull/26737#issuecomment-5829826160

   <!-- camel-backport-bot -->
   
   ### 🔄 Backport Bot
   
   **Conflicts (🤖 agent dispatched to resolve):**
   - âš ī¸ `camel-4.22.x` — Cherry-pick conflict in: docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
   - âš ī¸ `camel-4.18.x` — Cherry-pick conflict in: catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/docling.json, components/camel-ai/camel-docling/src/generated/java/org/apache/camel/component/docling/DoclingEndpointUriFactory.java, components/camel-ai/camel-docling/src/generated/resources/META-INF/org/apache/camel/component/docling/docling.json, docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc, dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/DoclingComponentBuilderFactory.java
   
   â„šī¸ If you push additional commits after `/port`, use `/port` again to update the port PRs.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd merged PR #26737:
URL: https://github.com/apache/camel/pull/26737


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #26737:
URL: https://github.com/apache/camel/pull/26737#issuecomment-5775761343

   <!-- ci-tested-modules -->
   :test_tube: **CI tested the following changed modules:**
   
   - `catalog/camel-catalog`
   - `components/camel-ai/camel-docling`
   - `docs`
   - `dsl/camel-componentdsl`
   - `dsl/camel-endpointdsl`
   
   ---
   
   <details><summary>:microscope: Scalpel shadow comparison — Scalpel: 10 of 692 tested, 23 compile-only — current: 10 all tested</summary>
   
   [Maveniverse Scalpel](https://github.com/maveniverse/scalpel) detected **37 affected modules** (current approach: 10).
   
   **Skip-tests mode would test 10 modules** (5 direct + 9 downstream), **skip tests for 23** (generated code, meta-modules)
   
   <details><summary>:warning: Modules only in Scalpel (27)</summary>
   
   - `apache-camel`
   - `camel-allcomponents`
   - `camel-catalog`
   - `camel-catalog-console`
   - `camel-catalog-maven`
   - `camel-catalog-suggest`
   - `camel-componentdsl`
   - `camel-endpointdsl`
   - `camel-endpointdsl-support`
   - `camel-itest`
   - `camel-jbang-core`
   - `camel-jbang-it`
   - `camel-jbang-main`
   - `camel-jbang-plugin-edit`
   - `camel-jbang-plugin-generate`
   - `camel-jbang-plugin-kubernetes`
   - `camel-jbang-plugin-test`
   - `camel-kamelet-main`
   - `camel-launcher`
   - `camel-report-maven-plugin`
   - `camel-route-parser`
   - `camel-yaml-dsl`
   - `camel-yaml-dsl-deserializers`
   - `camel-yaml-dsl-maven-plugin`
   - `coverage`
   - `docs`
   - `dummy-component`
   
   </details>
   
   
   <details><summary>Modules Scalpel would test (10)</summary>
   
   - `camel-catalog` ← catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/docling.json, catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/docling-component.adoc
   - `camel-componentdsl` ← dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/DoclingComponentBuilderFactory.java
   - `camel-docling` ← components/camel-ai/camel-docling/src/generated/java/org/apache/camel/component/docling/DoclingComponentConfigurer.java, components/camel-ai/camel-docling/src/generated/java/org/apache/camel/component/docling/DoclingConfigurationConfigurer.java, components/camel-ai/camel-docling/src/generated/java/org/apache/camel/component/docling/DoclingEndpointConfigurer.java, components/camel-ai/camel-docling/src/generated/java/org/apache/camel/component/docling/DoclingEndpointUriFactory.java, components/camel-ai/camel-docling/src/generated/resources/META-INF/org/apache/camel/component/docling/docling.json, components/camel-ai/camel-docling/src/main/docs/docling-component.adoc, components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingConfiguration.java, components/camel-ai/camel-docling/src/main/java/org/apache/camel/component/docling/DoclingProducer.java, components/camel-ai/camel-docling/src/test/java/org/apache/camel/component/docling/D
 oclingOutputPathValidationTest.java
   - `camel-endpointdsl` ← dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/DoclingEndpointBuilderFactory.java
   - `camel-jbang-mcp` ← downstream of org.apache.camel:camel-catalog
   - `camel-jbang-plugin-mcp` ← downstream of org.apache.camel:camel-jbang-core
   - `camel-jbang-plugin-route-parser` ← downstream of org.apache.camel:camel-route-parser
   - `camel-jbang-plugin-tui` ← downstream of org.apache.camel:camel-catalog
   - `camel-jbang-plugin-validate` ← downstream of org.apache.camel:camel-yaml-dsl-validator
   - `camel-langchain4j-ingest` ← downstream of org.apache.camel:camel-docling
   - `camel-launcher-container` ← downstream of org.apache.camel:camel-launcher
   - `camel-yaml-dsl-validator` ← downstream of org.apache.camel:camel-catalog
   - `camel-yaml-dsl-validator-maven-plugin` ← downstream of org.apache.camel:camel-yaml-dsl-validator
   - `docs` ← docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
   
   </details>
   
   <details><summary>Modules with tests skipped (23)</summary>
   
   - `apache-camel`
   - `camel-allcomponents`
   - `camel-catalog-console`
   - `camel-catalog-maven`
   - `camel-catalog-suggest`
   - `camel-endpointdsl-support`
   - `camel-itest`
   - `camel-jbang-core`
   - `camel-jbang-it`
   - `camel-jbang-main`
   - `camel-jbang-plugin-edit`
   - `camel-jbang-plugin-generate`
   - `camel-jbang-plugin-kubernetes`
   - `camel-jbang-plugin-test`
   - `camel-kamelet-main`
   - `camel-launcher`
   - `camel-report-maven-plugin`
   - `camel-route-parser`
   - `camel-yaml-dsl`
   - `camel-yaml-dsl-deserializers`
   - `camel-yaml-dsl-maven-plugin`
   - `coverage`
   - `dummy-component`
   
   </details>
   
   > :information_source: Shadow mode — Scalpel observes but does not affect test execution. [Learn more](https://github.com/maveniverse/scalpel)
   
   </details>
   
   <details><summary>All tested modules (37 modules, 5m 44s total)</summary>
   
   **Total reactor time:** 5m 44s
   
   | Module | Duration | Status |
   | --- | --- | --- |
   | Camel :: Launcher | 49.9s | SUCCESS |
   | Camel :: JBang :: MCP | 41.4s | SUCCESS |
   | Camel :: JBang :: Plugin :: TUI | 36.8s | SUCCESS |
   | Camel :: AI :: LangChain4j :: Ingest | 29.6s | SUCCESS |
   | Camel :: Catalog :: Camel Catalog | 23.6s | SUCCESS |
   | Camel :: Component DSL | 23.0s | SUCCESS |
   | Camel :: AI :: Docling | 21.7s | SUCCESS |
   | Camel :: JBang :: Plugin :: Kubernetes | 16.2s | SUCCESS |
   | Camel :: Docs | 15.1s | SUCCESS |
   | Camel :: Kamelet Main | 10.8s | SUCCESS |
   | Camel :: YAML DSL :: Validator | 9.5s | SUCCESS |
   | Camel :: Catalog :: Camel Report Maven Plugin | 8.9s | SUCCESS |
   | Camel :: JBang :: Plugin :: Testing | 8.2s | SUCCESS |
   | Camel :: Catalog :: Camel Route Parser | 8.1s | SUCCESS |
   | Camel :: JBang :: Plugin :: Validate | 5.9s | SUCCESS |
   | Camel :: YAML DSL :: Deserializers | 5.2s | SUCCESS |
   | Camel :: All Components Sync point | 5.1s | SUCCESS |
   | Camel :: YAML DSL :: Validator Maven Plugin | 4.2s | SUCCESS |
   | Camel :: YAML DSL :: Maven Plugins | 3.0s | SUCCESS |
   | Camel :: Catalog :: Maven | 2.6s | SUCCESS |
   | Camel :: Catalog :: Suggest (deprecated) | 2.5s | SUCCESS |
   | Camel :: Assembly | 1.9s | SUCCESS |
   | Camel :: JBang :: Plugin :: Edit | 1.9s | SUCCESS |
   | Camel :: Endpoint DSL :: Support | 1.2s | SUCCESS |
   | Camel :: Coverage | 1.2s | SUCCESS |
   | Camel :: JBang :: Main | 0.9s | SUCCESS |
   | Camel :: JBang :: Plugin :: Generate | 0.9s | SUCCESS |
   | Camel :: Catalog :: Dummy Component | 0.9s | SUCCESS |
   | Camel :: JBang :: Integration tests | 0.9s | SUCCESS |
   | Camel :: Catalog :: Console | 0.8s | SUCCESS |
   | Camel :: Launcher :: Container | 0.7s | SUCCESS |
   | Camel :: JBang :: Plugin :: MCP | 0.7s | SUCCESS |
   | Camel :: JBang :: Plugin :: Route Parser | 0.6s | SUCCESS |
   | Camel :: Endpoint DSL | n/a |  |
   | Camel :: Integration Tests | n/a |  |
   | Camel :: JBang :: Core | n/a |  |
   | Camel :: YAML DSL | n/a |  |
   
   **Top 20 slowest modules:**
   - `Camel :: Launcher` (49.9s)
   - `Camel :: JBang :: MCP` (41.4s)
   - `Camel :: JBang :: Plugin :: TUI` (36.8s)
   - `Camel :: AI :: LangChain4j :: Ingest` (29.6s)
   - `Camel :: Catalog :: Camel Catalog` (23.6s)
   - `Camel :: Component DSL` (23.0s)
   - `Camel :: AI :: Docling` (21.7s)
   - `Camel :: JBang :: Plugin :: Kubernetes` (16.2s)
   - `Camel :: Docs` (15.1s)
   - `Camel :: Kamelet Main` (10.8s)
   - `Camel :: YAML DSL :: Validator` (9.5s)
   - `Camel :: Catalog :: Camel Report Maven Plugin` (8.9s)
   - `Camel :: JBang :: Plugin :: Testing` (8.2s)
   - `Camel :: Catalog :: Camel Route Parser` (8.1s)
   - `Camel :: JBang :: Plugin :: Validate` (5.9s)
   - `Camel :: YAML DSL :: Deserializers` (5.2s)
   - `Camel :: All Components Sync point` (5.1s)
   - `Camel :: YAML DSL :: Validator Maven Plugin` (4.2s)
   - `Camel :: YAML DSL :: Maven Plugins` (3.0s)
   - `Camel :: Catalog :: Maven` (2.6s)
   
   </details>
   
   ---
   :gear: [View full build and test results](https://github.com/apache/camel/actions/runs/35719324016)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #26737:
URL: https://github.com/apache/camel/pull/26737#issuecomment-5774992718

   <!-- regen-patch -->
   ### :warning: Generated files are out of date
   
   The [CI build](https://github.com/apache/camel/actions/runs/35714226016) regenerated files that are not committed on this PR.
   
   If *Allow edits from maintainers* is enabled, a maintainer bot will automatically
   push a "Regen" commit to this branch shortly.
   
   Otherwise, you can apply the patch manually — the missing changes are available
   as the `regen-patch` artifact of that run:
   
   ```bash
   gh pr checkout 26737 --repo apache/camel
   gh run download 35714226016 --repo apache/camel -n regen-patch
   git apply --index regen.patch && rm regen.patch pr-number
   git commit -m "Regen" && git push
   ```
   
   Alternatively, run `./etc/scripts/regen.sh` locally and commit the resulting changes.
   If the patch does not apply cleanly, update the branch from the base branch first —
   the patch was generated against the merge with the base branch.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] CAMEL-24894: camel-docling - make output path handling consistent with input path and custom-argument handling [camel]

Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on PR #26737:
URL: https://github.com/apache/camel/pull/26737#issuecomment-5808392323

   Thanks — both non-blocking nits addressed in `223a7d8`:
   
   - **Reflection dropped.** `buildDoclingCommand` is now package-private (`// visible for testing`) and `buildDoclingCommandFor` calls it directly, so a rename or added parameter becomes a compile error rather than a runtime `NoSuchMethodException` on the normalization test.
   - **Bare `baseDir()` calls commented** — they create the directory the jailed route uses as `outputBaseDirectory`.
   
   _Claude Code on behalf of oscerd_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org