Skip to content

Commit 015ae2e

Browse files
committed
Refine error handling in MountInfo lookup.
We now do not cache failures caused by VaultException but rather return an unavailable MountInfo. Also, VaultKeyValueAdapter now throws an exception if the mount info isn't available. Closes gh-889
1 parent e315af5 commit 015ae2e

File tree

4 files changed

+86
-0
lines changed

4 files changed

+86
-0
lines changed

spring-vault-core/src/main/java/org/springframework/vault/core/util/KeyValueDelegate.java

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.springframework.lang.Nullable;
2424
import org.springframework.util.ConcurrentReferenceHashMap;
2525
import org.springframework.util.StringUtils;
26+
import org.springframework.vault.VaultException;
2627
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
2728
import org.springframework.vault.core.VaultOperations;
2829
import org.springframework.vault.support.VaultResponse;
@@ -127,6 +128,9 @@ public MountInfo getMountInfo(String path) {
127128

128129
mountInfo = doGetMountInfo(path);
129130
}
131+
catch (VaultException e) {
132+
return MountInfo.unavailable();
133+
}
130134
catch (RuntimeException e) {
131135
mountInfo = MountInfo.unavailable();
132136
}

spring-vault-core/src/main/java/org/springframework/vault/repository/core/VaultKeyValueAdapter.java

+4
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,10 @@ private VaultKeyValueKeyspaceAccessor getAccessor(String keyspace) {
255255

256256
KeyValueDelegate.MountInfo mountInfo = keyValueDelegate.getMountInfo(keyspace);
257257

258+
if (!mountInfo.isAvailable()) {
259+
throw new VaultException("Cannot determine MountInfo");
260+
}
261+
258262
return accessors.computeIfAbsent(keyspace, it -> {
259263

260264
if (keyValueDelegate.isVersioned(it)) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.vault.repository.core;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.api.extension.ExtendWith;
20+
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.test.context.ContextConfiguration;
23+
import org.springframework.test.context.junit.jupiter.SpringExtension;
24+
import org.springframework.vault.VaultException;
25+
import org.springframework.vault.core.VaultIntegrationTestConfiguration;
26+
import org.springframework.vault.core.VaultTemplate;
27+
import org.springframework.vault.core.util.KeyValueDelegate;
28+
import org.springframework.vault.domain.Person;
29+
import org.springframework.vault.util.IntegrationTestSupport;
30+
31+
import static org.assertj.core.api.Assertions.*;
32+
33+
/**
34+
* Integration tests for {@link VaultKeyValueAdapter}.
35+
*
36+
* @author Mark Paluch
37+
*/
38+
@ExtendWith(SpringExtension.class)
39+
@ContextConfiguration(classes = VaultIntegrationTestConfiguration.class)
40+
class VaultKeyValueAdapterIntegrationTests extends IntegrationTestSupport {
41+
42+
@Autowired
43+
VaultTemplate template;
44+
45+
@Test
46+
void shouldFailOnAbsentKeyspace() {
47+
48+
VaultKeyValueAdapter adapter = new VaultKeyValueAdapter(template);
49+
50+
assertThatExceptionOfType(VaultException.class).isThrownBy(() -> adapter.get("some-id", "absent", Person.class))
51+
.withMessageContaining("Cannot determine MountInfo");
52+
}
53+
54+
@Test
55+
void shouldReturnVersionedMountInfo() {
56+
57+
KeyValueDelegate delegate = new KeyValueDelegate(template);
58+
59+
KeyValueDelegate.MountInfo mountInfo = delegate.getMountInfo("versioned/nothing/here");
60+
61+
assertThat(mountInfo.isAvailable()).isTrue();
62+
assertThat(mountInfo.getOptions()).containsEntry("version", "2");
63+
}
64+
65+
@Test
66+
void shouldReturnUnversionedMountInfo() {
67+
68+
KeyValueDelegate delegate = new KeyValueDelegate(template);
69+
70+
KeyValueDelegate.MountInfo mountInfo = delegate.getMountInfo("secret/nothing/here");
71+
72+
assertThat(mountInfo.isAvailable()).isTrue();
73+
assertThat(mountInfo.getOptions()).doesNotContainEntry("version", "2");
74+
}
75+
76+
}

src/main/antora/modules/ROOT/pages/vault/vault-repositories.adoc

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ As of version 2.4, Spring Vault can use additionally key/value version 2 secrets
99

1010
NOTE: Deletes within versioned key/value secrets engine use the `DELETE` operation. Secrets are not destroyed through `CrudRepository.delete(…)`.
1111

12+
NOTE: Vault Repositories determine the mount path through Vault's `sys/internal/ui/mounts/…` endpoint. Make sure that your policy allows accessing that path, otherwise you won't be able to use the repository abstraction.
13+
1214
NOTE: Read more about Spring Data Repositories in the https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories[Spring Data Commons reference documentation].
1315
The reference documentation will give you an introduction to Spring Data repositories.
1416

0 commit comments

Comments
 (0)