This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new 17eecc61af issue #6716 (small path prefix feature for the Hashicorp 
Vault variable resolver) (#6722)
17eecc61af is described below

commit 17eecc61afbf035572df8a9319184dbaa36da54e
Author: Matt Casters <[email protected]>
AuthorDate: Fri Mar 6 13:39:08 2026 +0100

    issue #6716 (small path prefix feature for the Hashicorp Vault variable 
resolver) (#6722)
---
 .../hashicorp-vault-variable-resolver.adoc         |  15 ++
 .../resolver/0001-vault-add-secrets.hpl            |  24 +++-
 ... => 0001-vault-resolve-secrets-with-prefix.hpl} | 152 ++++++++++-----------
 .../resolver/main-0001-resolve-secrets.hwf         |  25 +++-
 ...001-vault-resolve-secrets-with-prefix UNIT.json |  53 +++++++
 .../metadata/variable-resolver/vault-prefix.json   |  17 +++
 .../resolver/vault/VaultVariableResolver.java      |  33 +++--
 .../vault/messages/messages_en_US.properties       |   1 +
 8 files changed, 230 insertions(+), 90 deletions(-)

diff --git 
a/docs/hop-user-manual/modules/ROOT/pages/metadata-types/variable-resolver/hashicorp-vault-variable-resolver.adoc
 
b/docs/hop-user-manual/modules/ROOT/pages/metadata-types/variable-resolver/hashicorp-vault-variable-resolver.adoc
index a89a345ba4..85db1acc79 100644
--- 
a/docs/hop-user-manual/modules/ROOT/pages/metadata-types/variable-resolver/hashicorp-vault-variable-resolver.adoc
+++ 
b/docs/hop-user-manual/modules/ROOT/pages/metadata-types/variable-resolver/hashicorp-vault-variable-resolver.adoc
@@ -27,6 +27,21 @@ Here are the options to use:
 
 * Vault address: The base address and port of the Vault server (for example: 
https://vault-server:8200)
 * Vault token: The token to use to authenticate
+* Path prefix: an optional path prefix which gets added before the key paths 
in the resolver expressions.  For example, if you put `kv-other/data` in here, 
expression
+
+[source]
+----
+#{vault:db:password}
+----
+
+will resolve internally to:
+
+[source]
+----
+#{vault:kv-other/data/db:password}
+----
+
+
 * Validate HTTPS connections?: It's recommended to enable connection 
validation in production. This secures the connection with the X.509 
certificate specified in one of either next option.
 * PEM file path: The name of the file (VFS) containing the X.509 certificate 
string
 * PEM string: The X.509 string itself in case you're not using a file
diff --git a/integration-tests/resolver/0001-vault-add-secrets.hpl 
b/integration-tests/resolver/0001-vault-add-secrets.hpl
index 9ad503a4f2..aa5deade06 100644
--- a/integration-tests/resolver/0001-vault-add-secrets.hpl
+++ b/integration-tests/resolver/0001-vault-add-secrets.hpl
@@ -19,7 +19,7 @@ limitations under the License.
 -->
 <pipeline>
   <info>
-    <name>0001-add-secrets</name>
+    <name>0001-vault-add-secrets</name>
     <name_sync_with_filename>Y</name_sync_with_filename>
     <description/>
     <extended_description/>
@@ -80,6 +80,10 @@ limitations under the License.
     <result>
       <name>result</name>
     </result>
+    <retryMethods>
+</retryMethods>
+    <retryStatusCodes>
+</retryStatusCodes>
     <trustStorePassword>Encrypted </trustStorePassword>
     <urlField>url</urlField>
     <urlInField>Y</urlInField>
@@ -103,7 +107,7 @@ limitations under the License.
     <data>
       <line>
         <item>myroot</item>
-        <item>http://vault:8200/v1/secret/data/hop</item>
+        <item>http://localhost:8200/v1/secret/data/hop</item>
         <item>application/json</item>
         <item>{
   "data": {
@@ -121,29 +125,45 @@ limitations under the License.
       <field>
         <length>-1</length>
         <precision>-1</precision>
+        <currency/>
         <set_empty_string>N</set_empty_string>
         <name>root</name>
+        <format/>
+        <group/>
+        <decimal/>
         <type>String</type>
       </field>
       <field>
         <length>-1</length>
         <precision>-1</precision>
+        <currency/>
         <set_empty_string>N</set_empty_string>
         <name>url</name>
+        <format/>
+        <group/>
+        <decimal/>
         <type>String</type>
       </field>
       <field>
         <length>-1</length>
         <precision>-1</precision>
+        <currency/>
         <set_empty_string>N</set_empty_string>
         <name>contentType</name>
+        <format/>
+        <group/>
+        <decimal/>
         <type>String</type>
       </field>
       <field>
         <length>-1</length>
         <precision>-1</precision>
+        <currency/>
         <set_empty_string>N</set_empty_string>
         <name>data</name>
+        <format/>
+        <group/>
+        <decimal/>
         <type>String</type>
       </field>
     </fields>
diff --git a/integration-tests/resolver/0001-vault-add-secrets.hpl 
b/integration-tests/resolver/0001-vault-resolve-secrets-with-prefix.hpl
similarity index 54%
copy from integration-tests/resolver/0001-vault-add-secrets.hpl
copy to integration-tests/resolver/0001-vault-resolve-secrets-with-prefix.hpl
index 9ad503a4f2..e19f293819 100644
--- a/integration-tests/resolver/0001-vault-add-secrets.hpl
+++ b/integration-tests/resolver/0001-vault-resolve-secrets-with-prefix.hpl
@@ -19,7 +19,7 @@ limitations under the License.
 -->
 <pipeline>
   <info>
-    <name>0001-add-secrets</name>
+    <name>0001-vault-resolve-secrets-with-prefix</name>
     <name_sync_with_filename>Y</name_sync_with_filename>
     <description/>
     <extended_description/>
@@ -31,22 +31,43 @@ limitations under the License.
     
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
     
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
     <created_user>-</created_user>
-    <created_date>2025/01/14 15:47:02.970</created_date>
+    <created_date>2025/01/14 15:54:11.134</created_date>
     <modified_user>-</modified_user>
-    <modified_date>2025/01/14 15:47:02.970</modified_date>
+    <modified_date>2025/01/14 15:54:11.134</modified_date>
   </info>
   <notepads>
+    <notepad>
+      <backgroundcolorblue>210</backgroundcolorblue>
+      <backgroundcolorgreen>136</backgroundcolorgreen>
+      <backgroundcolorred>15</backgroundcolorred>
+      <bordercolorblue>250</bordercolorblue>
+      <bordercolorgreen>231</bordercolorgreen>
+      <bordercolorred>200</bordercolorred>
+      <fontbold>N</fontbold>
+      <fontcolorblue>250</fontcolorblue>
+      <fontcolorgreen>231</fontcolorgreen>
+      <fontcolorred>200</fontcolorred>
+      <fontitalic>N</fontitalic>
+      <fontname>Cantarell</fontname>
+      <fontsize>11</fontsize>
+      <height>32</height>
+      <xloc>48</xloc>
+      <yloc>112</yloc>
+      <note>The vault-prefix resolver contains the path prefix making the 
expressions shorter.
+This tests that functionality.</note>
+      <width>32</width>
+    </notepad>
   </notepads>
   <order>
     <hop>
-      <from>Secrets</from>
-      <to>REST client</to>
+      <from>Get variables</from>
+      <to>Output</to>
       <enabled>Y</enabled>
     </hop>
   </order>
   <transform>
-    <name>REST client</name>
-    <type>Rest</type>
+    <name>Get variables</name>
+    <type>GetVariable</type>
     <description/>
     <distribute>Y</distribute>
     <custom_distribution/>
@@ -55,102 +76,77 @@ limitations under the License.
       <method>none</method>
       <schema_name/>
     </partitioning>
-    <applicationType>TEXT PLAIN</applicationType>
-    <bodyField>data</bodyField>
-    <connectionTimeout>10000</connectionTimeout>
-    <dynamicMethod>N</dynamicMethod>
-    <headers>
-      <header>
-        <field>contentType</field>
-        <name>Content-Type</name>
-      </header>
-      <header>
-        <field>root</field>
-        <name>X-Vault-Token</name>
-      </header>
-    </headers>
-    <ignoreSsl>N</ignoreSsl>
-    <matrixParameters>
-</matrixParameters>
-    <method>POST</method>
-    <parameters>
-</parameters>
-    <preemptive>N</preemptive>
-    <readTimeout>10000</readTimeout>
-    <result>
-      <name>result</name>
-    </result>
-    <trustStorePassword>Encrypted </trustStorePassword>
-    <urlField>url</urlField>
-    <urlInField>Y</urlInField>
-    <attributes/>
-    <GUI>
-      <xloc>208</xloc>
-      <yloc>64</yloc>
-    </GUI>
-  </transform>
-  <transform>
-    <name>Secrets</name>
-    <type>DataGrid</type>
-    <description/>
-    <distribute>Y</distribute>
-    <custom_distribution/>
-    <copies>1</copies>
-    <partitioning>
-      <method>none</method>
-      <schema_name/>
-    </partitioning>
-    <data>
-      <line>
-        <item>myroot</item>
-        <item>http://vault:8200/v1/secret/data/hop</item>
-        <item>application/json</item>
-        <item>{
-  "data": {
-    "db": "test",
-    "hostname": "localhost",
-    "password": "some-password",
-    "port": "3306",
-    "username": "john"
-  },
-  "options": {}
-}</item>
-      </line>
-    </data>
     <fields>
       <field>
         <length>-1</length>
+        <name>json-data</name>
+        <precision>-1</precision>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <variable>#{vault-prefix:hop}</variable>
+      </field>
+      <field>
+        <length>-1</length>
+        <name>hostname</name>
         <precision>-1</precision>
-        <set_empty_string>N</set_empty_string>
-        <name>root</name>
+        <trim_type>none</trim_type>
         <type>String</type>
+        <variable>#{vault-prefix:hop:hostname}</variable>
       </field>
       <field>
         <length>-1</length>
+        <name>port</name>
         <precision>-1</precision>
-        <set_empty_string>N</set_empty_string>
-        <name>url</name>
+        <trim_type>none</trim_type>
         <type>String</type>
+        <variable>#{vault-prefix:hop:port}</variable>
       </field>
       <field>
         <length>-1</length>
+        <name>db</name>
         <precision>-1</precision>
-        <set_empty_string>N</set_empty_string>
-        <name>contentType</name>
+        <trim_type>none</trim_type>
         <type>String</type>
+        <variable>#{vault-prefix:hop:db}</variable>
       </field>
       <field>
         <length>-1</length>
+        <name>username</name>
         <precision>-1</precision>
-        <set_empty_string>N</set_empty_string>
-        <name>data</name>
+        <trim_type>none</trim_type>
         <type>String</type>
+        <variable>#{vault-prefix:hop:username}</variable>
+      </field>
+      <field>
+        <length>-1</length>
+        <name>password</name>
+        <precision>-1</precision>
+        <trim_type>none</trim_type>
+        <type>String</type>
+        <variable>#{vault-prefix:hop:password}</variable>
       </field>
     </fields>
     <attributes/>
     <GUI>
       <xloc>64</xloc>
-      <yloc>64</yloc>
+      <yloc>48</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Output</name>
+    <type>Dummy</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>288</xloc>
+      <yloc>48</yloc>
     </GUI>
   </transform>
   <transform_error_handling>
diff --git a/integration-tests/resolver/main-0001-resolve-secrets.hwf 
b/integration-tests/resolver/main-0001-resolve-secrets.hwf
index ed5f53cb6a..de9c30c47b 100644
--- a/integration-tests/resolver/main-0001-resolve-secrets.hwf
+++ b/integration-tests/resolver/main-0001-resolve-secrets.hwf
@@ -36,6 +36,7 @@ limitations under the License.
       <type>SPECIAL</type>
       <attributes/>
       <DayOfMonth>1</DayOfMonth>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
       <hour>12</hour>
       <intervalMinutes>60</intervalMinutes>
       <intervalSeconds>0</intervalSeconds>
@@ -60,8 +61,6 @@ limitations under the License.
       <create_parent_folder>N</create_parent_folder>
       <exec_per_row>N</exec_per_row>
       <filename>${PROJECT_HOME}/0001-vault-add-secrets.hpl</filename>
-      <logext/>
-      <logfile/>
       <loglevel>Basic</loglevel>
       <parameters>
         <pass_all_parameters>Y</pass_all_parameters>
@@ -85,6 +84,9 @@ limitations under the License.
         <test_name>
           <name>0001-vault-resolve-secrets UNIT</name>
         </test_name>
+        <test_name>
+          <name>0001-vault-resolve-secrets-with-prefix UNIT</name>
+        </test_name>
       </test_names>
       <parallel>N</parallel>
       <xloc>416</xloc>
@@ -109,6 +111,25 @@ limitations under the License.
     </hop>
   </hops>
   <notepads>
+    <notepad>
+      <backgroundcolorblue>251</backgroundcolorblue>
+      <backgroundcolorgreen>232</backgroundcolorgreen>
+      <backgroundcolorred>201</backgroundcolorred>
+      <bordercolorblue>90</bordercolorblue>
+      <bordercolorgreen>58</bordercolorgreen>
+      <bordercolorred>14</bordercolorred>
+      <fontbold>N</fontbold>
+      <fontcolorblue>90</fontcolorblue>
+      <fontcolorgreen>58</fontcolorgreen>
+      <fontcolorred>14</fontcolorred>
+      <fontitalic>N</fontitalic>
+      <fontsize>-1</fontsize>
+      <height>32</height>
+      <xloc>119</xloc>
+      <yloc>196</yloc>
+      <note>VAULT_ADDR='http://0.0.0.0:8200'</note>
+      <width>32</width>
+    </notepad>
   </notepads>
   <attributes/>
 </workflow>
diff --git 
a/integration-tests/resolver/metadata/unit-test/0001-vault-resolve-secrets-with-prefix
 UNIT.json 
b/integration-tests/resolver/metadata/unit-test/0001-vault-resolve-secrets-with-prefix
 UNIT.json
new file mode 100644
index 0000000000..8a5f7271cc
--- /dev/null
+++ 
b/integration-tests/resolver/metadata/unit-test/0001-vault-resolve-secrets-with-prefix
 UNIT.json    
@@ -0,0 +1,53 @@
+{
+  "database_replacements": [],
+  "autoOpening": true,
+  "description": "",
+  "persist_filename": "",
+  "test_type": "UNIT_TEST",
+  "variableValues": [],
+  "basePath": "${HOP_UNIT_TESTS_FOLDER}",
+  "golden_data_sets": [
+    {
+      "field_mappings": [
+        {
+          "transform_field": "json-data",
+          "data_set_field": "json-data"
+        },
+        {
+          "transform_field": "hostname",
+          "data_set_field": "hostname"
+        },
+        {
+          "transform_field": "port",
+          "data_set_field": "port"
+        },
+        {
+          "transform_field": "db",
+          "data_set_field": "db"
+        },
+        {
+          "transform_field": "username",
+          "data_set_field": "username"
+        },
+        {
+          "transform_field": "password",
+          "data_set_field": "password"
+        }
+      ],
+      "field_order": [
+        "json-data",
+        "hostname",
+        "port",
+        "db",
+        "username",
+        "password"
+      ],
+      "data_set_name": "0001-golden-resolved-variables",
+      "transform_name": "Output"
+    }
+  ],
+  "input_data_sets": [],
+  "name": "0001-vault-resolve-secrets-with-prefix UNIT",
+  "trans_test_tweaks": [],
+  "pipeline_filename": "./0001-vault-resolve-secrets-with-prefix.hpl"
+}
\ No newline at end of file
diff --git 
a/integration-tests/resolver/metadata/variable-resolver/vault-prefix.json 
b/integration-tests/resolver/metadata/variable-resolver/vault-prefix.json
new file mode 100644
index 0000000000..4f4165e96f
--- /dev/null
+++ b/integration-tests/resolver/metadata/variable-resolver/vault-prefix.json
@@ -0,0 +1,17 @@
+{
+  "virtualPath": "",
+  "name": "vault-prefix",
+  "description": "Hashicorp Vault",
+  "variable-resolver": {
+    "Vault-Variable-Resolver": {
+      "vaultAddress": "http://vault:8200";,
+      "pemString": "",
+      "openTimeout": "",
+      "verifyingSsl": false,
+      "pemFilePath": "",
+      "readTimeout": "",
+      "pathPrefix": "secret/data/",
+      "vaultToken": "myroot"
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/plugins/tech/vault/src/main/java/org/apache/hop/core/variables/resolver/vault/VaultVariableResolver.java
 
b/plugins/tech/vault/src/main/java/org/apache/hop/core/variables/resolver/vault/VaultVariableResolver.java
index 45982924ff..aa232253b8 100644
--- 
a/plugins/tech/vault/src/main/java/org/apache/hop/core/variables/resolver/vault/VaultVariableResolver.java
+++ 
b/plugins/tech/vault/src/main/java/org/apache/hop/core/variables/resolver/vault/VaultVariableResolver.java
@@ -54,7 +54,7 @@ public class VaultVariableResolver implements 
IVariableResolver {
 
   @GuiWidgetElement(
       id = "vaultAddress",
-      order = "01",
+      order = "10",
       label =
           
"i18n:org.apache.hop.core.variables.resolver.vault:VaultVariableResolver.label.vaultAddress",
       type = GuiElementType.TEXT,
@@ -64,7 +64,7 @@ public class VaultVariableResolver implements 
IVariableResolver {
 
   @GuiWidgetElement(
       id = "vaultToken",
-      order = "02",
+      order = "20",
       label =
           
"i18n:org.apache.hop.core.variables.resolver.vault:VaultVariableResolver.label.vaultToken",
       type = GuiElementType.TEXT,
@@ -73,9 +73,19 @@ public class VaultVariableResolver implements 
IVariableResolver {
   @HopMetadataProperty
   private String vaultToken;
 
+  @GuiWidgetElement(
+      id = "pathPrefix",
+      order = "30",
+      label =
+          
"i18n:org.apache.hop.core.variables.resolver.vault:VaultVariableResolver.label.pathPrefix",
+      type = GuiElementType.TEXT,
+      parentId = VariableResolver.GUI_PLUGIN_ELEMENT_PARENT_ID)
+  @HopMetadataProperty
+  private String pathPrefix;
+
   @GuiWidgetElement(
       id = "verifyingSsl",
-      order = "03",
+      order = "40",
       label =
           
"i18n:org.apache.hop.core.variables.resolver.vault:VaultVariableResolver.label.verifyingSsl",
       toolTip =
@@ -87,7 +97,7 @@ public class VaultVariableResolver implements 
IVariableResolver {
 
   @GuiWidgetElement(
       id = "pemFilePath",
-      order = "04",
+      order = "50",
       label =
           
"i18n:org.apache.hop.core.variables.resolver.vault:VaultVariableResolver.label.pemFilePath",
       type = GuiElementType.FILENAME,
@@ -97,7 +107,7 @@ public class VaultVariableResolver implements 
IVariableResolver {
 
   @GuiWidgetElement(
       id = "pemString",
-      order = "05",
+      order = "60",
       label =
           
"i18n:org.apache.hop.core.variables.resolver.vault:VaultVariableResolver.label.pemString",
       type = GuiElementType.TEXT,
@@ -108,7 +118,7 @@ public class VaultVariableResolver implements 
IVariableResolver {
 
   @GuiWidgetElement(
       id = "openTimeout",
-      order = "06",
+      order = "70",
       label =
           
"i18n:org.apache.hop.core.variables.resolver.vault:VaultVariableResolver.label.openTimeout",
       type = GuiElementType.TEXT,
@@ -118,7 +128,7 @@ public class VaultVariableResolver implements 
IVariableResolver {
 
   @GuiWidgetElement(
       id = "readTimeout",
-      order = "07",
+      order = "80",
       label =
           
"i18n:org.apache.hop.core.variables.resolver.vault:VaultVariableResolver.label.readTimeout",
       type = GuiElementType.TEXT,
@@ -173,7 +183,14 @@ public class VaultVariableResolver implements 
IVariableResolver {
 
       final Vault vault = new Vault(vaultConfig);
 
-      LogicalResponse logicalResponse = vault.logical().read(secretPath);
+      String path;
+      if (StringUtils.isNotEmpty(pathPrefix)) {
+        path = variables.resolve(pathPrefix) + secretPath;
+      } else {
+        path = secretPath;
+      }
+
+      LogicalResponse logicalResponse = vault.logical().read(path);
       if (logicalResponse == null) {
         LogChannel.GENERAL.logDetailed(
             "The secret with path '" + secretPath + "' was not found in the 
vault");
diff --git 
a/plugins/tech/vault/src/main/resources/org/apache/hop/core/variables/resolver/vault/messages/messages_en_US.properties
 
b/plugins/tech/vault/src/main/resources/org/apache/hop/core/variables/resolver/vault/messages/messages_en_US.properties
index 7b07c4180d..361b8e92d1 100644
--- 
a/plugins/tech/vault/src/main/resources/org/apache/hop/core/variables/resolver/vault/messages/messages_en_US.properties
+++ 
b/plugins/tech/vault/src/main/resources/org/apache/hop/core/variables/resolver/vault/messages/messages_en_US.properties
@@ -18,6 +18,7 @@
 
 VaultVariableResolver.label.vaultAddress = Vault address
 VaultVariableResolver.label.vaultToken = Vault token
+VaultVariableResolver.label.pathPrefix = Path prefix (optional)
 VaultVariableResolver.label.verifyingSsl = Validate HTTPS connections?
 VaultVariableResolver.tooltip.verifyingSsl = Enable this in production!  It 
validates connections with an X.509 certificate specified with one of the PEM 
options below.
 VaultVariableResolver.label.pemFilePath = PEM (X.509 certificate) file path

Reply via email to