From 6c40bb1b2dc7cb72e3426eedc6aef51b59eb9694 Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Thu, 3 Jul 2025 14:10:42 +0300 Subject: [PATCH 01/10] Add deploy-oss --- deploy-oss/pom.xml | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 deploy-oss/pom.xml diff --git a/deploy-oss/pom.xml b/deploy-oss/pom.xml new file mode 100644 index 0000000..2e415a7 --- /dev/null +++ b/deploy-oss/pom.xml @@ -0,0 +1,96 @@ + + 4.0.0 + com.sap.cds + deploy-oss + ${revision} + pom + + Deploy to OSS + This artifact can be used to deploy all required artifacts of cds-feature-auditlog-ng to OSS Nexus + + + true + true + + + + + + maven-install-plugin + 3.1.4 + + + install-cds-feature-auditlog-ng + install + + install-file + + + ${project.groupId} + cds-feature-auditlog-ng + jar + ../cds-feature-auditlog-ng/target/cds-feature-auditlog-ng.jar + ../cds-feature-auditlog-ng/target/cds-feature-auditlog-ng-sources.jar + ../cds-feature-auditlog-ng/target/cds-feature-auditlog-ng-javadoc.jar + ../cds-feature-auditlog-ng/.flattened-pom.xml + ${revision} + + + + install-cds-feature-auditlog-ng-root + install + + install-file + + + ${project.groupId} + cds-feature-auditlog-ng-root + pom + ../.flattened-pom.xml + ../.flattened-pom.xml + ${revision} + + + + + + maven-gpg-plugin + 3.2.7 + + + deploy-cds-feature-auditlog-ng + deploy + + sign-and-deploy-file + + + ${project.groupId} + cds-feature-auditlog-ng + jar + ../cds-feature-auditlog-ng/target/cds-feature-auditlog-ng.jar + ../cds-feature-auditlog-ng/target/cds-feature-auditlog-ng-sources.jar + ../cds-feature-auditlog-ng/target/cds-feature-auditlog-ng-javadoc.jar + ../cds-feature-auditlog-ng/.flattened-pom.xml + ${revision} + + + + deploy-cds-feature-auditlog-ng-root + deploy + + sign-and-deploy-file + + + ${project.groupId} + cds-feature-auditlog-ng-root + pom + ../.flattened-pom.xml + ../.flattened-pom.xml + ${revision} + + + + + + + From 034b8a81ae2b2f6d86642f99d3591a317f9a4ddd Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Thu, 3 Jul 2025 16:37:38 +0300 Subject: [PATCH 02/10] Add finalName and fix the java doc --- cds-feature-auditlog-ng/pom.xml | 27 +++++++++++++++++++ .../auditlog/ng/AuditLogNGCommunicator.java | 4 --- .../ng/CertificateHttpClientConfig.java | 10 +++---- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/cds-feature-auditlog-ng/pom.xml b/cds-feature-auditlog-ng/pom.xml index 4ddffc8..1717030 100644 --- a/cds-feature-auditlog-ng/pom.xml +++ b/cds-feature-auditlog-ng/pom.xml @@ -52,6 +52,7 @@ + ${project.artifactId} maven-surefire-plugin @@ -59,6 +60,32 @@ false + + maven-javadoc-plugin + + ${skipDuringDeploy} + true + all,-missing + + + + + jar + + + + + + + maven-source-plugin + + + + jar + + + + \ No newline at end of file diff --git a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGCommunicator.java b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGCommunicator.java index 6d3cdc4..454a9c8 100644 --- a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGCommunicator.java +++ b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGCommunicator.java @@ -25,10 +25,6 @@ import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceDecorator; import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceIsolationMode; -/** - * Implementation for an audit log {@link Communicator} which provides - * connectivity to the audit log api via the Cloud SDK. - */ public class AuditLogNGCommunicator { private static final Logger logger = LoggerFactory.getLogger(AuditLogNGCommunicator.class); diff --git a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/CertificateHttpClientConfig.java b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/CertificateHttpClientConfig.java index 8a987c8..c45e656 100644 --- a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/CertificateHttpClientConfig.java +++ b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/CertificateHttpClientConfig.java @@ -35,7 +35,7 @@ /** * Provides a configurable HTTP client for certificate-based authentication with retry logic. * Usage example: - * CloseableHttpClient client = RetryHttpClientConfig.builder() + * CloseableHttpClient client = CertificateHttpClientConfig.builder() * .certPem(certString) * .keyPem(keyString) * .keyPassphrase(passphrase) // optional, only for encrypted keys @@ -84,7 +84,7 @@ public CloseableHttpClient getHttpClient() { } /** - * Returns a builder for {@link RetryHttpClientConfig}. + * Returns a builder for {@link CertificateHttpClientConfig}. * * @return a new Builder instance */ @@ -93,7 +93,7 @@ public static Builder builder() { } /** - * Builder for {@link RetryHttpClientConfig}. + * Builder for {@link CertificateHttpClientConfig}. *

* All fields are optional except for certPem and keyPem, which are required. *

@@ -152,8 +152,8 @@ public Builder timeoutMillis(int timeoutMillis) { return this; } /** - * Builds the {@link RetryHttpClientConfig} instance. - * @return a configured RetryHttpClientConfig + * Builds the {@link CertificateHttpClientConfig} instance. + * @return a configured CertificateHttpClientConfig * @throws IllegalArgumentException if certPem or keyPem is missing */ public CertificateHttpClientConfig build() { From 747e9881f1c85acba68a92be3128aa6467869206 Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Wed, 29 Oct 2025 21:16:55 +0200 Subject: [PATCH 03/10] Add support for all event types from the catalog --- .../auditlog/ng/AuditLogNGCommunicator.java | 2 +- .../auditlog/ng/AuditLogNGHandler.java | 71 +++++++++++++++++-- pom.xml | 2 +- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGCommunicator.java b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGCommunicator.java index 454a9c8..b5ebfb9 100644 --- a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGCommunicator.java +++ b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGCommunicator.java @@ -68,7 +68,7 @@ public AuditLogNGCommunicator(ServiceBinding binding) { } } - public String sendBulkRequest(Object auditLogEvents) throws JsonProcessingException { + String sendBulkRequest(Object auditLogEvents) throws JsonProcessingException { logger.debug("Sending bulk request to audit log service"); String bulkRequestJson = serializeBulkRequest(auditLogEvents); HttpPost request = new HttpPost(serviceUrl + AUDITLOG_EVENTS_ENDPOINT); diff --git a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java index 1ef1262..7c17a00 100644 --- a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java +++ b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java @@ -3,20 +3,26 @@ */ package com.sap.cds.feature.auditlog.ng; +import static java.util.Objects.*; +import static org.slf4j.LoggerFactory.*; + import java.time.Instant; import java.util.Collection; -import static java.util.Objects.requireNonNull; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; import org.slf4j.Logger; -import static org.slf4j.LoggerFactory.getLogger; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.sap.cds.CdsData; +import com.sap.cds.services.EventContext; import com.sap.cds.services.auditlog.Access; import com.sap.cds.services.auditlog.Attachment; import com.sap.cds.services.auditlog.Attribute; @@ -62,6 +68,61 @@ public class AuditLogNGHandler implements EventHandler { } @On + public void handleGeneralEvent(EventContext context) { + try { + if (context instanceof SecurityLogContext || context.getEvent().equals("securityLog")) { + LOGGER.debug("Handling security log event"); + handleSecurityEvent(context.as(SecurityLogContext.class)); + return; + } else if (context instanceof DataAccessLogContext || context.getEvent().equals("dataAccessLog")) { + LOGGER.debug("Handling data access log event"); + handleDataAccessEvent(context.as(DataAccessLogContext.class)); + return; + } else if (context instanceof ConfigChangeLogContext || context.getEvent().equals("configChangeLog")) { + LOGGER.debug("Handling configuration change log event"); + handleConfigChangeEvent(context.as(ConfigChangeLogContext.class)); + return; + } else if (context instanceof DataModificationLogContext || context.getEvent().equals("dataModificationLog")) { + LOGGER.debug("Handling data modification log event"); + handleDataModificationEvent(context.as(DataModificationLogContext.class)); + return; + } else { + ArrayNode alsEvents = createGeneralEvent(context); + communicator.sendBulkRequest(alsEvents); + } + } catch (JsonProcessingException e) { + LOGGER.error("Audit Log write exception occurred for general event", e); + throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); + } catch (ErrorStatusException e) { + LOGGER.error("Audit Log service not available for general event", e); + throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_NOT_AVAILABLE, e); + } catch (Exception e) { + LOGGER.error("Unexpected exception while handling general event", e); + throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); + } + } + + private ArrayNode createGeneralEvent(EventContext context) throws JsonProcessingException { + UserInfo userInfo = requireNonNull(context.getUserInfo(), "UserInfo in EventContext must not be null"); + String eventType = requireNonNull((String) context.getEvent(), "EventType in EventContext must not be null"); + Map data = (Map) context.get("data"); + String eventJson = (String) data.get("event"); + + ObjectNode eventEnvelope = buildEventEnvelope(OBJECT_MAPPER, eventType, userInfo); + ObjectNode metadata = buildEventMetadata(); + ObjectNode parsedEventNode = (ObjectNode) OBJECT_MAPPER.readTree(eventJson); + ObjectNode wrappedDataNode = OBJECT_MAPPER.createObjectNode(); + wrappedDataNode.set(eventType, parsedEventNode); + ObjectNode alsData = buildAuditLogEventData(metadata, wrappedDataNode); + eventEnvelope.set("data", alsData); + + ArrayNode result = OBJECT_MAPPER.createArrayNode(); + result.add(eventEnvelope); + + LOGGER.debug("Created general event for Audit Log NG: {}", result.toString()); + return result; + } + public void handleSecurityEvent(SecurityLogContext context) { try { ArrayNode alsEvents = createSecurityEvent(context); @@ -141,7 +202,6 @@ private ObjectNode createLegacySecurityOrigEvent(UserInfo userInfo, SecurityLog return envelop; } - @On public void handleDataAccessEvent(DataAccessLogContext context) { try { ArrayNode alsEvents = createAlsDataAccessEvents(context); @@ -221,7 +281,6 @@ private void addAttributeAccessEvents(UserInfo userInfo, ArrayNode eventArray, A } } - @On public void handleConfigChangeEvent(ConfigChangeLogContext context) { try { ArrayNode alsEvents = createAlsConfigChangeEvents(context); @@ -280,7 +339,6 @@ private ObjectNode buildConfigChangeEvent(UserInfo userInfo, ConfigChange config return buildAlsEvent("configurationChange", userInfo, metadata, "configurationChange", changeNode); } - @On public void handleDataModificationEvent(DataModificationLogContext context) { try { ArrayNode alsEvents = createAlsDataModificationEvents(context); @@ -473,9 +531,8 @@ private ObjectNode buildDataAccessNode(Access access, String attribute, String a */ private void addValueDetails(ObjectNode node, ChangedAttribute attribute, String fieldName) { String attributeName = requireNonNull(attribute.getName(), "ChangedAttribute.getName() is null"); - String newValue = requireNonNull(attribute.getNewValue(), "ChangedAttribute.getNewValue() is null"); node.put(fieldName, attributeName); - node.put("newValue", newValue); + node.put("newValue", attribute.getNewValue() != null ? attribute.getNewValue() : "null"); node.put("oldValue", attribute.getOldValue() != null ? attribute.getOldValue() : "null"); } diff --git a/pom.xml b/pom.xml index ab4b3a5..9e4a285 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ 17 ${java.version} UTF-8 - 4.1.1 + 4.5.0-SNAPSHOT 1.5.8 2.7.2 2.8.3 From 7197725f47bd9f1e18455c507b9179f2bdbe4f1b Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Thu, 30 Oct 2025 10:37:28 +0200 Subject: [PATCH 04/10] Add Unit test --- .../auditlog/ng/AuditLogNGHandlerTest.java | 43 +++++++++++++++++-- .../test/resources/general-event-schema.json | 38 ++++++++++++++++ 2 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 cds-feature-auditlog-ng/src/test/resources/general-event-schema.json diff --git a/cds-feature-auditlog-ng/src/test/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandlerTest.java b/cds-feature-auditlog-ng/src/test/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandlerTest.java index 6b203d1..0ac2756 100644 --- a/cds-feature-auditlog-ng/src/test/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandlerTest.java +++ b/cds-feature-auditlog-ng/src/test/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandlerTest.java @@ -1,21 +1,22 @@ package com.sap.cds.feature.auditlog.ng; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + import java.io.File; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import org.junit.jupiter.api.Assertions; -import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.Mockito; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import org.mockito.MockitoAnnotations; import com.fasterxml.jackson.databind.JsonNode; @@ -25,6 +26,7 @@ import com.networknt.schema.JsonSchemaFactory; import com.networknt.schema.SpecVersion; import com.networknt.schema.ValidationMessage; +import com.sap.cds.services.EventContext; import com.sap.cds.services.auditlog.Access; import com.sap.cds.services.auditlog.Attachment; import com.sap.cds.services.auditlog.Attribute; @@ -292,6 +294,39 @@ public void testHandleLegacyWrapperEvent() throws Exception { runAndAssertEvent("src/test/resources/legacy-security-wrapper-schema.json", () -> handler.handleSecurityEvent(context)); } + @Test + public void testHandleGeneralEvent_DataExportWrapping() throws Exception { + // Prepare general context + EventContext generalContext = mock(EventContext.class); + when(generalContext.getUserInfo()).thenReturn(userInfo); + when(generalContext.getEvent()).thenReturn("dataExport"); + + // Simulate context.get("data") returning a Map with an 'event' JSON String + String innerJson = "{\"channelType\":\"UNSPECIFIED\",\"channelId\":\"string\",\"objectType\":\"string\",\"objectId\":\"string\",\"destinationUri\":\"string\"}"; + Map outer = new HashMap(); + outer.put("event", innerJson); + when(generalContext.get("data")).thenReturn(outer); + + // Execute + handler.handleGeneralEvent(generalContext); + + // Capture and validate + ArgumentCaptor captor = ArgumentCaptor.forClass(ArrayNode.class); + verify(communicator).sendBulkRequest(captor.capture()); + ArrayNode events = captor.getValue(); + Assertions.assertEquals(1, events.size(), "Exactly one general event expected"); + JsonNode event = events.get(0); + // Basic top-level assertions + Assertions.assertEquals("dataExport", event.get("type").asText()); + JsonNode dataNode = event.get("data").get("data"); + Assertions.assertTrue(dataNode.has("dataExport"), "Inner data should be wrapped under 'dataExport'"); + JsonNode wrapped = dataNode.get("dataExport"); + Assertions.assertEquals("UNSPECIFIED", wrapped.get("channelType").asText()); + Assertions.assertEquals("string", wrapped.get("channelId").asText()); + // Schema validation (generic general event schema) + assertJsonMatchesSchema("src/test/resources/general-event-schema.json", events); + } + private ChangedAttribute mockChangedAttribute(String name, String oldValue, String newValue) { ChangedAttribute attr = mock(ChangedAttribute.class); when(attr.getName()).thenReturn(name); diff --git a/cds-feature-auditlog-ng/src/test/resources/general-event-schema.json b/cds-feature-auditlog-ng/src/test/resources/general-event-schema.json new file mode 100644 index 0000000..7fa3008 --- /dev/null +++ b/cds-feature-auditlog-ng/src/test/resources/general-event-schema.json @@ -0,0 +1,38 @@ +[ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [ + "id", + "specversion", + "source", + "type", + "time", + "data" + ], + "properties": { + "id": {"type": "string"}, + "specversion": {"type": ["string","integer"]}, + "source": {"type": "string"}, + "type": {"type": "string"}, + "time": {"type": "string", "format": "date-time"}, + "data": { + "type": "object", + "required": ["metadata", "data"], + "properties": { + "metadata": { + "type": "object", + "required": ["ts"], + "properties": { + "ts": {"type": "string"} + } + }, + "data": { + "type": "object" + } + } + } + }, + "additionalProperties": false + } +] From 5ee58b0bdf52367c1647ade5bdab9abad2d33a9b Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Thu, 30 Oct 2025 10:48:30 +0200 Subject: [PATCH 05/10] Change dep version and add changelog --- CHANGELOG.md | 6 ++++++ .../com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java | 3 --- pom.xml | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c6f8ac..ce6a8cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Version 0.0.2 - 2025-10-30 + +### Added + +- Support for sending generic audit log events + ## Version 0.0.1 - 2025-07-04 ### Added diff --git a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java index 7c17a00..4643f16 100644 --- a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java +++ b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java @@ -8,7 +8,6 @@ import java.time.Instant; import java.util.Collection; -import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; import java.util.stream.Collectors; @@ -17,11 +16,9 @@ import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.sap.cds.CdsData; import com.sap.cds.services.EventContext; import com.sap.cds.services.auditlog.Access; import com.sap.cds.services.auditlog.Attachment; diff --git a/pom.xml b/pom.xml index 9e4a285..9a82842 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ 17 ${java.version} UTF-8 - 4.5.0-SNAPSHOT + 4.5.0 1.5.8 2.7.2 2.8.3 From 58ffb00e6aed0ec192a202a617586233526a08c0 Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Thu, 30 Oct 2025 10:56:24 +0200 Subject: [PATCH 06/10] fix the cds services version to poin to milestone 4.5.0-m2544 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9a82842..248f9b3 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ 17 ${java.version} UTF-8 - 4.5.0 + 4.5.0-m2544 1.5.8 2.7.2 2.8.3 From 0b1ffe579450027679488e6ef10fca52b69031d3 Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Thu, 30 Oct 2025 10:57:37 +0200 Subject: [PATCH 07/10] remove the snapshot --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 248f9b3..5ea7729 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ - 0.0.2-SNAPSHOT + 0.0.2 17 ${java.version} UTF-8 From c6dcda800959eb88f1a0fe5890438823c9f18f5f Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Thu, 30 Oct 2025 11:20:50 +0200 Subject: [PATCH 08/10] change cds services version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5ea7729..38f27b6 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ 17 ${java.version} UTF-8 - 4.5.0-m2544 + 4.4.1 1.5.8 2.7.2 2.8.3 From aa33f65ebf5358f41618cd74d1e7d62a63cf673c Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Mon, 3 Nov 2025 10:31:40 +0200 Subject: [PATCH 09/10] refactor --- .../auditlog/ng/AuditLogNGHandler.java | 69 ++++--------------- .../auditlog/ng/AuditLogNGHandlerTest.java | 15 ++-- 2 files changed, 20 insertions(+), 64 deletions(-) diff --git a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java index 4643f16..83299b1 100644 --- a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java +++ b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java @@ -14,7 +14,6 @@ import org.slf4j.Logger; -import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -120,20 +119,9 @@ private ArrayNode createGeneralEvent(EventContext context) throws JsonProcessing return result; } - public void handleSecurityEvent(SecurityLogContext context) { - try { - ArrayNode alsEvents = createSecurityEvent(context); - communicator.sendBulkRequest(alsEvents); - } catch (JsonParseException e) { - LOGGER.error("Audit Log write exception occurred for security event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); - } catch (ErrorStatusException e) { - LOGGER.error("Audit Log service not available for security event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_NOT_AVAILABLE, e); - } catch (Exception e) { - LOGGER.error("Unexpected exception while handling security event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); - } + public void handleSecurityEvent(SecurityLogContext context) throws JsonProcessingException { + ArrayNode alsEvents = createSecurityEvent(context); + communicator.sendBulkRequest(alsEvents); } /** @@ -199,20 +187,9 @@ private ObjectNode createLegacySecurityOrigEvent(UserInfo userInfo, SecurityLog return envelop; } - public void handleDataAccessEvent(DataAccessLogContext context) { - try { - ArrayNode alsEvents = createAlsDataAccessEvents(context); - communicator.sendBulkRequest(alsEvents); - } catch (JsonParseException e) { - LOGGER.error("Audit Log write exception occurred for data access event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); - } catch (ErrorStatusException e) { - LOGGER.error("Audit Log service not available for data access event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_NOT_AVAILABLE, e); - } catch (Exception e) { - LOGGER.error("Unexpected exception while handling data access event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); - } + public void handleDataAccessEvent(DataAccessLogContext context) throws JsonProcessingException { + ArrayNode alsEvents = createAlsDataAccessEvents(context); + communicator.sendBulkRequest(alsEvents); } /** @@ -278,20 +255,9 @@ private void addAttributeAccessEvents(UserInfo userInfo, ArrayNode eventArray, A } } - public void handleConfigChangeEvent(ConfigChangeLogContext context) { - try { - ArrayNode alsEvents = createAlsConfigChangeEvents(context); - communicator.sendBulkRequest(alsEvents); - } catch (JsonParseException e) { - LOGGER.error("Audit Log write exception occurred for configuration change event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); - } catch (ErrorStatusException e) { - LOGGER.error("Audit Log service not available for configuration change event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_NOT_AVAILABLE, e); - } catch (Exception e) { - LOGGER.error("Unexpected exception while handling configuration change event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); - } + public void handleConfigChangeEvent(ConfigChangeLogContext context) throws JsonProcessingException { + ArrayNode alsEvents = createAlsConfigChangeEvents(context); + communicator.sendBulkRequest(alsEvents); } /** @@ -336,20 +302,9 @@ private ObjectNode buildConfigChangeEvent(UserInfo userInfo, ConfigChange config return buildAlsEvent("configurationChange", userInfo, metadata, "configurationChange", changeNode); } - public void handleDataModificationEvent(DataModificationLogContext context) { - try { - ArrayNode alsEvents = createAlsDataModificationEvents(context); - communicator.sendBulkRequest(alsEvents); - } catch (JsonParseException e) { - LOGGER.error("Audit Log write exception occurred for data modification event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); - } catch (ErrorStatusException e) { - LOGGER.error("Audit Log service not available for data modification event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_NOT_AVAILABLE, e); - } catch (Exception e) { - LOGGER.error("Unexpected exception while handling data modification event", e); - throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); - } + public void handleDataModificationEvent(DataModificationLogContext context) throws JsonProcessingException { + ArrayNode alsEvents = createAlsDataModificationEvents(context); + communicator.sendBulkRequest(alsEvents); } /** diff --git a/cds-feature-auditlog-ng/src/test/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandlerTest.java b/cds-feature-auditlog-ng/src/test/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandlerTest.java index 0ac2756..59eec0a 100644 --- a/cds-feature-auditlog-ng/src/test/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandlerTest.java +++ b/cds-feature-auditlog-ng/src/test/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandlerTest.java @@ -46,7 +46,6 @@ import com.sap.cds.services.auditlog.SecurityLogContext; import com.sap.cds.services.mt.TenantProviderService; import com.sap.cds.services.request.UserInfo; -import com.sap.cds.services.utils.ErrorStatusException; public class AuditLogNGHandlerTest { @@ -65,7 +64,10 @@ public void setUp() { handler = new AuditLogNGHandler(communicator, tenantService); } - private void runAndAssertEvent(String schemaPath, Runnable handlerMethod) throws Exception { + @FunctionalInterface + private interface ThrowingRunnable { void run() throws Exception; } + + private void runAndAssertEvent(String schemaPath, ThrowingRunnable handlerMethod) throws Exception { ArgumentCaptor captor = ArgumentCaptor.forClass(ArrayNode.class); handlerMethod.run(); verify(communicator).sendBulkRequest(captor.capture()); @@ -80,7 +82,7 @@ public void testHandleSecurityEventSchemaValidation() throws Exception { when(context.getUserInfo()).thenReturn(userInfo); when(context.getData()).thenReturn(securityLog); when(securityLog.getData()).thenReturn("security event data"); - runAndAssertEvent("src/test/resources/legacy-security-wrapper-schema.json", () -> handler.handleSecurityEvent(context)); + runAndAssertEvent("src/test/resources/legacy-security-wrapper-schema.json", () -> handler.handleSecurityEvent(context)); } @Test @@ -112,7 +114,7 @@ public void testHandleDataAccessEvent_MultiAttrAttach_MultiAccess() throws Excep when(dataAccessLog.getAccesses()).thenReturn(List.of(access1, access2)); when(context.getData()).thenReturn(dataAccessLog); when(context.getUserInfo()).thenReturn(userInfo); - runAndAssertEvent("src/test/resources/dpp-data-access-schema.json", () -> handler.handleDataAccessEvent(context)); + runAndAssertEvent("src/test/resources/dpp-data-access-schema.json", () -> handler.handleDataAccessEvent(context)); } @Test @@ -206,8 +208,7 @@ public void testHandleDataAccessEvent_NullAttributesAndAttachments() throws Exce when(context.getData()).thenReturn(dataAccessLog); when(context.getUserInfo()).thenReturn(userInfo); - ErrorStatusException ex = assertThrows(ErrorStatusException.class, () -> handler.handleDataAccessEvent(context)); - Assertions.assertTrue(ex.getCause() instanceof NullPointerException); + assertThrows(NullPointerException.class, () -> handler.handleDataAccessEvent(context)); } @Test @@ -291,7 +292,7 @@ public void testHandleLegacyWrapperEvent() throws Exception { when(context.getUserInfo()).thenReturn(userInfo); when(context.getData()).thenReturn(securityLog); when(securityLog.getData()).thenReturn("{\"legacy\":true}"); - runAndAssertEvent("src/test/resources/legacy-security-wrapper-schema.json", () -> handler.handleSecurityEvent(context)); + runAndAssertEvent("src/test/resources/legacy-security-wrapper-schema.json", () -> handler.handleSecurityEvent(context)); } @Test From 37624dab14fa883c37cc5dbe8ac0eae877a2058e Mon Sep 17 00:00:00 2001 From: Miroslav Tsvetanov Date: Mon, 3 Nov 2025 12:49:35 +0200 Subject: [PATCH 10/10] fix message --- .../com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java index 83299b1..d6670f9 100644 --- a/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java +++ b/cds-feature-auditlog-ng/src/main/java/com/sap/cds/feature/auditlog/ng/AuditLogNGHandler.java @@ -87,13 +87,13 @@ public void handleGeneralEvent(EventContext context) { communicator.sendBulkRequest(alsEvents); } } catch (JsonProcessingException e) { - LOGGER.error("Audit Log write exception occurred for general event", e); + LOGGER.error("Audit Log write exception occurred", e); throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); } catch (ErrorStatusException e) { - LOGGER.error("Audit Log service not available for general event", e); + LOGGER.error("Audit Log service not available", e); throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_NOT_AVAILABLE, e); } catch (Exception e) { - LOGGER.error("Unexpected exception while handling general event", e); + LOGGER.error("Unexpected exception", e); throw new ErrorStatusException(CdsErrorStatuses.AUDITLOG_SERVICE_INVALID_MESSAGE, e); } }