Skip to content

CAMEL-26919: camel-hashicorp-vault - a Vault client without a CamelContext, for the Spring Boot early resolution - #29819

Open
oscerd wants to merge 1 commit into
apache:mainfrom
oscerd:feature/CAMEL-26919-hashicorp-vault-early-resolution
Open

oscerd wants to merge 1 commit into
apache:mainfrom
oscerd:feature/CAMEL-26919-hashicorp-vault-early-resolution

Conversation

@oscerd

@oscerd oscerd commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes CAMEL-26919, a follow-up of CAMEL-25675 (#29235, #29619, #29708).

Camel on Spring Boot can resolve hashicorp: properties early (camel.component.hashicorp-vault.early-resolve-properties=true), before there is a CamelContext. That early resolution builds its own VaultTemplate with camel.vault.hashicorp.token, so the logins of CAMEL-25675 (AppRole, Kubernetes, JWT, cert, cloud) and the TLS options do not apply to it: an application that logs in with AppRole needs a fixed token again just for the early resolution. It cannot use HashicorpVaultClient as it is, because the token renewal runs on the executor service manager of the CamelContext.

This PR adds what camel-spring-boot needs:

  • HashicorpVaultClient.create(HashicorpVaultClientSettings) creates a client without a CamelContext. It renews its token on a daemon thread of its own (Camel HashicorpVaultTokenRenewal), and close() stops that thread and revokes the token of the login, as for the clients of the endpoint, the properties function and the secret refresh task. The two create methods share their code: only where the renewal runs differs.
  • HashicorpVaultClientSettings.fromConfiguration(HashicorpVaultConfiguration) takes the settings of the camel.vault.hashicorp options alone. Spring Boot binds these options itself, and the CAMEL_HASHICORP_VAULT_* environment variables belong to the properties function. fromEnvironmentOrConfiguration now delegates to it.
  • The Spring Boot section of the component documentation says that the early resolution logs in as the properties function does, and revokes the token of its login once the properties are resolved.

The camel-spring-boot side is apache/camel-spring-boot#2091, a draft until this change is in the SNAPSHOT: the early resolution binds camel.vault.hashicorp with Spring Boot's relaxed binding, logs in with HashicorpVaultClient.create(settings), and closes the client once the properties are resolved.

Tests

  • HashicorpVaultClientTest.aClientWithoutCamelContextRenewsItsTokenOnADaemonThreadAndRevokesItOnClose: an AppRole login against the fake Vault. The token is renewed on a daemon thread, and closing the client revokes it.
  • HashicorpVaultClientSettingsTest.takesTheSettingsOfTheConfigurationAlone.
  • All 81 unit tests and all 38 integration tests of the module pass (Vault container). Full reactor build (mvn clean install -DskipTests -DskipITs): the only regenerated file is the catalog copy of the component documentation, committed.
  • The camel-spring-boot change was built against these artifacts. Its tests include an AppRole login of the early resolution against a Vault container, which also checks that the token of the login is revoked once the properties are resolved.

Claude Code on behalf of oscerd

🤖 Generated with Claude Code

…ntext, for the Spring Boot early resolution

The early resolution of hashicorp: properties of Camel on Spring Boot runs before there is a CamelContext,
so it cannot create a HashicorpVaultClient, whose token renewal runs on the executor service manager of
the context. It therefore logs in only with a token.

- HashicorpVaultClient.create(HashicorpVaultClientSettings) creates a client that renews its token on a
  daemon thread of its own, which closing the client stops.
- HashicorpVaultClientSettings.fromConfiguration(HashicorpVaultConfiguration) takes the settings of the
  camel.vault.hashicorp options alone, without the CAMEL_HASHICORP_VAULT_* environment variables.
- The Spring Boot section of the component documentation says that the early resolution logs in as the
  properties function does, and revokes the token of its login once the properties are resolved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.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.

@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.

Clean refactoring. The extraction of Supplier<ScheduledExecutorService> + Consumer<ScheduledExecutorService> strategy into the private create is well-designed — it eliminates the CamelContext dependency from instance fields while keeping the two code paths consistent.

One minor nit on the fromConfiguration Javadoc — missing @return. Not blocking.

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

Comment on lines +130 to +131
* @param configuration the vault configuration
* @since 4.24

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.

💡 Nit: Missing @return tag. Add it between @param and @since:

Suggested change
* @param configuration the vault configuration
* @since 4.24
* @param configuration the vault configuration
* @return the settings
* @since 4.24

@github-actions

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • catalog/camel-catalog
  • components/camel-hashicorp-vault

🔁 1 test passed only after a retry on JDK 21 (1 retried attempt)

Recovered flaky tests on JDK 21 (1)
Module Test Failed attempts First failure
dsl/camel-jbang/camel-jbang-plugin-tui ArchitectureViewTest.showsGroupsWithTheirFacts 1 the first group is selected ==> expected: <group:billing> but was: <null>

ℹ️ These tests did not fail the build. Surefire retried them and they passed.
Retries are enabled project-wide by surefire.rerunFailingTestsCount in parent/pom.xml.


🔬 Scalpel shadow comparison — Scalpel: 9 of 722 tested, 26 compile-only — current: 9 all tested

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

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

Modules Scalpel would test (9)
  • camel-hashicorp-vault ← components/camel-hashicorp-vault/src/main/docs/hashicorp-vault-component.adoc, components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClient.java, components/camel-hashicorp-vault/src/main/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettings.java, components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientSettingsTest.java, components/camel-hashicorp-vault/src/test/java/org/apache/camel/component/hashicorp/vault/HashicorpVaultClientTest.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-jbang-run ← downstream of org.apache.camel:camel-catalog
  • 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-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
  • docs
  • dummy-component

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

All tested modules (36 modules, 5m 23s total)

Total reactor time: 5m 23s

Module Duration Status
Camel :: HashiCorp :: Key Vault 35.9s SUCCESS
Camel :: YAML DSL :: Validator 30.6s SUCCESS
Camel :: Catalog :: Camel Catalog 25.5s SUCCESS
Camel :: JBang :: Plugin :: Validate 24.9s SUCCESS
Camel :: JBang :: Run 24.5s SUCCESS
Camel :: JBang :: Plugin :: Kubernetes 24.3s SUCCESS
Camel :: YAML DSL 23.9s SUCCESS
Camel :: Component DSL 21.5s SUCCESS
Camel :: Docs 16.3s SUCCESS
Camel :: Kamelet Main 16.0s SUCCESS
Camel :: JBang :: Plugin :: Testing 14.6s SUCCESS
Camel :: YAML DSL :: Deserializers 8.8s SUCCESS
Camel :: Catalog :: Camel Route Parser 7.9s SUCCESS
Camel :: Catalog :: Camel Report Maven Plugin 7.5s SUCCESS
Camel :: JBang :: Plugin :: Generate 6.3s SUCCESS
Camel :: Assembly 5.8s SUCCESS
Camel :: All Components Sync point 5.1s SUCCESS
Camel :: YAML DSL :: Validator Maven Plugin 4.1s SUCCESS
Camel :: Catalog :: Maven 3.3s SUCCESS
Camel :: YAML DSL :: Maven Plugins 3.2s SUCCESS
Camel :: Catalog :: Suggest (deprecated) 2.1s SUCCESS
Camel :: JBang :: Plugin :: MCP 2.1s SUCCESS
Camel :: Coverage 1.7s SUCCESS
Camel :: JBang :: Main 1.3s SUCCESS
Camel :: Catalog :: Dummy Component 1.1s SUCCESS
Camel :: JBang :: Plugin :: Edit 1.1s SUCCESS
Camel :: JBang :: Integration tests 1.1s SUCCESS
Camel :: Catalog :: Console 0.9s SUCCESS
Camel :: Endpoint DSL :: Support 0.8s SUCCESS
Camel :: Launcher :: Container 0.7s SUCCESS
Camel :: Endpoint DSL n/a
Camel :: Integration Tests n/a
Camel :: JBang :: Core n/a
Camel :: JBang :: MCP n/a
Camel :: JBang :: Plugin :: TUI n/a
Camel :: Launcher n/a

Top 20 slowest modules:

  • Camel :: HashiCorp :: Key Vault (35.9s)
  • Camel :: YAML DSL :: Validator (30.6s)
  • Camel :: Catalog :: Camel Catalog (25.5s)
  • Camel :: JBang :: Plugin :: Validate (24.9s)
  • Camel :: JBang :: Run (24.5s)
  • Camel :: JBang :: Plugin :: Kubernetes (24.3s)
  • Camel :: YAML DSL (23.9s)
  • Camel :: Component DSL (21.5s)
  • Camel :: Docs (16.3s)
  • Camel :: Kamelet Main (16.0s)
  • Camel :: JBang :: Plugin :: Testing (14.6s)
  • Camel :: YAML DSL :: Deserializers (8.8s)
  • Camel :: Catalog :: Camel Route Parser (7.9s)
  • Camel :: Catalog :: Camel Report Maven Plugin (7.5s)
  • Camel :: JBang :: Plugin :: Generate (6.3s)
  • Camel :: Assembly (5.8s)
  • Camel :: All Components Sync point (5.1s)
  • Camel :: YAML DSL :: Validator Maven Plugin (4.1s)
  • Camel :: Catalog :: Maven (3.3s)
  • Camel :: YAML DSL :: Maven Plugins (3.2s)

⚙️ View full build and test results

@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.

This adds a HashiCorp Vault client that needs no CamelContext, for the early property resolution of Camel on Spring Boot, and pulls the camel.vault.hashicorp mapping out into HashicorpVaultClientSettings.fromConfiguration. The refactoring is small and keeps the context-based path as it was. Looks good to me.

What I checked:

  • Both create methods now share the private create(settings, renewals, shutdown) (HashicorpVaultClient.java:141), so the context-free client gets the same behaviour: the same validate, the TLS context from HashicorpVaultTls.sslContext (it reads plain files and needs no CamelContext), the cloud namespace only on the login client, the same logins, and the same cleanup when building the session manager fails.
  • No change for existing users: create(CamelContext, Object, settings) still asks the context's ExecutorServiceManager for the HashicorpVaultTokenRenewal scheduler and calls shutdownNow on it in close() (:421), as before. The constructor is private, so the new constructor signature does not break any public API.
  • The context-free renewal thread is a daemon (Camel HashicorpVaultTokenRenewal), so a caller that forgets close() does not keep the JVM running. close() still stops the renewal, then revokes the login token through sessionManager.destroy(), then closes the login resources.
  • fromConfiguration copies all 22 client fields of HashicorpVaultConfiguration (all getters except refresh/secrets, which are not client settings), the same list as before. fromEnvironmentOrConfiguration delegates to it, and the environment variables still win.
  • Nothing new is logged, and the validation messages do not include secrets.
  • Tests: the new AppRole test against the fake Vault checks the renewal on a daemon thread and the revoke-self on close (HashicorpVaultClientTest.java:176), and the settings test covers fromConfiguration. Awaitility uses atMost, there is no Thread.sleep, and the JUnit assertions match the module style. @since 4.24 is on the new public methods. The catalog doc copy is regenerated, and the _logging_in_to_hashicorp_vault / _tls anchors exist.

Small points, none blocking:

  • HashicorpVaultClientSettings.java:130: gnodet-bot's @return nit is still open. It is consistent with fromEnvironmentOrConfiguration, which also has no @return. Adding @return the settings to both would be fine.
  • The new doc paragraph says the early resolution revokes "the token of its login". With authentication=token, nothing is revoked (by design, see the close() Javadoc). A short "(a token given for the token login is not revoked)" would avoid surprising readers. The paragraph also describes the behaviour of apache/camel-spring-boot#2091, so that PR should land in the same release.

Claude Code on behalf of davsclaus. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants