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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new d653807aee17 CAMEL-25773: camel-aws-secrets-manager - use one start 
time for all CloudTrail lookups of a refresh check (#28256)
d653807aee17 is described below

commit d653807aee17d689450a6be5c6f4302ce1172d42
Author: allthingssecurity <[email protected]>
AuthorDate: Fri Oct 23 02:18:52 2026 +0530

    CAMEL-25773: camel-aws-secrets-manager - use one start time for all 
CloudTrail lookups of a refresh check (#28256)
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../vault/CloudTrailReloadTriggerTask.java         | 47 ++++++++++--------
 .../CloudTrailReloadTriggerTaskLookupTest.java     | 57 +++++++++++++++++++++-
 2 files changed, 82 insertions(+), 22 deletions(-)

diff --git 
a/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
 
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
index 060f5656cd00..0006ce6e966b 100644
--- 
a/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
+++ 
b/components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java
@@ -281,18 +281,21 @@ public class CloudTrailReloadTriggerTask extends 
ServiceSupport implements Camel
     }
 
     /**
-     * Adds every event with the given event name since the last check to the 
list, reading all pages.
+     * Adds every event with the given event name since the given time to the 
list, reading all pages.
+     *
+     * @param since the start time of the lookup, the same for every page and 
every event name of one check; null to
+     *              look up without a start time
      */
-    private void lookupEvents(String eventName, List<Event> events) {
+    private void lookupEvents(String eventName, Instant since, List<Event> 
events) {
         String nextToken = null;
         do {
             LookupEventsRequest.Builder eventsRequestBuilder = 
LookupEventsRequest.builder()
                     .maxResults(LOOKUP_MAX_RESULTS)
                     
.lookupAttributes(LookupAttribute.builder().attributeKey(LookupAttributeKey.EVENT_NAME)
                             .attributeValue(eventName).build());
-            if (lastTime != null) {
+            if (since != null) {
                 // inclusive, so an event in the same second as the newest 
event seen is not skipped
-                eventsRequestBuilder.startTime(lastTime);
+                eventsRequestBuilder.startTime(since);
             }
             if (nextToken != null) {
                 eventsRequestBuilder.nextToken(nextToken);
@@ -314,13 +317,15 @@ public class CloudTrailReloadTriggerTask extends 
ServiceSupport implements Camel
                 // read every page of the update events since the last check. 
LookupEvents takes a single lookup
                 // attribute, so there is one lookup per event name: filtering 
on the event source instead would also
                 // return every read (GetSecretValue, DescribeSecret), and the 
pages would grow with the read traffic
+                // read lastTime once: every page of both lookups of this 
check uses the same start time
+                Instant since = lastTime;
                 List<Event> events = new ArrayList<>();
                 for (String eventName : UPDATE_EVENT_NAMES) {
-                    lookupEvents(eventName, events);
+                    lookupEvents(eventName, since, events);
                 }
 
                 LOG.debug("Found {} events", events.size());
-                Instant newest = lastTime;
+                Instant newest = since;
                 Set<String> newestEventIds = new HashSet<>();
                 for (Event event : events) {
                     if (lastTimeEventIds.contains(event.eventId())) {
@@ -335,25 +340,25 @@ public class CloudTrailReloadTriggerTask extends 
ServiceSupport implements Camel
                     } else if (eventTime.equals(newest)) {
                         newestEventIds.add(event.eventId());
                     }
-                    if 
(event.eventSource().equalsIgnoreCase(SECRETSMANAGER_AMAZONAWS_COM)) {
-                        if 
(event.eventName().equalsIgnoreCase(SECRETSMANAGER_UPDATE_EVENT)
-                                || 
event.eventName().equalsIgnoreCase(SECRETSMANAGER_UPDATE_SECRET_EVENT)) {
-                            List<Resource> a = event.resources();
-                            for (Resource res : a) {
-                                String name = res.resourceName();
-                                if (matchSecret(name)) {
-                                    updates.put(name, event.eventTime());
-                                    if (isReloadEnabled()) {
-                                        LOG.info("Update for AWS secret: {} 
detected, triggering CamelContext reload", name);
-                                        triggerReloading = true;
-                                    }
-                                    break;
-                                }
+                    // the lookups are filtered by event name (PutSecretValue 
or UpdateSecret), but event names are not
+                    // unique across AWS services, so the event source is 
still checked
+                    if 
(!SECRETSMANAGER_AMAZONAWS_COM.equalsIgnoreCase(event.eventSource())) {
+                        continue;
+                    }
+                    List<Resource> a = event.resources();
+                    for (Resource res : a) {
+                        String name = res.resourceName();
+                        if (matchSecret(name)) {
+                            updates.put(name, event.eventTime());
+                            if (isReloadEnabled()) {
+                                LOG.info("Update for AWS secret: {} detected, 
triggering CamelContext reload", name);
+                                triggerReloading = true;
                             }
+                            break;
                         }
                     }
                 }
-                if (newest != null && newest.equals(lastTime)) {
+                if (newest != null && newest.equals(since)) {
                     // no newer event: the events at lastTime seen before are 
still returned by the next lookup
                     newestEventIds.addAll(lastTimeEventIds);
                 }
diff --git 
a/components/camel-aws/camel-aws-secrets-manager/src/test/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTaskLookupTest.java
 
b/components/camel-aws/camel-aws-secrets-manager/src/test/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTaskLookupTest.java
index 4888bf91084b..51161e2439ef 100644
--- 
a/components/camel-aws/camel-aws-secrets-manager/src/test/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTaskLookupTest.java
+++ 
b/components/camel-aws/camel-aws-secrets-manager/src/test/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTaskLookupTest.java
@@ -62,6 +62,8 @@ class CloudTrailReloadTriggerTaskLookupTest {
     private final ContextReloadStrategy reload = 
mock(ContextReloadStrategy.class);
     private DefaultCamelContext context;
     private int eventIds;
+    // run in each LookupEvents call, to change the task while its lookups run
+    private Runnable onLookup;
 
     @BeforeEach
     void setUp() throws Exception {
@@ -78,6 +80,9 @@ class CloudTrailReloadTriggerTaskLookupTest {
 
     private LookupEventsResponse lookup(LookupEventsRequest request) {
         requests.add(request);
+        if (onLookup != null) {
+            onLookup.run();
+        }
         // the service takes at most one lookup attribute
         assertTrue(request.lookupAttributes().size() <= 1, "LookupEvents takes 
at most one lookup attribute");
         LookupAttribute attribute = request.lookupAttributes().isEmpty() ? 
null : request.lookupAttributes().get(0);
@@ -105,7 +110,11 @@ class CloudTrailReloadTriggerTaskLookupTest {
     }
 
     private void addEvent(String name, String secret, Instant time) {
-        visibleEvents.add(Event.builder().eventId("id-" + 
eventIds++).eventSource(SOURCE).eventName(name)
+        addEvent(SOURCE, name, secret, time);
+    }
+
+    private void addEvent(String source, String name, String secret, Instant 
time) {
+        visibleEvents.add(Event.builder().eventId("id-" + 
eventIds++).eventSource(source).eventName(name)
                 
.eventTime(time).resources(Resource.builder().resourceName(secret).build()).build());
     }
 
@@ -227,4 +236,50 @@ class CloudTrailReloadTriggerTaskLookupTest {
         assertEquals(2, requests.size());
         assertTrue(requests.stream().allMatch(r -> 
t0.plusSeconds(5).equals(r.startTime())));
     }
+
+    @Test
+    void everyPageOfBothLookupsOfOneCheckUsesTheSameStartTime() throws 
Exception {
+        Instant t0 = Instant.parse("2026-10-17T10:00:00Z");
+        CloudTrailReloadTriggerTask task = task(t0);
+        // two pages of PutSecretValue events and one page of UpdateSecret 
events
+        for (int i = 0; i < 60; i++) {
+            addEvent("PutSecretValue", "other-secret", t0.plusSeconds(1 + i % 
20));
+        }
+        addEvent("UpdateSecret", "tracked-secret", t0.plusSeconds(5));
+        // lastTime changes while the first page is read: the other pages and 
the other lookup keep the start time
+        onLookup = () -> {
+            if (requests.size() == 1) {
+                try {
+                    setField(task, "lastTime", null);
+                } catch (Exception e) {
+                    throw new IllegalStateException(e);
+                }
+            }
+        };
+
+        task.run();
+
+        assertEquals(3, requests.size(), "two pages of PutSecretValue and one 
page of UpdateSecret");
+        for (LookupEventsRequest request : requests) {
+            assertEquals(t0, request.startTime(), "every page of both lookups 
must use the start time of the check");
+        }
+        assertTrue(task.getUpdates().containsKey("tracked-secret"));
+    }
+
+    @Test
+    void updateEventOfAnotherServiceIsIgnored() throws Exception {
+        Instant t0 = Instant.parse("2026-10-17T10:00:00Z");
+        CloudTrailReloadTriggerTask task = task(t0);
+        // the lookup filters by event name only, and event names are not 
unique across AWS services
+        addEvent("other-service.amazonaws.com", "UpdateSecret", 
"tracked-secret", t0.plusSeconds(5));
+
+        task.run();
+
+        assertFalse(task.getUpdates().containsKey("tracked-secret"), "an event 
of another service is not an update");
+        verify(reload, times(0)).onReload(task);
+        // the event still moves the start time of the next check
+        requests.clear();
+        task.run();
+        assertTrue(requests.stream().allMatch(r -> 
t0.plusSeconds(5).equals(r.startTime())));
+    }
 }

Reply via email to