This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/main by this push:
new 64521b045d Restrict Dev UI JSON-RPC bridge to declared console IDs,
allowed options and values
64521b045d is described below
commit 64521b045d5bfd42e910c8e53fabd9a9a55420e7
Author: James Netherton <[email protected]>
AuthorDate: Fri Jul 24 14:16:51 2026 +0100
Restrict Dev UI JSON-RPC bridge to declared console IDs, allowed options
and values
Co-authored-by: Claude Opus 4.6 <[email protected]>
---
.../contributor-guide/create-new-dev-ui-page.adoc | 34 ++++++++-
.../devui/CamelCoreDevConsoleProcessor.java | 80 +++++++++++++++++---
.../core/deployment/devui/CamelDevUIConstants.java | 46 ++++++++++++
.../devui/CamelQuarkusCoreDevUITest.java | 27 +++++++
.../quarkus/devui/CamelCoreDevUIRecorder.java | 33 +++++++++
.../camel/quarkus/devui/CamelCoreDevUIService.java | 85 +++++++++++++++++++++-
.../devui/JasyptUtilsDevUIProcessor.java | 4 +-
.../deployment/devui/MicrometerDevUIProcessor.java | 4 +-
.../MicroprofileFaultToleranceDevUIProcessor.java | 4 +-
.../devui/VertxWebsocketDevUIProcessor.java | 4 +-
10 files changed, 304 insertions(+), 17 deletions(-)
diff --git
a/docs/modules/ROOT/pages/contributor-guide/create-new-dev-ui-page.adoc
b/docs/modules/ROOT/pages/contributor-guide/create-new-dev-ui-page.adoc
index 0b5cdd58e9..b3315011a0 100644
--- a/docs/modules/ROOT/pages/contributor-guide/create-new-dev-ui-page.adoc
+++ b/docs/modules/ROOT/pages/contributor-guide/create-new-dev-ui-page.adoc
@@ -65,7 +65,39 @@ customElements.define('qwc-camel-foo', QwcCamelFoo);
<4> When iterating over the console data you can access the returned JSON
fields by referring to their name. E.g. if the console returns JSON `[{"dataA":
"valueA", "dataB": "valueB"}]` you can refer to the data like `item.dataA` etc.
<5> You must register the component at the end of the file.
+
-3. Finally, you must create a `BuildStep` to add a UI link to the extension
Dev UI card as described in the
https://quarkus.io/guides/dev-ui#adding-pages-to-the-dev-ui[guide].
+3. In the `BuildStep` that registers the Dev UI card page, you must set the
`consoleId` metadata on each page that uses a Camel console. This is required
for security — only console IDs declared via metadata are accessible through
the Dev UI JSON-RPC bridge.
++
+[source,java]
+----
+import org.apache.camel.quarkus.core.deployment.devui.CamelDevUIConstants;
+
+cardPageBuildItem.addPage(Page.webComponentPageBuilder()
+ .title("Foo")
+ .icon("font-awesome-solid:bars")
+ .componentLink("qwc-camel-foo.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY, "foo"));
+----
++
+If a page with a `qwc-camel` component link does not declare this metadata,
the build will fail.
+Pages that do not use the JSON-RPC console bridge (e.g. pages extending
`LitElement` directly) should set the value to
`CamelDevUIConstants.CONSOLE_ID_NONE`.
++
+If your page passes options to the Camel console (via the second argument to
`super()` or via `super.putOption()`), you must also declare the allowed option
keys and their permitted values:
++
+[source,java]
+----
+// Only the 'limit' option is allowed, with any value
+.metadata(CamelDevUIConstants.ALLOWED_OPTIONS_METADATA_KEY, "limit=*")
+
+// Only the 'dump' option is allowed, and only with value 'false'
+.metadata(CamelDevUIConstants.ALLOWED_OPTIONS_METADATA_KEY, "dump=false")
+
+// Multiple options: semicolon-separated. Multiple allowed values:
pipe-separated
+.metadata(CamelDevUIConstants.ALLOWED_OPTIONS_METADATA_KEY,
"key1=val1|val2;key2=*")
+----
++
+Options not declared in this metadata are silently stripped at runtime. Pages
that do not use options need not declare this metadata — the secure default is
to allow no options.
++
+4. Finally, the Dev UI card must be registered as described in the
https://quarkus.io/guides/dev-ui#adding-pages-to-the-dev-ui[guide].
=== Finding the Camel console ID
diff --git
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/devui/CamelCoreDevConsoleProcessor.java
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/devui/CamelCoreDevConsoleProcessor.java
index dabc356296..c3fdcf7b87 100644
---
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/devui/CamelCoreDevConsoleProcessor.java
+++
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/devui/CamelCoreDevConsoleProcessor.java
@@ -16,13 +16,22 @@
*/
package org.apache.camel.quarkus.core.deployment.devui;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
import io.quarkus.deployment.IsDevelopment;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
import io.quarkus.devui.spi.JsonRPCProvidersBuildItem;
import io.quarkus.devui.spi.page.CardPageBuildItem;
import io.quarkus.devui.spi.page.Page;
+import org.apache.camel.quarkus.devui.CamelCoreDevUIRecorder;
import org.apache.camel.quarkus.devui.CamelCoreDevUIService;
@BuildSteps(onlyIf = IsDevelopment.class)
@@ -35,47 +44,58 @@ public class CamelCoreDevConsoleProcessor {
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Blocked Exchanges")
.icon("font-awesome-solid:circle-xmark")
- .componentLink("qwc-camel-core-blocked-exchanges.js"));
+ .componentLink("qwc-camel-core-blocked-exchanges.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"blocked"));
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Browse")
.icon("font-awesome-solid:magnifying-glass")
- .componentLink("qwc-camel-core-browse.js"));
+ .componentLink("qwc-camel-core-browse.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"browse")
+ .metadata(CamelDevUIConstants.ALLOWED_OPTIONS_METADATA_KEY,
"dump=false"));
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Camel Context")
.icon("font-awesome-solid:gear")
- .componentLink("qwc-camel-core-context.js"));
+ .componentLink("qwc-camel-core-context.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"context"));
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Diagram")
.icon("font-awesome-solid:sitemap")
- .componentLink("qwc-camel-core-diagram.js"));
+ .componentLink("qwc-camel-core-diagram.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
CamelDevUIConstants.CONSOLE_ID_NONE));
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Events")
.icon("font-awesome-solid:bolt-lightning")
- .componentLink("qwc-camel-core-events.js"));
+ .componentLink("qwc-camel-core-events.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"event"));
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Inflight Exchanges")
.icon("font-awesome-solid:plane")
- .componentLink("qwc-camel-core-inflight-exchanges.js"));
+ .componentLink("qwc-camel-core-inflight-exchanges.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"inflight"));
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("REST")
.icon("font-awesome-solid:circle-nodes")
- .componentLink("qwc-camel-core-rest.js"));
+ .componentLink("qwc-camel-core-rest.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"rest"));
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Routes")
.icon("font-awesome-solid:route")
- .componentLink("qwc-camel-core-routes.js"));
+ .componentLink("qwc-camel-core-routes.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY, "route")
+ .metadata(CamelDevUIConstants.ALLOWED_OPTIONS_METADATA_KEY,
"limit=*"));
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Variables")
.icon("font-awesome-solid:code")
- .componentLink("qwc-camel-core-variables.js"));
+ .componentLink("qwc-camel-core-variables.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"variables"));
cardsProducer.produce(cardPageBuildItem);
}
@@ -84,4 +104,46 @@ public class CamelCoreDevConsoleProcessor {
JsonRPCProvidersBuildItem createJsonRPCServiceForCache() {
return new JsonRPCProvidersBuildItem(CamelCoreDevUIService.class);
}
+
+ @BuildStep
+ @Record(ExecutionTime.STATIC_INIT)
+ void recordAllowedConsoleMetadata(
+ CamelCoreDevUIRecorder recorder,
+ List<CardPageBuildItem> cardPages) {
+ Set<String> allowedIds = new HashSet<>();
+ Map<String, String> allowedOptions = new HashMap<>();
+
+ cardPages.stream()
+ .flatMap(card -> card.getPages().stream())
+ .forEach(pageBuilder -> {
+ Page page = pageBuilder.build();
+ String componentLink = page.getComponentLink();
+ boolean isCamelPage = componentLink != null &&
componentLink.startsWith("qwc-camel");
+ if (!isCamelPage) {
+ return;
+ }
+
+ Map<String, String> metadata = page.getMetadata();
+ boolean hasConsoleId = metadata != null
+ &&
metadata.containsKey(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY);
+ if (!hasConsoleId) {
+ throw new IllegalStateException(
+ "Camel Dev UI page '" + componentLink
+ + "' is missing required metadata key
'" + CamelDevUIConstants.CONSOLE_ID_METADATA_KEY
+ + "'. Set it to the Camel dev console
id, or to CamelDevUIConstants.CONSOLE_ID_NONE"
+ + " if the page does not use the
JSON-RPC console bridge.");
+ }
+
+ String consoleId =
metadata.get(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY);
+ if
(!CamelDevUIConstants.CONSOLE_ID_NONE.equals(consoleId)) {
+ allowedIds.add(consoleId);
+ if
(metadata.containsKey(CamelDevUIConstants.ALLOWED_OPTIONS_METADATA_KEY)) {
+ allowedOptions.put(consoleId,
metadata.get(CamelDevUIConstants.ALLOWED_OPTIONS_METADATA_KEY));
+ }
+ }
+ });
+
+ recorder.setAllowedConsoleIds(allowedIds);
+ recorder.setAllowedConsoleOptions(allowedOptions);
+ }
}
diff --git
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/devui/CamelDevUIConstants.java
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/devui/CamelDevUIConstants.java
new file mode 100644
index 0000000000..0500b6c6fa
--- /dev/null
+++
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/devui/CamelDevUIConstants.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.core.deployment.devui;
+
+/**
+ * Constants for Camel Dev UI page metadata.
+ */
+public final class CamelDevUIConstants {
+
+ /**
+ * Page metadata key for the Camel dev console id. Every {@code
qwc-camel*} page must set this
+ * metadata so that the console id is included in the runtime allowlist
for the JSON-RPC bridge.
+ */
+ public static final String CONSOLE_ID_METADATA_KEY = "consoleId";
+
+ /**
+ * Sentinel value for {@link #CONSOLE_ID_METADATA_KEY} indicating the page
does not use the
+ * JSON-RPC console bridge (e.g. pages extending {@code LitElement}
directly).
+ */
+ public static final String CONSOLE_ID_NONE = "none";
+
+ /**
+ * Page metadata key for allowed console options. The value is a
semicolon-delimited
+ * specification of allowed option keys and their permitted values.
+ * Format: {@code key1=val1|val2;key2=*} where {@code *} means any value
is accepted.
+ * Pages that do not declare this metadata allow no options (secure
default).
+ */
+ public static final String ALLOWED_OPTIONS_METADATA_KEY = "allowedOptions";
+
+ private CamelDevUIConstants() {
+ }
+}
diff --git
a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/devui/CamelQuarkusCoreDevUITest.java
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/devui/CamelQuarkusCoreDevUITest.java
index 63708016f4..6802a498f7 100644
---
a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/devui/CamelQuarkusCoreDevUITest.java
+++
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/devui/CamelQuarkusCoreDevUITest.java
@@ -43,4 +43,31 @@ public class CamelQuarkusCoreDevUITest extends
DevUIJsonRPCTest {
assertEquals("camel-1", json.getString("name"));
assertEquals("Started", json.getString("state"));
}
+
+ @Test
+ void getNonAllowedConsoleReturnsEmptyJSON() throws Exception {
+ // 'send' console is registered from camel-console, but is not in the
allowlist, so expect an empty JSON response
+ String result = super.executeJsonRPCMethod(String.class,
"getConsoleJSON",
+ Map.of("id", "send", "options", Map.of()));
+ assertEquals("{}", result);
+ }
+
+ @Test
+ void browseConsoleStripsDisallowedDumpTrue() throws Exception {
+ String withBadOption = super.executeJsonRPCMethod(String.class,
"getConsoleJSON",
+ Map.of("id", "browse", "options", Map.of("dump", "true")));
+ String withGoodOption = super.executeJsonRPCMethod(String.class,
"getConsoleJSON",
+ Map.of("id", "browse", "options", Map.of("dump", "false")));
+ assertEquals(withGoodOption, withBadOption);
+ }
+
+ @Test
+ void contextConsoleStripsAllOptions() throws Exception {
+ // context has no allowed options, so malicious keys should be
stripped and the console should still respond
+ String result = super.executeJsonRPCMethod(String.class,
"getConsoleJSON",
+ Map.of("id", "context", "options", Map.of("malicious",
"payload")));
+ JsonObject json = (JsonObject) Json.decodeValue(result);
+ assertEquals("camel-1", json.getString("name"));
+ assertEquals("Started", json.getString("state"));
+ }
}
diff --git
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/devui/CamelCoreDevUIRecorder.java
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/devui/CamelCoreDevUIRecorder.java
new file mode 100644
index 0000000000..6af0b5348c
--- /dev/null
+++
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/devui/CamelCoreDevUIRecorder.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.devui;
+
+import java.util.Map;
+import java.util.Set;
+
+import io.quarkus.runtime.annotations.Recorder;
+
+@Recorder
+public class CamelCoreDevUIRecorder {
+ public void setAllowedConsoleIds(Set<String> consoleIds) {
+ CamelCoreDevUIService.setAllowedConsoleIds(consoleIds);
+ }
+
+ public void setAllowedConsoleOptions(Map<String, String> optionSpecs) {
+ CamelCoreDevUIService.setAllowedConsoleOptions(optionSpecs);
+ }
+}
diff --git
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/devui/CamelCoreDevUIService.java
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/devui/CamelCoreDevUIService.java
index 04b2ae053f..b6045aeaed 100644
---
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/devui/CamelCoreDevUIService.java
+++
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/devui/CamelCoreDevUIService.java
@@ -17,8 +17,11 @@
package org.apache.camel.quarkus.devui;
import java.time.Duration;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import io.quarkus.arc.Arc;
@@ -40,8 +43,38 @@ import org.jboss.logging.Logger;
@ApplicationScoped
public class CamelCoreDevUIService {
private static final Logger LOG =
Logger.getLogger(CamelCoreDevUIService.class);
+ private static volatile Set<String> ALLOWED_CONSOLE_IDS =
Collections.emptySet();
+ private static volatile Map<String, Map<String, Set<String>>>
ALLOWED_CONSOLE_OPTIONS = Collections.emptyMap();
private final Map<String, ConsoleSubscription> PROCESSORS = new
ConcurrentHashMap<>();
+ static void setAllowedConsoleIds(Set<String> consoleIds) {
+ ALLOWED_CONSOLE_IDS = Set.copyOf(consoleIds);
+ }
+
+ static void setAllowedConsoleOptions(Map<String, String> optionSpecs) {
+ Map<String, Map<String, Set<String>>> parsed = new HashMap<>();
+ for (Map.Entry<String, String> entry : optionSpecs.entrySet()) {
+ String spec = entry.getValue();
+ Map<String, Set<String>> optionRules = new HashMap<>();
+ if (spec != null && !spec.isEmpty()) {
+ for (String optionEntry : spec.split(";")) {
+ String[] parts = optionEntry.split("=", 2);
+ if (parts.length == 2) {
+ String optionKey = parts[0].trim();
+ String valuesStr = parts[1].trim();
+ if ("*".equals(valuesStr)) {
+ optionRules.put(optionKey, Set.of("*"));
+ } else {
+ optionRules.put(optionKey,
Set.of(valuesStr.split("\\|")));
+ }
+ }
+ }
+ }
+ parsed.put(entry.getKey(),
Collections.unmodifiableMap(optionRules));
+ }
+ ALLOWED_CONSOLE_OPTIONS = Collections.unmodifiableMap(parsed);
+ }
+
/**
* Deactivates a Dev UI subscription for the given Camel console id.
*
@@ -67,7 +100,11 @@ public class CamelCoreDevUIService {
* @return JSON String representation of the Camel console
*/
public String getConsoleJSON(String id, Map<String, Object> options) {
- return getOrCreateConsoleSubscription(id, options).callDevConsole();
+ if (!isConsoleAllowed(id)) {
+ LOG.debugf("Rejected Dev UI request for console '%s' — not in the
allowlist", id);
+ return "{}";
+ }
+ return getOrCreateConsoleSubscription(id, sanitizeOptions(id,
options)).callDevConsole();
}
/**
@@ -78,7 +115,11 @@ public class CamelCoreDevUIService {
* @return {@link Multi} of JSON String representation of the
Camel console
*/
public Multi<String> streamConsole(String id, Map<String, Object> options)
{
- return getOrCreateConsoleSubscription(id, options).getBroadcaster();
+ if (!isConsoleAllowed(id)) {
+ LOG.debugf("Rejected Dev UI stream request for console '%s' — not
in the allowlist", id);
+ return Multi.createFrom().empty();
+ }
+ return getOrCreateConsoleSubscription(id, sanitizeOptions(id,
options)).getBroadcaster();
}
/**
@@ -89,12 +130,50 @@ public class CamelCoreDevUIService {
* @return {@code true} if the options were updated, else {@code
false}
*/
public boolean updateConsoleOptions(String id, Map<String, Object>
options) {
+ if (!isConsoleAllowed(id)) {
+ LOG.debugf("Rejected Dev UI options update for console '%s' — not
in the allowlist", id);
+ return false;
+ }
+ Map<String, Object> sanitized = sanitizeOptions(id, options);
return PROCESSORS.computeIfPresent(id, (key, consoleSubscription) -> {
- consoleSubscription.setOptions(options);
+ consoleSubscription.setOptions(sanitized);
return consoleSubscription;
}) != null;
}
+ private static boolean isConsoleAllowed(String id) {
+ return ALLOWED_CONSOLE_IDS.contains(id);
+ }
+
+ private static Map<String, Object> sanitizeOptions(String id, Map<String,
Object> options) {
+ if (options == null || options.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map<String, Set<String>> rules = ALLOWED_CONSOLE_OPTIONS.get(id);
+ if (rules == null || rules.isEmpty()) {
+ if (!options.isEmpty()) {
+ LOG.debugf("Stripped all options for console '%s' — no options
are allowed", id);
+ }
+ return Collections.emptyMap();
+ }
+ Map<String, Object> sanitized = new HashMap<>();
+ for (Map.Entry<String, Object> entry : options.entrySet()) {
+ String key = entry.getKey();
+ Set<String> allowedValues = rules.get(key);
+ if (allowedValues == null) {
+ LOG.debugf("Stripped disallowed option key '%s' for console
'%s'", key, id);
+ continue;
+ }
+ String stringValue = String.valueOf(entry.getValue());
+ if (allowedValues.contains("*") ||
allowedValues.contains(stringValue)) {
+ sanitized.put(key, entry.getValue());
+ } else {
+ LOG.debugf("Stripped option '%s' for console '%s' — value '%s'
is not allowed", key, id, stringValue);
+ }
+ }
+ return sanitized;
+ }
+
ConsoleSubscription getOrCreateConsoleSubscription(String id, Map<String,
Object> options) {
return PROCESSORS.computeIfAbsent(id, consoleId -> new
ConsoleSubscription(consoleId, options));
}
diff --git
a/extensions/jasypt/deployment/src/main/java/org/apache/camel/quarkus/component/jasypt/deployment/devui/JasyptUtilsDevUIProcessor.java
b/extensions/jasypt/deployment/src/main/java/org/apache/camel/quarkus/component/jasypt/deployment/devui/JasyptUtilsDevUIProcessor.java
index 96abf86c05..2e90d2f43e 100644
---
a/extensions/jasypt/deployment/src/main/java/org/apache/camel/quarkus/component/jasypt/deployment/devui/JasyptUtilsDevUIProcessor.java
+++
b/extensions/jasypt/deployment/src/main/java/org/apache/camel/quarkus/component/jasypt/deployment/devui/JasyptUtilsDevUIProcessor.java
@@ -26,6 +26,7 @@ import io.quarkus.devui.spi.page.CardPageBuildItem;
import io.quarkus.devui.spi.page.Page;
import org.apache.camel.quarkus.component.jasypt.CamelJasyptBuildTimeConfig;
import org.apache.camel.quarkus.component.jasypt.CamelJasyptDevUIService;
+import org.apache.camel.quarkus.core.deployment.devui.CamelDevUIConstants;
@BuildSteps(onlyIf = { IsDevelopment.class,
JasyptUtilsDevUIProcessor.CamelJasyptEnabled.class })
public class JasyptUtilsDevUIProcessor {
@@ -35,7 +36,8 @@ public class JasyptUtilsDevUIProcessor {
card.addPage(Page.webComponentPageBuilder()
.title("Utilities")
.componentLink("qwc-camel-jasypt-utils.js")
- .icon("font-awesome-solid:house-lock"));
+ .icon("font-awesome-solid:house-lock")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
CamelDevUIConstants.CONSOLE_ID_NONE));
return card;
}
diff --git
a/extensions/micrometer/deployment/src/main/java/org/apache/camel/quarkus/component/micrometer/deployment/devui/MicrometerDevUIProcessor.java
b/extensions/micrometer/deployment/src/main/java/org/apache/camel/quarkus/component/micrometer/deployment/devui/MicrometerDevUIProcessor.java
index 660d06d46d..accd79a417 100644
---
a/extensions/micrometer/deployment/src/main/java/org/apache/camel/quarkus/component/micrometer/deployment/devui/MicrometerDevUIProcessor.java
+++
b/extensions/micrometer/deployment/src/main/java/org/apache/camel/quarkus/component/micrometer/deployment/devui/MicrometerDevUIProcessor.java
@@ -22,6 +22,7 @@ import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.devui.spi.page.CardPageBuildItem;
import io.quarkus.devui.spi.page.Page;
+import org.apache.camel.quarkus.core.deployment.devui.CamelDevUIConstants;
@BuildSteps(onlyIf = IsDevelopment.class)
public class MicrometerDevUIProcessor {
@@ -32,7 +33,8 @@ public class MicrometerDevUIProcessor {
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Metrics")
.icon("font-awesome-solid:chart-line")
- .componentLink("qwc-camel-micrometer.js"));
+ .componentLink("qwc-camel-micrometer.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"micrometer"));
cardsProducer.produce(cardPageBuildItem);
}
diff --git
a/extensions/microprofile-fault-tolerance/deployment/src/main/java/org/apache/camel/quarkus/component/microprofile/fault/tolerance/deployment/devui/MicroprofileFaultToleranceDevUIProcessor.java
b/extensions/microprofile-fault-tolerance/deployment/src/main/java/org/apache/camel/quarkus/component/microprofile/fault/tolerance/deployment/devui/MicroprofileFaultToleranceDevUIProcessor.java
index ce36b79d72..a01b298d8e 100644
---
a/extensions/microprofile-fault-tolerance/deployment/src/main/java/org/apache/camel/quarkus/component/microprofile/fault/tolerance/deployment/devui/MicroprofileFaultToleranceDevUIProcessor.java
+++
b/extensions/microprofile-fault-tolerance/deployment/src/main/java/org/apache/camel/quarkus/component/microprofile/fault/tolerance/deployment/devui/MicroprofileFaultToleranceDevUIProcessor.java
@@ -22,6 +22,7 @@ import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.devui.spi.page.CardPageBuildItem;
import io.quarkus.devui.spi.page.Page;
+import org.apache.camel.quarkus.core.deployment.devui.CamelDevUIConstants;
@BuildSteps(onlyIf = IsDevelopment.class)
public class MicroprofileFaultToleranceDevUIProcessor {
@@ -32,7 +33,8 @@ public class MicroprofileFaultToleranceDevUIProcessor {
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Circuit Breakers")
.icon("font-awesome-solid:plug")
- .componentLink("qwc-camel-microprofile-fault-tolerance.js"));
+ .componentLink("qwc-camel-microprofile-fault-tolerance.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"fault-tolerance"));
cardsProducer.produce(cardPageBuildItem);
}
diff --git
a/extensions/vertx-websocket/deployment/src/main/java/org/apache/camel/quarkus/component/vertx/websocket/deployment/devui/VertxWebsocketDevUIProcessor.java
b/extensions/vertx-websocket/deployment/src/main/java/org/apache/camel/quarkus/component/vertx/websocket/deployment/devui/VertxWebsocketDevUIProcessor.java
index 2fd7eed4b9..1ecc9f167b 100644
---
a/extensions/vertx-websocket/deployment/src/main/java/org/apache/camel/quarkus/component/vertx/websocket/deployment/devui/VertxWebsocketDevUIProcessor.java
+++
b/extensions/vertx-websocket/deployment/src/main/java/org/apache/camel/quarkus/component/vertx/websocket/deployment/devui/VertxWebsocketDevUIProcessor.java
@@ -22,6 +22,7 @@ import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.devui.spi.page.CardPageBuildItem;
import io.quarkus.devui.spi.page.Page;
+import org.apache.camel.quarkus.core.deployment.devui.CamelDevUIConstants;
@BuildSteps(onlyIf = IsDevelopment.class)
public class VertxWebsocketDevUIProcessor {
@@ -32,7 +33,8 @@ public class VertxWebsocketDevUIProcessor {
cardPageBuildItem.addPage(Page.webComponentPageBuilder()
.title("Endpoints")
.icon("font-awesome-solid:plug")
- .componentLink("qwc-camel-vertx-websocket.js"));
+ .componentLink("qwc-camel-vertx-websocket.js")
+ .metadata(CamelDevUIConstants.CONSOLE_ID_METADATA_KEY,
"vertx-websocket"));
cardsProducer.produce(cardPageBuildItem);
}