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 4e36e2d6e2 [closes #8504] Add camel-quarkus-ocsf extension
4e36e2d6e2 is described below
commit 4e36e2d6e2897b7944af817af6cac8bdcbe45d3d
Author: Lukas Lowinger <[email protected]>
AuthorDate: Fri Jun 5 12:16:15 2026 +0200
[closes #8504] Add camel-quarkus-ocsf extension
---
catalog/pom.xml | 13 +
docs/modules/ROOT/examples/dataformats/ocsf.yml | 13 +
docs/modules/ROOT/nav.adoc | 1 +
.../ROOT/pages/reference/extensions/ocsf.adoc | 127 +++++++
extensions/ocsf/deployment/pom.xml | 67 ++++
.../component/ocsf/deployment/OcsfProcessor.java | 52 +++
extensions/ocsf/pom.xml | 39 +++
extensions/ocsf/runtime/pom.xml | 105 ++++++
extensions/ocsf/runtime/src/main/doc/usage.adoc | 71 ++++
.../main/resources/META-INF/quarkus-extension.yaml | 32 ++
extensions/pom.xml | 1 +
integration-tests/ocsf/pom.xml | 129 +++++++
.../quarkus/component/ocsf/it/OcsfResource.java | 378 +++++++++++++++++++++
.../quarkus/component/ocsf/it/OcsfRoutes.java | 51 +++
.../ocsf/src/main/resources/application.properties | 19 ++
.../resources/ocsf-detection-finding-example.json | 168 +++++++++
.../camel/quarkus/component/ocsf/it/OcsfIT.java | 24 ++
.../camel/quarkus/component/ocsf/it/OcsfTest.java | 350 +++++++++++++++++++
integration-tests/pom.xml | 1 +
poms/bom/pom.xml | 15 +
poms/bom/src/main/generated/flattened-full-pom.xml | 15 +
.../src/main/generated/flattened-reduced-pom.xml | 15 +
.../generated/flattened-reduced-verbose-pom.xml | 15 +
tooling/scripts/test-categories.yaml | 1 +
24 files changed, 1702 insertions(+)
diff --git a/catalog/pom.xml b/catalog/pom.xml
index eb05ef8a55..64c1aca3cc 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -3061,6 +3061,19 @@
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-ognl</artifactId>
diff --git a/docs/modules/ROOT/examples/dataformats/ocsf.yml
b/docs/modules/ROOT/examples/dataformats/ocsf.yml
new file mode 100644
index 0000000000..8717eb0329
--- /dev/null
+++ b/docs/modules/ROOT/examples/dataformats/ocsf.yml
@@ -0,0 +1,13 @@
+# Do not edit directly!
+# This file was generated by
camel-quarkus-maven-plugin:update-extension-doc-page
+cqArtifactId: camel-quarkus-ocsf
+cqArtifactIdBase: ocsf
+cqNativeSupported: true
+cqStatus: Stable
+cqDeprecated: false
+cqJvmSince: 3.37.0
+cqNativeSince: 3.37.0
+cqCamelPartName: ocsf
+cqCamelPartTitle: OCSF
+cqCamelPartDescription: Marshal and unmarshal OCSF (Open Cybersecurity Schema
Framework) security events to/from JSON.
+cqExtensionPageTitle: OCSF
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
index e383ad40a0..605bf9bf5e 100644
--- a/docs/modules/ROOT/nav.adoc
+++ b/docs/modules/ROOT/nav.adoc
@@ -246,6 +246,7 @@
*** xref:reference/extensions/netty.adoc[Netty]
*** xref:reference/extensions/netty-http.adoc[Netty HTTP]
*** xref:reference/extensions/oaipmh.adoc[OAI-PMH]
+*** xref:reference/extensions/ocsf.adoc[OCSF]
*** xref:reference/extensions/ognl.adoc[OGNL]
*** xref:reference/extensions/milo.adoc[OPC UA Browser]
*** xref:reference/extensions/oauth.adoc[Oauth]
diff --git a/docs/modules/ROOT/pages/reference/extensions/ocsf.adoc
b/docs/modules/ROOT/pages/reference/extensions/ocsf.adoc
new file mode 100644
index 0000000000..5e80044ec0
--- /dev/null
+++ b/docs/modules/ROOT/pages/reference/extensions/ocsf.adoc
@@ -0,0 +1,127 @@
+// Do not edit directly!
+// This file was generated by
camel-quarkus-maven-plugin:update-extension-doc-page
+[id="extensions-ocsf"]
+= OCSF
+:linkattrs:
+:cq-artifact-id: camel-quarkus-ocsf
+:cq-native-supported: true
+:cq-status: Stable
+:cq-status-deprecation: Stable
+:cq-description: Marshal and unmarshal OCSF (Open Cybersecurity Schema
Framework) security events to/from JSON.
+:cq-deprecated: false
+:cq-jvm-since: 3.37.0
+:cq-native-since: 3.37.0
+
+ifeval::[{doc-show-badges} == true]
+[.badges]
+[.badge-key]##JVM since##[.badge-supported]##3.37.0## [.badge-key]##Native
since##[.badge-supported]##3.37.0##
+endif::[]
+
+Marshal and unmarshal OCSF (Open Cybersecurity Schema Framework) security
events to/from JSON.
+
+[id="extensions-ocsf-whats-inside"]
+== What's inside
+
+* xref:{cq-camel-components}:dataformats:ocsf-dataformat.adoc[OCSF data format]
+
+Please refer to the above link for usage and configuration details.
+
+[id="extensions-ocsf-maven-coordinates"]
+== Maven coordinates
+
+https://{link-quarkus-code-generator}/?extension-search=camel-quarkus-ocsf[Create
a new project with this extension on {link-quarkus-code-generator},
window="_blank"]
+
+Or add the coordinates to your existing project:
+
+[source,xml]
+----
+<dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf</artifactId>
+</dependency>
+----
+ifeval::[{doc-show-user-guide-link} == true]
+Check the xref:user-guide/index.adoc[User guide] for more information about
writing Camel Quarkus applications.
+endif::[]
+
+[id="extensions-ocsf-usage"]
+== Usage
+The OCSF (Open Cybersecurity Schema Framework) extension provides support for
marshalling and unmarshalling security events following the OCSF specification.
+
+[id="extensions-ocsf-usage-basic-usage"]
+== Basic Usage
+
+[id="extensions-ocsf-usage-marshalling-ocsf-events"]
+=== Marshalling OCSF Events
+
+[source,java]
+----
+from("direct:start")
+ .marshal().ocsf()
+ .to("kafka:security-events");
+----
+
+[id="extensions-ocsf-usage-unmarshalling-ocsf-events"]
+=== Unmarshalling OCSF Events
+
+[source,java]
+----
+from("kafka:security-events")
+ .unmarshal().ocsf()
+ .to("direct:process");
+----
+
+[id="extensions-ocsf-usage-unmarshalling-to-a-specific-event-class"]
+=== Unmarshalling to a Specific Event Class
+
+[source,java]
+----
+from("kafka:security-events")
+ .unmarshal().ocsf(DetectionFinding.class)
+ .to("direct:process");
+----
+
+[id="extensions-ocsf-usage-supported-ocsf-event-classes"]
+== Supported OCSF Event Classes
+
+This extension includes support for 34 OCSF event classes including:
+
+* *Findings*: `DetectionFinding`, `SecurityFinding`, `VulnerabilityFinding`,
`ComplianceFinding`
+* *System Activity*: `FileActivity`, `ProcessActivity`, `KernelActivity`,
`MemoryActivity`
+* *Network Activity*: `NetworkActivity`, `HttpActivity`, `DnsActivity`,
`SshActivity`
+* *IAM*: `Authentication`, `AuthorizeSession`, `AccountChange`,
`GroupManagement`
+* *Application Activity*: `ApiActivity`, `DatastoreActivity`,
`WebResourcesActivity`
+
+All event classes extend `OcsfEvent` which provides common attributes like
`time`, `severity_id`, `class_uid`, and `metadata`.
+
+[id="extensions-ocsf-usage-example-creating-a-detection-finding"]
+== Example: Creating a Detection Finding
+
+[source,java]
+----
+import org.apache.camel.dataformat.ocsf.model.DetectionFinding;
+import org.apache.camel.dataformat.ocsf.model.FindingInfo;
+import org.apache.camel.dataformat.ocsf.OcsfConstants;
+
+DetectionFinding finding = new DetectionFinding();
+finding.setActivityId(OcsfConstants.ACTIVITY_CREATE);
+finding.setSeverityId(OcsfConstants.SEVERITY_HIGH);
+finding.setTime(System.currentTimeMillis());
+finding.setIsAlert(true);
+
+FindingInfo info = new FindingInfo();
+info.setTitle("Malware Detection");
+info.setDesc("Potential malware detected on endpoint");
+finding.setFindingInfo(info);
+
+from("direct:start")
+ .setBody(constant(finding))
+ .marshal().ocsf()
+ .to("splunk-hec:...");
+----
+
+[id="extensions-ocsf-usage-native-mode-support"]
+== Native Mode Support
+
+The OCSF extension fully supports native mode compilation. All OCSF model
classes are automatically registered for reflection during the build process.
+
diff --git a/extensions/ocsf/deployment/pom.xml
b/extensions/ocsf/deployment/pom.xml
new file mode 100644
index 0000000000..6b3a5cd366
--- /dev/null
+++ b/extensions/ocsf/deployment/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf-parent</artifactId>
+ <version>3.37.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>camel-quarkus-ocsf-deployment</artifactId>
+ <name>Camel Quarkus :: OCSF :: Deployment</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-core-deployment</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-jackson-deployment</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <annotationProcessorPaths>
+ <path>
+ <groupId>io.quarkus</groupId>
+
<artifactId>quarkus-extension-processor</artifactId>
+ <version>${quarkus.version}</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git
a/extensions/ocsf/deployment/src/main/java/org/apache/camel/quarkus/component/ocsf/deployment/OcsfProcessor.java
b/extensions/ocsf/deployment/src/main/java/org/apache/camel/quarkus/component/ocsf/deployment/OcsfProcessor.java
new file mode 100644
index 0000000000..491e74dcc5
--- /dev/null
+++
b/extensions/ocsf/deployment/src/main/java/org/apache/camel/quarkus/component/ocsf/deployment/OcsfProcessor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.component.ocsf.deployment;
+
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import org.jboss.jandex.IndexView;
+
+class OcsfProcessor {
+
+ private static final String FEATURE = "camel-ocsf";
+
+ @BuildStep
+ FeatureBuildItem feature() {
+ return new FeatureBuildItem(FEATURE);
+ }
+
+ @BuildStep
+ void registerForReflection(CombinedIndexBuildItem combinedIndex,
+ BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
+ IndexView index = combinedIndex.getIndex();
+
+ // Register all OCSF model classes for reflection (generated from JSON
schemas)
+ String[] modelClasses = index.getKnownClasses().stream()
+ .map(ci -> ci.name().toString())
+ .filter(n ->
n.startsWith("org.apache.camel.dataformat.ocsf.model"))
+ .sorted()
+ .toArray(String[]::new);
+
+ reflectiveClass.produce(ReflectiveClassBuildItem.builder(modelClasses)
+ .methods()
+ .fields()
+ .build());
+ }
+}
diff --git a/extensions/ocsf/pom.xml b/extensions/ocsf/pom.xml
new file mode 100644
index 0000000000..81ee496b05
--- /dev/null
+++ b/extensions/ocsf/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-extensions</artifactId>
+ <version>3.37.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>camel-quarkus-ocsf-parent</artifactId>
+ <name>Camel Quarkus :: OCSF</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>deployment</module>
+ <module>runtime</module>
+ </modules>
+</project>
diff --git a/extensions/ocsf/runtime/pom.xml b/extensions/ocsf/runtime/pom.xml
new file mode 100644
index 0000000000..1b6a4e3ecb
--- /dev/null
+++ b/extensions/ocsf/runtime/pom.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf-parent</artifactId>
+ <version>3.37.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>camel-quarkus-ocsf</artifactId>
+ <name>Camel Quarkus :: OCSF :: Runtime</name>
+ <description>Marshal and unmarshal OCSF (Open Cybersecurity Schema
Framework) security events to/from JSON.</description>
+
+ <properties>
+ <camel.quarkus.jvmSince>3.37.0</camel.quarkus.jvmSince>
+ <camel.quarkus.nativeSince>3.37.0</camel.quarkus.nativeSince>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-ocsf</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-jackson</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-extension-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <annotationProcessorPaths>
+ <path>
+ <groupId>io.quarkus</groupId>
+
<artifactId>quarkus-extension-processor</artifactId>
+ <version>${quarkus.version}</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+
+ <profiles>
+ <profile>
+ <id>full</id>
+ <activation>
+ <property>
+ <name>!quickly</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>update-extension-doc-page</id>
+ <goals>
+ <goal>update-extension-doc-page</goal>
+ </goals>
+ <phase>process-classes</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/extensions/ocsf/runtime/src/main/doc/usage.adoc
b/extensions/ocsf/runtime/src/main/doc/usage.adoc
new file mode 100644
index 0000000000..9766f91ccd
--- /dev/null
+++ b/extensions/ocsf/runtime/src/main/doc/usage.adoc
@@ -0,0 +1,71 @@
+The OCSF (Open Cybersecurity Schema Framework) extension provides support for
marshalling and unmarshalling security events following the OCSF specification.
+
+== Basic Usage
+
+=== Marshalling OCSF Events
+
+[source,java]
+----
+from("direct:start")
+ .marshal().ocsf()
+ .to("kafka:security-events");
+----
+
+=== Unmarshalling OCSF Events
+
+[source,java]
+----
+from("kafka:security-events")
+ .unmarshal().ocsf()
+ .to("direct:process");
+----
+
+=== Unmarshalling to a Specific Event Class
+
+[source,java]
+----
+from("kafka:security-events")
+ .unmarshal().ocsf(DetectionFinding.class)
+ .to("direct:process");
+----
+
+== Supported OCSF Event Classes
+
+This extension includes support for 34 OCSF event classes including:
+
+* *Findings*: `DetectionFinding`, `SecurityFinding`, `VulnerabilityFinding`,
`ComplianceFinding`
+* *System Activity*: `FileActivity`, `ProcessActivity`, `KernelActivity`,
`MemoryActivity`
+* *Network Activity*: `NetworkActivity`, `HttpActivity`, `DnsActivity`,
`SshActivity`
+* *IAM*: `Authentication`, `AuthorizeSession`, `AccountChange`,
`GroupManagement`
+* *Application Activity*: `ApiActivity`, `DatastoreActivity`,
`WebResourcesActivity`
+
+All event classes extend `OcsfEvent` which provides common attributes like
`time`, `severity_id`, `class_uid`, and `metadata`.
+
+== Example: Creating a Detection Finding
+
+[source,java]
+----
+import org.apache.camel.dataformat.ocsf.model.DetectionFinding;
+import org.apache.camel.dataformat.ocsf.model.FindingInfo;
+import org.apache.camel.dataformat.ocsf.OcsfConstants;
+
+DetectionFinding finding = new DetectionFinding();
+finding.setActivityId(OcsfConstants.ACTIVITY_CREATE);
+finding.setSeverityId(OcsfConstants.SEVERITY_HIGH);
+finding.setTime(System.currentTimeMillis());
+finding.setIsAlert(true);
+
+FindingInfo info = new FindingInfo();
+info.setTitle("Malware Detection");
+info.setDesc("Potential malware detected on endpoint");
+finding.setFindingInfo(info);
+
+from("direct:start")
+ .setBody(constant(finding))
+ .marshal().ocsf()
+ .to("splunk-hec:...");
+----
+
+== Native Mode Support
+
+The OCSF extension fully supports native mode compilation. All OCSF model
classes are automatically registered for reflection during the build process.
diff --git
a/extensions/ocsf/runtime/src/main/resources/META-INF/quarkus-extension.yaml
b/extensions/ocsf/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000000..b3ddf5ed72
--- /dev/null
+++ b/extensions/ocsf/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+# This is a generated file. Do not edit directly!
+# To re-generate, run the following command from the top level directory:
+#
+# mvn -N cq:update-quarkus-metadata
+#
+---
+name: "Camel OCSF"
+description: "Marshal and unmarshal OCSF (Open Cybersecurity Schema Framework)
security events to/from JSON"
+metadata:
+ icon-url:
"https://raw.githubusercontent.com/apache/camel-website/main/antora-ui-camel/src/img/logo-d.svg"
+ sponsor: "Apache Software Foundation"
+ guide:
"https://camel.apache.org/camel-quarkus/latest/reference/extensions/ocsf.html"
+ categories:
+ - "integration"
+ status: "stable"
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 5594eb8e69..7516fe9884 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -220,6 +220,7 @@
<module>oaipmh</module>
<module>oauth</module>
<module>observability-services</module>
+ <module>ocsf</module>
<module>ognl</module>
<module>olingo4</module>
<module>once</module>
diff --git a/integration-tests/ocsf/pom.xml b/integration-tests/ocsf/pom.xml
new file mode 100644
index 0000000000..1cf5e6be8a
--- /dev/null
+++ b/integration-tests/ocsf/pom.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-build-parent-it</artifactId>
+ <version>3.37.0-SNAPSHOT</version>
+ <relativePath>../../poms/build-parent-it/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>camel-quarkus-integration-test-ocsf</artifactId>
+ <name>Camel Quarkus :: Integration Tests :: OCSF</name>
+ <description>Integration tests for Camel Quarkus OCSF
extension</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-direct</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-resteasy-jackson</artifactId>
+ </dependency>
+
+ <!-- test dependencies -->
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>native</id>
+ <activation>
+ <property>
+ <name>native</name>
+ </property>
+ </activation>
+ <properties>
+ <quarkus.native.enabled>true</quarkus.native.enabled>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>virtualDependencies</id>
+ <activation>
+ <property>
+ <name>!noVirtualDependencies</name>
+ </property>
+ </activation>
+ <dependencies>
+ <!-- The following dependencies guarantee that this module is
built after them. You can update them by running `mvn process-resources
-Pformat -N` from the source tree root directory -->
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-direct-deployment</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf-deployment</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
+
+</project>
diff --git
a/integration-tests/ocsf/src/main/java/org/apache/camel/quarkus/component/ocsf/it/OcsfResource.java
b/integration-tests/ocsf/src/main/java/org/apache/camel/quarkus/component/ocsf/it/OcsfResource.java
new file mode 100644
index 0000000000..8ad2b9496a
--- /dev/null
+++
b/integration-tests/ocsf/src/main/java/org/apache/camel/quarkus/component/ocsf/it/OcsfResource.java
@@ -0,0 +1,378 @@
+/*
+ * 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.component.ocsf.it;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.dataformat.ocsf.OcsfConstants;
+import org.apache.camel.dataformat.ocsf.model.Attack;
+import org.apache.camel.dataformat.ocsf.model.DetectionFinding;
+import org.apache.camel.dataformat.ocsf.model.FindingInfo;
+import org.apache.camel.dataformat.ocsf.model.Metadata;
+import org.apache.camel.dataformat.ocsf.model.OcsfEvent;
+import org.apache.camel.dataformat.ocsf.model.Product;
+import org.apache.camel.dataformat.ocsf.model.Remediation;
+import org.apache.camel.dataformat.ocsf.model.ResourceDetails;
+import org.apache.camel.dataformat.ocsf.model.Tactic;
+import org.apache.camel.dataformat.ocsf.model.Technique;
+
+@Path("/ocsf")
+@ApplicationScoped
+public class OcsfResource {
+
+ @Inject
+ ProducerTemplate producerTemplate;
+
+ @Inject
+ ObjectMapper objectMapper;
+
+ @Path("/marshal/event")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response marshalEvent(String message) {
+ OcsfEvent event = new OcsfEvent();
+ event.setClassUid(OcsfConstants.CLASS_DETECTION_FINDING);
+ event.setCategoryUid(OcsfConstants.CATEGORY_FINDINGS);
+ event.setActivityId(OcsfConstants.ACTIVITY_CREATE);
+ event.setSeverityId(OcsfConstants.SEVERITY_HIGH);
+ event.setTime(System.currentTimeMillis());
+ event.setMessage(message);
+
+ String json = producerTemplate.requestBody("direct:marshal-event",
event, String.class);
+ return Response.ok(json).build();
+ }
+
+ @Path("/unmarshal/event")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response unmarshalEvent(String json) {
+ OcsfEvent event =
producerTemplate.requestBody("direct:unmarshal-event", json, OcsfEvent.class);
+ return Response.ok(event.getMessage()).build();
+ }
+
+ @Path("/marshal/finding")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response marshalFinding(String title) {
+ DetectionFinding finding = new DetectionFinding();
+ finding.setIsAlert(true);
+
+ FindingInfo info = new FindingInfo();
+ info.setTitle(title);
+ info.setDesc("Test security finding");
+ finding.setFindingInfo(info);
+
+ String json = producerTemplate.requestBody("direct:marshal-finding",
finding, String.class);
+ return Response.ok(json).build();
+ }
+
+ @Path("/unmarshal/finding")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response unmarshalFinding(String json) {
+ DetectionFinding finding =
producerTemplate.requestBody("direct:unmarshal-finding", json,
DetectionFinding.class);
+ return Response.ok(finding.getFindingInfo().getTitle()).build();
+ }
+
+ @Path("/roundtrip/event")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response roundtripEvent(String message) {
+ // Create event, marshal to JSON, unmarshal back to event
+ OcsfEvent event = new OcsfEvent();
+ event.setMessage(message);
+ event.setSeverityId(OcsfConstants.SEVERITY_MEDIUM);
+ event.setTime(System.currentTimeMillis());
+
+ String json = producerTemplate.requestBody("direct:marshal-event",
event, String.class);
+ OcsfEvent result =
producerTemplate.requestBody("direct:unmarshal-event", json, OcsfEvent.class);
+ return Response.ok(result.getMessage()).build();
+ }
+
+ @Path("/roundtrip/finding")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response roundtripFinding(String title) {
+ // Create finding via JSON, unmarshal to DetectionFinding, marshal
back, unmarshal again
+ String inputJson = String.format("""
+ {
+ "finding_info": {
+ "title": "%s"
+ },
+ "is_alert": true
+ }
+ """, title);
+
+ DetectionFinding finding =
producerTemplate.requestBody("direct:unmarshal-finding", inputJson,
+ DetectionFinding.class);
+ String json = producerTemplate.requestBody("direct:marshal-finding",
finding, String.class);
+ DetectionFinding result =
producerTemplate.requestBody("direct:unmarshal-finding", json,
DetectionFinding.class);
+
+ return Response.ok(result.getFindingInfo().getTitle()).build();
+ }
+
+ @Path("/unmarshal/unknown-properties")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response unmarshalWithUnknownProperties(String json) {
+ OcsfEvent event =
producerTemplate.requestBody("direct:unmarshal-event", json, OcsfEvent.class);
+ Map<String, Object> additionalProps = event.getAdditionalProperties();
+ if (additionalProps != null &&
additionalProps.containsKey("unknown_property")) {
+ return
Response.ok(additionalProps.get("unknown_property").toString()).build();
+ }
+ return Response.ok("no_unknown_properties").build();
+ }
+
+ @Path("/marshal/complex-event")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response marshalComplexEvent(String message) {
+ OcsfEvent event = new OcsfEvent();
+ event.setClassUid(OcsfConstants.CLASS_DETECTION_FINDING);
+ event.setClassName("Detection Finding");
+ event.setCategoryUid(OcsfConstants.CATEGORY_FINDINGS);
+ event.setCategoryName("Findings");
+ event.setActivityId(OcsfConstants.ACTIVITY_CREATE);
+ event.setSeverityId(OcsfConstants.SEVERITY_HIGH);
+ event.setTime(System.currentTimeMillis());
+ event.setMessage(message);
+
+ String json = producerTemplate.requestBody("direct:marshal-event",
event, String.class);
+ return Response.ok(json).build();
+ }
+
+ @Path("/marshal/complex-finding")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response marshalComplexFinding(String title) {
+ DetectionFinding finding = new DetectionFinding();
+ finding.setAdditionalProperty("activity_id",
OcsfConstants.ACTIVITY_CREATE);
+ finding.setAdditionalProperty("severity_id",
OcsfConstants.SEVERITY_CRITICAL);
+ finding.setAdditionalProperty("time", System.currentTimeMillis() /
1000);
+ finding.setAdditionalProperty("class_uid",
OcsfConstants.CLASS_DETECTION_FINDING);
+ finding.setIsAlert(true);
+ finding.setRiskLevelId(Integer.valueOf(4));
+ finding.setRiskLevel("High");
+ finding.setConfidence("High");
+ finding.setConfidenceScore(90);
+
+ FindingInfo info = new FindingInfo();
+ info.setUid("finding-123");
+ info.setTitle(title);
+ info.setDesc("Test complex finding");
+ finding.setFindingInfo(info);
+
+ String json = producerTemplate.requestBody("direct:marshal-finding",
finding, String.class);
+ return Response.ok(json).build();
+ }
+
+ @Path("/parse/complete-finding")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response parseCompleteFinding() {
+ try {
+ InputStream is =
getClass().getResourceAsStream("/ocsf-detection-finding-example.json");
+ if (is == null) {
+ return Response.serverError().entity("Resource
/ocsf-detection-finding-example.json not found").build();
+ }
+ String json = new String(is.readAllBytes(),
StandardCharsets.UTF_8);
+
+ DetectionFinding finding =
producerTemplate.requestBody("direct:unmarshal-finding", json,
+ DetectionFinding.class);
+
+ Map<String, Object> result = new HashMap<>();
+ result.put("is_alert", finding.getIsAlert());
+ result.put("risk_level", finding.getRiskLevel());
+ result.put("confidence", finding.getConfidence());
+ result.put("title", finding.getFindingInfo().getTitle());
+
+ if (finding.getFindingInfo().getAttacks() != null &&
!finding.getFindingInfo().getAttacks().isEmpty()) {
+ Attack attack = finding.getFindingInfo().getAttacks().get(0);
+ result.put("tactic_name", attack.getTactic().getName());
+ result.put("technique_uid", attack.getTechnique().getUid());
+ }
+
+ if (finding.getResources() != null &&
!finding.getResources().isEmpty()) {
+ result.put("resource_name",
finding.getResources().get(0).getName());
+ }
+
+ if (finding.getRemediation() != null) {
+ result.put("has_remediation", true);
+ }
+
+ return Response.ok(result).build();
+ } catch (Exception e) {
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+ }
+
+ @Path("/build/complex-finding")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response buildComplexFinding(String title) {
+ DetectionFinding finding = new DetectionFinding();
+
+ finding.setAdditionalProperty("class_uid",
OcsfConstants.CLASS_DETECTION_FINDING);
+ finding.setAdditionalProperty("class_name", "Detection Finding");
+ finding.setAdditionalProperty("category_uid",
OcsfConstants.CATEGORY_FINDINGS);
+ finding.setAdditionalProperty("category_name", "Findings");
+ finding.setAdditionalProperty("activity_id",
OcsfConstants.ACTIVITY_CREATE);
+ finding.setAdditionalProperty("activity_name", "Create");
+ finding.setAdditionalProperty("severity_id",
OcsfConstants.SEVERITY_HIGH);
+ finding.setAdditionalProperty("severity", "High");
+ finding.setAdditionalProperty("time", 1706198400L);
+ finding.setAdditionalProperty("message", "Security finding detected");
+
+ finding.setIsAlert(true);
+ finding.setRiskLevel("High");
+ finding.setRiskLevelId(Integer.valueOf(4));
+ finding.setRiskScore(85);
+ finding.setConfidence("High");
+ finding.setConfidenceId(Integer.valueOf(3));
+ finding.setConfidenceScore(90);
+
+ FindingInfo info = new FindingInfo();
+ info.setUid("finding-001");
+ info.setTitle(title);
+ info.setDesc("Test security finding with complete details");
+ info.setTypes(Arrays.asList("Application/Injection", "TTPs/Initial
Access"));
+ finding.setFindingInfo(info);
+
+ Attack attack = new Attack();
+ Tactic tactic = new Tactic();
+ tactic.setName("Initial Access");
+ tactic.setUid("TA0001");
+ attack.setTactic(tactic);
+
+ Technique technique = new Technique();
+ technique.setName("Exploit Public-Facing Application");
+ technique.setUid("T1190");
+ attack.setTechnique(technique);
+ attack.setVersion("14.0");
+ info.setAttacks(Arrays.asList(attack));
+
+ Remediation remediation = new Remediation();
+ remediation.setDesc("Investigate and remediate the security finding");
+
remediation.setReferences(Arrays.asList("https://example.com/remediation"));
+ finding.setRemediation(remediation);
+
+ ResourceDetails resource = new ResourceDetails();
+ resource.setUid("resource-001");
+ resource.setName("test-resource");
+ resource.setType("Test::Resource");
+ finding.setResources(Arrays.asList(resource));
+
+ Metadata metadata = new Metadata();
+ metadata.setVersion("1.8.0");
+ Product product = new Product();
+ product.setName("Test Product");
+ product.setVendorName("Test Vendor");
+ metadata.setProduct(product);
+ finding.setAdditionalProperty("metadata", metadata);
+
+ String json = producerTemplate.requestBody("direct:marshal-finding",
finding, String.class);
+ return Response.ok(json).build();
+ }
+
+ @Path("/parse/generic-event")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response parseGenericEvent(String json) {
+ OcsfEvent event =
producerTemplate.requestBody("direct:unmarshal-generic", json, OcsfEvent.class);
+
+ Map<String, Object> result = new HashMap<>();
+ result.put("class_uid", event.getClassUid());
+ result.put("severity_id", event.getSeverityId());
+ result.put("message", event.getMessage());
+
+ if (event.getMetadata() != null) {
+ result.put("metadata_version", event.getMetadata().getVersion());
+ if (event.getMetadata().getProduct() != null) {
+ result.put("product_name",
event.getMetadata().getProduct().getName());
+ }
+ }
+
+ result.put("has_additional_properties",
+ event.getAdditionalProperties() != null &&
!event.getAdditionalProperties().isEmpty());
+
+ return Response.ok(result).build();
+ }
+
+ @Path("/filter/severity")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response filterBySeverity(String json) {
+ try {
+ // Parse JSON to read severity_id directly
+ JsonNode node = objectMapper.readTree(json);
+ int severityId = node.has("severity_id") ?
node.get("severity_id").asInt(1) : 1;
+
+ // Simulate AWS Security Hub pattern: route based on severity
+ // severity_id: 1=Other, 2=Informational, 3=Low, 4=Medium, 5=High,
6=Critical
+ if (severityId >= 4) {
+ return Response.ok("high-severity").build();
+ } else {
+ return Response.ok("normal-severity").build();
+ }
+ } catch (Exception e) {
+ return Response.serverError().entity("Error parsing JSON: " +
e.getMessage()).build();
+ }
+ }
+
+ @Path("/marshal/pretty")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response marshalPretty(String message) {
+ OcsfEvent event = new OcsfEvent();
+ event.setAdditionalProperty("class_uid",
OcsfConstants.CLASS_DETECTION_FINDING);
+ event.setAdditionalProperty("severity_id",
OcsfConstants.SEVERITY_MEDIUM);
+ event.setAdditionalProperty("time", System.currentTimeMillis());
+ event.setMessage(message);
+
+ String json = producerTemplate.requestBody("direct:marshal-pretty",
event, String.class);
+ return Response.ok(json).build();
+ }
+}
diff --git
a/integration-tests/ocsf/src/main/java/org/apache/camel/quarkus/component/ocsf/it/OcsfRoutes.java
b/integration-tests/ocsf/src/main/java/org/apache/camel/quarkus/component/ocsf/it/OcsfRoutes.java
new file mode 100644
index 0000000000..597084a094
--- /dev/null
+++
b/integration-tests/ocsf/src/main/java/org/apache/camel/quarkus/component/ocsf/it/OcsfRoutes.java
@@ -0,0 +1,51 @@
+/*
+ * 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.component.ocsf.it;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.dataformat.ocsf.model.DetectionFinding;
+
+@ApplicationScoped
+public class OcsfRoutes extends RouteBuilder {
+ @Override
+ public void configure() throws Exception {
+ // Marshal OcsfEvent to JSON
+ from("direct:marshal-event")
+ .marshal().ocsf();
+
+ // Unmarshal JSON to OcsfEvent
+ from("direct:unmarshal-event")
+ .unmarshal().ocsf();
+
+ // Marshal DetectionFinding to JSON
+ from("direct:marshal-finding")
+ .marshal().ocsf();
+
+ // Unmarshal JSON to DetectionFinding
+ from("direct:unmarshal-finding")
+ .unmarshal().ocsf(DetectionFinding.class);
+
+ // Unmarshal JSON to generic OcsfEvent
+ from("direct:unmarshal-generic")
+ .unmarshal().ocsf();
+
+ // Marshal with pretty print
+ from("direct:marshal-pretty")
+ .marshal().ocsf();
+ }
+}
diff --git a/integration-tests/ocsf/src/main/resources/application.properties
b/integration-tests/ocsf/src/main/resources/application.properties
new file mode 100644
index 0000000000..c5d4ed544f
--- /dev/null
+++ b/integration-tests/ocsf/src/main/resources/application.properties
@@ -0,0 +1,19 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+# Include JSON resources in native image
+quarkus.native.resources.includes=*.json
diff --git
a/integration-tests/ocsf/src/main/resources/ocsf-detection-finding-example.json
b/integration-tests/ocsf/src/main/resources/ocsf-detection-finding-example.json
new file mode 100644
index 0000000000..ea45129849
--- /dev/null
+++
b/integration-tests/ocsf/src/main/resources/ocsf-detection-finding-example.json
@@ -0,0 +1,168 @@
+{
+ "class_uid": 2004,
+ "class_name": "Detection Finding",
+ "category_uid": 2,
+ "category_name": "Findings",
+ "activity_id": 1,
+ "activity_name": "Create",
+ "severity_id": 4,
+ "severity": "High",
+ "status_id": 1,
+ "status": "New",
+ "time": 1706198400,
+ "time_dt": "2024-01-25T12:00:00Z",
+ "timezone_offset": 0,
+ "type_uid": 200401,
+ "type_name": "Detection Finding: Create",
+ "message": "Potential cryptocurrency mining activity detected on EC2
instance",
+
+ "metadata": {
+ "version": "1.8.0",
+ "product": {
+ "name": "GuardDuty",
+ "vendor_name": "AWS",
+ "uid": "arn:aws:securityhub:us-east-1::product/aws/guardduty",
+ "version": "2.0"
+ },
+ "profiles": ["cloud", "security_control"],
+ "log_name": "Security Hub Findings",
+ "log_provider": "AWS",
+ "original_time": "2024-01-25T11:58:32Z"
+ },
+
+ "is_alert": true,
+ "risk_level": "High",
+ "risk_level_id": 4,
+ "risk_score": 78,
+ "confidence": "High",
+ "confidence_id": 3,
+ "confidence_score": 85,
+
+ "finding_info": {
+ "uid":
"arn:aws:securityhub:us-east-1:123456789012:finding/a1b2c3d4-5678-90ab-cdef-example11111",
+ "title": "CryptoCurrency:EC2/BitcoinTool.B!DNS",
+ "desc": "EC2 instance i-1234567890abcdef0 is querying a domain name that
is associated with Bitcoin-related activity.",
+ "types": ["TTPs/Impact/Resource Hijacking"],
+ "first_seen_time": 1706194800,
+ "last_seen_time": 1706198400,
+ "created_time": 1706198400,
+ "modified_time": 1706198400,
+ "src_url":
"https://console.aws.amazon.com/guardduty/home?region=us-east-1#/findings",
+ "attacks": [
+ {
+ "tactic": {
+ "name": "Impact",
+ "uid": "TA0040"
+ },
+ "technique": {
+ "name": "Resource Hijacking",
+ "uid": "T1496"
+ },
+ "version": "14.0"
+ }
+ ]
+ },
+
+ "resources": [
+ {
+ "uid": "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0",
+ "name": "production-web-server",
+ "type": "AWS::EC2::Instance",
+ "cloud_partition": "aws",
+ "region": "us-east-1",
+ "labels": ["Environment:Production", "Team:WebPlatform"],
+ "data": {
+ "InstanceId": "i-1234567890abcdef0",
+ "InstanceType": "t3.large",
+ "LaunchTime": "2024-01-10T08:30:00Z",
+ "ImageId": "ami-0abcdef1234567890",
+ "VpcId": "vpc-1234567890abcdef0",
+ "SubnetId": "subnet-1234567890abcdef0",
+ "PrivateIpAddress": "10.0.1.50",
+ "PublicIpAddress": "54.123.45.67"
+ }
+ }
+ ],
+
+ "evidences": [
+ {
+ "data": {
+ "dns_query": "pool.bitcoin.com",
+ "dns_record_type": "A",
+ "query_count": 150,
+ "first_query_time": "2024-01-25T10:00:00Z",
+ "last_query_time": "2024-01-25T11:58:00Z"
+ }
+ }
+ ],
+
+ "actor": {
+ "process": {
+ "name": "xmrig",
+ "pid": 12345,
+ "cmd_line": "/tmp/xmrig --donate-level 1 -o pool.bitcoin.com:3333",
+ "file": {
+ "name": "xmrig",
+ "path": "/tmp/xmrig",
+ "type": "Regular File",
+ "type_id": 1
+ },
+ "user": {
+ "name": "ec2-user",
+ "uid": "1000"
+ }
+ }
+ },
+
+ "cloud": {
+ "provider": "AWS",
+ "region": "us-east-1",
+ "zone": "us-east-1a",
+ "account": {
+ "uid": "123456789012",
+ "name": "production-account",
+ "type": "AWS Account"
+ },
+ "org": {
+ "uid": "o-exampleorgid",
+ "name": "MyCompany"
+ }
+ },
+
+ "remediation": {
+ "desc": "Investigate the EC2 instance for unauthorized cryptocurrency
mining software. Check running processes and terminate suspicious ones. Review
security groups and network ACLs.",
+ "references": [
+
"https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_finding-types-ec2.html",
+ "https://attack.mitre.org/techniques/T1496/"
+ ]
+ },
+
+ "observables": [
+ {
+ "name": "dst_endpoint.domain",
+ "type": "Hostname",
+ "type_id": 1,
+ "value": "pool.bitcoin.com"
+ },
+ {
+ "name": "src_endpoint.ip",
+ "type": "IP Address",
+ "type_id": 2,
+ "value": "10.0.1.50"
+ },
+ {
+ "name": "actor.process.name",
+ "type": "Process Name",
+ "type_id": 9,
+ "value": "xmrig"
+ }
+ ],
+
+ "unmapped": {
+ "ProductArn": "arn:aws:securityhub:us-east-1::product/aws/guardduty",
+ "GeneratorId":
"arn:aws:guardduty:us-east-1:123456789012:detector/12abc34d567e8fa901bc2d34e56789f0",
+ "AwsAccountId": "123456789012",
+ "WorkflowState": "NEW",
+ "RecordState": "ACTIVE"
+ }
+}
diff --git
a/integration-tests/ocsf/src/test/java/org/apache/camel/quarkus/component/ocsf/it/OcsfIT.java
b/integration-tests/ocsf/src/test/java/org/apache/camel/quarkus/component/ocsf/it/OcsfIT.java
new file mode 100644
index 0000000000..ff9d0ed937
--- /dev/null
+++
b/integration-tests/ocsf/src/test/java/org/apache/camel/quarkus/component/ocsf/it/OcsfIT.java
@@ -0,0 +1,24 @@
+/*
+ * 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.component.ocsf.it;
+
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+
+@QuarkusIntegrationTest
+class OcsfIT extends OcsfTest {
+
+}
diff --git
a/integration-tests/ocsf/src/test/java/org/apache/camel/quarkus/component/ocsf/it/OcsfTest.java
b/integration-tests/ocsf/src/test/java/org/apache/camel/quarkus/component/ocsf/it/OcsfTest.java
new file mode 100644
index 0000000000..cc162056fa
--- /dev/null
+++
b/integration-tests/ocsf/src/test/java/org/apache/camel/quarkus/component/ocsf/it/OcsfTest.java
@@ -0,0 +1,350 @@
+/*
+ * 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.component.ocsf.it;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+
+@QuarkusTest
+class OcsfTest {
+
+ @Test
+ void testMarshalEvent() {
+ String message = "Test security event";
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body(message)
+ .post("/ocsf/marshal/event")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .body(containsString("\"message\":\"" + message + "\""))
+ .body(containsString("\"severity_id\":4"));
+ }
+
+ @Test
+ void testUnmarshalEvent() {
+ String json = """
+ {
+ "class_uid": 2004,
+ "category_uid": 2,
+ "activity_id": 1,
+ "severity_id": 4,
+ "time": 1706000000,
+ "message": "Suspicious activity detected"
+ }
+ """;
+
+ RestAssured.given()
+ .contentType(ContentType.JSON)
+ .body(json)
+ .post("/ocsf/unmarshal/event")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.TEXT)
+ .body(equalTo("Suspicious activity detected"));
+ }
+
+ @Test
+ void testMarshalDetectionFinding() {
+ String title = "Malware Detected";
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body(title)
+ .post("/ocsf/marshal/finding")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .body(containsString("\"title\":\"" + title + "\""))
+ .body(containsString("\"is_alert\":true"));
+ }
+
+ @Test
+ void testUnmarshalDetectionFinding() {
+ String json = """
+ {
+ "finding_info": {
+ "title": "Data Exfiltration Attempt",
+ "desc": "Unusual outbound data transfer detected"
+ },
+ "is_alert": true
+ }
+ """;
+
+ RestAssured.given()
+ .contentType(ContentType.JSON)
+ .body(json)
+ .post("/ocsf/unmarshal/finding")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.TEXT)
+ .body(equalTo("Data Exfiltration Attempt"));
+ }
+
+ @Test
+ void testRoundtripEvent() {
+ String message = "Test roundtrip event";
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body(message)
+ .post("/ocsf/roundtrip/event")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.TEXT)
+ .body(equalTo(message));
+ }
+
+ @Test
+ void testRoundtripDetectionFinding() {
+ String title = "Test roundtrip finding";
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body(title)
+ .post("/ocsf/roundtrip/finding")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.TEXT)
+ .body(equalTo(title));
+ }
+
+ @Test
+ void testUnmarshalWithUnknownProperties() {
+ String json = """
+ {
+ "class_uid": 2004,
+ "severity_id": 3,
+ "time": 1706000000,
+ "unknown_property": "should be captured",
+ "another_unknown": 123
+ }
+ """;
+
+ RestAssured.given()
+ .contentType(ContentType.JSON)
+ .body(json)
+ .post("/ocsf/unmarshal/unknown-properties")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.TEXT)
+ .body(equalTo("should be captured"));
+ }
+
+ @Test
+ void testMarshalComplexEvent() {
+ String message = "Test complex event";
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body(message)
+ .post("/ocsf/marshal/complex-event")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .body(containsString("\"class_uid\":2004"))
+ .body(containsString("\"class_name\":\"Detection Finding\""))
+ .body(containsString("\"category_name\":\"Findings\""))
+ .body(containsString("\"message\":\"" + message + "\""));
+ }
+
+ @Test
+ void testMarshalComplexFinding() {
+ String title = "Complex Security Finding";
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body(title)
+ .post("/ocsf/marshal/complex-finding")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .body(containsString("\"class_uid\":2004"))
+ .body(containsString("\"is_alert\":true"))
+ .body(containsString("\"risk_level\":\"High\""))
+ .body(containsString("\"risk_level_id\":4"))
+ .body(containsString("\"confidence\":\"High\""))
+ .body(containsString("\"confidence_score\":90"))
+ .body(containsString("\"title\":\"" + title + "\""))
+ .body(containsString("\"uid\":\"finding-123\""));
+ }
+
+ @Test
+ void testParseCompleteFinding() {
+ RestAssured.given()
+ .get("/ocsf/parse/complete-finding")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .body("is_alert", is(true))
+ .body("risk_level", equalTo("High"))
+ .body("confidence", equalTo("High"))
+ .body("title", containsString("CryptoCurrency"))
+ .body("tactic_name", equalTo("Impact"))
+ .body("technique_uid", equalTo("T1496"))
+ .body("resource_name", equalTo("production-web-server"))
+ .body("has_remediation", is(true));
+ }
+
+ @Test
+ void testBuildComplexFinding() {
+ String title = "SQL Injection Attempt";
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body(title)
+ .post("/ocsf/build/complex-finding")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .body(containsString("\"class_uid\":2004"))
+ .body(containsString("\"is_alert\":true"))
+ .body(containsString("\"risk_level\":\"High\""))
+ .body(containsString("\"confidence_score\":90"))
+ .body(containsString("\"title\":\"" + title + "\""))
+ .body(containsString("\"tactic\""))
+ .body(containsString("\"uid\":\"TA0001\""))
+ .body(containsString("\"technique\""))
+ .body(containsString("\"uid\":\"T1190\""))
+ .body(containsString("\"remediation\""))
+ .body(containsString("\"resources\""))
+ .body(containsString("\"metadata\""))
+ .body(containsString("\"version\":\"1.8.0\""));
+ }
+
+ @Test
+ void testParseGenericEvent() {
+ String json = """
+ {
+ "class_uid": 1001,
+ "class_name": "File System Activity",
+ "category_uid": 1,
+ "category_name": "System Activity",
+ "activity_id": 1,
+ "activity_name": "Create",
+ "severity_id": 2,
+ "severity": "Informational",
+ "time": 1706198400,
+ "message": "File created: /var/log/application.log",
+ "metadata": {
+ "version": "1.8.0",
+ "product": {
+ "name": "File Integrity Monitor",
+ "vendor_name": "SecurityTools"
+ }
+ },
+ "file": {
+ "name": "application.log",
+ "path": "/var/log/application.log"
+ }
+ }
+ """;
+
+ RestAssured.given()
+ .contentType(ContentType.JSON)
+ .body(json)
+ .post("/ocsf/parse/generic-event")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .body("class_uid", is(1001))
+ .body("severity_id", is(2))
+ .body("message", equalTo("File created:
/var/log/application.log"))
+ .body("metadata_version", equalTo("1.8.0"))
+ .body("product_name", equalTo("File Integrity Monitor"))
+ .body("has_additional_properties", is(true));
+ }
+
+ @Test
+ void testFilterBySeverityHighSeverity() {
+ String json = """
+ {
+ "severity_id": 5,
+ "finding_info": {
+ "title": "Critical Security Alert"
+ }
+ }
+ """;
+
+ RestAssured.given()
+ .contentType(ContentType.JSON)
+ .body(json)
+ .post("/ocsf/filter/severity")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.TEXT)
+ .body(equalTo("high-severity"));
+ }
+
+ @Test
+ void testFilterBySeverityNormalSeverity() {
+ String json = """
+ {
+ "severity_id": 2,
+ "finding_info": {
+ "title": "Informational Alert"
+ }
+ }
+ """;
+
+ RestAssured.given()
+ .contentType(ContentType.JSON)
+ .body(json)
+ .post("/ocsf/filter/severity")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.TEXT)
+ .body(equalTo("normal-severity"));
+ }
+
+ @Test
+ void testFilterBySeverityMediumSeverity() {
+ String json = """
+ {
+ "severity_id": 4,
+ "finding_info": {
+ "title": "Medium Severity Alert"
+ }
+ }
+ """;
+
+ RestAssured.given()
+ .contentType(ContentType.JSON)
+ .body(json)
+ .post("/ocsf/filter/severity")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.TEXT)
+ .body(equalTo("high-severity"));
+ }
+
+ @Test
+ void testMarshalPretty() {
+ String message = "Pretty printed event";
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body(message)
+ .post("/ocsf/marshal/pretty")
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.JSON)
+ .body(containsString("\"message\""))
+ .body(containsString("\"" + message + "\""))
+ .body(containsString("\"severity_id\""));
+ }
+}
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index e912e8dd10..cccbb2b8c2 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -191,6 +191,7 @@
<module>oaipmh</module>
<module>oauth</module>
<module>observability-services</module>
+ <module>ocsf</module>
<module>ognl</module>
<module>olingo4</module>
<module>once</module>
diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml
index bde25a7bd5..024dfa3bee 100644
--- a/poms/bom/pom.xml
+++ b/poms/bom/pom.xml
@@ -2397,6 +2397,11 @@
<artifactId>camel-observability-services</artifactId>
<version>${camel.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-ocsf</artifactId>
+ <version>${camel.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-ognl</artifactId>
@@ -5725,6 +5730,16 @@
<artifactId>camel-quarkus-observability-services-deployment</artifactId>
<version>${camel-quarkus.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf</artifactId>
+ <version>${camel-quarkus.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf-deployment</artifactId>
+ <version>${camel-quarkus.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-ognl</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-full-pom.xml
b/poms/bom/src/main/generated/flattened-full-pom.xml
index e0c2990197..f02da07f75 100644
--- a/poms/bom/src/main/generated/flattened-full-pom.xml
+++ b/poms/bom/src/main/generated/flattened-full-pom.xml
@@ -2310,6 +2310,11 @@
<artifactId>camel-observability-services</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<version>4.20.0</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <artifactId>camel-ocsf</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <version>4.20.0</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<artifactId>camel-ognl</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
@@ -5610,6 +5615,16 @@
<artifactId>camel-quarkus-observability-services-deployment</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<version>3.37.0-SNAPSHOT</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <artifactId>camel-quarkus-ocsf</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <version>3.37.0-SNAPSHOT</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <artifactId>camel-quarkus-ocsf-deployment</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <version>3.37.0-SNAPSHOT</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<artifactId>camel-quarkus-ognl</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
diff --git a/poms/bom/src/main/generated/flattened-reduced-pom.xml
b/poms/bom/src/main/generated/flattened-reduced-pom.xml
index 57bfef4a4b..c7097f1cbf 100644
--- a/poms/bom/src/main/generated/flattened-reduced-pom.xml
+++ b/poms/bom/src/main/generated/flattened-reduced-pom.xml
@@ -2300,6 +2300,11 @@
<artifactId>camel-oauth</artifactId>
<version>4.20.0</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-ocsf</artifactId>
+ <version>4.20.0</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-ognl</artifactId>
@@ -5589,6 +5594,16 @@
<artifactId>camel-quarkus-observability-services-deployment</artifactId>
<version>3.37.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf</artifactId>
+ <version>3.37.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ocsf-deployment</artifactId>
+ <version>3.37.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-ognl</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
index b1ab376d11..29ed7b774c 100644
--- a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
+++ b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
@@ -2300,6 +2300,11 @@
<artifactId>camel-oauth</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<version>4.20.0</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <artifactId>camel-ocsf</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <version>4.20.0</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<artifactId>camel-ognl</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
@@ -5589,6 +5594,16 @@
<artifactId>camel-quarkus-observability-services-deployment</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<version>3.37.0-SNAPSHOT</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <artifactId>camel-quarkus-ocsf</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <version>3.37.0-SNAPSHOT</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <artifactId>camel-quarkus-ocsf-deployment</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <version>3.37.0-SNAPSHOT</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<artifactId>camel-quarkus-ognl</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
diff --git a/tooling/scripts/test-categories.yaml
b/tooling/scripts/test-categories.yaml
index 1c4804f4b3..fe0e4e24d0 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -50,6 +50,7 @@ group-02:
- keycloak
- langchain4j-agent
- oaipmh
+ - ocsf
- pubnub
- protobuf
- smallrye-reactive-messaging