This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch graphql-gate-processevents
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to refs/heads/graphql-gate-processevents by 
this push:
     new ecbc97782 Cover the GraphQL restricted-event-type gate with unit tests.
ecbc97782 is described below

commit ecbc9778262f3b17947d7b17b364047843dba4e1
Author: Serge Huber <[email protected]>
AuthorDate: Thu Sep 17 12:27:10 2026 +0200

    Cover the GraphQL restricted-event-type gate with unit tests.
---
 .../graphql/commands/ProcessEventsCommand.java     | 18 ++---
 .../graphql/commands/ProcessEventsCommandTest.java | 82 ++++++++++++++++++++++
 2 files changed, 91 insertions(+), 9 deletions(-)

diff --git 
a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/ProcessEventsCommand.java
 
b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/ProcessEventsCommand.java
index 712c06d6e..5d4147f58 100644
--- 
a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/ProcessEventsCommand.java
+++ 
b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/ProcessEventsCommand.java
@@ -165,7 +165,8 @@ public class ProcessEventsCommand extends 
BaseCommand<Integer> {
     private void processEvent(final Event event) {
         final EventService eventService = 
serviceManager.getService(EventService.class);
 
-        if (!isEventAllowedForCurrentTenant(event, eventService)) {
+        if (!isEventAllowedForCurrentTenant(event, eventService,
+                serviceManager.getService(ExecutionContextManager.class))) {
             LOGGER.debug("Event type {} is not authorized for this tenant, 
skipping it", event.getEventType());
             return;
         }
@@ -179,15 +180,14 @@ public class ProcessEventsCommand extends 
BaseCommand<Integer> {
     }
 
     /**
-     * Applies the same restricted-event-type gate the REST event paths apply 
before handing an event to
-     * {@link EventService#send(Event)}, which performs no such check of its 
own. Without this, an event
-     * submitted through this mutation skipped a control the REST path 
enforces.
-     * <p>
-     * This transport carries no source IP to match against a tenant's 
authorized IP list, so a restricted
-     * event type is refused whenever such a list is configured.
+     * Same restricted-event-type check as REST {@code EventService#send} 
callers. GraphQL does not
+     * currently thread a client IP through this command, so the source IP is 
{@code null}: a
+     * restricted type is refused when the tenant has an authorized-IP list, 
and unrestricted types
+     * still pass.
      */
-    private boolean isEventAllowedForCurrentTenant(final Event event, final 
EventService eventService) {
-        final ExecutionContextManager executionContextManager = 
serviceManager.getService(ExecutionContextManager.class);
+    static boolean isEventAllowedForCurrentTenant(final Event event,
+                                                  final EventService 
eventService,
+                                                  final 
ExecutionContextManager executionContextManager) {
         final ExecutionContext executionContext = executionContextManager != 
null
                 ? executionContextManager.getCurrentContext() : null;
         final String tenantId = executionContext != null ? 
executionContext.getTenantId() : null;
diff --git 
a/graphql/cxs-impl/src/test/java/org/apache/unomi/graphql/commands/ProcessEventsCommandTest.java
 
b/graphql/cxs-impl/src/test/java/org/apache/unomi/graphql/commands/ProcessEventsCommandTest.java
new file mode 100644
index 000000000..a387637c9
--- /dev/null
+++ 
b/graphql/cxs-impl/src/test/java/org/apache/unomi/graphql/commands/ProcessEventsCommandTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.unomi.graphql.commands;
+
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.ExecutionContext;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.services.EventService;
+import org.apache.unomi.api.services.ExecutionContextManager;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class ProcessEventsCommandTest {
+
+    private static final String TENANT_ID = "tenant-1";
+
+    @Mock
+    private EventService eventService;
+    @Mock
+    private ExecutionContextManager executionContextManager;
+    @Mock
+    private ExecutionContext executionContext;
+
+    @Test
+    void allowsEventWhenTenantGatePasses() {
+        Event event = viewEvent();
+        
when(executionContextManager.getCurrentContext()).thenReturn(executionContext);
+        when(executionContext.getTenantId()).thenReturn(TENANT_ID);
+        when(eventService.isEventAllowedForTenant(event, TENANT_ID, 
null)).thenReturn(true);
+
+        assertTrue(ProcessEventsCommand.isEventAllowedForCurrentTenant(event, 
eventService, executionContextManager));
+        verify(eventService).isEventAllowedForTenant(event, TENANT_ID, null);
+    }
+
+    @Test
+    void refusesEventWhenTenantGateFails() {
+        Event event = viewEvent();
+        
when(executionContextManager.getCurrentContext()).thenReturn(executionContext);
+        when(executionContext.getTenantId()).thenReturn(TENANT_ID);
+        when(eventService.isEventAllowedForTenant(event, TENANT_ID, 
null)).thenReturn(false);
+
+        assertFalse(ProcessEventsCommand.isEventAllowedForCurrentTenant(event, 
eventService, executionContextManager));
+        verify(eventService).isEventAllowedForTenant(event, TENANT_ID, null);
+    }
+
+    @Test
+    void passesNullTenantWhenThereIsNoExecutionContext() {
+        Event event = viewEvent();
+        when(eventService.isEventAllowedForTenant(event, null, 
null)).thenReturn(false);
+
+        assertFalse(ProcessEventsCommand.isEventAllowedForCurrentTenant(event, 
eventService, null));
+        verify(eventService).isEventAllowedForTenant(event, null, null);
+    }
+
+    private static Event viewEvent() {
+        return new Event("view", null, new Profile(), null, null, null, new 
Date());
+    }
+}

Reply via email to