Skip to content

CAMEL-25729: camel-aws-secrets-manager - read every CloudTrail event since the last check in the refresh task - #28036

Merged
davsclaus merged 2 commits into
apache:mainfrom
allthingssecurity:camel-aws-secrets-manager-cloudtrail-reload-all-events
Oct 18, 2026
Merged

davsclaus merged 2 commits into
apache:mainfrom
allthingssecurity:camel-aws-secrets-manager-cloudtrail-reload-all-events

Conversation

@allthingssecurity

@allthingssecurity allthingssecurity commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Description

CAMEL-25729

With camel.vault.aws.refreshEnabled=true and without SQS notification, CloudTrailReloadTriggerTask.run sent one LookupEvents request per check with maxResults(100) (the API accepts 1 to 50), never read nextToken, and started the next check at lastTime + 1 s. The lookup is by event source only, so it returns every Secrets Manager call of the account and Region (for example GetSecretValue of other applications), newest first. An update of a tracked secret that was not on the first page, or that was recorded in the same second as the newest event of the previous check, was never looked at: the context was not reloaded and kept the old secret values, without a log line. The first check, which had no start time, looked at the newest events of the last 90 days and could reload the context for an old update.

Change (in CloudTrailReloadTriggerTask), the same approach as CloudtrailConsumer.poll since CAMEL-24082:

  • each check looks up the PutSecretValue events and the UpdateSecret events (one lookup per event name, as LookupEvents takes a single lookup attribute; before: every event of the secretsmanager.amazonaws.com event source) and reads every page from the newest event time seen, inclusive, 50 events per page;
  • the events of that instant that the previous check handled are skipped by event id;
  • the position starts when the task starts;
  • if a page fails, the position does not move, and the next check reads the same events again.

What users can notice: an update is seen whatever the number of other Secrets Manager events in the check period; the first check no longer reloads the context for an update made before the start. Upgrade guide (4.24): a note under camel-aws-secrets-manager. Cost: two requests per check, one per event name, and one more per further 50 updates since the previous check (before: always one request, for all Secrets Manager events). Reads of secrets (GetSecretValue, DescribeSecret) are not returned and add no requests. LookupEvents allows two requests per second per account and Region; a throttled request is retried by the SDK, and a check that still fails leaves the position where it was, so the next check reads the same events again.

Tests:

  • New CloudTrailReloadTriggerTaskLookupTest (4 tests, mocked CloudTrailClient that answers like the service: only the events that match the single lookup attribute and are at or after startTime, newest first, at most 50 per page, a next token while events are left). The first three fail on main, 3 of 3 runs: an update behind 60 other updates, an update in the same second as the newest event seen (also checks that a third check does not reload again), and the first check looking at an update made a day before the start. readsOfSecretsDoNotAddLookupRequests (200 reads and one UpdateSecret) checks that a check sends exactly two EVENT_NAME lookups; it fails with the event-source lookup (5 requests).
  • With the change the camel-aws-secrets-manager tests pass: 10 run, 0 failures, 0 errors, 0 skipped.

What is not changed: an event that CloudTrail makes visible after a newer one was seen by an earlier check (delivery delay) is still missed, as in the camel-aws-cloudtrail consumer. The SQS mode is unchanged.

What was not run: the full root build; no test against AWS (what the service does with maxResults=100 was not checked; the change is right whether it rejects it or answers with 50 events).

Target

  • I checked that the commit is targeting the correct branch (Camel 4 uses the main branch)

Tracking

  • If this is a large change, bug fix, or code improvement, I checked there is a JIRA issue filed for the change (usually before you start working on it): CAMEL-25729.

Apache Camel coding standards and style

  • I checked that each commit in the pull request has a meaningful subject line and body.
  • I have run mvn clean install -DskipTests locally from root folder and I have committed all auto-generated changes.
    (I built and tested camel-aws-secrets-manager, including the formatter and import-sort plugins. No option or generated file changed. I did not run the full root build.)

AI-assisted contributions

  • If this PR includes AI-generated code, commits have proper co-authorship attribution (e.g., Co-authored-by trailers) and the PR description identifies the AI tool used.
    This PR was prepared with Claude Code (Claude Opus 5.5). The commit carries a Co-Authored-By trailer.

Claude Code on behalf of allthingssecurity

🤖 Generated with Claude Code

…since the last check in the refresh task

The CloudTrail refresh task (used when refreshEnabled=true without SQS
notification) sent one LookupEvents request per check, with maxResults=100
(the service accepts at most 50), never followed nextToken, and started the
next lookup one second after the newest event it had seen. The task filters on
the secretsmanager.amazonaws.com event source, which includes every
GetSecretValue / DescribeSecret call in the account and Region, so an update
of a tracked secret that was not on the first page, or that shares its second
with the newest event of the previous check, was never seen: the context was
not reloaded and kept the old secret values, with nothing logged.

Each check now reads every page from the newest event time seen (inclusive),
50 events per page, and skips the events of that instant that the previous
check already handled, by event id (the same approach as the
aws-cloudtrail consumer, CAMEL-24082). The position starts when the task
starts, instead of the first check reading the newest events of the last 90
days (which could reload the context for an old update). If a page fails,
the position is not moved and the next check reads the same events again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @allthingssecurity.

The bug is real, and the fix matches what CAMEL-24082 did in the aws-cloudtrail consumer: read every page from the newest time seen, inclusive, skip the event ids already handled at that instant, start at task start, and leave the position alone when a page fails. I traced the boundary handling (no new events, only events at lastTime, a newer event) and it holds, and all three tests fail on main for the reasons stated.

One design point before this goes in. The lookup still filters on EventSource=secretsmanager.amazonaws.com, so every check now pages through every GetSecretValue/DescribeSecret call in the account and Region, only to keep PutSecretValue and UpdateSecret. LookupEvents has a 2 requests/s limit shared by the whole account and Region, so with several Camel instances using the refresh task a busy account will get throttled, and since a failed check keeps the old position, the next window is larger and needs more pages. Before this change it was always one request per check.

LookupEvents can filter on EventName instead: two lookups per check, one for PutSecretValue and one for UpdateSecret (the API takes only one lookup attribute), both from the same lastTime, with the merged list going through the same newest/event-id logic unchanged. Only update events are read then, so a second page should be rare and the cost does not grow with read traffic. The eventSource check in the loop can stay as a guard. If you go this way, please update the upgrade-guide sentence about one request per 50 events.

Claude Code on behalf of Claus Ibsen

@github-actions

github-actions Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-aws/camel-aws-secrets-manager
  • docs

🔬 Scalpel shadow comparison — Scalpel: 8 of 706 tested, 26 compile-only — current: 8 all tested

Maveniverse Scalpel detected 8 affected modules (current approach: 8).

Skip-tests mode would test 8 modules (2 direct + 7 downstream), skip tests for 26 (generated code, meta-modules)

Modules Scalpel would test (8)
  • camel-aws-secrets-manager ← components/camel-aws/camel-aws-secrets-manager/src/main/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTask.java, components/camel-aws/camel-aws-secrets-manager/src/test/java/org/apache/camel/component/aws/secretsmanager/vault/CloudTrailReloadTriggerTaskLookupTest.java
  • camel-jbang-mcp ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-mcp ← downstream of org.apache.camel:camel-jbang-core
  • camel-jbang-plugin-tui ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-validate ← downstream of org.apache.camel:camel-yaml-dsl-validator
  • camel-launcher-container ← downstream of org.apache.camel:camel-launcher
  • camel-yaml-dsl-validator ← downstream of org.apache.camel:camel-catalog
  • camel-yaml-dsl-validator-maven-plugin ← downstream of org.apache.camel:camel-yaml-dsl-validator
Modules with tests skipped (26)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

All tested modules (35 modules, 6m 8s total)

Total reactor time: 6m 8s

Module Duration Status
Camel :: Launcher 51.4s SUCCESS
Camel :: JBang :: MCP 42.0s SUCCESS
Camel :: AWS2 Secrets Manager 37.0s SUCCESS
Camel :: JBang :: Plugin :: Validate 29.1s SUCCESS
Camel :: Component DSL 26.9s SUCCESS
Camel :: Catalog :: Camel Catalog 22.8s SUCCESS
Camel :: YAML DSL :: Validator 20.7s SUCCESS
Camel :: YAML DSL 19.2s SUCCESS
Camel :: Docs 15.3s SUCCESS
Camel :: Kamelet Main 13.8s SUCCESS
Camel :: Catalog :: Camel Report Maven Plugin 13.5s SUCCESS
Camel :: JBang :: Plugin :: Testing 13.1s SUCCESS
Camel :: JBang :: Plugin :: Kubernetes 12.5s SUCCESS
Camel :: YAML DSL :: Deserializers 7.8s SUCCESS
Camel :: Catalog :: Camel Route Parser 7.6s SUCCESS
Camel :: YAML DSL :: Validator Maven Plugin 5.8s SUCCESS
Camel :: Catalog :: Suggest (deprecated) 5.5s SUCCESS
Camel :: All Components Sync point 5.4s SUCCESS
Camel :: YAML DSL :: Maven Plugins 3.3s SUCCESS
Camel :: Catalog :: Maven 2.6s SUCCESS
Camel :: Assembly 2.1s SUCCESS
Camel :: JBang :: Plugin :: Edit 1.7s SUCCESS
Camel :: Endpoint DSL :: Support 1.5s SUCCESS
Camel :: JBang :: Plugin :: Generate 1.3s SUCCESS
Camel :: Coverage 1.2s SUCCESS
Camel :: Catalog :: Dummy Component 1.1s SUCCESS
Camel :: JBang :: Main 0.9s SUCCESS
Camel :: Catalog :: Console 0.8s SUCCESS
Camel :: JBang :: Integration tests 0.7s SUCCESS
Camel :: Launcher :: Container 0.7s SUCCESS
Camel :: JBang :: Plugin :: MCP 0.5s SUCCESS
Camel :: Endpoint DSL n/a
Camel :: Integration Tests n/a
Camel :: JBang :: Core n/a
Camel :: JBang :: Plugin :: TUI n/a

Top 20 slowest modules:

  • Camel :: Launcher (51.4s)
  • Camel :: JBang :: MCP (42.0s)
  • Camel :: AWS2 Secrets Manager (37.0s)
  • Camel :: JBang :: Plugin :: Validate (29.1s)
  • Camel :: Component DSL (26.9s)
  • Camel :: Catalog :: Camel Catalog (22.8s)
  • Camel :: YAML DSL :: Validator (20.7s)
  • Camel :: YAML DSL (19.2s)
  • Camel :: Docs (15.3s)
  • Camel :: Kamelet Main (13.8s)
  • Camel :: Catalog :: Camel Report Maven Plugin (13.5s)
  • Camel :: JBang :: Plugin :: Testing (13.1s)
  • Camel :: JBang :: Plugin :: Kubernetes (12.5s)
  • Camel :: YAML DSL :: Deserializers (7.8s)
  • Camel :: Catalog :: Camel Route Parser (7.6s)
  • Camel :: YAML DSL :: Validator Maven Plugin (5.8s)
  • Camel :: Catalog :: Suggest (deprecated) (5.5s)
  • Camel :: All Components Sync point (5.4s)
  • Camel :: YAML DSL :: Maven Plugins (3.3s)
  • Camel :: Catalog :: Maven (2.6s)

⚙️ View full build and test results

…ts in the CloudTrail refresh task

Filter LookupEvents on the event names PutSecretValue and UpdateSecret (one lookup each, the API
takes a single lookup attribute) instead of the Secrets Manager event source, so reads of secrets
no longer add pages and a check sends about two requests whatever the read traffic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid fix — the pagination bug is real, the deduplication logic is sound, and the new tests are thorough and realistic. Two points worth addressing.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@allthingssecurity

Copy link
Copy Markdown
Contributor Author

Thanks for the careful review. I went the EventName way you described in 6be0d46: two lookups per check (PutSecretValue and UpdateSecret) from the same lastTime, the merged events through the unchanged newest/event-id logic, and the eventSource check kept as a guard. A check is now two requests whatever the read traffic, plus one per further 50 updates. The upgrade-guide sentence about one request per 50 events is updated accordingly, and the PR description too. Details and the new test are in the inline reply.

Claude Code on behalf of allthingssecurity

@gnodet gnodet added the lts label Oct 18, 2026
@github-actions github-actions Bot removed the lts label Oct 18, 2026

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @allthingssecurity.

The earlier point is fixed in 6be0d46. Each check now sends one LookupEvents per update event name (PutSecretValue, UpdateSecret) with LookupAttributeKey.EVENT_NAME, reads every page of each from the same inclusive lastTime, and runs the merged list through the same newest-time/event-id loop. That loop finds the maximum and does not need the merged list in order, so the boundary handling I traced on the previous commit still holds. Reads of secrets no longer cost requests, and readsOfSecretsDoNotAddLookupRequests pins the two requests per check. The fake LookupEvents in the test now applies the lookup attribute and rejects more than one, which is what the service does. The upgrade-guide note was updated to match. The test class uses JUnit assertions like the other tests in the module.

On the two gnodet-bot threads, neither blocks this PR:

  • The eventSource check can stay as a guard, as suggested earlier. The lookup filters on event name only, and event names are not unique across AWS services, so it is not dead code. The eventName check is now redundant but harmless.
  • Reading lastTime once at the start of run() and passing it to both lookupEvents calls would be a small cleanup. Both lookups would then use the same start by construction, not only because nothing else writes the field during a check. Optional.

As the description says, an update that CloudTrail makes visible after a newer event was already seen is still missed here. If #28038 is merged, a follow-up could give the refresh task the same late-event lookup.

Good to merge once CI is green.

Claude Code on behalf of Claus Ibsen

@davsclaus davsclaus added this to the 4.24.0 milestone Oct 18, 2026
@davsclaus davsclaus added the bug Something isn't working label Oct 18, 2026
@davsclaus
davsclaus merged commit d5f34a8 into apache:main Oct 18, 2026
7 checks passed
@allthingssecurity
allthingssecurity deleted the camel-aws-secrets-manager-cloudtrail-reload-all-events branch October 19, 2026 12:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants