Skip to content

Commit 3a33cc4

Browse files
committed
fix(secretsmanager): resolve partial ARNs without random suffix
1 parent fddb1c7 commit 3a33cc4

3 files changed

Lines changed: 109 additions & 4 deletions

File tree

compatibility-tests/sdk-test-java/src/test/java/com/floci/test/SecretsManagerTest.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,60 @@ void getSecretValueNonExistentThrows400() {
307307
.isEqualTo(400);
308308
}
309309

310+
// ─────────────────────────────────────────────────────────────────────────
311+
// Issue #340 — GetSecretValue must resolve partial ARNs (no random suffix)
312+
// ─────────────────────────────────────────────────────────────────────────
313+
310314
@Test
311315
@Order(17)
316+
@DisplayName("#340 getSecretValue resolves partial ARN (without random suffix)")
317+
void getSecretValueByPartialArn() {
318+
Assumptions.assumeTrue(secretArn != null, "CreateSecret must succeed first");
319+
320+
// Full ARN: arn:aws:secretsmanager:...:secret:<name>-XXXXXX (7 chars: hyphen + 6)
321+
// Partial: arn:aws:secretsmanager:...:secret:<name>
322+
String partialArn = secretArn.substring(0, secretArn.length() - 7);
323+
324+
GetSecretValueResponse response = sm.getSecretValue(GetSecretValueRequest.builder()
325+
.secretId(partialArn)
326+
.build());
327+
328+
assertThat(response.secretString()).isEqualTo(UPDATED_VALUE);
329+
assertThat(response.name()).isEqualTo(secretName);
330+
}
331+
332+
@Test
333+
@Order(18)
334+
@DisplayName("#340 getSecretValue resolves partial ARN for secret with slashes in name")
335+
void getSecretValueByPartialArnWithSlashesInName() {
336+
String slashName = "compat-340/dev/database-" + System.currentTimeMillis();
337+
338+
try {
339+
CreateSecretResponse created = sm.createSecret(CreateSecretRequest.builder()
340+
.name(slashName)
341+
.secretString("db-pass")
342+
.build());
343+
344+
String partialArn = created.arn().substring(0, created.arn().length() - 7);
345+
346+
GetSecretValueResponse response = sm.getSecretValue(GetSecretValueRequest.builder()
347+
.secretId(partialArn)
348+
.build());
349+
350+
assertThat(response.secretString()).isEqualTo("db-pass");
351+
assertThat(response.name()).isEqualTo(slashName);
352+
} finally {
353+
try {
354+
sm.deleteSecret(DeleteSecretRequest.builder()
355+
.secretId(slashName)
356+
.forceDeleteWithoutRecovery(true)
357+
.build());
358+
} catch (Exception ignored) {}
359+
}
360+
}
361+
362+
@Test
363+
@Order(19)
312364
void batchGetSecretValue() {
313365
String s1 = "batch-secret-1-" + System.currentTimeMillis();
314366
String s2 = "batch-secret-2-" + System.currentTimeMillis();

src/main/java/io/github/hectorvent/floci/services/secretsmanager/SecretsManagerService.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,15 +311,33 @@ public record BatchSecretValue(
311311

312312
private Secret resolveSecret(String secretId, String region) {
313313
if (secretId.startsWith("arn:")) {
314+
// 1. Exact full-ARN match
314315
List<Secret> found = store.scan(key -> {
315316
Secret s = store.get(key).orElse(null);
316317
return s != null && secretId.equals(s.getArn());
317318
});
318-
if (found.isEmpty()) {
319-
throw new AwsException("ResourceNotFoundException",
320-
"Secrets Manager can't find the specified secret.", 400);
319+
if (!found.isEmpty()) {
320+
return found.getFirst();
321+
}
322+
323+
// 2. Partial-ARN fallback: extract region + name and do a name-based lookup.
324+
// AWS supports ARNs without the trailing "-XXXXXX" random suffix.
325+
// ARN format: arn:aws:secretsmanager:<region>:<account>:secret:<name>
326+
String smPrefix = "arn:aws:secretsmanager:";
327+
if (secretId.startsWith(smPrefix)) {
328+
String[] parts = secretId.substring(smPrefix.length()).split(":", 4);
329+
if (parts.length == 4 && "secret".equals(parts[2])) {
330+
String arnRegion = parts[0];
331+
String nameFromArn = parts[3];
332+
Secret byName = store.get(regionKey(arnRegion, nameFromArn)).orElse(null);
333+
if (byName != null) {
334+
return byName;
335+
}
336+
}
321337
}
322-
return found.getFirst();
338+
339+
throw new AwsException("ResourceNotFoundException",
340+
"Secrets Manager can't find the specified secret.", 400);
323341
}
324342

325343
String storageKey = regionKey(region, secretId);

src/test/java/io/github/hectorvent/floci/services/secretsmanager/SecretsManagerServiceTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,41 @@ void batchGetSecretValueThrowsIfNotFound() {
234234
service.batchGetSecretValue(List.of("secret1", "non-existent"), REGION));
235235
}
236236

237+
@Test
238+
void getSecretValueByPartialArnSucceeds() {
239+
Secret secret = service.createSecret("my-secret", "value", null, null, null, null, REGION);
240+
// Full ARN: arn:aws:secretsmanager:us-east-1:000000000000:secret:my-secret-XXXXXX
241+
// Partial: arn:aws:secretsmanager:us-east-1:000000000000:secret:my-secret
242+
String partialArn = secret.getArn().substring(0, secret.getArn().length() - 7);
243+
244+
SecretVersion version = service.getSecretValue(partialArn, null, null, REGION);
245+
assertEquals("value", version.getSecretString());
246+
}
247+
248+
@Test
249+
void getSecretValueByPartialArnWithSlashesInNameSucceeds() {
250+
Secret secret = service.createSecret("my-app/dev/database", "db-pass", null, null, null, null, REGION);
251+
String partialArn = secret.getArn().substring(0, secret.getArn().length() - 7);
252+
253+
SecretVersion version = service.getSecretValue(partialArn, null, null, REGION);
254+
assertEquals("db-pass", version.getSecretString());
255+
}
256+
257+
@Test
258+
void getSecretValueByFullArnStillWorks() {
259+
Secret secret = service.createSecret("my-secret", "value", null, null, null, null, REGION);
260+
261+
SecretVersion version = service.getSecretValue(secret.getArn(), null, null, REGION);
262+
assertEquals("value", version.getSecretString());
263+
}
264+
265+
@Test
266+
void getSecretValueByNonExistentPartialArnThrows() {
267+
String nonExistent = "arn:aws:secretsmanager:us-east-1:000000000000:secret:does-not-exist";
268+
assertThrows(AwsException.class, () ->
269+
service.getSecretValue(nonExistent, null, null, REGION));
270+
}
271+
237272
@Test
238273
void kmsKeyIdIsPreserved() {
239274
String kmsKeyId = "arn:aws:kms:us-east-1:000000000000:key/my-key";

0 commit comments

Comments
 (0)