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

wanghailin pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new 6145da9628 [Improve][Zeta] Handle user privacy when submitting a task 
print config logs (#7247)
6145da9628 is described below

commit 6145da96283f2115f18c19c53269be37000e71b2
Author: zhangdonghao <[email protected]>
AuthorDate: Sat Aug 24 16:13:05 2024 +0800

    [Improve][Zeta] Handle user privacy when submitting a task print config 
logs (#7247)
---
 config/seatunnel.yaml                              |  2 +-
 .../core/starter/utils/ConfigBuilder.java          | 69 +++++++++++++++++++++-
 .../core/starter/utils/ConfigShadeUtils.java       |  6 +-
 .../core/starter/utils/ConfigShadeTest.java        | 43 ++++++++++++++
 .../src/test/resources/config.shade.json           | 41 +++++++++++++
 .../seatunnel/engine/server/utils/RestUtil.java    |  2 +-
 6 files changed, 156 insertions(+), 7 deletions(-)

diff --git a/config/seatunnel.yaml b/config/seatunnel.yaml
index 5961c83923..6b81b92ea3 100644
--- a/config/seatunnel.yaml
+++ b/config/seatunnel.yaml
@@ -33,4 +33,4 @@ seatunnel:
         plugin-config:
           namespace: /tmp/seatunnel/checkpoint_snapshot
           storage.type: hdfs
-          fs.defaultFS: file:///tmp/ # Ensure that the directory has written 
permission
\ No newline at end of file
+          fs.defaultFS: file:///tmp/ # Ensure that the directory has written 
permission
diff --git 
a/seatunnel-core/seatunnel-core-starter/src/main/java/org/apache/seatunnel/core/starter/utils/ConfigBuilder.java
 
b/seatunnel-core/seatunnel-core-starter/src/main/java/org/apache/seatunnel/core/starter/utils/ConfigBuilder.java
index 57d26ee0e7..0bd85213f5 100644
--- 
a/seatunnel-core/seatunnel-core-starter/src/main/java/org/apache/seatunnel/core/starter/utils/ConfigBuilder.java
+++ 
b/seatunnel-core/seatunnel-core-starter/src/main/java/org/apache/seatunnel/core/starter/utils/ConfigBuilder.java
@@ -22,9 +22,11 @@ import 
org.apache.seatunnel.shade.com.typesafe.config.ConfigFactory;
 import org.apache.seatunnel.shade.com.typesafe.config.ConfigParseOptions;
 import org.apache.seatunnel.shade.com.typesafe.config.ConfigRenderOptions;
 import org.apache.seatunnel.shade.com.typesafe.config.ConfigResolveOptions;
+import org.apache.seatunnel.shade.com.typesafe.config.ConfigSyntax;
 import org.apache.seatunnel.shade.com.typesafe.config.impl.Parseable;
 
 import org.apache.seatunnel.api.configuration.ConfigAdapter;
+import org.apache.seatunnel.common.utils.JsonUtils;
 import org.apache.seatunnel.common.utils.ParserException;
 
 import lombok.NonNull;
@@ -32,10 +34,14 @@ import lombok.extern.slf4j.Slf4j;
 
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static 
org.apache.seatunnel.core.starter.utils.ConfigShadeUtils.DEFAULT_SENSITIVE_KEYWORDS;
 
 /** Used to build the {@link Config} from config file. */
 @Slf4j
@@ -76,14 +82,19 @@ public class ConfigBuilder {
                 adapterSupplier
                         .map(adapter -> of(adapter, filePath, variables))
                         .orElseGet(() -> ofInner(filePath, variables));
+        boolean isJson = filePath.getFileName().toString().endsWith(".json");
+        log.info(
+                "Parsed config file: \n{}",
+                mapToString(configDesensitization(config.root().unwrapped()), 
isJson));
         return config;
     }
 
     public static Config of(@NonNull Map<String, Object> objectMap) {
-        return of(objectMap, false);
+        return of(objectMap, false, false);
     }
 
-    public static Config of(@NonNull Map<String, Object> objectMap, boolean 
isEncrypt) {
+    public static Config of(
+            @NonNull Map<String, Object> objectMap, boolean isEncrypt, boolean 
isJson) {
         log.info("Loading config file from objectMap");
         Config config =
                 ConfigFactory.parseMap(objectMap)
@@ -94,9 +105,49 @@ public class ConfigBuilder {
         if (!isEncrypt) {
             config = ConfigShadeUtils.decryptConfig(config);
         }
+        log.info(
+                "Parsed config file: \n{}",
+                mapToString(configDesensitization(config.root().unwrapped()), 
isJson));
         return config;
     }
 
+    public static Map<String, Object> configDesensitization(Map<String, 
Object> configMap) {
+        return configMap.entrySet().stream()
+                .collect(
+                        Collectors.toMap(
+                                Map.Entry::getKey,
+                                entry -> {
+                                    String key = entry.getKey();
+                                    if 
(Arrays.asList(DEFAULT_SENSITIVE_KEYWORDS)
+                                            .contains(key.toLowerCase())) {
+                                        return "******";
+                                    }
+                                    Object value = entry.getValue();
+                                    if (value instanceof Map) {
+                                        if ("schema".equals(key)) {
+                                            return value;
+                                        }
+                                        return 
configDesensitization((Map<String, Object>) value);
+                                    } else if (value instanceof List) {
+                                        return ((List<?>) value)
+                                                .stream()
+                                                        .map(
+                                                                v -> {
+                                                                    if (v 
instanceof Map) {
+                                                                        return 
configDesensitization(
+                                                                               
 (Map<
+                                                                               
                 String,
+                                                                               
                 Object>)
+                                                                               
         v);
+                                                                    }
+                                                                    return v;
+                                                                })
+                                                        
.collect(Collectors.toList());
+                                    }
+                                    return value;
+                                }));
+    }
+
     public static Config of(
             @NonNull ConfigAdapter configAdapter, @NonNull Path filePath, 
List<String> variables) {
         log.info("With config adapter spi {}", 
configAdapter.getClass().getName());
@@ -133,4 +184,18 @@ public class ConfigBuilder {
         }
         return config;
     }
+
+    public static String mapToString(Map<String, Object> configMap, boolean 
isJson) {
+        ConfigRenderOptions configRenderOptions =
+                
ConfigRenderOptions.concise().setFormatted(true).setJson(isJson);
+        ConfigParseOptions configParseOptions =
+                ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON);
+        Config config =
+                ConfigFactory.parseString(JsonUtils.toJsonString(configMap), 
configParseOptions)
+                        
.resolve(ConfigResolveOptions.defaults().setAllowUnresolved(true))
+                        .resolveWith(
+                                ConfigFactory.systemProperties(),
+                                
ConfigResolveOptions.defaults().setAllowUnresolved(true));
+        return config.root().render(configRenderOptions);
+    }
 }
diff --git 
a/seatunnel-core/seatunnel-core-starter/src/main/java/org/apache/seatunnel/core/starter/utils/ConfigShadeUtils.java
 
b/seatunnel-core/seatunnel-core-starter/src/main/java/org/apache/seatunnel/core/starter/utils/ConfigShadeUtils.java
index a1e3dffe01..3269ab8cd8 100644
--- 
a/seatunnel-core/seatunnel-core-starter/src/main/java/org/apache/seatunnel/core/starter/utils/ConfigShadeUtils.java
+++ 
b/seatunnel-core/seatunnel-core-starter/src/main/java/org/apache/seatunnel/core/starter/utils/ConfigShadeUtils.java
@@ -47,8 +47,8 @@ public final class ConfigShadeUtils {
 
     private static final String SHADE_IDENTIFIER_OPTION = "shade.identifier";
 
-    private static final String[] DEFAULT_SENSITIVE_OPTIONS =
-            new String[] {"password", "username", "auth"};
+    public static final String[] DEFAULT_SENSITIVE_KEYWORDS =
+            new String[] {"password", "username", "auth", "token"};
 
     private static final Map<String, ConfigShade> CONFIG_SHADES = new 
HashMap<>();
 
@@ -126,7 +126,7 @@ public final class ConfigShadeUtils {
     @SuppressWarnings("unchecked")
     private static Config processConfig(String identifier, Config config, 
boolean isDecrypted) {
         ConfigShade configShade = CONFIG_SHADES.getOrDefault(identifier, 
DEFAULT_SHADE);
-        List<String> sensitiveOptions = new 
ArrayList<>(Arrays.asList(DEFAULT_SENSITIVE_OPTIONS));
+        List<String> sensitiveOptions = new 
ArrayList<>(Arrays.asList(DEFAULT_SENSITIVE_KEYWORDS));
         sensitiveOptions.addAll(Arrays.asList(configShade.sensitiveOptions()));
         BiFunction<String, Object, String> processFunction =
                 (key, value) -> {
diff --git 
a/seatunnel-core/seatunnel-core-starter/src/test/java/org/apache/seatunnel/core/starter/utils/ConfigShadeTest.java
 
b/seatunnel-core/seatunnel-core-starter/src/test/java/org/apache/seatunnel/core/starter/utils/ConfigShadeTest.java
index 9382c68663..4463597e9a 100644
--- 
a/seatunnel-core/seatunnel-core-starter/src/test/java/org/apache/seatunnel/core/starter/utils/ConfigShadeTest.java
+++ 
b/seatunnel-core/seatunnel-core-starter/src/test/java/org/apache/seatunnel/core/starter/utils/ConfigShadeTest.java
@@ -19,7 +19,9 @@ package org.apache.seatunnel.core.starter.utils;
 
 import 
org.apache.seatunnel.shade.com.fasterxml.jackson.databind.node.ObjectNode;
 import org.apache.seatunnel.shade.com.typesafe.config.Config;
+import org.apache.seatunnel.shade.com.typesafe.config.ConfigFactory;
 import org.apache.seatunnel.shade.com.typesafe.config.ConfigObject;
+import org.apache.seatunnel.shade.com.typesafe.config.ConfigResolveOptions;
 
 import org.apache.seatunnel.api.configuration.ConfigShade;
 import org.apache.seatunnel.common.utils.JsonUtils;
@@ -27,6 +29,7 @@ import org.apache.seatunnel.common.utils.JsonUtils;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
+import com.beust.jcommander.internal.Lists;
 import lombok.extern.slf4j.Slf4j;
 
 import java.net.URISyntaxException;
@@ -68,6 +71,46 @@ public class ConfigShadeTest {
                 config.getConfigList("source").get(0).getString("password"), 
PASSWORD);
     }
 
+    @Test
+    public void testUsePrivacyHandlerHocon() throws URISyntaxException {
+        URL resource = ConfigShadeTest.class.getResource("/config.shade.conf");
+        Assertions.assertNotNull(resource);
+        Config config = ConfigBuilder.of(Paths.get(resource.toURI()), 
Lists.newArrayList());
+        config =
+                ConfigFactory.parseMap(
+                                
ConfigBuilder.configDesensitization(config.root().unwrapped()))
+                        
.resolve(ConfigResolveOptions.defaults().setAllowUnresolved(true))
+                        .resolveWith(
+                                ConfigFactory.systemProperties(),
+                                
ConfigResolveOptions.defaults().setAllowUnresolved(true));
+        Assertions.assertEquals(
+                config.getConfigList("source").get(0).getString("username"), 
"******");
+        Assertions.assertEquals(
+                config.getConfigList("source").get(0).getString("password"), 
"******");
+        String conf = ConfigBuilder.mapToString(config.root().unwrapped(), 
false);
+        Assertions.assertTrue(conf.contains("username=\"******\""));
+    }
+
+    @Test
+    public void testUsePrivacyHandlerJson() throws URISyntaxException {
+        URL resource = ConfigShadeTest.class.getResource("/config.shade.json");
+        Assertions.assertNotNull(resource);
+        Config config = ConfigBuilder.of(Paths.get(resource.toURI()), 
Lists.newArrayList());
+        config =
+                ConfigFactory.parseMap(
+                                
ConfigBuilder.configDesensitization(config.root().unwrapped()))
+                        
.resolve(ConfigResolveOptions.defaults().setAllowUnresolved(true))
+                        .resolveWith(
+                                ConfigFactory.systemProperties(),
+                                
ConfigResolveOptions.defaults().setAllowUnresolved(true));
+        Assertions.assertEquals(
+                config.getConfigList("source").get(0).getString("username"), 
"******");
+        Assertions.assertEquals(
+                config.getConfigList("source").get(0).getString("password"), 
"******");
+        String json = ConfigBuilder.mapToString(config.root().unwrapped(), 
true);
+        Assertions.assertTrue(json.contains("\"password\" : \"******\""));
+    }
+
     @Test
     public void testVariableReplacement() throws URISyntaxException {
         String jobName = "seatunnel variable test job";
diff --git 
a/seatunnel-core/seatunnel-core-starter/src/test/resources/config.shade.json 
b/seatunnel-core/seatunnel-core-starter/src/test/resources/config.shade.json
new file mode 100644
index 0000000000..594c3db8fa
--- /dev/null
+++ b/seatunnel-core/seatunnel-core-starter/src/test/resources/config.shade.json
@@ -0,0 +1,41 @@
+{
+  "env" : {
+    "shade.identifier" : "base64",
+    "parallelism" : 1
+  },
+  "source" : [
+    {
+      "plugin_name" : "MySQL-CDC",
+      "base-url" : "jdbc:mysql://localhost:56725",
+      "username" : "c2VhdHVubmVs",
+      "password" : "c2VhdHVubmVsX3Bhc3N3b3Jk",
+      "hostname" : "127.0.0.1",
+      "port" : 56725,
+      "database-name" : "inventory_vwyw0n",
+      "parallelism" : 1,
+      "table-name" : "products",
+      "server-id" : 5656,
+      "schema" : {
+        "fields" : {
+          "name" : "string",
+          "age" : "int",
+          "sex" : "boolean"
+        }
+      },
+      "result_table_name" : "fake"
+    }
+  ],
+  "transform" : [],
+  "sink" : [
+    {
+      "plugin_name" : "Clickhouse",
+      "host" : "localhost:8123",
+      "username" : "c2VhdHVubmVs",
+      "password" : "c2VhdHVubmVsX3Bhc3N3b3Jk",
+      "database" : "default",
+      "table" : "fake_all",
+      "support_upsert" : true,
+      "primary_key" : "id"
+    }
+  ]
+}
diff --git 
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/utils/RestUtil.java
 
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/utils/RestUtil.java
index c2e92c1948..9aaa8cd595 100644
--- 
a/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/utils/RestUtil.java
+++ 
b/seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/utils/RestUtil.java
@@ -67,6 +67,6 @@ public class RestUtil {
 
     public static Config buildConfig(JsonNode jsonNode, boolean isEncrypt) {
         Map<String, Object> objectMap = JsonUtils.toMap(jsonNode);
-        return ConfigBuilder.of(objectMap, isEncrypt);
+        return ConfigBuilder.of(objectMap, isEncrypt, true);
     }
 }

Reply via email to