• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

devonfw / IDEasy / 22345446363

24 Feb 2026 09:49AM UTC coverage: 70.247% (-0.2%) from 70.474%
22345446363

Pull #1714

github

web-flow
Merge 5655b6589 into 379acdc9d
Pull Request #1714: #404: #1713: advanced logging

4065 of 6384 branches covered (63.67%)

Branch coverage included in aggregate %.

10597 of 14488 relevant lines covered (73.14%)

3.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.67
cli/src/main/java/com/devonfw/tools/ide/util/PrivacyUtil.java
1
package com.devonfw.tools.ide.util;
2

3
import java.util.Locale;
4
import java.util.Set;
5

6
/**
7
 * Utility to remove private or sensitive information from log output.
8
 *
9
 * @see com.devonfw.tools.ide.context.IdeStartContext#isPrivacyMode()
10
 */
11
public final class PrivacyUtil {
12

13
  private static final Set<String> UNSENSITIVE_SEGMENTS = Set.of("project", "projects", "workspace", "workspaces", "conf", "settings", "software", "plugins",
437✔
14
      "setup", "update", "templates", "urls", "ide", "intellij", "eclipse", "vscode", "java", "mvn", "maven", "tmp", "backups", "backup", "bak", "src",
15
      "target", "main", "test", "master", "resource", "resources", "text", "txt", "less", "more", "com", "org", "javax", "groovy", "scala", "cpp", "common",
16
      "data", "doc", "documentation", "generated", "web", "public", "dataaccess", "persistence", "logic", "general", "git", "lock", "jpa", "tar", "tgz", "bz2",
17
      "tbz2", "zip", "compress", "compression", "global", "value", "code", "branch", "string", "long", "number", "numeric", "apache", "commons", "hibernate",
18
      "storage", "db", "spring", "springframework", "boot", "quarkus", "mnt", "usr", "user", "users", "windows", "etc", "var", "log", "lib", "drivers",
19
      "system", "system32", "appdata", "module", "info", "sha1", "md5", "sha256", "sha512", "pkcs", "p12", "cert", "file", "files", "bin", "bash", "program",
20
      "mingw64", "dummy", "hosts");
21

22
  // construction forbidden
23
  private PrivacyUtil() {
24

25
  }
26

27
  private static int indexOfSlash(String arg, int start) {
28
    int index = arg.indexOf('/', start);
5✔
29
    int index2 = arg.indexOf('\\', start);
5✔
30
    if (index2 < 0) {
2✔
31
      return index;
2✔
32
    } else if ((index < 0) || (index2 < index)) {
5✔
33
      return index2;
2✔
34
    }
35
    return index;
2✔
36
  }
37

38
  /**
39
   * @param arg the path or any {@link String} containing one or multiple paths.
40
   * @return a normalized form of the
41
   */
42
  public static String removeSensitivePathInformation(String arg) {
43
    int index = indexOfSlash(arg, 0);
4✔
44
    if (index < 0) {
2✔
45
      return arg;
2✔
46
    }
47
    int length = arg.length();
3✔
48
    StringBuilder result = new StringBuilder(length);
5✔
49
    int start = 0;
2✔
50
    while (index >= 0) {
2✔
51
      // index is pointing to the first slash of an absolute or relative path, we first search backwards from start to index to find a potential starting folder-name
52
      int i = start;
2✔
53
      int folderStart = start;
2✔
54
      while (i < index) {
3✔
55
        int cp = arg.codePointAt(i);
4✔
56
        i += Character.charCount(cp);
5✔
57
        if (!isFileSegment(cp) && !isSeparator(cp)) {
6!
58
          folderStart = i;
2✔
59
        }
60
      }
1✔
61
      result.append(arg, start, folderStart);
6✔
62
      start = folderStart;
2✔
63
      index = folderStart;
2✔
64
      // now we remove sensitive information from the current path
65
      while (index < length) {
3✔
66
        int cp = arg.codePointAt(index);
4✔
67
        boolean slash = isSlash(cp);
3✔
68
        if (slash) {
2✔
69
          cp = '/'; // normalize Windows backslash
2✔
70
        }
71
        if (slash || isSeparator(cp)) {
5✔
72
          appendSegment(arg, result, start, index);
5✔
73
          index += Character.charCount(cp);
5✔
74
          start = index;
2✔
75
          result.appendCodePoint(cp);
5✔
76
        } else if (!isFileSegment(cp)) {
3✔
77
          appendSegment(arg, result, start, index);
5✔
78
          start = index;
2✔
79
          break;
1✔
80
        } else {
81
          index += Character.charCount(cp);
5✔
82
        }
83
      }
1✔
84
      index = indexOfSlash(arg, index);
4✔
85
      if (index < 0) {
2✔
86
        // append rest
87
        int end = start;
2✔
88
        while (end < length) {
3✔
89
          int cp = arg.codePointAt(end);
4✔
90
          if ((cp == ' ') || (cp == '"') || (cp == '\'')) {
9!
91
            break;
×
92
          }
93
          end++;
1✔
94
        }
1✔
95
        appendSegment(arg, result, start, end);
5✔
96
        if (end < length) {
3✔
97
          result.append(arg, end, length);
6✔
98
        }
99
      }
100
    }
1✔
101
    return result.toString();
3✔
102
  }
103

104
  private static void appendSegment(String arg, StringBuilder result, int start, int index) {
105

106
    String segment = arg.substring(start, index);
5✔
107
    if (UNSENSITIVE_SEGMENTS.contains(segment.toLowerCase(Locale.ROOT)) || segment.length() <= 2) {
10✔
108
      result.append(segment);
5✔
109
    } else {
110
      result.repeat('*', segment.length());
6✔
111
    }
112
  }
1✔
113

114
  private static boolean isSlash(int cp) {
115

116
    return (cp == '/') || (cp == '\\');
10✔
117
  }
118

119
  private static boolean isSeparator(int cp) {
120

121
    return (cp == '.') || (cp == '-') || (cp == '_');
13✔
122
  }
123

124
  private static boolean isFileSegment(int cp) {
125

126
    return Character.isLetter(cp) || Character.isDigit(cp);
10✔
127
  }
128

129

130
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc