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

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


The following commit(s) were added to refs/heads/main by this push:
     new 17e7b77283 [#14231] fix(secret): Omit reserved+hidden properties from 
getSecrets (#14232)
17e7b77283 is described below

commit 17e7b77283a6e4c84e8ee919450bc78b5dc71e59
Author: MaSai <[email protected]>
AuthorDate: Mon Oct 26 19:06:50 2026 +0800

    [#14231] fix(secret): Omit reserved+hidden properties from getSecrets 
(#14232)
    
    ### What changes were proposed in this pull request?
    
    - Exclude reserved+hidden properties (e.g. `gravitino.identifier`) from
    `SecretPropertyUtils.shouldRecoverSensitiveNamedSecret` / `buildSecrets`
    - Align docs with `HiddenPropertyMaskUtils` omit semantics
    - Add unit coverage
    
    ### Why are the changes needed?
    
    `getSecrets` treated every declared hidden property as recoverable, so
    the internal `gravitino.identifier` leaked into secret responses.
    
    Fix: #14231
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes — `getSecrets` no longer returns reserved+hidden internal keys such
    as `gravitino.identifier`. Real hidden secrets (e.g. `jdbc-password`)
    are unchanged.
    
    ### How was this patch tested?
    
    `./gradlew :core:test --tests
    org.apache.gravitino.secret.TestSecretPropertyUtils -PskipITs`
    
    Co-authored-by: Cursor <[email protected]>
---
 .../apache/gravitino/secret/SupportsSecrets.java   |  7 +++--
 .../connector/HiddenPropertyMaskUtils.java         |  8 +++---
 .../gravitino/secret/SecretPropertyUtils.java      | 20 +++++++++-----
 .../gravitino/secret/TestSecretPropertyUtils.java  | 32 ++++++++++++++++++++++
 4 files changed, 53 insertions(+), 14 deletions(-)

diff --git a/api/src/main/java/org/apache/gravitino/secret/SupportsSecrets.java 
b/api/src/main/java/org/apache/gravitino/secret/SupportsSecrets.java
index db87435dfa..3f835733e8 100644
--- a/api/src/main/java/org/apache/gravitino/secret/SupportsSecrets.java
+++ b/api/src/main/java/org/apache/gravitino/secret/SupportsSecrets.java
@@ -28,9 +28,10 @@ import java.util.Map;
  * <ul>
  *   <li>Every secret-URN property value, resolved via the secret manager 
(including keys that may
  *       also be delivered via {@link 
org.apache.gravitino.credential.SupportsCredentials}).
- *   <li>Stored plaintext for every property declared {@code hidden} in entity 
metadata (no
- *       sensitive-name keyword gate), so shortening the server sensitive-key 
keyword list cannot
- *       leave a masked property without a recovery path.
+ *   <li>Stored plaintext for every property declared {@code hidden} but not 
{@code reserved} in
+ *       entity metadata (no sensitive-name keyword gate), so shortening the 
server sensitive-key
+ *       keyword list cannot leave a masked property without a recovery path. 
Reserved+hidden
+ *       internal keys such as {@code gravitino.identifier} are never returned.
  *   <li>Stored plaintext for undeclared keys whose names look sensitive 
(contain {@code secret},
  *       {@code password}, {@code token}, {@code credential}, {@code access}, 
or {@code account},
  *       case-insensitive), so mistyped / undeclared credential properties 
remain usable after API
diff --git 
a/core/src/main/java/org/apache/gravitino/connector/HiddenPropertyMaskUtils.java
 
b/core/src/main/java/org/apache/gravitino/connector/HiddenPropertyMaskUtils.java
index 8301e73639..e4f407fc56 100644
--- 
a/core/src/main/java/org/apache/gravitino/connector/HiddenPropertyMaskUtils.java
+++ 
b/core/src/main/java/org/apache/gravitino/connector/HiddenPropertyMaskUtils.java
@@ -56,10 +56,10 @@ import org.slf4j.LoggerFactory;
  *       in-use}, {@code numFiles}).
  * </ul>
  *
- * <p>Recovery via {@code getSecrets} covers secret-URN values, declared 
{@code hidden} keys (except
- * credential-vending keys), and sensitive-named undeclared keys. Credential 
property keys are
- * recovered via {@code getCredentials()} instead. See {@code
- * org.apache.gravitino.secret.SupportsSecrets}.
+ * <p>Recovery via {@code getSecrets} covers secret-URN values, declared 
{@code hidden} keys that
+ * are not also {@code reserved} (reserved+hidden keys such as {@code 
gravitino.identifier} stay
+ * omitted), and sensitive-named undeclared keys. Credential property keys are 
recovered via {@code
+ * getCredentials()} instead. See {@code 
org.apache.gravitino.secret.SupportsSecrets}.
  *
  * <p><b>Write (create / alter)</b>: reject any value equal to {@link 
#MASKED_VALUE} so the
  * placeholder is never persisted. Reserved / immutable rejection remains in 
{@code
diff --git 
a/core/src/main/java/org/apache/gravitino/secret/SecretPropertyUtils.java 
b/core/src/main/java/org/apache/gravitino/secret/SecretPropertyUtils.java
index 5b4f6341e0..710eb28b27 100644
--- a/core/src/main/java/org/apache/gravitino/secret/SecretPropertyUtils.java
+++ b/core/src/main/java/org/apache/gravitino/secret/SecretPropertyUtils.java
@@ -89,9 +89,12 @@ public final class SecretPropertyUtils {
    * <ul>
    *   <li>{@code metadata == null}: do <strong>not</strong> recover 
(URN-only). Used when the
    *       catalog does not expose properties metadata for the entity type.
-   *   <li>declared {@code hidden}: always recover, without the 
sensitive-keyword gate — so
-   *       shortening {@link Configs#SENSITIVE_KEY_KEYWORDS} cannot leave a 
masked property without
-   *       a recovery path.
+   *   <li>declared {@code hidden} and not {@code reserved}: always recover, 
without the
+   *       sensitive-keyword gate — so shortening {@link 
Configs#SENSITIVE_KEY_KEYWORDS} cannot
+   *       leave a masked property without a recovery path.
+   *   <li>declared {@code reserved} and {@code hidden} (for example {@code 
gravitino.identifier}):
+   *       never recover — these are internal system properties omitted from 
API responses, not user
+   *       secrets.
    *   <li>undeclared: recover only when the key name matches {@link 
#isSensitivePropertyKey}
    *       (historical fuzzy recovery).
    *   <li>declared non-hidden: never recover here (for example {@code 
credential-providers} stays
@@ -112,7 +115,9 @@ public final class SecretPropertyUtils {
       return false;
     }
     if (metadata.containsProperty(key)) {
-      return metadata.isHiddenProperty(key);
+      // Align with HiddenPropertyMaskUtils: reserved+hidden keys are internal 
(e.g.
+      // gravitino.identifier) and must not appear in getSecrets.
+      return metadata.isHiddenProperty(key) && 
!metadata.isReservedProperty(key);
     }
     return isSensitivePropertyKey(key);
   }
@@ -154,9 +159,10 @@ public final class SecretPropertyUtils {
    *   <li>Include every entry where {@link #isSecretProperty} is true, 
resolving the secret URN via
    *       {@link SecretManager#readSecret}.
    *   <li>Include every inline entry when {@link 
#shouldRecoverSensitiveNamedSecret} is true:
-   *       declared {@code hidden} (no keyword gate), or undeclared with a 
sensitive-looking name.
-   *       Declared non-hidden keys are excluded even when the name looks 
sensitive. When {@code
-   *       metadata} is {@code null}, inline plaintext is not recovered 
(URN-only).
+   *       declared {@code hidden} and not {@code reserved} (no keyword gate), 
or undeclared with a
+   *       sensitive-looking name. Reserved+hidden keys (for example {@code 
gravitino.identifier})
+   *       and declared non-hidden keys are excluded. When {@code metadata} is 
{@code null}, inline
+   *       plaintext is not recovered (URN-only).
    * </ol>
    *
    * <p>Normal non-sensitive, non-hidden properties are not included. Clients 
merge this map over
diff --git 
a/core/src/test/java/org/apache/gravitino/secret/TestSecretPropertyUtils.java 
b/core/src/test/java/org/apache/gravitino/secret/TestSecretPropertyUtils.java
index 97c67d5bdf..85b7a53f20 100644
--- 
a/core/src/test/java/org/apache/gravitino/secret/TestSecretPropertyUtils.java
+++ 
b/core/src/test/java/org/apache/gravitino/secret/TestSecretPropertyUtils.java
@@ -18,6 +18,8 @@
  */
 package org.apache.gravitino.secret;
 
+import static org.apache.gravitino.StringIdentifier.ID_KEY;
+
 import com.google.common.collect.ImmutableMap;
 import java.util.HashMap;
 import java.util.List;
@@ -254,6 +256,36 @@ public class TestSecretPropertyUtils {
     }
   }
 
+  @Test
+  void testBuildSecretsOmitsReservedHiddenProperties() {
+    try (SecretManager sm = memorySecretManager()) {
+      PropertiesMetadata metadata =
+          new PropertiesMetadata() {
+            @Override
+            public Map<String, PropertyEntry<?>> propertyEntries() {
+              return ImmutableMap.of(
+                  ID_KEY,
+                  PropertyEntry.stringReservedPropertyEntry(
+                      ID_KEY, "internal entity identifier", true),
+                  "jdbc-password",
+                  PropertyEntry.stringOptionalPropertyEntry(
+                      "jdbc-password", "password", false, null, true));
+            }
+          };
+      Map<String, String> entityProps =
+          Map.of(ID_KEY, "gravitino.v1.uid123", "jdbc-password", "s3cr3t");
+      Map<String, String> secrets = SecretPropertyUtils.buildSecrets(sm, 
entityProps, metadata);
+      Assertions.assertEquals("s3cr3t", secrets.get("jdbc-password"));
+      Assertions.assertFalse(
+          secrets.containsKey(ID_KEY),
+          "reserved+hidden gravitino.identifier must not appear in 
getSecrets");
+      Assertions.assertFalse(
+          SecretPropertyUtils.shouldRecoverSensitiveNamedSecret(ID_KEY, 
metadata));
+      Assertions.assertTrue(
+          
SecretPropertyUtils.shouldRecoverSensitiveNamedSecret("jdbc-password", 
metadata));
+    }
+  }
+
   @Test
   void testMergeProperties() {
     Map<String, String> merged =

Reply via email to