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

[PR] CAMEL-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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

   ## Summary
   
   Fixes two related bugs in `camel_configuration_validate` (MCP tool) that caused it to return `{accepted:false, valid:true}` for `camel.server.*`, `camel.management.*`, `camel.vault.*`, and all other `camel.*` groups not in the ten hardcoded prefixes.
   
   ## Root Cause
   
   **Bug 1 — `AbstractCamelCatalog.acceptConfigurationPropertyKey()`** hardcoded only 10 of the 36 `camel.*` groups defined in `camel-main-configuration-metadata.json`:
   
   ```
   camel.component.  camel.dataformat.  camel.language.  camel.main.
   camel.resilience4j.  camel.faulttolerance.  camel.threadpool.
   camel.health.  camel.lra.  camel.rest.
   ```
   
   Missing: `camel.server.*`, `camel.management.*`, `camel.ssl.*`, `camel.debug.*`, `camel.trace.*`, `camel.security.*`, `camel.vault.*`, `camel.opentelemetry.*`, `camel.metrics.*`, `camel.cluster.*`, `camel.routecontroller.*`, `camel.startupcondition.*`, and others (26 groups total).
   
   When a key was not accepted, `validateConfigurationProperty()` set `accepted=false` and returned immediately without recording any error. Since `PropertiesValidationResult.isSuccess()` returns `true` when there are no recorded errors, the result was the contradictory `{accepted:false, valid:true}`.
   
   **Bug 2 — `ConfigurationValidateTools.toPropertyValidationInfo()`** at the MCP layer computed `valid = result.isSuccess()`, ignoring the `accepted` flag entirely.
   
   ## Fix
   
   **`AbstractCamelCatalog`**: `acceptConfigurationPropertyKey()` is now an instance method that reads `mainModel().getGroups()` dynamically. Any group declared in `camel-main-configuration-metadata.json` is automatically accepted without requiring a code change. `component/dataformat/language` keep their static prefixes because they use a different per-artifact model.
   
   The validation branch for main-model groups is also updated to use the same dynamic lookup (`matchMainModelGroup()`) to correctly locate the option suffix offset for nested groups like `camel.vault.aws.*` (3-segment group name).
   
   **`ConfigurationValidateTools`**: `valid` is now computed as `accepted && result.isSuccess()`, so an unaccepted key is never reported as valid even when the catalog returned no validation errors.
   
   ## Test
   
   Six new test cases added to `ConfigurationValidateToolsTest`:
   - `camelServerPortIsAcceptedAndValid` — `camel.server.port=9999` must be `accepted=true, valid=true`
   - `camelServerInventedKeyIsAcceptedButNotValid` — `camel.server.bindPort=9999` (nonexistent) must be `accepted=true, valid=false` with an `unknown` issue
   - `acceptedFalseImpliesValidFalseForNonCamelKey` — invented namespace: `accepted=false, valid=false`, summary `valid=0`
   - `camelManagementKeyIsAccepted` — `camel.management.enabled=true` must be accepted and valid
   - `camelVaultAwsKeyIsAccepted` — nested 3-segment group `camel.vault.aws.*` must be accepted
   - Extended `nonCamelKeyMarkedNotAccepted` with `valid=false` regression guard
   
   All 16 tests in `ConfigurationValidateToolsTest` pass.
   
   _Hermes Agent (Claude Sonnet 4.6) on behalf of Guillaume Nodet_
   


-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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

   All review findings from @davsclaus have been addressed across the subsequent commits:
   - Unchecked lines now read as `checked=false` / `unchecked` count (not rejected)
   - Group matching is dash- and case-insensitive (`camel.error-registry.*` etc.)
   - Spring Boot false positives downgraded to `checked=false` via `onlyUnknownOptionErrors`
   - `mainModel()` is skipped for `camel.component.*`, `camel.dataformat.*`, `camel.language.*` keys
   - Dead code and `matchMainModelGroup` prefix bug fixed
   - All new tests pass: `testValidateConfigurationPropertyNestedGroup`, `testValidateConfigurationPropertyDashedGroupName`, `testValidateConfigurationPropertyServerInventedOption`, `springBootStarterOnlyOptionIsUnchecked`
   
   CI is green. All review threads are resolved. PTAL @davsclaus for a re-review when you get a chance.


-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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

   <!-- camel-backport-bot -->
   
   ### 🔄 Backport Bot
   
   This bugfix targets `main` and may need porting to:
   - `camel-4.22.x`
   
   Add a `port/<branch>` label to automatically create a backport PR for that branch.
   
   Backport PRs will be created automatically on merge (once a port label is added). Comment `/port` to create them immediately.
   
   ℹ️ 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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


##########
core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java:
##########
@@ -1232,33 +1235,42 @@ public ConfigurationPropertiesValidationResult validateConfigurationProperty(Str
                 int posBracket = nOption.indexOf('[');
                 validateConfigurationProperty(posDot, posBracket, suffix, nOption, result, rows, name, value, longKey);
             }
-        } else if (key.startsWith("main.")
-                || key.startsWith("resilience4j.")
-                || key.startsWith("faulttolerance.")
-                || key.startsWith("threadpool.")
-                || key.startsWith("lra.")
-                || key.startsWith("health.")
-                || key.startsWith("rest.")) {
-            String name = StringHelper.before(key, ".");
-            if (value != null) {
-                MainModel model = mainModel();
-                if (model == null) {
-                    result.addIncapable("camel-main not detected on classpath");
-                    return result;
-                }
-                Map<String, BaseOptionModel> rows = new HashMap<>();
-                model.getOptions().forEach(o -> rows.put(dashToCamelCase(o.getName()), o));
-
-                // lower case option and remove dash
-                String nOption = longKey.replace("-", "").toLowerCase(Locale.ENGLISH);
-
-                // look for suffix or array index after 2nd dot
-                int secondDot = nOption.indexOf('.', nOption.indexOf('.') + 1) + 1;
+        } else {
+            // Check if the key matches a main-model group (dynamic — replaces the hardcoded list)
+            MainModel.MainGroupModel matchedGroup = matchMainModelGroup(key, cachedMainModel);
+            if (matchedGroup != null) {
+                String name = StringHelper.before(key, ".");
+                if (value != null) {
+                    // cachedMainModel is guaranteed non-null here: acceptConfigurationPropertyKey returned true
+                    // for a camel.* key that is not component/dataformat/language, which means matchMainModelGroup
+                    // already found a match — so the model must have been available.
+                    MainModel model = cachedMainModel;
+                    if (model == null) {
+                        result.addIncapable("camel-main not detected on classpath");
+                        return result;
+                    }

Review Comment:
   💡 **Dead code:** the comment at line 1244 says `cachedMainModel` is *guaranteed non-null* here (because `matchMainModelGroup` already found a match, which requires a non-null model), yet the `if (model == null)` branch at line 1248 is still present. Either remove the branch or drop the "guaranteed" claim — keeping both contradicts itself and could mislead future readers about the contract.



##########
core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java:
##########
@@ -1185,7 +1185,10 @@ public ConfigurationPropertiesValidationResult validateConfigurationProperty(Str
         }
 
         ConfigurationPropertiesValidationResult result = new ConfigurationPropertiesValidationResult();
-        boolean accept = acceptConfigurationPropertyKey(key);
+        // Load the main model once here to avoid repeated JSON parsing in acceptConfigurationPropertyKey
+        // and matchMainModelGroup (both called for camel.* keys that are not component/dataformat/language).
+        MainModel cachedMainModel = key != null && key.startsWith("camel.") ? mainModel() : null;

Review Comment:
   ⚠️ **Performance regression:** `mainModel()` is called eagerly for **all** `camel.*` keys, including `camel.component.*`, `camel.dataformat.*`, and `camel.language.*` — which never use the result (they hit the static-prefix fast-path at lines 1432–1435 and return before the model is accessed). `mainModel()` parses a 229 KB JSON on every call with no cache in `DefaultCamelCatalog`, so every component/dataformat/language property lookup now pays a full parse that it didn't before.
   
   ```suggestion
           // Load the main model once, but only for dynamic main-model keys.
           // Component, dataformat, and language keys are accepted statically (no model needed).
           MainModel cachedMainModel = key != null && key.startsWith("camel.")
                   && !key.startsWith("camel.component.")
                   && !key.startsWith("camel.dataformat.")
                   && !key.startsWith("camel.language.") ? mainModel() : null;
   ```



##########
core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java:
##########
@@ -1408,20 +1420,60 @@ private static boolean isValidSuffix(String suffix) {
         return suffix == null || suffix.isEmpty() || suffix.equals(".");
     }
 
-    private static boolean acceptConfigurationPropertyKey(String key) {
+    private boolean acceptConfigurationPropertyKey(String key, MainModel cachedModel) {
         if (key == null) {
             return false;
         }
-        return key.startsWith("camel.component.")
+        // Keys outside the camel.* namespace are never checked by this catalog
+        if (!key.startsWith("camel.")) {
+            return false;
+        }
+        // Always-accepted static prefixes (component/dataformat/language have their own models)
+        if (key.startsWith("camel.component.")
                 || key.startsWith("camel.dataformat.")
-                || key.startsWith("camel.language.")
-                || key.startsWith("camel.main.")
-                || key.startsWith("camel.resilience4j.")
-                || key.startsWith("camel.faulttolerance.")
-                || key.startsWith("camel.threadpool.")
-                || key.startsWith("camel.health.")
-                || key.startsWith("camel.lra.")
-                || key.startsWith("camel.rest.");
+                || key.startsWith("camel.language.")) {
+            return true;
+        }
+        // Dynamic: accept any prefix that matches a group in the main-model metadata.
+        // camel-main binds keys after normalising dashes and case (MainHelper.optionKey /
+        // startsWithIgnoreCase), so we compare normalised forms to match e.g.
+        // camel.error-registry.* against the group name "camel.errorRegistry".
+        String normKey = key.replace("-", "").toLowerCase(Locale.ENGLISH);
+        MainModel model = cachedModel != null ? cachedModel : mainModel();
+        if (model != null) {
+            for (MainModel.MainGroupModel group : model.getGroups()) {
+                String normGroup = group.getName().replace("-", "").toLowerCase(Locale.ENGLISH) + ".";
+                if (normKey.startsWith(normGroup)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }

Review Comment:
   💡 **Duplication:** `acceptConfigurationPropertyKey` (lines 1423–1452) and `matchMainModelGroup` (lines 1461–1477) both iterate `model.getGroups()` with normalise-and-`startsWith` logic. They differ only in key convention (full `camel.*` key vs stripped key), which makes a direct delegation tricky but is worth a comment explaining why both exist separately, or consider unifying by always passing the stripped key.



##########
dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateToolsTest.java:
##########
@@ -172,14 +172,114 @@ void multipleLinesAggregated() {
     }
 
     @Test
-    void nonCamelKeyMarkedNotAccepted() {
+    void nonCamelKeyMarkedNotChecked() {
+        // Non-Camel keys (e.g. server.port) are not checked by this catalog: checked=false,
+        // valid=false, and counted in summary.unchecked (not in summary.errors or summary.valid).
         ConfigurationValidateTools tools = createTools();
 
         ConfigurationValidateTools.ConfigurationValidateResult result
                 = tools.camel_configuration_validate("server.port=8080", null, null, null);
 
         ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
-        assertThat(info.accepted()).isFalse();
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+        assertThat(result.summary().errors()).isZero();
+        assertThat(result.summary().valid()).isZero();
+    }
+
+    // --- CAMEL-25538 regression tests ---
+
+    @Test
+    void camelServerPortIsAcceptedAndValid() {
+        // camel.server.* was previously not in the hardcoded prefix list — it must now be
+        // accepted and validated against the main-model metadata.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.port=9999", null, null, null);
+
+        assertThat(result.summary().total()).isEqualTo(1);
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+        assertThat(info.errors()).isZero();
+        assertThat(info.issues()).isEmpty();
+    }
+
+    @Test
+    void camelServerInventedKeyIsCheckedButNotValid() {
+        // An invented key under an accepted camel.server.* group must be reported as unknown,
+        // not silently passed as valid.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.bindPort=9999", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isFalse();
+        assertThat(info.issues()).anyMatch(i -> "unknown".equals(i.kind()));
+    }
+
+    @Test
+    void uncheckedKeyImpliesValidFalseAndNotCountedInErrors() {
+        // Invented key outside any known camel.* group: checked=false AND valid=false.
+        // Before the fix, valid was true despite accepted=false (CAMEL-25538 bug #2).
+        // The key must not appear in summary.errors — it is unchecked, not rejected.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.invented.completely.unknown=foo", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        // The summary must not count unchecked keys as valid or as errors
+        assertThat(result.summary().valid()).isZero();
+        assertThat(result.summary().errors()).isZero();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+    }
+
+    @Test
+    void camelManagementKeyIsCheckedAndValid() {
+        // camel.management.* was also missing from the old hardcoded list.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.management.enabled=true", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+    }
+
+    @Test
+    void camelVaultAwsKeyIsCheckedAndValid() {
+        // camel.vault.aws.* is a nested group (3-segment name) — must also be accepted.
+        // The dot-offset logic that skips the group prefix is exercised here.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.vault.aws.accessKey=AKIA1234", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();

Review Comment:
   💡 `camelVaultAwsKeyIsCheckedAndValid` asserts `checked=true` and `valid=true` but has no assertion on `issues()`. Since this test is specifically validating a nested group key that exercises the dot-offset logic, asserting `info.issues().isEmpty()` would guard against silent validation errors that happen to leave `valid=true`.



-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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

   Approved and ready to merge, but it now conflicts with main in `docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc`: several PRs merged today added entries to the 4.23 → 4.24 section. Could you rebase on main? It can be merged once CI is green again.
   
   _Claude Code on behalf of Claus Ibsen_


-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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

   <!-- ci-tested-modules -->
   :test_tube: **CI tested the following changed modules:**
   
   - `core/camel-core-catalog`
   - `dsl/camel-jbang/camel-jbang-mcp`
   
   > :information_source: Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the `test-dependents` label to force testing all dependents.
   
   ---
   
   <details><summary>:microscope: Scalpel shadow comparison — Scalpel: 490 of 703 tested, 28 compile-only — current: 490 all tested</summary>
   
   [Maveniverse Scalpel](https://github.com/maveniverse/scalpel) detected **490 affected modules** (current approach: 490).
   
   **Skip-tests mode would test 490 modules** (2 direct + 488 downstream), **skip tests for 28** (generated code, meta-modules)
   
   <details><summary>Modules Scalpel would test (490)</summary>
   
   - `archetypes` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-a2a` ← downstream of org.apache.camel:camel-vertx-http
   - `camel-activemq` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-activemq6` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-ai-observability` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ai-observability-api` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ai-resource` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ai-tool` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-alibaba-eventbridge` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-alibaba-fc` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-alibaba-kms` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-alibaba-mns` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-alibaba-oss` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-alibaba-ots` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-alibaba-sls` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-alibaba-sms` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-amqp` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-api-component-maven-plugin` ← downstream of org.apache.camel:camel-core
   - `camel-arangodb` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-archetype-api-component` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-archetype-component` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-archetype-dataformat` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-archetype-java` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-archetype-main` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-as2` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-as2-api` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-asn1` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-asterisk` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-atmosphere-websocket` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-atom` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-attachments` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-avro` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-avro-rpc` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-aws-bedrock` ← downstream of org.apache.camel:camel-jq
   - `camel-aws-cloudtrail` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws-config` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-aws-parameter-store` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws-secrets-manager` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws-security-hub` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-athena` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-comprehend` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-cw` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-ddb` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-ec2` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-ecs` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-eks` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-eventbridge` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-iam` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-kinesis` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-aws2-kms` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-aws2-lambda` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-mq` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-msk` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-polly` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-redshift` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-rekognition` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-s3` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-s3-vectors` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-ses` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-sns` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-sqs` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-step-functions` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-sts` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-aws2-textract` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-timestream` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-aws2-transcribe` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-aws2-translate` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-azure-cosmosdb` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-azure-eventgrid` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-azure-eventhubs` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-azure-files` ← downstream of org.apache.camel:camel-ftp
   - `camel-azure-functions` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-azure-key-vault` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-azure-schema-registry` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-azure-servicebus` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-azure-storage-blob` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-azure-storage-datalake` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-azure-storage-queue` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-barcode` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-base64` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-bean-validator` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-beanio` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-bindy` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-bonita` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-box` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-braintree` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-caffeine` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-camunda` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-cassandraql` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-cbor` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-chatscript` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-chunk` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-cli-connector` ← downstream of org.apache.camel:camel-management
   - `camel-cli-debug` ← downstream of org.apache.camel:camel-cli-connector
   - `camel-clickhouse` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-clickup` ← downstream of org.apache.camel:camel-netty-http
   - `camel-cloudevents` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-cm-sms` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-coap` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-cometd` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-console` ← downstream of org.apache.camel:camel-core
   - `camel-consul` ← downstream of org.apache.camel:camel-http
   - `camel-core` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-core-all` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-core-catalog` ← core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java
   - `camel-couchbase` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-couchdb` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-cron` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-crypto` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-crypto-pgp` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-csv` ← downstream of org.apache.camel:camel-main
   - `camel-cxf-common` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-cxf-rest` ← downstream of org.apache.camel:camel-http
   - `camel-cxf-soap` ← downstream of org.apache.camel:camel-http
   - `camel-cxf-spring-common` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-cxf-spring-rest` ← downstream of org.apache.camel:camel-http
   - `camel-cxf-spring-soap` ← downstream of org.apache.camel:camel-http
   - `camel-cxf-spring-transport` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-cxf-transport` ← downstream of org.apache.camel:camel-undertow
   - `camel-cyberark-vault` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-dapr` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-datasonnet` ← downstream of org.apache.camel:camel-core
   - `camel-debezium-common` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-debezium-db2` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-debezium-maven-plugin` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-debezium-mongodb` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-debezium-mysql` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-debezium-oracle` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-debezium-postgres` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-debezium-sqlserver` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-debug` ← downstream of org.apache.camel:camel-management
   - `camel-dfdl` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-dhis2` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-dhis2-api` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-dhis2-parent` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-diagram` ← downstream of org.apache.camel:camel-management
   - `camel-disruptor` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-djl` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-dns` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-docker` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-docling` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-drill` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-dropbox` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-dsl-modeline` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-duckdb` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-dynamic-router` ← downstream of org.apache.camel:camel-management
   - `camel-ehcache` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-elasticsearch` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-elasticsearch-rest-client` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-event` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-exec` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-fastjson` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-fhir` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-file-watch` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-flatpack` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-flink` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-flowable` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-fop` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-fory` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-freemarker` ← downstream of org.apache.camel:camel-management
   - `camel-ftp` ← downstream of org.apache.camel:camel-ftp-common
   - `camel-ftp-common` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-geocoder` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-git` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-github2` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-google-bigquery` ← downstream of org.apache.camel:camel-google-common
   - `camel-google-calendar` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-google-common` ← downstream of org.apache.camel:camel-core
   - `camel-google-drive` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-google-firestore` ← downstream of org.apache.camel:camel-google-common
   - `camel-google-functions` ← downstream of org.apache.camel:camel-google-common
   - `camel-google-mail` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-google-pubsub` ← downstream of org.apache.camel:camel-google-common
   - `camel-google-secret-manager` ← downstream of org.apache.camel:camel-google-common
   - `camel-google-sheets` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-google-speech-to-text` ← downstream of org.apache.camel:camel-google-common
   - `camel-google-storage` ← downstream of org.apache.camel:camel-google-common
   - `camel-google-text-to-speech` ← downstream of org.apache.camel:camel-google-common
   - `camel-google-vertexai` ← downstream of org.apache.camel:camel-google-common
   - `camel-google-vision` ← downstream of org.apache.camel:camel-google-common
   - `camel-graphql` ← downstream of org.apache.camel:camel-http
   - `camel-grok` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-groovy` ← downstream of org.apache.camel:camel-core
   - `camel-grpc` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-gson` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-hashicorp-vault` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-hazelcast` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-hivemq` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-hl7` ← downstream of org.apache.camel:camel-core
   - `camel-http` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-http-base` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-http-common` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-huaweicloud-dms` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-huaweicloud-frs` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-huaweicloud-functiongraph` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-huaweicloud-iam` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-huaweicloud-imagerecognition` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-huaweicloud-obs` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-huaweicloud-smn` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-huggingface` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ibm-cos` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ibm-secrets-manager` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ibm-watson-discovery` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ibm-watson-language` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ibm-watson-speech-to-text` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ibm-watson-text-to-speech` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ibm-watsonx-ai` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ibm-watsonx-data` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ical` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-iggy` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-ignite` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-infinispan` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-infinispan-common` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-infinispan-embedded` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-influxdb` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-influxdb2` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-iso8583` ← downstream of org.apache.camel:camel-groovy
   - `camel-jackson` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-jackson-avro` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jackson-protobuf` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jackson3` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-jackson3-avro` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jackson3-protobuf` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jackson3xml` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-jacksonxml` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-jactl` ← downstream of org.apache.camel:camel-core
   - `camel-jandex` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jasypt` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-java-joor-dsl` ← downstream of org.apache.camel:camel-main
   - `camel-javascript` ← downstream of org.apache.camel:camel-core
   - `camel-jaxb` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-jbang-console` ← downstream of org.apache.camel:camel-management
   - `camel-jbang-mcp` ← dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateTools.java, dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateToolsTest.java
   - `camel-jbang-plugin-mcp` ← downstream of org.apache.camel:camel-jbang-core
   - `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-jcache` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jcr` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jdbc` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-jetty` ← downstream of org.apache.camel:camel-http
   - `camel-jetty-common` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-jfr` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jgroups` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jgroups-raft` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jira` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jms` ← downstream of org.apache.camel:camel-management
   - `camel-jmx` ← downstream of org.apache.camel:camel-management
   - `camel-jolt` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jooq` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-joor` ← downstream of org.apache.camel:camel-core
   - `camel-jpa` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-jq` ← downstream of org.apache.camel:camel-core
   - `camel-jsch` ← downstream of org.apache.camel:camel-ftp
   - `camel-jslt` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-json-validator` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jsonapi` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jsonata` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jsonb` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-jsonpath` ← downstream of org.apache.camel:camel-core
   - `camel-jsoup` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jt400` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-jta` ← downstream of org.apache.camel:camel-core
   - `camel-jte` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-kafka` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-kafka-common` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-kafka-share` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-kamelet` ← downstream of org.apache.camel:camel-http
   - `camel-kamelet-main-support` ← downstream of org.apache.camel:camel-main
   - `camel-keycloak` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-knative` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-knative-api` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-knative-http` ← downstream of org.apache.camel:camel-http
   - `camel-kserve` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-kubernetes` ← downstream of org.apache.camel:camel-http
   - `camel-kudu` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-langchain4j-agent` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-langchain4j-chat` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-langchain4j-core` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-langchain4j-embeddings` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-langchain4j-embeddingstore` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-langchain4j-ingest` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-langchain4j-tokenizer` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-langchain4j-web-search` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-launcher-container` ← downstream of org.apache.camel:camel-launcher
   - `camel-ldap` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-ldif` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-lra` ← downstream of org.apache.camel:camel-undertow
   - `camel-lucene` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-lumberjack` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-lzf` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-mail` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-mail-microsoft-oauth` ← downstream of org.apache.camel:camel-mail
   - `camel-main` ← downstream of org.apache.camel:camel-core
   - `camel-management` ← downstream of org.apache.camel:camel-core
   - `camel-mapstruct` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-master` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-maven-plugin` ← downstream of org.apache.camel:camel-core
   - `camel-mcp-server` ← downstream of org.apache.camel:camel-main
   - `camel-mcp-server-api` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-mdc` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-metrics` ← downstream of org.apache.camel:camel-management
   - `camel-micrometer` ← downstream of org.apache.camel:camel-management
   - `camel-micrometer-observability` ← downstream of org.apache.camel:camel-undertow
   - `camel-micrometer-prometheus` ← downstream of org.apache.camel:camel-micrometer
   - `camel-microprofile-config` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-microprofile-fault-tolerance` ← downstream of org.apache.camel:camel-management
   - `camel-microprofile-health` ← downstream of org.apache.camel:camel-main
   - `camel-milo` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-milvus` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-mina` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-mina-sftp` ← downstream of org.apache.camel:camel-ftp-common
   - `camel-minio` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-mllp` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-mongodb` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-mongodb-gridfs` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-mustache` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-mvel` ← downstream of org.apache.camel:camel-core
   - `camel-mybatis` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-nats` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-neo4j` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-netty` ← downstream of org.apache.camel:camel-management
   - `camel-netty-http` ← downstream of org.apache.camel:camel-http
   - `camel-oaipmh` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-oauth` ← downstream of org.apache.camel:camel-netty-http
   - `camel-observability-services` ← downstream of org.apache.camel:camel-management
   - `camel-observation` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-ocsf` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-odata` ← downstream of org.apache.camel:camel-http
   - `camel-ognl` ← downstream of org.apache.camel:camel-core
   - `camel-olingo2` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-olingo2-api` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-olingo4` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-olingo4-api` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-once` ← downstream of org.apache.camel:camel-groovy
   - `camel-opa` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-openai` ← downstream of org.apache.camel:camel-platform-http-vertx
   - `camel-openapi-java` ← downstream of org.apache.camel:camel-management
   - `camel-openapi-validator` ← downstream of org.apache.camel:camel-rest-openapi
   - `camel-openfeature` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-openfga` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-opensearch` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-openstack` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-opentelemetry` ← downstream of org.apache.camel:camel-undertow
   - `camel-opentelemetry-metrics` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-opentelemetry2` ← downstream of org.apache.camel:camel-undertow
   - `camel-optaplanner` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-paho` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-paho-mqtt5` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-parquet-avro` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-pdf` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-pg-replication-slot` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-pgevent` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-pgvector` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-pinecone` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-platform-http` ← downstream of org.apache.camel:camel-http
   - `camel-platform-http-jolokia` ← downstream of org.apache.camel:camel-core
   - `camel-platform-http-main` ← downstream of org.apache.camel:camel-main
   - `camel-platform-http-vertx` ← downstream of org.apache.camel:camel-http
   - `camel-plc4x` ← downstream of org.apache.camel:camel-main
   - `camel-pqc` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-printer` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-protobuf` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-pubnub` ← downstream of org.apache.camel:camel-main
   - `camel-pulsar` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-python` ← downstream of org.apache.camel:camel-core
   - `camel-python3` ← downstream of org.apache.camel:camel-core
   - `camel-qdrant` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-quartz` ← downstream of org.apache.camel:camel-management
   - `camel-quickfix` ← downstream of org.apache.camel:camel-jetty
   - `camel-quickjs` ← downstream of org.apache.camel:camel-core
   - `camel-reactive-streams` ← downstream of org.apache.camel:camel-management
   - `camel-reactor` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-redis` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-resilience4j` ← downstream of org.apache.camel:camel-management
   - `camel-resilience4j-micrometer` ← downstream of org.apache.camel:camel-management
   - `camel-resourceresolver-github` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-rest-openapi` ← downstream of org.apache.camel:camel-http
   - `camel-rest-postman` ← downstream of org.apache.camel:camel-http
   - `camel-restdsl-openapi-plugin` ← downstream of org.apache.camel:camel-core
   - `camel-robotframework` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-rocketmq` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-rss` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-rxjava` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-salesforce` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-salesforce-codegen` ← downstream of org.apache.camel:camel-salesforce
   - `camel-sap-netweaver` ← downstream of org.apache.camel:camel-http
   - `camel-saxon` ← downstream of org.apache.camel:camel-core
   - `camel-schematron` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-semantic` ← downstream of org.apache.camel:camel-management
   - `camel-servicenow` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-servicenow-maven-plugin` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-servlet` ← downstream of org.apache.camel:camel-management
   - `camel-shell` ← downstream of org.apache.camel:camel-test-junit5
   - `camel-shiro` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-sjms` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-sjms2` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-slack` ← downstream of org.apache.camel:camel-undertow
   - `camel-smb` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-smooks` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-smpp` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-snakeyaml` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-snmp` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-soap` ← downstream of org.apache.camel:camel-cxf-soap
   - `camel-solr` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-spiffe` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-splunk-hec` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-spring` ← downstream of org.apache.camel:camel-cron
   - `camel-spring-ai-chat` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-spring-ai-embeddings` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-spring-ai-image` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-spring-ai-vector-store` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-spring-batch` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-spring-cloud-config` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-spring-jdbc` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-spring-ldap` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-spring-main` ← downstream of org.apache.camel:camel-main
   - `camel-spring-rabbitmq` ← downstream of org.apache.camel:camel-http
   - `camel-spring-redis` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-spring-security` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-spring-ws` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-spring-xml` ← downstream of org.apache.camel:camel-core
   - `camel-sql` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-ssh` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-state-store` ← downstream of org.apache.camel:camel-test-main-junit5
   - `camel-stax` ← downstream of org.apache.camel:camel-core
   - `camel-stitch` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-stream` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-streamcaching-test` ← downstream of org.apache.camel:camel-core
   - `camel-stringtemplate` ← downstream of org.apache.camel:camel-management
   - `camel-stripe` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-swift` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-syslog` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-tahu` ← downstream of org.apache.camel:camel-test-infra-core
   - `camel-tarfile` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-telegram` ← downstream of org.apache.camel:camel-netty-http
   - `camel-telemetry` ← downstream of org.apache.camel:camel-undertow
   - `camel-telemetry-dev` ← downstream of org.apache.camel:camel-undertow
   - `camel-tensorflow-serving` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-test-infra-all` ← downstream of org.apache.camel:camel-test-infra-artemis
   - `camel-test-infra-artemis` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-test-infra-core` ← downstream of org.apache.camel:camel-core
   - `camel-test-infra-smb` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-test-junit5` ← downstream of org.apache.camel:camel-management
   - `camel-test-junit6` ← downstream of org.apache.camel:camel-management
   - `camel-test-main-junit5` ← downstream of org.apache.camel:camel-yaml-io
   - `camel-test-main-junit6` ← downstream of org.apache.camel:camel-yaml-io
   - `camel-test-spring-junit5` ← downstream of org.apache.camel:camel-management
   - `camel-test-spring-junit6` ← downstream of org.apache.camel:camel-management
   - `camel-thrift` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-thymeleaf` ← downstream of org.apache.camel:camel-management
   - `camel-tika` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-toon` ← downstream of org.apache.camel:camel-test-junit5
   - `camel-tracing` ← downstream of org.apache.camel:camel-test-spring-junit6
   - `camel-twilio` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-twitter` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-typesafe-ai` ← downstream of org.apache.camel:camel-main
   - `camel-ubl` ← downstream of org.apache.camel:camel-test-junit5
   - `camel-undertow` ← downstream of org.apache.camel:camel-http
   - `camel-undertow-spring-security` ← downstream of org.apache.camel:camel-undertow
   - `camel-univocity-parsers` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-velocity` ← downstream of org.apache.camel:camel-management
   - `camel-vertx` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-vertx-http` ← downstream of org.apache.camel:camel-http
   - `camel-vertx-websocket` ← downstream of org.apache.camel:camel-main
   - `camel-wasm` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-weather` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-weaviate` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-web3j` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-webhook` ← downstream of org.apache.camel:camel-netty-http
   - `camel-whatsapp` ← downstream of org.apache.camel:camel-netty-http
   - `camel-wolf-defender` ← downstream of org.apache.camel:camel-main
   - `camel-wordpress` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-workday` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-xchange` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-xj` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-xml-io-dsl` ← downstream of org.apache.camel:camel-core
   - `camel-xml-jaxb-dsl` ← downstream of org.apache.camel:camel-core
   - `camel-xml-jaxb-dsl-test-definition` ← downstream of org.apache.camel:camel-core
   - `camel-xml-jaxb-dsl-test-spring` ← downstream of org.apache.camel:camel-core
   - `camel-xmlsecurity` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-xmpp` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-xslt-saxon` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-yaml-dsl-validator` ← downstream of org.apache.camel:camel-yaml-io
   - `camel-yaml-dsl-validator-maven-plugin` ← downstream of org.apache.camel:camel-yaml-dsl-validator
   - `camel-yaml-io` ← downstream of org.apache.camel:camel-core-catalog
   - `camel-zendesk` ← downstream of org.apache.camel:camel-api-component-maven-plugin
   - `camel-zip-deflater` ← downstream of org.apache.camel:camel-test-junit6
   - `camel-zipfile` ← downstream of org.apache.camel:camel-spring-xml
   - `camel-zookeeper` ← downstream of org.apache.camel:camel-http
   - `camel-zookeeper-master` ← downstream of org.apache.camel:camel-ftp
   
   </details>
   
   <details><summary>Modules with tests skipped (28)</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-salesforce-maven-plugin`
   - `camel-yaml-dsl`
   - `camel-yaml-dsl-deserializers`
   - `camel-yaml-dsl-maven-plugin`
   - `coverage`
   - `docs`
   - `dummy-component`
   
   </details>
   
   > :information_source: Shadow mode — Scalpel observes but does not affect test execution. [Learn more](https://github.com/maveniverse/scalpel)
   
   </details>
   
   :warning: **Some tests are disabled on GitHub Actions** (`@DisabledIfSystemProperty(named = "ci.env.name")`) and require manual verification:
   
   - `dsl/camel-jbang/camel-jbang-mcp`: 1 test(s) disabled on GitHub Actions
   
   <details><summary>Build reactor — dependencies compiled but only changed modules were tested (2 modules, 37.1s total)</summary>
   
   **Total reactor time:** 37.1s
   
   | Module | Duration | Status |
   | --- | --- | --- |
   | Camel :: JBang :: MCP | 31.7s | SUCCESS |
   | Camel :: Core Catalog | 5.4s | SUCCESS |
   
   **Top 20 slowest modules:**
   - `Camel :: JBang :: MCP` (31.7s)
   - `Camel :: Core Catalog` (5.4s)
   
   </details>
   
   ---
   :gear: [View full build and test results](https://github.com/apache/camel/actions/runs/38592291127)


-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


##########
core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java:
##########
@@ -1185,7 +1185,10 @@ public ConfigurationPropertiesValidationResult validateConfigurationProperty(Str
         }
 
         ConfigurationPropertiesValidationResult result = new ConfigurationPropertiesValidationResult();
-        boolean accept = acceptConfigurationPropertyKey(key);
+        // Load the main model once here to avoid repeated JSON parsing in acceptConfigurationPropertyKey
+        // and matchMainModelGroup (both called for camel.* keys that are not component/dataformat/language).
+        MainModel cachedMainModel = key != null && key.startsWith("camel.") ? mainModel() : null;

Review Comment:
   This loads the main model for `camel.component.*`, `camel.dataformat.*` and `camel.language.*` keys as well (the comment above says it does not), but `acceptConfigurationPropertyKey` returns true for those before it looks at the model. Since `mainModel()` parses the JSON on each call, every component line now parses the main metadata. Skipping those prefixes keeps the single load for main-group keys:
   ```suggestion
           MainModel cachedMainModel = key != null && key.startsWith("camel.")
                   && !key.startsWith("camel.component.")
                   && !key.startsWith("camel.dataformat.")
                   && !key.startsWith("camel.language.")
                           ? mainModel() : null;
   ```



##########
dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateToolsTest.java:
##########
@@ -172,14 +172,114 @@ void multipleLinesAggregated() {
     }
 
     @Test
-    void nonCamelKeyMarkedNotAccepted() {
+    void nonCamelKeyMarkedNotChecked() {
+        // Non-Camel keys (e.g. server.port) are not checked by this catalog: checked=false,
+        // valid=false, and counted in summary.unchecked (not in summary.errors or summary.valid).
         ConfigurationValidateTools tools = createTools();
 
         ConfigurationValidateTools.ConfigurationValidateResult result
                 = tools.camel_configuration_validate("server.port=8080", null, null, null);
 
         ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
-        assertThat(info.accepted()).isFalse();
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+        assertThat(result.summary().errors()).isZero();
+        assertThat(result.summary().valid()).isZero();
+    }
+
+    // --- CAMEL-25538 regression tests ---
+
+    @Test
+    void camelServerPortIsAcceptedAndValid() {
+        // camel.server.* was previously not in the hardcoded prefix list — it must now be
+        // accepted and validated against the main-model metadata.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.port=9999", null, null, null);
+
+        assertThat(result.summary().total()).isEqualTo(1);
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+        assertThat(info.errors()).isZero();
+        assertThat(info.issues()).isEmpty();
+    }
+
+    @Test
+    void camelServerInventedKeyIsCheckedButNotValid() {
+        // An invented key under an accepted camel.server.* group must be reported as unknown,
+        // not silently passed as valid.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.bindPort=9999", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isFalse();
+        assertThat(info.issues()).anyMatch(i -> "unknown".equals(i.kind()));
+    }
+
+    @Test
+    void uncheckedKeyImpliesValidFalseAndNotCountedInErrors() {
+        // Invented key outside any known camel.* group: checked=false AND valid=false.
+        // Before the fix, valid was true despite accepted=false (CAMEL-25538 bug #2).
+        // The key must not appear in summary.errors — it is unchecked, not rejected.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.invented.completely.unknown=foo", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        // The summary must not count unchecked keys as valid or as errors
+        assertThat(result.summary().valid()).isZero();
+        assertThat(result.summary().errors()).isZero();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+    }
+
+    @Test
+    void camelManagementKeyIsCheckedAndValid() {
+        // camel.management.* was also missing from the old hardcoded list.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.management.enabled=true", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+    }
+
+    @Test
+    void camelVaultAwsKeyIsCheckedAndValid() {
+        // camel.vault.aws.* is a nested group (3-segment name) — must also be accepted.
+        // The dot-offset logic that skips the group prefix is exercised here.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.vault.aws.accessKey=AKIA1234", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+    }
+
+    @Test
+    void camelVaultAwsInventedKeyIsCheckedButNotValid() {
+        // An invented option under a nested group (camel.vault.aws.*) exercises the dot-offset
+        // logic: the option name starts after the 3rd dot and must be checked against the model.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.vault.aws.inventedOption=foo", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isFalse();
     }

Review Comment:
   Dash-insensitive group matching is the main change of this round, but no test covers it. `camel.errorRegistry.enabled` exists in the main metadata, so something like:
   ```suggestion
       }
   
       @Test
       void dashedGroupNameIsCheckedAndValid() {
           // camel-main binds camel.error-registry.* to the camel.errorRegistry group
           ConfigurationValidateTools tools = createTools();
   
           ConfigurationValidateTools.ConfigurationValidateResult result
                   = tools.camel_configuration_validate("camel.error-registry.enabled=true", null, null, null);
   
           ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
           assertThat(info.checked()).isTrue();
           assertThat(info.valid()).isTrue();
       }
   ```



-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateTools.java:
##########
@@ -105,16 +130,62 @@ public ConfigurationValidateResult camel_configuration_validate(
     }
 
     private PropertyValidationInfo toPropertyValidationInfo(
-            int lineNumber, String text, ConfigurationPropertiesValidationResult result) {
-        boolean valid = result.isSuccess();
-        boolean accepted = result.isAccepted();
-        int errors = result.getNumberOfErrors();
-        int warnings = result.getNumberOfWarnings();
+            int lineNumber, String text, ConfigurationPropertiesValidationResult result, boolean isSpringBoot) {
+        boolean checked = result.isAccepted();
+        // A checked line is valid when the catalog found no errors; an unchecked line
+        // (not recognised as a Camel property) is neither valid nor invalid — it is simply
+        // not inspected by this catalog.
+        boolean valid = checked && result.isSuccess();
+
+        // For Spring Boot, the catalog uses camel-main metadata which does not include
+        // starter-specific options (e.g. camel.metrics.uriTagEnabled from camel-micrometer-starter).
+        // When the only issues are "unknown option" errors AND the key belongs to a group that is
+        // newly accepted by this fix (not one of the original 10 hardcoded prefixes), downgrade to
+        // unchecked to avoid false positives — the starter may legitimately bind options outside the
+        // main schema. Keys under the original 10 groups (component, dataformat, language, main,
+        // resilience4j, faulttolerance, threadpool, health, lra, rest) retain full validation since
+        // the catalog has always covered them.
+        boolean springBootDowngraded = false;
+        if (isSpringBoot && checked && !valid) {
+            String propertyKey = text != null && text.contains("=") ? text.substring(0, text.indexOf('=')).trim() : text;
+            boolean isOriginalGroup = propertyKey != null && (propertyKey.startsWith("camel.component.")
+                    || propertyKey.startsWith("camel.dataformat.")
+                    || propertyKey.startsWith("camel.language.")
+                    || propertyKey.startsWith("camel.main.")
+                    || propertyKey.startsWith("camel.resilience4j.")
+                    || propertyKey.startsWith("camel.faulttolerance.")
+                    || propertyKey.startsWith("camel.threadpool.")
+                    || propertyKey.startsWith("camel.health.")
+                    || propertyKey.startsWith("camel.lra.")
+                    || propertyKey.startsWith("camel.rest."));

Review Comment:
   ⚠️ **Bug: `isOriginalGroup` prefix check doesn't account for Spring Boot relaxed-binding key format**
   
   `propertyKey` is extracted with no normalization (just `.trim()`), but the prefix checks use canonical camelCase-free forms (`"camel.faulttolerance."`, `"camel.threadpool."`). Spring Boot's relaxed-binding convention writes these as `camel.fault-tolerance.*` and `camel.thread-pool.*` (with dashes), which will **not** match the dash-free prefix checks — causing them to fall through to `isOriginalGroup = false`, and then be incorrectly downgraded to unchecked.
   
   Fix: normalize `propertyKey` before the prefix check, the same way the catalog does:
   
   ```suggestion
               boolean isOriginalGroup = propertyKey != null && (propertyKey.startsWith("camel.component.")
                       || propertyKey.startsWith("camel.dataformat.")
                       || propertyKey.startsWith("camel.language.")
                       || propertyKey.startsWith("camel.main.")
                       || propertyKey.startsWith("camel.resilience4j.")
                       || propertyKey.startsWith("camel.faulttolerance.")
                       || propertyKey.replace("-", "").startsWith("camel.faulttolerance.")
                       || propertyKey.startsWith("camel.threadpool.")
                       || propertyKey.replace("-", "").startsWith("camel.threadpool.")
                       || propertyKey.startsWith("camel.health.")
                       || propertyKey.startsWith("camel.lra.")
                       || propertyKey.startsWith("camel.rest."));
   ```
   
   Or more robustly, normalize the whole key once upfront: `propertyKey.replace("-", "").toLowerCase()` and rewrite the prefixes to match.



-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateTools.java:
##########
@@ -105,16 +130,41 @@ public ConfigurationValidateResult camel_configuration_validate(
     }
 
     private PropertyValidationInfo toPropertyValidationInfo(
-            int lineNumber, String text, ConfigurationPropertiesValidationResult result) {
-        boolean valid = result.isSuccess();
-        boolean accepted = result.isAccepted();
-        int errors = result.getNumberOfErrors();
-        int warnings = result.getNumberOfWarnings();
+            int lineNumber, String text, ConfigurationPropertiesValidationResult result, boolean isSpringBoot) {
+        boolean checked = result.isAccepted();
+        // A checked line is valid when the catalog found no errors; an unchecked line
+        // (not recognised as a Camel property) is neither valid nor invalid — it is simply
+        // not inspected by this catalog.
+        boolean valid = checked && result.isSuccess();
+
+        // For Spring Boot, the catalog uses camel-main metadata which does not include
+        // starter-specific options (e.g. camel.metrics.uriTagEnabled from camel-micrometer-starter).
+        // When the only issues are "unknown option" errors, downgrade to unchecked to avoid
+        // false positives — the starter may legitimately bind options outside the main schema.
+        if (isSpringBoot && checked && !valid) {

Review Comment:
   This also downgrades `camel.component.*`, `camel.dataformat.*`, `camel.language.*` and `camel.main.*` lines. On main, `camel.component.kafka.brokerz=x` with `runtime=spring-boot` was `valid=false` with a "did you mean brokers" suggestion. Now it is `checked=false` with no issues. Could the downgrade apply only to the groups this PR newly accepts, and keep `collectIssues(result)` on downgraded lines so the suggestions are still returned?



##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -13,6 +13,33 @@ See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
 
 == Upgrading Camel 4.23 to 4.24
 
+=== camel-report-maven-plugin:validate / configuration-validate
+
+The catalog now accepts all `camel.*` groups defined in `camel-main-configuration-metadata.json`
+(previously only 10 groups out of 36 were recognized). As a result,
+`camel-report-maven-plugin:validate` and the camel-jbang MCP `camel_configuration_validate` tool
+now validate approximately 26 additional `camel.*` groups (including `camel.server.*`,

Review Comment:
   On main, 7 of the 10 old prefixes were main groups (main, resilience4j, faulttolerance, threadpool, health, lra, rest). The other 3 were component, dataformat and language. So 29 of the 36 groups are newly checked, not about 26. It would also help to say here that Spring Boot projects may see "Unknown option" for starter-only keys such as `camel.metrics.uriTagEnabled`, since `validate` uses the camel-main metadata.



##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -13,6 +13,33 @@ See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
 
 == Upgrading Camel 4.23 to 4.24
 
+=== camel-report-maven-plugin:validate / configuration-validate
+
+The catalog now accepts all `camel.*` groups defined in `camel-main-configuration-metadata.json`
+(previously only 10 groups out of 36 were recognized). As a result,
+`camel-report-maven-plugin:validate` and the camel-jbang MCP `camel_configuration_validate` tool
+now validate approximately 26 additional `camel.*` groups (including `camel.server.*`,
+`camel.management.*`, `camel.vault.*`, `camel.ssl.*`, and others).
+
+Group names are now matched with dash- and case-insensitive normalisation, matching how
+camel-main binds keys at runtime. For example, `camel.error-registry.enabled` and
+`camel.ai-observability.enabled` are now accepted alongside their camel-case equivalents.
+
+If your project uses `camel-report-maven-plugin:validate` with `failOnError=true`,
+a key that was silently ignored before (e.g. a misspelled option under one of the newly accepted
+groups) may now cause the build to fail. Review the validation output and correct any misspelled keys.
+
+The `camel_configuration_validate` MCP tool response format has changed:
+
+* `PropertyValidationInfo.accepted` is renamed to `checked`.
+* `ConfigurationValidateSummary` gains a new `unchecked` integer field counting lines whose
+  namespace is not recognized as a Camel property (e.g. `server.port=8080` or `quarkus.*` keys).
+  Such lines had no `accepted` flag before; they are now explicitly classified as `checked=false`

Review Comment:
   These lines did have the flag before: the tool returned `accepted=false` and `valid=true` for them. Maybe: "Before, such lines were returned with `accepted=false` and `valid=true`; they are now `checked=false` and are left out of `summary.valid` and `summary.errors`."



-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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

   <!-- regen-patch -->
   ### :warning: Generated files are out of date
   
   The [CI build](https://github.com/apache/camel/actions/runs/38861661454) 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 27841 --repo apache/camel
   gh run download 38861661454 --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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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

   :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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


##########
core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java:
##########
@@ -1408,20 +1419,65 @@ private static boolean isValidSuffix(String suffix) {
         return suffix == null || suffix.isEmpty() || suffix.equals(".");
     }
 
-    private static boolean acceptConfigurationPropertyKey(String key) {
+    private boolean acceptConfigurationPropertyKey(String key, MainModel cachedModel) {
         if (key == null) {
             return false;
         }
-        return key.startsWith("camel.component.")
+        // Keys outside the camel.* namespace are never checked by this catalog
+        if (!key.startsWith("camel.")) {
+            return false;
+        }
+        // Always-accepted static prefixes (component/dataformat/language have their own models)
+        if (key.startsWith("camel.component.")
                 || key.startsWith("camel.dataformat.")
-                || key.startsWith("camel.language.")
-                || key.startsWith("camel.main.")
-                || key.startsWith("camel.resilience4j.")
-                || key.startsWith("camel.faulttolerance.")
-                || key.startsWith("camel.threadpool.")
-                || key.startsWith("camel.health.")
-                || key.startsWith("camel.lra.")
-                || key.startsWith("camel.rest.");
+                || key.startsWith("camel.language.")) {
+            return true;
+        }
+        // Dynamic: accept any prefix that matches a group in the main-model metadata.
+        // camel-main binds keys after normalising dashes and case (MainHelper.optionKey /
+        // startsWithIgnoreCase), so we compare normalised forms to match e.g.
+        // camel.error-registry.* against the group name "camel.errorRegistry".
+        String normKey = key.replace("-", "").toLowerCase(Locale.ENGLISH);
+        MainModel model = cachedModel;
+        if (model != null) {
+            for (MainModel.MainGroupModel group : model.getGroups()) {
+                String normGroup = group.getName().replace("-", "").toLowerCase(Locale.ENGLISH) + ".";
+                if (normKey.startsWith(normGroup)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the matched group from the main-model metadata when the key (with the leading {@code camel.} stripped)
+     * corresponds to one of the registered groups, or {@code null} if no group matches.
+     * <p>
+     * Comparison is normalised (dashes removed, lower-cased) to mirror how camel-main binds keys at runtime via
+     * {@code MainHelper.optionKey} and {@code startsWithIgnoreCase}.
+     * <p>
+     * Note: {@link #acceptConfigurationPropertyKey} also iterates the groups with the same normalisation, but it
+     * receives the full {@code camel.*} key (not the stripped form) and returns a boolean rather than the matched
+     * group. A direct delegation is awkward because the two callers need different key conventions, so both methods are
+     * kept separate and share the normalisation comment above.
+     */
+    private MainModel.MainGroupModel matchMainModelGroup(String key, MainModel cachedModel) {
+        MainModel model = cachedModel;
+        if (model == null) {
+            return null;
+        }
+        // Normalise the incoming key once
+        String normKey = key.replace("-", "").toLowerCase(Locale.ENGLISH);
+        for (MainModel.MainGroupModel group : model.getGroups()) {
+            // group name is e.g. "camel.server" — strip the leading "camel." to get "server"
+            String groupName = group.getName().substring("camel.".length());
+            String normGroupName = groupName.replace("-", "").toLowerCase(Locale.ENGLISH);
+            if (normKey.startsWith(normGroupName + ".")) {

Review Comment:
   ⚠️ **Bug: `normKey` still carries the `"camel."` prefix but `normGroupName` does not — `startsWith` always fails.**
   
   `normKey` = `"camel.errorregistry.enabled"` (full key, as passed by the caller).
   `groupName` = `group.getName().substring("camel.".length())` = `"errorRegistry"` → `normGroupName` = `"errorregistry"`.
   `"camel.errorregistry.enabled".startsWith("errorregistry.")` → **`false`**.
   
   The `for` loop never returns a non-null group; `matchMainModelGroup` always returns `null`; the `else` branch in `validateConfigurationProperty` never executes → unknown options under accepted groups are silently ignored (no validation error raised).
   
   `acceptConfigurationPropertyKey` avoids this because it uses `group.getName()` directly (the full `"camel.errorRegistry"` string), not the stripped form. Apply the same pattern here:
   
   ```suggestion
           for (MainModel.MainGroupModel group : model.getGroups()) {
               String normGroup = group.getName().replace("-", "").toLowerCase(Locale.ENGLISH) + ".";
               if (normKey.startsWith(normGroup)) {
                   return group;
               }
           }
   ```



-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


##########
dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateToolsTest.java:
##########
@@ -172,14 +172,146 @@ void multipleLinesAggregated() {
     }
 
     @Test
-    void nonCamelKeyMarkedNotAccepted() {
+    void nonCamelKeyMarkedNotChecked() {
+        // Non-Camel keys (e.g. server.port) are not checked by this catalog: checked=false,
+        // valid=false, and counted in summary.unchecked (not in summary.errors or summary.valid).
         ConfigurationValidateTools tools = createTools();
 
         ConfigurationValidateTools.ConfigurationValidateResult result
                 = tools.camel_configuration_validate("server.port=8080", null, null, null);
 
         ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
-        assertThat(info.accepted()).isFalse();
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+        assertThat(result.summary().errors()).isZero();
+        assertThat(result.summary().valid()).isZero();
+    }
+
+    // --- CAMEL-25538 regression tests ---
+
+    @Test
+    void camelServerPortIsAcceptedAndValid() {
+        // camel.server.* was previously not in the hardcoded prefix list — it must now be
+        // accepted and validated against the main-model metadata.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.port=9999", null, null, null);
+
+        assertThat(result.summary().total()).isEqualTo(1);
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+        assertThat(info.errors()).isZero();
+        assertThat(info.issues()).isEmpty();
+    }
+
+    @Test
+    void camelServerInventedKeyIsCheckedButNotValid() {
+        // An invented key under an accepted camel.server.* group must be reported as unknown,
+        // not silently passed as valid.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.bindPort=9999", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isFalse();
+        assertThat(info.issues()).anyMatch(i -> "unknown".equals(i.kind()));
+    }
+
+    @Test
+    void uncheckedKeyImpliesValidFalseAndNotCountedInErrors() {
+        // Invented key outside any known camel.* group: checked=false AND valid=false.
+        // Before the fix, valid was true despite accepted=false (CAMEL-25538 bug #2).
+        // The key must not appear in summary.errors — it is unchecked, not rejected.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.invented.completely.unknown=foo", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        // The summary must not count unchecked keys as valid or as errors
+        assertThat(result.summary().valid()).isZero();
+        assertThat(result.summary().errors()).isZero();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+    }
+
+    @Test
+    void camelManagementKeyIsCheckedAndValid() {
+        // camel.management.* was also missing from the old hardcoded list.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.management.enabled=true", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+    }
+
+    @Test
+    void camelVaultAwsKeyIsCheckedAndValid() {
+        // camel.vault.aws.* is a nested group (3-segment name) — must also be accepted.
+        // The dot-offset logic that skips the group prefix is exercised here.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.vault.aws.accessKey=AKIA1234", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+        assertThat(info.issues()).isEmpty();
+    }
+
+    @Test
+    void camelVaultAwsInventedKeyIsCheckedButNotValid() {
+        // An invented option under a nested group (camel.vault.aws.*) exercises the dot-offset
+        // logic: the option name starts after the 3rd dot and must be checked against the model.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.vault.aws.inventedOption=foo", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isFalse();
+    }
+
+    @Test
+    void dashedGroupNameIsCheckedAndValid() {
+        // camel-main binds camel.error-registry.* to the camel.errorRegistry group
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.error-registry.enabled=true", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+    }
+
+    @Test
+    void springBootStarterOnlyOptionIsUnchecked() {
+        // camel.metrics.uriTagEnabled exists in camel-micrometer-starter but not in the
+        // camel-main metadata the catalog uses — it must not be reported as an error for
+        // runtime=spring-boot.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate(
+                        "camel.metrics.uriTagEnabled=true", "spring-boot", null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+        assertThat(result.summary().errors()).isZero();
     }

Review Comment:
   ⚠️ **Weak test — passes before the fix for the wrong reason.**
   
   `camel.metrics.uriTagEnabled` with `runtime=spring-boot` would produce `checked=false` even _before_ this PR: the old hardcoded prefix list did not include `camel.metrics.*`, so `acceptConfigurationPropertyKey` returned `false` directly — the `isSpringBoot` downgrade path was never reached.
   
   The test asserts `checked=false` but cannot distinguish between:
   1. ❌ `accepted=false` (old behaviour — `camel.metrics` not in hardcoded list)
   2. ✅ `accepted=true`, spring-boot downgrade fires (new behaviour — group matched dynamically, then unknown-option errors downgraded to unchecked)
   
   Add a counterpart assertion that the same key with no runtime flag is `checked=true` (this would fail on the old code since `camel.metrics.*` was never accepted there):
   
   ```suggestion
           assertThat(info.checked()).isFalse();
           assertThat(info.valid()).isFalse();
           assertThat(result.summary().unchecked()).isEqualTo(1);
           assertThat(result.summary().errors()).isZero();
   
           // Counterpart: without the spring-boot flag, camel.metrics.uriTagEnabled IS checked
           // (camel.metrics is a known main-model group) but flagged as unknown option.
           // This assertion FAILS on the old code (camel.metrics not in hardcoded prefix list)
           // and confirms the dynamic group-matching path is exercised, not just the old fallback.
           ConfigurationValidateTools.ConfigurationValidateResult nonSbResult
                   = tools.camel_configuration_validate(
                           "camel.metrics.uriTagEnabled=true", null, null, null);
           ConfigurationValidateTools.PropertyValidationInfo nonSbInfo = nonSbResult.properties().get(0);
           assertThat(nonSbInfo.checked()).isTrue();  // camel.metrics group is known
           assertThat(nonSbInfo.valid()).isFalse();   // but uriTagEnabled is not in main metadata
       }
   ```



-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateTools.java:
##########
@@ -106,8 +106,12 @@ public ConfigurationValidateResult camel_configuration_validate(
 
     private PropertyValidationInfo toPropertyValidationInfo(
             int lineNumber, String text, ConfigurationPropertiesValidationResult result) {
-        boolean valid = result.isSuccess();
         boolean accepted = result.isAccepted();
+        // A key that is not accepted by the catalog is by definition not valid: the catalog
+        // returned no errors (because it returned early without checking anything), but the
+        // property is outside the set of known camel.* groups, so reporting valid=true would
+        // be misleading to the caller.
+        boolean valid = accepted && result.isSuccess();

Review Comment:
   This makes `server.port=8080`, `quarkus.http.port`, `camel.beans.*` and `camel.jbang.*` read as rejected. CAMEL-25538 item 4 asks for these to read as "not checked": keep `valid = result.isSuccess()` for checked lines, report a `checked` flag (or rename `accepted`), leave unchecked lines out of `summary.valid`, add `summary.unchecked`, and describe it in the `@Tool` description.



##########
core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java:
##########
@@ -1408,20 +1414,46 @@ private static boolean isValidSuffix(String suffix) {
         return suffix == null || suffix.isEmpty() || suffix.equals(".");
     }
 
-    private static boolean acceptConfigurationPropertyKey(String key) {
+    private boolean acceptConfigurationPropertyKey(String key) {
         if (key == null) {
             return false;
         }
-        return key.startsWith("camel.component.")
+        // Always-accepted static prefixes (component/dataformat/language have their own models)
+        if (key.startsWith("camel.component.")
                 || key.startsWith("camel.dataformat.")
-                || key.startsWith("camel.language.")
-                || key.startsWith("camel.main.")
-                || key.startsWith("camel.resilience4j.")
-                || key.startsWith("camel.faulttolerance.")
-                || key.startsWith("camel.threadpool.")
-                || key.startsWith("camel.health.")
-                || key.startsWith("camel.lra.")
-                || key.startsWith("camel.rest.");
+                || key.startsWith("camel.language.")) {
+            return true;
+        }
+        // Dynamic: accept any prefix that matches a group in the main-model metadata
+        MainModel model = mainModel();
+        if (model != null) {
+            for (MainModel.MainGroupModel group : model.getGroups()) {
+                String groupPrefix = group.getName() + ".";
+                if (key.startsWith(groupPrefix)) {

Review Comment:
   Case- and dash-sensitive. camel-main binds `camel.error-registry.*`, `camel.ai-observability.*` and `camel.telemetry-dev.*` (`MainHelper.optionKey` and `startsWithIgnoreCase`), but these keys are not accepted here. Comparing normalised forms would match the runtime, for example `key.replace("-", "").toLowerCase(Locale.ENGLISH).startsWith(group.getName().replace("-", "").toLowerCase(Locale.ENGLISH) + ".")`, and the same in `matchMainModelGroup`.



##########
dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateToolsTest.java:
##########
@@ -180,6 +180,83 @@ void nonCamelKeyMarkedNotAccepted() {
 
         ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
         assertThat(info.accepted()).isFalse();
+        // accepted=false must imply valid=false (regression guard for CAMEL-25538 bug #2)
+        assertThat(info.valid()).isFalse();
+    }
+
+    // --- CAMEL-25538 regression tests ---
+
+    @Test
+    void camelServerPortIsAcceptedAndValid() {
+        // camel.server.* was previously not in the hardcoded prefix list — it must now be
+        // accepted and validated against the main-model metadata.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.port=9999", null, null, null);
+
+        assertThat(result.summary().total()).isEqualTo(1);
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.accepted()).isTrue();
+        assertThat(info.valid()).isTrue();
+        assertThat(info.errors()).isZero();
+        assertThat(info.issues()).isEmpty();
+    }
+
+    @Test
+    void camelServerInventedKeyIsAcceptedButNotValid() {
+        // An invented key under an accepted camel.server.* group must be reported as unknown,
+        // not silently passed as valid.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.bindPort=9999", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.accepted()).isTrue();
+        assertThat(info.valid()).isFalse();
+        assertThat(info.issues()).anyMatch(i -> "unknown".equals(i.kind()));
+    }
+
+    @Test
+    void acceptedFalseImpliesValidFalseForNonCamelKey() {
+        // Invented key outside any known camel.* group: accepted=false AND valid=false.
+        // Before the fix, valid was true despite accepted=false (CAMEL-25538 bug #2).
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.invented.completely.unknown=foo", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.accepted()).isFalse();
+        assertThat(info.valid()).isFalse();
+        // The summary must not count unaccepted keys as valid
+        assertThat(result.summary().valid()).isZero();
+    }
+
+    @Test
+    void camelManagementKeyIsAccepted() {
+        // camel.management.* was also missing from the old hardcoded list.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.management.enabled=true", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.accepted()).isTrue();
+        assertThat(info.valid()).isTrue();
+    }
+
+    @Test
+    void camelVaultAwsKeyIsAccepted() {
+        // camel.vault.aws.* is a nested group (3-segment name) — must also be accepted.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.vault.aws.accessKey=AKIA1234", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.accepted()).isTrue();

Review Comment:
   Please also assert `valid`, and cover an invented option under a nested group, which is where the new dot-offset logic matters:
   
   ```suggestion
           assertThat(info.accepted()).isTrue();
           assertThat(info.valid()).isTrue();
   ```



##########
core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java:
##########
@@ -1408,20 +1414,46 @@ private static boolean isValidSuffix(String suffix) {
         return suffix == null || suffix.isEmpty() || suffix.equals(".");
     }
 
-    private static boolean acceptConfigurationPropertyKey(String key) {
+    private boolean acceptConfigurationPropertyKey(String key) {
         if (key == null) {
             return false;
         }
-        return key.startsWith("camel.component.")
+        // Always-accepted static prefixes (component/dataformat/language have their own models)
+        if (key.startsWith("camel.component.")
                 || key.startsWith("camel.dataformat.")
-                || key.startsWith("camel.language.")
-                || key.startsWith("camel.main.")
-                || key.startsWith("camel.resilience4j.")
-                || key.startsWith("camel.faulttolerance.")
-                || key.startsWith("camel.threadpool.")
-                || key.startsWith("camel.health.")
-                || key.startsWith("camel.lra.")
-                || key.startsWith("camel.rest.");
+                || key.startsWith("camel.language.")) {
+            return true;
+        }
+        // Dynamic: accept any prefix that matches a group in the main-model metadata
+        MainModel model = mainModel();

Review Comment:
   On a catalog without cache (`ValidateMojo` uses `new DefaultCamelCatalog()`) this parses the 229 KB main metadata for every line, including keys outside Camel, and again in `matchMainModelGroup` and the main branch. Returning early with `if (!key.startsWith("camel.")) return false;` and loading the model once in `validateConfigurationProperty` avoids that. The "camel-main not detected" incapable branch can then no longer be reached, as a matched group implies a model.



-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


##########
dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateToolsTest.java:
##########
@@ -172,14 +172,157 @@ void multipleLinesAggregated() {
     }
 
     @Test
-    void nonCamelKeyMarkedNotAccepted() {
+    void nonCamelKeyMarkedNotChecked() {
+        // Non-Camel keys (e.g. server.port) are not checked by this catalog: checked=false,
+        // valid=false, and counted in summary.unchecked (not in summary.errors or summary.valid).
         ConfigurationValidateTools tools = createTools();
 
         ConfigurationValidateTools.ConfigurationValidateResult result
                 = tools.camel_configuration_validate("server.port=8080", null, null, null);
 
         ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
-        assertThat(info.accepted()).isFalse();
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+        assertThat(result.summary().errors()).isZero();
+        assertThat(result.summary().valid()).isZero();
+    }
+
+    // --- CAMEL-25538 regression tests ---
+
+    @Test
+    void camelServerPortIsAcceptedAndValid() {
+        // camel.server.* was previously not in the hardcoded prefix list — it must now be
+        // accepted and validated against the main-model metadata.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.port=9999", null, null, null);
+
+        assertThat(result.summary().total()).isEqualTo(1);
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+        assertThat(info.errors()).isZero();
+        assertThat(info.issues()).isEmpty();
+    }
+
+    @Test
+    void camelServerInventedKeyIsCheckedButNotValid() {
+        // An invented key under an accepted camel.server.* group must be reported as unknown,
+        // not silently passed as valid.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.server.bindPort=9999", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isFalse();
+        assertThat(info.issues()).anyMatch(i -> "unknown".equals(i.kind()));
+    }
+
+    @Test
+    void uncheckedKeyImpliesValidFalseAndNotCountedInErrors() {
+        // Invented key outside any known camel.* group: checked=false AND valid=false.
+        // Before the fix, valid was true despite accepted=false (CAMEL-25538 bug #2).
+        // The key must not appear in summary.errors — it is unchecked, not rejected.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.invented.completely.unknown=foo", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        // The summary must not count unchecked keys as valid or as errors
+        assertThat(result.summary().valid()).isZero();
+        assertThat(result.summary().errors()).isZero();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+    }
+
+    @Test
+    void camelManagementKeyIsCheckedAndValid() {
+        // camel.management.* was also missing from the old hardcoded list.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.management.enabled=true", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+    }
+
+    @Test
+    void camelVaultAwsKeyIsCheckedAndValid() {
+        // camel.vault.aws.* is a nested group (3-segment name) — must also be accepted.
+        // The dot-offset logic that skips the group prefix is exercised here.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.vault.aws.accessKey=AKIA1234", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+        assertThat(info.issues()).isEmpty();
+    }
+
+    @Test
+    void camelVaultAwsInventedKeyIsCheckedButNotValid() {
+        // An invented option under a nested group (camel.vault.aws.*) exercises the dot-offset
+        // logic: the option name starts after the 3rd dot and must be checked against the model.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.vault.aws.inventedOption=foo", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isFalse();
+    }
+
+    @Test
+    void dashedGroupNameIsCheckedAndValid() {
+        // camel-main binds camel.error-registry.* to the camel.errorRegistry group
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate("camel.error-registry.enabled=true", null, null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isTrue();
+        assertThat(info.valid()).isTrue();
+    }
+
+    @Test
+    void springBootStarterOnlyOptionIsUnchecked() {
+        // camel.metrics.uriTagEnabled exists in camel-micrometer-starter but not in the
+        // camel-main metadata the catalog uses — it must not be reported as an error for
+        // runtime=spring-boot.
+        ConfigurationValidateTools tools = createTools();
+
+        ConfigurationValidateTools.ConfigurationValidateResult result
+                = tools.camel_configuration_validate(
+                        "camel.metrics.uriTagEnabled=true", "spring-boot", null, null);
+
+        ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
+        assertThat(info.checked()).isFalse();
+        assertThat(info.valid()).isFalse();
+        assertThat(result.summary().unchecked()).isEqualTo(1);
+        assertThat(result.summary().errors()).isZero();

Review Comment:
   The narrowing in 006252680b / be91daafd2 has no test, so a later change could bring back the broad downgrade without any test failing. It would help to assert here that the downgraded line keeps its issues:
   ```suggestion
           assertThat(result.summary().errors()).isZero();
           assertThat(info.issues()).anyMatch(i -> "unknown".equals(i.kind()));
   ```
   and to add a test where an original group stays fully checked under Spring Boot, including the dashed form:
   ```java
   @Test
   void springBootKeepsValidationForOriginalGroups() {
       ConfigurationValidateTools tools = createTools();
   
       ConfigurationValidateTools.ConfigurationValidateResult result = tools.camel_configuration_validate(
               "camel.component.kafka.brokerz=x\ncamel.fault-tolerance.timeoutEnabledz=true", "spring-boot", null, null);
   
       assertThat(result.properties()).allSatisfy(info -> {
           assertThat(info.checked()).isTrue();
           assertThat(info.valid()).isFalse();
           assertThat(info.issues()).anyMatch(i -> "unknown".equals(i.kind()));
       });
       assertThat(result.summary().unchecked()).isZero();
   }
   ```



##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateTools.java:
##########
@@ -105,16 +130,66 @@ public ConfigurationValidateResult camel_configuration_validate(
     }
 
     private PropertyValidationInfo toPropertyValidationInfo(
-            int lineNumber, String text, ConfigurationPropertiesValidationResult result) {
-        boolean valid = result.isSuccess();
-        boolean accepted = result.isAccepted();
-        int errors = result.getNumberOfErrors();
-        int warnings = result.getNumberOfWarnings();
+            int lineNumber, String text, ConfigurationPropertiesValidationResult result, boolean isSpringBoot) {
+        boolean checked = result.isAccepted();
+        // A checked line is valid when the catalog found no errors; an unchecked line
+        // (not recognised as a Camel property) is neither valid nor invalid — it is simply
+        // not inspected by this catalog.
+        boolean valid = checked && result.isSuccess();
+
+        // For Spring Boot, the catalog uses camel-main metadata which does not include
+        // starter-specific options (e.g. camel.metrics.uriTagEnabled from camel-micrometer-starter).
+        // When the only issues are "unknown option" errors AND the key belongs to a group that is
+        // newly accepted by this fix (not one of the original 10 hardcoded prefixes), downgrade to
+        // unchecked to avoid false positives — the starter may legitimately bind options outside the
+        // main schema. Keys under the original 10 groups (component, dataformat, language, main,
+        // resilience4j, faulttolerance, threadpool, health, lra, rest) retain full validation since
+        // the catalog has always covered them.
+        boolean springBootDowngraded = false;
+        if (isSpringBoot && checked && !valid) {
+            String propertyKey = text != null && text.contains("=") ? text.substring(0, text.indexOf('=')).trim() : text;
+            // Normalize to dash-free lowercase so that Spring Boot relaxed-binding forms
+            // (e.g. camel.fault-tolerance.*, camel.thread-pool.*) match the original group
+            // prefixes the same way the catalog normalises them internally.
+            String normKey = propertyKey != null ? propertyKey.replace("-", "").toLowerCase(java.util.Locale.ENGLISH) : null;

Review Comment:
   Nit: please import `java.util.Locale` instead of writing it fully qualified (CLAUDE.md: no FQCNs outside generated code):
   ```suggestion
               String normKey = propertyKey != null ? propertyKey.replace("-", "").toLowerCase(Locale.ENGLISH) : null;
   ```
   (plus `import java.util.Locale;`)



##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -13,6 +13,37 @@ See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
 
 == Upgrading Camel 4.23 to 4.24
 
+=== camel-report-maven-plugin:validate / configuration-validate
+
+The catalog now accepts all `camel.*` groups defined in `camel-main-configuration-metadata.json`
+(previously only 10 groups out of 36 were recognized). As a result,
+`camel-report-maven-plugin:validate` and the camel-jbang MCP `camel_configuration_validate` tool
+now validate approximately 29 additional `camel.*` groups (including `camel.server.*`,
+`camel.management.*`, `camel.vault.*`, `camel.ssl.*`, and others).
+
+If your project uses Spring Boot and has options such as `camel.metrics.uriTagEnabled` (from a
+Camel starter) that are not in the camel-main schema, `camel-report-maven-plugin:validate` may
+report them as "Unknown option". See below for details.

Review Comment:
   Nothing below follows up on "See below for details": the next paragraphs are about dash matching, `failOnError` and the MCP response format. Maybe end with the consequence instead: "...may report them as "Unknown option", which fails the build when `failOnError=true`. The `camel_configuration_validate` MCP tool with `runtime=spring-boot` reports such keys as `checked=false` instead."



##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -13,6 +13,37 @@ See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
 
 == Upgrading Camel 4.23 to 4.24
 
+=== camel-report-maven-plugin:validate / configuration-validate
+
+The catalog now accepts all `camel.*` groups defined in `camel-main-configuration-metadata.json`
+(previously only 10 groups out of 36 were recognized). As a result,

Review Comment:
   Small inaccuracy: before, 7 of the 36 groups were recognised. The other 3 old prefixes (`camel.component.`, `camel.dataformat.`, `camel.language.`) are not main groups. Maybe: "(previously only 7 of the 36 groups were recognized, besides `camel.component.*`, `camel.dataformat.*` and `camel.language.*`)". Line 21 could then say "29 additional" without "approximately".



-- 
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-25538: fix configuration-validate to accept all camel.* groups and report accepted=false as valid=false [camel]

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


##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ConfigurationValidateTools.java:
##########
@@ -105,16 +130,41 @@ public ConfigurationValidateResult camel_configuration_validate(
     }
 
     private PropertyValidationInfo toPropertyValidationInfo(
-            int lineNumber, String text, ConfigurationPropertiesValidationResult result) {
-        boolean valid = result.isSuccess();
-        boolean accepted = result.isAccepted();
-        int errors = result.getNumberOfErrors();
-        int warnings = result.getNumberOfWarnings();
+            int lineNumber, String text, ConfigurationPropertiesValidationResult result, boolean isSpringBoot) {
+        boolean checked = result.isAccepted();
+        // A checked line is valid when the catalog found no errors; an unchecked line
+        // (not recognised as a Camel property) is neither valid nor invalid — it is simply
+        // not inspected by this catalog.
+        boolean valid = checked && result.isSuccess();
+
+        // For Spring Boot, the catalog uses camel-main metadata which does not include
+        // starter-specific options (e.g. camel.metrics.uriTagEnabled from camel-micrometer-starter).
+        // When the only issues are "unknown option" errors, downgrade to unchecked to avoid
+        // false positives — the starter may legitimately bind options outside the main schema.
+        if (isSpringBoot && checked && !valid) {
+            Set<String> unknownKeys = result.getUnknown() != null ? result.getUnknown() : Collections.emptySet();
+            boolean onlyUnknownOptionErrors = !unknownKeys.isEmpty()
+                    && result.getNumberOfErrors() == unknownKeys.size()
+                    && result.getSyntaxError() == null
+                    && result.getIncapable() == null
+                    && result.getInvalidBoolean() == null
+                    && result.getInvalidEnum() == null
+                    && result.getInvalidInteger() == null
+                    && result.getInvalidNumber() == null
+                    && result.getInvalidDuration() == null;
+            if (onlyUnknownOptionErrors) {
+                checked = false;
+                valid = false;
+            }

Review Comment:
   💡 **Missing test for Spring Boot downgrade path.** The `isSpringBoot && onlyUnknownOptionErrors` branch added in this commit has no test in `ConfigurationValidateToolsTest`. A starter-only option (e.g. `camel.metrics.uriTagEnabled`) validated with `runtime="spring-boot"` should come back as `checked=false, valid=false` — and this isn't exercised anywhere.
   
   Minimal test to add:
   
   ```java
   @Test
   void springBootStarterOnlyOptionIsUnchecked() {
       // camel.metrics.uriTagEnabled exists in camel-micrometer-starter but not in the
       // camel-main metadata the catalog uses — it must not be reported as an error for
       // runtime=spring-boot.
       ConfigurationValidateTools tools = createTools();
   
       ConfigurationValidateTools.ConfigurationValidateResult result
               = tools.camel_configuration_validate(
                       "camel.metrics.uriTagEnabled=true", "spring-boot", null, null);
   
       ConfigurationValidateTools.PropertyValidationInfo info = result.properties().get(0);
       assertThat(info.checked()).isFalse();
       assertThat(info.valid()).isFalse();
       assertThat(result.summary().unchecked()).isEqualTo(1);
       assertThat(result.summary().errors()).isZero();
   }
   ```



-- 
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