oscerd commented on code in PR #25051:
URL: https://github.com/apache/camel/pull/25051#discussion_r3655532498


##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencySecurityAuditTools.java:
##########
@@ -0,0 +1,282 @@
+/*
+ * 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.dsl.jbang.core.commands.mcp;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+import io.quarkiverse.mcp.server.Tool;
+import io.quarkiverse.mcp.server.ToolArg;
+import io.quarkiverse.mcp.server.ToolCallException;
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.tooling.model.ComponentModel;
+import org.apache.camel.tooling.model.SecurityAdvisoryModel;
+
+/**
+ * MCP Tool for performing security vulnerability analysis on Camel project 
dependencies.
+ * <p>
+ * Distinct from {@link DependencyCheckTools} (dependency hygiene) and {@link 
AdvisoryTools} (Camel CVE listing), this
+ * tool cross-references a project's declared dependencies with the Camel 
security advisory database and component
+ * metadata to produce actionable vulnerability findings per artifact.
+ */
+@ApplicationScoped
+public class DependencySecurityAuditTools {
+
+    @Inject
+    CatalogService catalogService;
+
+    @Inject
+    AdvisoryService advisoryService;
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = "Perform a security vulnerability audit on a Camel 
project's dependencies. "
+                        + "Cross-references the project's pom.xml dependencies 
with the Camel security advisory "
+                        + "database to identify CVEs affecting each artifact 
at the project's Camel version. "
+                        + "Reports severity, affected version ranges, fixed 
versions, and whether the vulnerable "
+                        + "component is directly used (reachable) or only a 
transitive dependency. "
+                        + "POM content is automatically sanitized to mask 
sensitive data.")
+    public AuditResult camel_dependency_security_audit(
+            @ToolArg(description = "The pom.xml file content") String 
pomContent,
+            @ToolArg(description = "Route definitions (YAML, XML, or Java DSL) 
to determine which components "
+                                   + "are actually used (for reachability 
analysis)") String routes,
+            @ToolArg(description = ToolArgDocs.RUNTIME) String runtime,
+            @ToolArg(description = ToolArgDocs.CAMEL_VERSION) String 
camelVersion,
+            @ToolArg(description = ToolArgDocs.PLATFORM_BOM) String 
platformBom,
+            @ToolArg(description = "If true (default), mask credentials in POM 
content") Boolean sanitizePom) {
+
+        if (pomContent == null || pomContent.isBlank()) {
+            throw new ToolCallException("pomContent is required", null);
+        }
+
+        try {
+            PomSanitizer.ProcessedPom processed = 
PomSanitizer.process(pomContent, sanitizePom);
+            CamelCatalog catalog = catalogService.loadCatalog(runtime, 
camelVersion, platformBom);
+            MigrationData.PomAnalysis pom = 
MigrationData.parsePomContent(processed.content());
+
+            String effectiveVersion = pom.camelVersion() != null ? 
pom.camelVersion() : catalog.getCatalogVersion();
+
+            List<SecurityAdvisoryModel> allAdvisories = 
advisoryService.advisories();
+
+            List<String> usedSchemes = routes != null && !routes.isBlank()
+                    ? extractUsedSchemes(routes) : List.of();
+
+            Map<String, ArtifactAudit> auditByArtifact = new LinkedHashMap<>();
+
+            for (String dep : pom.dependencies()) {
+                List<AdvisoryService.AdvisoryView> matched
+                        = AdvisoryService.query(allAdvisories, 
effectiveVersion, dep, null);
+
+                if (!matched.isEmpty()) {
+                    boolean reachable = isReachable(dep, usedSchemes, catalog);
+                    List<VulnerabilityFinding> findings = new ArrayList<>();
+                    for (AdvisoryService.AdvisoryView adv : matched) {
+                        findings.add(new VulnerabilityFinding(
+                                adv.cve(),
+                                adv.summary(),
+                                mapSeverity(adv.summary()),
+                                adv.affected(),
+                                adv.fixed(),
+                                AdvisoryService.SECURITY_PAGE_URL + 
adv.cve().toLowerCase().replace("-", "-")));
+                    }
+                    auditByArtifact.put(dep, new ArtifactAudit(dep, reachable, 
findings));
+                }
+            }
+
+            for (String compName : catalog.findComponentNames()) {
+                ComponentModel model = catalog.componentModel(compName);
+                if (model == null || model.getArtifactId() == null) {
+                    continue;
+                }
+                String artifactId = model.getArtifactId();
+                if (auditByArtifact.containsKey(artifactId)) {
+                    continue;
+                }
+
+                List<AdvisoryService.AdvisoryView> matched
+                        = AdvisoryService.query(allAdvisories, 
effectiveVersion, artifactId, null);
+                if (!matched.isEmpty()) {
+                    boolean reachable = usedSchemes.contains(compName);
+                    boolean declaredDep = 
pom.dependencies().contains(artifactId);
+                    List<VulnerabilityFinding> findings = new ArrayList<>();
+                    for (AdvisoryService.AdvisoryView adv : matched) {
+                        findings.add(new VulnerabilityFinding(
+                                adv.cve(), adv.summary(), 
mapSeverity(adv.summary()),
+                                adv.affected(), adv.fixed(),
+                                AdvisoryService.SECURITY_PAGE_URL + 
adv.cve().toLowerCase().replace("-", "-")));
+                    }
+                    if (declaredDep || reachable) {
+                        auditByArtifact.put(artifactId, new 
ArtifactAudit(artifactId, reachable, findings));
+                    }
+                }
+            }
+
+            List<ArtifactAudit> vulnerableArtifacts = new 
ArrayList<>(auditByArtifact.values());
+            int totalCves = vulnerableArtifacts.stream().mapToInt(a -> 
a.findings().size()).sum();
+            long criticalCount = vulnerableArtifacts.stream()
+                    .flatMap(a -> a.findings().stream())
+                    .filter(f -> "critical".equals(f.severity()) || 
"high".equals(f.severity()))
+                    .count();
+            long reachableCount = 
vulnerableArtifacts.stream().filter(ArtifactAudit::reachable).count();
+
+            List<String> recommendations = 
buildRecommendations(vulnerableArtifacts, effectiveVersion, catalog);
+
+            AuditSummary summary = new AuditSummary(
+                    effectiveVersion,
+                    pom.dependencies().size(),
+                    vulnerableArtifacts.size(),
+                    totalCves,
+                    (int) criticalCount,
+                    (int) reachableCount,
+                    totalCves == 0);
+
+            return new AuditResult(
+                    processed.warnings().isEmpty() ? null : 
processed.warnings(),
+                    vulnerableArtifacts.isEmpty() ? null : vulnerableArtifacts,
+                    recommendations.isEmpty() ? null : recommendations,
+                    summary);
+
+        } catch (ToolCallException e) {
+            throw e;
+        } catch (Throwable e) {
+            throw new ToolCallException(
+                    "Failed to audit dependencies (" + e.getClass().getName() 
+ "): " + e.getMessage(), null);
+        }
+    }
+
+    private List<String> extractUsedSchemes(String routes) {
+        List<String> schemes = new ArrayList<>();
+        String lower = routes.toLowerCase();
+        for (String token : lower.split("[^a-z0-9-]+")) {
+            if (token.length() > 2 && lower.contains(token + ":")) {
+                if (!schemes.contains(token)) {
+                    schemes.add(token);
+                }
+            }
+        }
+        return schemes;
+    }
+
+    private boolean isReachable(String artifactId, List<String> usedSchemes, 
CamelCatalog catalog) {
+        if (usedSchemes.isEmpty()) {
+            return true;
+        }
+        for (String scheme : usedSchemes) {
+            ComponentModel model = catalog.componentModel(scheme);
+            if (model != null && artifactId.equals(model.getArtifactId())) {
+                return true;
+            }
+        }
+        String schemeName = artifactId.replace("camel-", "");
+        return usedSchemes.contains(schemeName);
+    }
+
+    private String mapSeverity(String title) {
+        if (title == null) {
+            return "unknown";
+        }
+        String lower = title.toLowerCase();
+        if (lower.contains("remote code") || lower.contains("rce") || 
lower.contains("deserialization")) {
+            return "critical";
+        }
+        if (lower.contains("injection") || lower.contains("bypass") || 
lower.contains("ssrf")
+                || lower.contains("traversal")) {
+            return "high";
+        }
+        if (lower.contains("disclosure") || lower.contains("xxe") || 
lower.contains("header")) {
+            return "medium";
+        }
+        return "medium";
+    }
+
+    private List<String> buildRecommendations(
+            List<ArtifactAudit> vulnerableArtifacts, String version, 
CamelCatalog catalog) {
+        List<String> recs = new ArrayList<>();
+
+        boolean hasCritical = vulnerableArtifacts.stream()
+                .flatMap(a -> a.findings().stream())
+                .anyMatch(f -> "critical".equals(f.severity()));
+        if (hasCritical) {
+            recs.add("URGENT: Critical vulnerabilities found. Upgrade Camel 
version immediately. "
+                     + "Use camel_migration_compatibility to check upgrade 
path.");
+        }

Review Comment:
   Done in c2179f9 — mapSeverity() was removed; the finding now carries 
adv.severity() directly (with an "unknown" fallback when null).\n\n_Claude Code 
on behalf of Andrea Cosentino (@oscerd)._



##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencySecurityAuditTools.java:
##########
@@ -0,0 +1,282 @@
+/*
+ * 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.dsl.jbang.core.commands.mcp;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+import io.quarkiverse.mcp.server.Tool;
+import io.quarkiverse.mcp.server.ToolArg;
+import io.quarkiverse.mcp.server.ToolCallException;
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.tooling.model.ComponentModel;
+import org.apache.camel.tooling.model.SecurityAdvisoryModel;
+
+/**
+ * MCP Tool for performing security vulnerability analysis on Camel project 
dependencies.
+ * <p>
+ * Distinct from {@link DependencyCheckTools} (dependency hygiene) and {@link 
AdvisoryTools} (Camel CVE listing), this
+ * tool cross-references a project's declared dependencies with the Camel 
security advisory database and component
+ * metadata to produce actionable vulnerability findings per artifact.
+ */
+@ApplicationScoped
+public class DependencySecurityAuditTools {
+
+    @Inject
+    CatalogService catalogService;
+
+    @Inject
+    AdvisoryService advisoryService;
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = "Perform a security vulnerability audit on a Camel 
project's dependencies. "
+                        + "Cross-references the project's pom.xml dependencies 
with the Camel security advisory "
+                        + "database to identify CVEs affecting each artifact 
at the project's Camel version. "
+                        + "Reports severity, affected version ranges, fixed 
versions, and whether the vulnerable "
+                        + "component is directly used (reachable) or only a 
transitive dependency. "
+                        + "POM content is automatically sanitized to mask 
sensitive data.")
+    public AuditResult camel_dependency_security_audit(
+            @ToolArg(description = "The pom.xml file content") String 
pomContent,
+            @ToolArg(description = "Route definitions (YAML, XML, or Java DSL) 
to determine which components "
+                                   + "are actually used (for reachability 
analysis)") String routes,
+            @ToolArg(description = ToolArgDocs.RUNTIME) String runtime,
+            @ToolArg(description = ToolArgDocs.CAMEL_VERSION) String 
camelVersion,
+            @ToolArg(description = ToolArgDocs.PLATFORM_BOM) String 
platformBom,
+            @ToolArg(description = "If true (default), mask credentials in POM 
content") Boolean sanitizePom) {
+
+        if (pomContent == null || pomContent.isBlank()) {
+            throw new ToolCallException("pomContent is required", null);
+        }
+
+        try {
+            PomSanitizer.ProcessedPom processed = 
PomSanitizer.process(pomContent, sanitizePom);
+            CamelCatalog catalog = catalogService.loadCatalog(runtime, 
camelVersion, platformBom);
+            MigrationData.PomAnalysis pom = 
MigrationData.parsePomContent(processed.content());
+
+            String effectiveVersion = pom.camelVersion() != null ? 
pom.camelVersion() : catalog.getCatalogVersion();
+
+            List<SecurityAdvisoryModel> allAdvisories = 
advisoryService.advisories();
+
+            List<String> usedSchemes = routes != null && !routes.isBlank()
+                    ? extractUsedSchemes(routes) : List.of();
+
+            Map<String, ArtifactAudit> auditByArtifact = new LinkedHashMap<>();
+
+            for (String dep : pom.dependencies()) {
+                List<AdvisoryService.AdvisoryView> matched
+                        = AdvisoryService.query(allAdvisories, 
effectiveVersion, dep, null);
+
+                if (!matched.isEmpty()) {
+                    boolean reachable = isReachable(dep, usedSchemes, catalog);
+                    List<VulnerabilityFinding> findings = new ArrayList<>();
+                    for (AdvisoryService.AdvisoryView adv : matched) {
+                        findings.add(new VulnerabilityFinding(
+                                adv.cve(),
+                                adv.summary(),
+                                mapSeverity(adv.summary()),
+                                adv.affected(),
+                                adv.fixed(),
+                                AdvisoryService.SECURITY_PAGE_URL + 
adv.cve().toLowerCase().replace("-", "-")));
+                    }
+                    auditByArtifact.put(dep, new ArtifactAudit(dep, reachable, 
findings));
+                }
+            }
+
+            for (String compName : catalog.findComponentNames()) {

Review Comment:
   Done in c2179f9 — the URL is now taken from adv.url() rather than 
reconstructed, so the no-op replace is gone.\n\n_Claude Code on behalf of 
Andrea Cosentino (@oscerd)._



##########
dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencySecurityAuditTools.java:
##########
@@ -0,0 +1,282 @@
+/*
+ * 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.dsl.jbang.core.commands.mcp;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+import io.quarkiverse.mcp.server.Tool;
+import io.quarkiverse.mcp.server.ToolArg;
+import io.quarkiverse.mcp.server.ToolCallException;
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.tooling.model.ComponentModel;
+import org.apache.camel.tooling.model.SecurityAdvisoryModel;
+
+/**
+ * MCP Tool for performing security vulnerability analysis on Camel project 
dependencies.
+ * <p>
+ * Distinct from {@link DependencyCheckTools} (dependency hygiene) and {@link 
AdvisoryTools} (Camel CVE listing), this
+ * tool cross-references a project's declared dependencies with the Camel 
security advisory database and component
+ * metadata to produce actionable vulnerability findings per artifact.
+ */
+@ApplicationScoped
+public class DependencySecurityAuditTools {
+
+    @Inject
+    CatalogService catalogService;
+
+    @Inject
+    AdvisoryService advisoryService;
+
+    @Tool(annotations = @Tool.Annotations(readOnlyHint = true, destructiveHint 
= false, openWorldHint = false),
+          description = "Perform a security vulnerability audit on a Camel 
project's dependencies. "
+                        + "Cross-references the project's pom.xml dependencies 
with the Camel security advisory "
+                        + "database to identify CVEs affecting each artifact 
at the project's Camel version. "
+                        + "Reports severity, affected version ranges, fixed 
versions, and whether the vulnerable "
+                        + "component is directly used (reachable) or only a 
transitive dependency. "
+                        + "POM content is automatically sanitized to mask 
sensitive data.")
+    public AuditResult camel_dependency_security_audit(
+            @ToolArg(description = "The pom.xml file content") String 
pomContent,
+            @ToolArg(description = "Route definitions (YAML, XML, or Java DSL) 
to determine which components "
+                                   + "are actually used (for reachability 
analysis)") String routes,
+            @ToolArg(description = ToolArgDocs.RUNTIME) String runtime,
+            @ToolArg(description = ToolArgDocs.CAMEL_VERSION) String 
camelVersion,
+            @ToolArg(description = ToolArgDocs.PLATFORM_BOM) String 
platformBom,
+            @ToolArg(description = "If true (default), mask credentials in POM 
content") Boolean sanitizePom) {
+
+        if (pomContent == null || pomContent.isBlank()) {
+            throw new ToolCallException("pomContent is required", null);
+        }
+
+        try {
+            PomSanitizer.ProcessedPom processed = 
PomSanitizer.process(pomContent, sanitizePom);
+            CamelCatalog catalog = catalogService.loadCatalog(runtime, 
camelVersion, platformBom);
+            MigrationData.PomAnalysis pom = 
MigrationData.parsePomContent(processed.content());
+
+            String effectiveVersion = pom.camelVersion() != null ? 
pom.camelVersion() : catalog.getCatalogVersion();
+
+            List<SecurityAdvisoryModel> allAdvisories = 
advisoryService.advisories();
+
+            List<String> usedSchemes = routes != null && !routes.isBlank()
+                    ? extractUsedSchemes(routes) : List.of();
+
+            Map<String, ArtifactAudit> auditByArtifact = new LinkedHashMap<>();
+
+            for (String dep : pom.dependencies()) {
+                List<AdvisoryService.AdvisoryView> matched
+                        = AdvisoryService.query(allAdvisories, 
effectiveVersion, dep, null);
+
+                if (!matched.isEmpty()) {
+                    boolean reachable = isReachable(dep, usedSchemes, catalog);
+                    List<VulnerabilityFinding> findings = new ArrayList<>();
+                    for (AdvisoryService.AdvisoryView adv : matched) {
+                        findings.add(new VulnerabilityFinding(
+                                adv.cve(),
+                                adv.summary(),
+                                mapSeverity(adv.summary()),
+                                adv.affected(),
+                                adv.fixed(),
+                                AdvisoryService.SECURITY_PAGE_URL + 
adv.cve().toLowerCase().replace("-", "-")));
+                    }
+                    auditByArtifact.put(dep, new ArtifactAudit(dep, reachable, 
findings));
+                }
+            }
+
+            for (String compName : catalog.findComponentNames()) {
+                ComponentModel model = catalog.componentModel(compName);
+                if (model == null || model.getArtifactId() == null) {
+                    continue;
+                }
+                String artifactId = model.getArtifactId();
+                if (auditByArtifact.containsKey(artifactId)) {
+                    continue;
+                }
+
+                List<AdvisoryService.AdvisoryView> matched
+                        = AdvisoryService.query(allAdvisories, 
effectiveVersion, artifactId, null);
+                if (!matched.isEmpty()) {
+                    boolean reachable = usedSchemes.contains(compName);
+                    boolean declaredDep = 
pom.dependencies().contains(artifactId);
+                    List<VulnerabilityFinding> findings = new ArrayList<>();
+                    for (AdvisoryService.AdvisoryView adv : matched) {

Review Comment:
   Done in c2179f9 — the URL is now taken from adv.url() rather than 
reconstructed, so the no-op replace is gone.\n\n_Claude Code on behalf of 
Andrea Cosentino (@oscerd)._



##########
dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencySecurityAuditToolsTest.java:
##########
@@ -0,0 +1,148 @@
+/*
+ * 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.dsl.jbang.core.commands.mcp;
+
+import io.quarkiverse.mcp.server.ToolCallException;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class DependencySecurityAuditToolsTest {
+
+    private static final String SIMPLE_POM = """
+            <project>
+                <properties>
+                    <camel.version>4.10.0</camel.version>
+                </properties>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.camel</groupId>
+                        <artifactId>camel-core</artifactId>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.camel</groupId>
+                        <artifactId>camel-http</artifactId>
+                    </dependency>
+                </dependencies>
+            </project>
+            """;
+
+    private static final String CURRENT_VERSION_POM = """
+            <project>
+                <properties>
+                    <camel.version>4.22.0</camel.version>
+                </properties>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.camel</groupId>
+                        <artifactId>camel-core</artifactId>
+                    </dependency>
+                </dependencies>
+            </project>
+            """;
+
+    private final DependencySecurityAuditTools tools = createTools();
+
+    private static DependencySecurityAuditTools createTools() {
+        DependencySecurityAuditTools t = new DependencySecurityAuditTools();
+        t.catalogService = new CatalogService();
+        t.advisoryService = new AdvisoryService();
+        return t;
+    }
+
+    @Test
+    void shouldRequirePomContent() {
+        assertThatThrownBy(() -> tools.camel_dependency_security_audit(null, 
null, null, null, null, null))
+                .isInstanceOf(ToolCallException.class)
+                .hasMessageContaining("pomContent is required");
+    }
+
+    @Test
+    void shouldAuditOlderVersionWithKnownCves() {
+        DependencySecurityAuditTools.AuditResult result
+                = tools.camel_dependency_security_audit(SIMPLE_POM, null, 
null, null, null, null);
+
+        assertThat(result).isNotNull();
+        assertThat(result.summary()).isNotNull();
+        assertThat(result.summary().camelVersion()).isEqualTo("4.10.0");
+        assertThat(result.summary().totalDependencies()).isGreaterThan(0);
+        assertThat(result.recommendations()).isNotNull();
+    }
+
+    @Test
+    void shouldReportCleanForCurrentVersion() {
+        DependencySecurityAuditTools.AuditResult result
+                = tools.camel_dependency_security_audit(CURRENT_VERSION_POM, 
null, null, null, null, null);
+
+        assertThat(result).isNotNull();

Review Comment:
   Done in c2179f9 — shouldReportCleanForCurrentVersion now asserts 
summary().clean() is true.\n\n_Claude Code on behalf of Andrea Cosentino 
(@oscerd)._



##########
dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/DependencySecurityAuditToolsTest.java:
##########
@@ -0,0 +1,148 @@
+/*
+ * 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.dsl.jbang.core.commands.mcp;
+
+import io.quarkiverse.mcp.server.ToolCallException;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class DependencySecurityAuditToolsTest {
+
+    private static final String SIMPLE_POM = """
+            <project>
+                <properties>
+                    <camel.version>4.10.0</camel.version>
+                </properties>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.camel</groupId>
+                        <artifactId>camel-core</artifactId>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.apache.camel</groupId>
+                        <artifactId>camel-http</artifactId>
+                    </dependency>
+                </dependencies>
+            </project>
+            """;
+
+    private static final String CURRENT_VERSION_POM = """
+            <project>
+                <properties>
+                    <camel.version>4.22.0</camel.version>
+                </properties>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.camel</groupId>
+                        <artifactId>camel-core</artifactId>
+                    </dependency>
+                </dependencies>
+            </project>
+            """;
+
+    private final DependencySecurityAuditTools tools = createTools();
+
+    private static DependencySecurityAuditTools createTools() {
+        DependencySecurityAuditTools t = new DependencySecurityAuditTools();
+        t.catalogService = new CatalogService();
+        t.advisoryService = new AdvisoryService();
+        return t;
+    }
+
+    @Test
+    void shouldRequirePomContent() {
+        assertThatThrownBy(() -> tools.camel_dependency_security_audit(null, 
null, null, null, null, null))
+                .isInstanceOf(ToolCallException.class)
+                .hasMessageContaining("pomContent is required");
+    }
+
+    @Test
+    void shouldAuditOlderVersionWithKnownCves() {
+        DependencySecurityAuditTools.AuditResult result
+                = tools.camel_dependency_security_audit(SIMPLE_POM, null, 
null, null, null, null);
+
+        assertThat(result).isNotNull();
+        assertThat(result.summary()).isNotNull();
+        assertThat(result.summary().camelVersion()).isEqualTo("4.10.0");
+        assertThat(result.summary().totalDependencies()).isGreaterThan(0);
+        assertThat(result.recommendations()).isNotNull();
+    }
+
+    @Test
+    void shouldReportCleanForCurrentVersion() {
+        DependencySecurityAuditTools.AuditResult result
+                = tools.camel_dependency_security_audit(CURRENT_VERSION_POM, 
null, null, null, null, null);
+
+        assertThat(result).isNotNull();
+        assertThat(result.summary()).isNotNull();
+    }
+
+    @Test
+    void shouldIncludeReachabilityWhenRoutesProvided() {
+        String routes = "from: \"http:example.com\"\nsteps:\n  - to: 
\"log:out\"";
+        DependencySecurityAuditTools.AuditResult result
+                = tools.camel_dependency_security_audit(SIMPLE_POM, routes, 
null, null, null, null);

Review Comment:
   Done in e513056 — the test now asserts camel-http is flagged reachable=true 
when a route uses the http component, and a new negative test asserts it is NOT 
reachable when the route uses a different component.\n\n_Claude Code on behalf 
of Andrea Cosentino (@oscerd)._



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

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to