From 5a580dfb3f3f6bb71c36e3da8aa9a9204c8e970c Mon Sep 17 00:00:00 2001 From: fjtirado Date: Thu, 20 Nov 2025 20:52:11 +0100 Subject: [PATCH] [Fix #999] Support for more than one level of indirection for secret Signed-off-by: fjtirado --- .../impl/config/ConfigSecretManager.java | 15 ++++++- .../impl/test/SecretExpressionTest.java | 42 ++++++++++--------- .../workflows-samples/secret-expression.yaml | 4 +- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/impl/core/src/main/java/io/serverlessworkflow/impl/config/ConfigSecretManager.java b/impl/core/src/main/java/io/serverlessworkflow/impl/config/ConfigSecretManager.java index b9e1b6ae..dff3f63a 100644 --- a/impl/core/src/main/java/io/serverlessworkflow/impl/config/ConfigSecretManager.java +++ b/impl/core/src/main/java/io/serverlessworkflow/impl/config/ConfigSecretManager.java @@ -17,6 +17,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; public class ConfigSecretManager implements SecretManager { @@ -41,9 +42,21 @@ private Map buildMap(String secretName) { if (name.startsWith(prefix)) { configManager .config(name, String.class) - .ifPresent(v -> map.put(name.substring(prefix.length()), v)); + .ifPresent(v -> addToMap(map, name.substring(prefix.length()), v)); } } return map; } + + private void addToMap(Map map, String name, Object v) { + StringTokenizer tokenizer = new StringTokenizer(name, "."); + while (tokenizer.hasMoreTokens()) { + name = tokenizer.nextToken(); + if (tokenizer.hasMoreTokens()) { + map = (Map) map.computeIfAbsent(name, k -> new HashMap<>()); + } else { + map.put(name, v); + } + } + } } diff --git a/impl/test/src/test/java/io/serverlessworkflow/impl/test/SecretExpressionTest.java b/impl/test/src/test/java/io/serverlessworkflow/impl/test/SecretExpressionTest.java index fd9f6bb4..c2e19b45 100644 --- a/impl/test/src/test/java/io/serverlessworkflow/impl/test/SecretExpressionTest.java +++ b/impl/test/src/test/java/io/serverlessworkflow/impl/test/SecretExpressionTest.java @@ -45,18 +45,18 @@ static void init() throws IOException { @ResourceLock(Resources.SYSTEM_PROPERTIES) void testDefault() { System.setProperty("superman.name", "ClarkKent"); + System.setProperty("superman.enemy.name", "Lex Luthor"); + System.setProperty("superman.enemy.isHuman", "true"); try (WorkflowApplication appl = WorkflowApplication.builder().build()) { - assertThat( - appl.workflowDefinition(workflow) - .instance(Map.of()) - .start() - .join() - .asMap() - .orElseThrow() - .get("superSecret")) - .isEqualTo("ClarkKent"); + Map map = + appl.workflowDefinition(workflow).instance(Map.of()).start().join().asMap().orElseThrow(); + assertThat(map.get("superSecret")).isEqualTo("ClarkKent"); + assertThat(map.get("theEnemy")).isEqualTo("Lex Luthor"); + assertThat(map.get("humanEnemy")).isEqualTo("true"); } finally { System.clearProperty("superman.name"); + System.clearProperty("superman.enemy.name"); + System.clearProperty("superman.enemy.isHuman"); } } @@ -78,16 +78,20 @@ void testMissing() { @Test void testCustom() { try (WorkflowApplication appl = - WorkflowApplication.builder().withSecretManager(k -> Map.of("name", "ClarkKent")).build()) { - assertThat( - appl.workflowDefinition(workflow) - .instance(Map.of()) - .start() - .join() - .asMap() - .orElseThrow() - .get("superSecret")) - .isEqualTo("ClarkKent"); + WorkflowApplication.builder() + .withSecretManager( + k -> + Map.of( + "name", + "ClarkKent", + "enemy", + Map.of("name", "Lex Luthor", "isHuman", true))) + .build()) { + Map map = + appl.workflowDefinition(workflow).instance(Map.of()).start().join().asMap().orElseThrow(); + assertThat(map.get("superSecret")).isEqualTo("ClarkKent"); + assertThat(map.get("theEnemy")).isEqualTo("Lex Luthor"); + assertThat(map.get("humanEnemy")).isEqualTo(true); } } } diff --git a/impl/test/src/test/resources/workflows-samples/secret-expression.yaml b/impl/test/src/test/resources/workflows-samples/secret-expression.yaml index 9abb1390..455a25f7 100644 --- a/impl/test/src/test/resources/workflows-samples/secret-expression.yaml +++ b/impl/test/src/test/resources/workflows-samples/secret-expression.yaml @@ -9,4 +9,6 @@ use: do: - useExpression: set: - superSecret: ${$secret.superman.name} \ No newline at end of file + superSecret: ${$secret.superman.name} + theEnemy: ${$secret.superman.enemy.name} + humanEnemy: ${$secret.superman.enemy.isHuman} \ No newline at end of file