CAMEL-23979: Expose published CVE security advisories via camel-catalog and camel-jbang-mcp#24573
CAMEL-23979: Expose published CVE security advisories via camel-catalog and camel-jbang-mcp#24573oscerd wants to merge 2 commits into
Conversation
…og and camel-jbang-mcp Sync the published Apache Camel security advisories (camel.apache.org/security) from camel-website into a JSON file shipped with camel-catalog, like the known releases sync: new update-security-advisories goal in camel-package-maven-plugin, new CamelCatalog.camelSecurityAdvisories() API and SecurityAdvisoryModel. The MCP server consumes the catalog fully offline: new camel_security_advisories tool, camel://security/advisories resources, and camel_route_harden_context now embeds the known CVEs affecting the components used by the route. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
gnodet
left a comment
There was a problem hiding this comment.
Well-structured, substantial feature addition that follows existing catalog patterns. The confirmed issue is that the component extraction regex (COMPONENT_TOKEN) in UpdateSecurityAdvisoriesMojo produces false-positive component names in the generated JSON: 6 JIRA ticket IDs (e.g., camel-12444) and 5 English words (e.g., camel-internal ×10, camel-prefixed ×13) are incorrectly treated as component artifact names, totaling ~32 bogus entries across 76 CVE advisories. This degrades component-based filtering accuracy in the AdvisoryService. The test coverage is comprehensive and well-written.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
| String url = jo.getString("download_url"); | ||
| if (url != null) { | ||
| answer.add(url); | ||
| } |
There was a problem hiding this comment.
The COMPONENT_TOKEN regex camel-[a-z0-9]+(?:-[a-z0-9]+)* extracts false-positive component names from advisory text. The generated camel-security-advisories.json contains bogus components including:
- JIRA issue IDs:
camel-10894,camel-12444,camel-23200,camel-23212,camel-23372,camel-23506— extracted from prose likeCAMEL-12444in mitigation URLs - Generic English words:
camel-internal(×10),camel-prefixed(×13),camel-specific,camel-side,camel-namespace— extracted from phrases like "Camel-namespace filter" and "camel-internal headers"
For example, CVE-2018-8027 has components ["camel-10894", "camel-12444"] which are JIRA ticket IDs, not actual Camel component artifacts.
Consider:
- Adding a negative lookahead to filter JIRA IDs:
camel-(?!\d+\b)[a-z][a-z0-9]+(?:-[a-z0-9]+)* - Validating extracted tokens against the catalog's known artifact IDs
- Adding a denylist for known false positives (
camel-internal,camel-prefixed, etc.)
Option 1 alone fixes the JIRA IDs but not the English words. Option 2 would be the most comprehensive.
| } | |
| private static final Pattern COMPONENT_TOKEN = Pattern.compile("camel-(?!\\d+\\b)[a-z][a-z0-9]+(?:-[a-z0-9]+)*"); |
There was a problem hiding this comment.
Fixed in 3531d80 with a combination of your options 1 and 3: the token regex now requires the first segment to start with a letter (camel-[a-z][a-z0-9]+(?:-[a-z0-9]+)*, which subsumes the digit lookahead and drops all 6 lowercased JIRA ids), plus a denylist for the English prose tokens (camel-internal, camel-prefixed, camel-specific, camel-side, camel-namespace, and a few likely future ones such as camel-case/camel-based). Regenerated JSON verified: exactly the 11 bogus tokens (32 occurrences) are gone and 78 legitimate tokens remain; regression test added.
On option 2 (validating against the catalog's known artifact ids) — I measured it and deliberately did not adopt it: strict validation would silently drop 10 legitimate component names across 9 CVEs, because old advisories name components that have since been removed or renamed: camel-xstream (CVE-2015-5344), camel-hessian (CVE-2017-12633), camel-castor (CVE-2017-12634), camel-xmljson (CVE-2019-0188), camel-stomp (CVE-2025-27636), and the legacy camel-cxf/camel-cxfrs/camel-cxf-common/camel-cxf-transport/camel-knative-http artifact names. For a security tool those are exactly the components users on older versions need to be able to filter by, so the denylist approach keeps them while removing all observed false positives. This rationale is documented in a code comment on the denylist.
Claude Code on behalf of oscerd
davsclaus
left a comment
There was a problem hiding this comment.
Nice work, Andrea — this is a well-structured feature that mirrors the existing camelReleases() / update-camel-releases pattern cleanly, and the test coverage is thorough. A couple of things to address before merging.
This review covers project rules and conventions. It does not replace specialized AI review tools (CodeRabbit, Sourcery) or static analysis (SonarCloud).
This review was generated by an AI agent (Claude Code on behalf of davsclaus) and may contain inaccuracies. Please verify all suggestions before applying.
| * not name components at all). | ||
| */ | ||
| static List<String> extractComponents(String... texts) { | ||
| TreeSet<String> found = new TreeSet<>(); |
There was a problem hiding this comment.
The COMPONENT_TOKEN regex camel-[a-z0-9]+(?:-[a-z0-9]+)* matches any camel-* token in the advisory text, producing 9 distinct spurious component entries across 32 occurrences in 25 CVE entries:
- JIRA ticket numbers:
camel-10894,camel-12444,camel-23200,camel-23212,camel-23372,camel-23506— from prose like "CAMEL-23212 fix" lowercased to match. - English words from prose:
camel-internal(10 CVEs),camel-prefixed(13 CVEs),camel-specific,camel-namespace,camel-side— from phrases like "camel-internal headers", "non-Camel-prefixed names".
These pollute filtering — e.g. camel_security_advisories(component="internal") returns 10 false matches, and matchAdvisories() in HardenTools would try to match route components against camel-internal.
Suggestion: post-filter extracted tokens against a known-component list from the catalog, or at minimum add a blocklist for common false positives (camel-internal, camel-prefixed, camel-specific, camel-side, camel-namespace, and tokens matching camel-\d+).
There was a problem hiding this comment.
Fixed in 3531d80: took your "at minimum" blocklist option, strengthened by a letter-first regex (camel-[a-z][a-z0-9]+...) that removes the camel-\d+ JIRA ids without a separate pattern. Regenerated JSON verified: exactly the 11 spurious tokens (32 occurrences across 25 entries) are gone, 78 legitimate tokens remain, and camel_security_advisories(component="internal") now returns nothing. I deliberately did not post-filter against the current catalog's component list because old advisories legitimately name removed/renamed components (camel-xstream, camel-hessian, camel-castor, camel-xmljson, legacy camel-cxf/camel-cxfrs artifacts) which would otherwise become unfilterable — details in the reply to Guillaume's comment and in a code comment on the denylist. Regression test added.
Claude Code on behalf of oscerd
| + "against components named in the advisory text - older advisories may not name " | ||
| + "components)") String component, | ||
| @ToolArg(description = "Severity to filter by as published, e.g. LOW, MEDIUM, MODERATE, IMPORTANT or " | ||
| + "CRITICAL (optional)") String severity) { |
There was a problem hiding this comment.
The description lists MODERATE and IMPORTANT as valid severity values, but the generated JSON only uses LOW, MEDIUM, HIGH, CRITICAL (the mojo normalizes with toUpperCase). Listing non-existent values will confuse the LLM into using filter values that never match.
| + "CRITICAL (optional)") String severity) { | |
| @ToolArg(description = "Severity to filter by: LOW, MEDIUM, HIGH, or CRITICAL " | |
| + "(optional)") String severity) { |
There was a problem hiding this comment.
Fixed in 3531d80, applied your suggested wording. Verified against the regenerated JSON: the actual severity set is exactly LOW, MEDIUM, HIGH, CRITICAL.
Claude Code on behalf of oscerd
| * <a href="https://camel.apache.org/security/">camel.apache.org/security</a>, synced into the catalog when it was | ||
| * built). | ||
| */ | ||
| List<SecurityAdvisoryModel> camelSecurityAdvisories(); |
There was a problem hiding this comment.
Minor: per project conventions, new public methods on API interfaces should include a @since Javadoc tag. Consider adding @since 4.22 to the method Javadoc.
There was a problem hiding this comment.
Added @since 4.22 in 3531d80.
Claude Code on behalf of oscerd
…(human review by davsclaus)
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
- PR apache#24573: bumped review timestamp to match updatedAt (CI activity, no author changes) - Added PR apache#24575 (dependabot) to skipped table Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 570 tested, 27 compile-only — current: 74 all testedMaveniverse Scalpel detected 597 affected modules (current approach: 74).
|
- Synced PR apache#24573 timestamp to 11:51:48Z (CI/labels only, no author changes) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Component token extraction no longer produces false positives: the first segment must start with a letter (drops lowercased JIRA ids) and common English prose such as Camel-internal is denylisted. Deliberately not validated against the current catalog so that advisories naming removed components (camel-xstream, camel-hessian, ...) remain filterable. - Regenerated camel-security-advisories.json: 11 bogus tokens removed. - Severity filter description now lists the actual values (LOW, MEDIUM, HIGH, CRITICAL). - Added @SInCE 4.22 to CamelCatalog#camelSecurityAdvisories(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
gnodet
left a comment
There was a problem hiding this comment.
Re-review after fix commit 3531d80: all prior findings fully addressed.
Prior findings status:
- ✅ Component token regex strengthened — letter-first requirement (
camel-[a-z][a-z0-9]+...) eliminates all JIRA ID false positives; prose denylist removes English words (camel-internal, camel-prefixed, etc.). 11 bogus tokens removed from generated JSON. - ✅ Severity filter description corrected — now lists actual values (LOW, MEDIUM, HIGH, CRITICAL)
- ✅
@since 4.22added toCamelCatalog#camelSecurityAdvisories() - ✅ Decision not to validate against catalog's known components is well-reasoned — preserves filterability for removed components (camel-xstream, camel-hessian, etc.) referenced in older CVEs
Regression test componentExtractionSkipsJiraIdsAndProse provides good coverage. Generated JSON verified: 76 advisories, 78 legitimate component tokens, zero false positives.
This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
Claude Code on behalf of Guillaume Nodet
|
⏺ The PR failed due to a flaky test in camel-milvus — completely unrelated to the PR's changes. The PR touches camel-catalog, camel-jbang-mcp, camel-tooling-model, and camel-package-maven-plugin (security advisories feature). The failure is in components/camel-ai/camel-milvus integration tests This is a known-flaky area — Milvus tests depend on a Testcontainers-managed vector DB that can be unreliable in CI. You can safely re-run the CI workflow or ignore the failure. |
JIRA: https://issues.apache.org/jira/browse/CAMEL-23979
Exposes the published Apache Camel CVE security advisories (the data behind https://camel.apache.org/security/) to tooling, following the approach suggested by @davsclaus on the issue: the advisories are synced from camel-website into a JSON file shipped with
camel-catalog, the same way the known releases are synced, and the MCP server consumes the catalog fully offline.Changes
camel-tooling-model
SecurityAdvisoryModel(cve, date, severity, summary, affected, fixed, mitigation, url, components) withJsonMapperserialization support.camel-package-maven-plugin
update-security-advisoriesgoal mirroringupdate-camel-releases: scanscontent/security/CVE-*.mdin the camel-website repository via the GitHub contents API, parses the YAML front matter (snakeyaml-engine, already a plugin dependency), skips drafts and non-advisory pages, extracts thecamel-*component tokens named by the advisory text, and writescamel-security-advisories.jsoninto camel-catalogsrc/generated.camel-xstream,camel-hessian,camel-castor,camel-xmljson, legacycamel-cxf/camel-cxfrsartifacts, ...) and those must remain filterable.camel-catalog
update-security-advisoriesprofile wiring the goal (run it like the releases sync:mvn -Pupdate-security-advisories generate-resourcesincatalog/camel-catalog).advisories/camel-security-advisories.json(currently 76 published advisories).CamelCatalog.camelSecurityAdvisories()API following thecamelReleases()pattern.camel-jbang-mcp
camel_security_advisoriestool: lists the published advisories, optionally filtered by Camel version, component and severity. Theaffectedprose is parsed best-effort (X before Yexclusive ranges,X up to Yinclusive ranges, bare versions) into anaffectsGivenVersionverdict; advisories whose ranges cannot be parsed are kept with the verdict unset so the LLM judges from the prose.camel://security/advisories(list) andcamel://security/advisory/{cve}(detail).camel_route_harden_contextnow embeds the known CVE advisories affecting the components used by the route at the given Camel version (matched via catalog artifact ids, capped at 20, failures degrade to a note without breaking the hardening analysis).Docs
camel-jbang-mcp.adoc: new tool row, advisory data source/freshness section, usage example.Data freshness semantics
The advisory data is as fresh as the catalog bundled with the release (same model as the known releases data); the tool description and docs state explicitly that advisories published after the release are not included and link to the website for the latest. The TUI CVE audit tab (OSV.dev, dependency-level) remains complementary; a possible follow-up is sharing
OsvClientand offering a dependency CVE audit tool in the MCP server too.Testing
UpdateSecurityAdvisoriesMojoTest: front-matter parsing against canned copies of two real advisories (recent + 2013-style), draft/non-advisory skipping, JIRA-id/prose filtering, JsonMapper round-trip (5 tests).CamelCatalogTest#camelSecurityAdvisories: validates the shipped JSON through the new API.AdvisoryServiceTest,AdvisoryToolsTest,AdvisoryResourcesTest,HardenToolsAdvisoryTest(20 tests) — catalog loading, both affected-range grammars, filtering, harden embedding/degradation. All fully offline.Claude Code on behalf of oscerd
🤖 Generated with Claude Code