From b08e7055936ef9d1c611901bb95843675084341a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Lys=C3=A9n?= Date: Sat, 30 Dec 2023 13:46:40 +0100 Subject: [PATCH] Add AWS regexp pattern (#62) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New feature that enhances the replacement functionality in the DefaultRegexpPairs. It allows for more flexible replacements by supporting dynamic replacement of matched groups from the regular expression pattern. - checkbox for explicit AWS usage - Refactored LogFileFilterOutputStream to handle multiple DefaultRegexpPairs --------- Authored-by: Fredrik Lysén --- .gitignore | 1 + .../com/tsystems/sbs/DefaultRegexpPairs.java | 11 +++ .../com/tsystems/sbs/LogFileFilterConfig.java | 11 +++ .../sbs/LogFileFilterOutputStream.java | 36 ++++++---- .../java/com/tsystems/sbs/RegexpPair.java | 6 ++ .../sbs/LogFileFilterConfig/config.jelly | 4 ++ .../help-enabledDefaultRegexpAWS.html | 31 +++++++++ .../sbs/DefaultRegexpPairsAWSTest.java | 68 +++++++++++++++++++ 8 files changed, 155 insertions(+), 13 deletions(-) create mode 100644 src/main/resources/com/tsystems/sbs/LogFileFilterConfig/help-enabledDefaultRegexpAWS.html create mode 100644 src/test/java/com/tsystems/sbs/DefaultRegexpPairsAWSTest.java diff --git a/.gitignore b/.gitignore index aa0f125..74cbf5e 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,4 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser +/.idea/ diff --git a/src/main/java/com/tsystems/sbs/DefaultRegexpPairs.java b/src/main/java/com/tsystems/sbs/DefaultRegexpPairs.java index 7dd1cf0..7d84672 100644 --- a/src/main/java/com/tsystems/sbs/DefaultRegexpPairs.java +++ b/src/main/java/com/tsystems/sbs/DefaultRegexpPairs.java @@ -19,7 +19,18 @@ public final class DefaultRegexpPairs { new RegexpPair("password=\\S*", "password=********") //PASSWORD MASKING )); + private final static List DEFAULT_REGEXES_AWS + = Collections.unmodifiableList( + Arrays.asList( + new RegexpPair("(AWS_[a-zA-Z_]+=)(\\S+)", "$1********"), // AWS RegExp MASKING + new RegexpPair("(aws_[a-zA-Z_]+=)(\\S+)", "$1********") + )); + public static List getDefaultRegexes() { return DEFAULT_REGEXES; } + + public static List getDefaultRegexesAWS() { + return DEFAULT_REGEXES_AWS; + } } diff --git a/src/main/java/com/tsystems/sbs/LogFileFilterConfig.java b/src/main/java/com/tsystems/sbs/LogFileFilterConfig.java index f65ac4a..4e46323 100644 --- a/src/main/java/com/tsystems/sbs/LogFileFilterConfig.java +++ b/src/main/java/com/tsystems/sbs/LogFileFilterConfig.java @@ -45,6 +45,7 @@ public static LogFileFilterConfig get() { * Determines whether the regexp replacements which come fixed with the plugin are enabled. */ private boolean enabledDefaultRegexp; + private boolean enabledDefaultRegexpAWS; /** * Represents the custom regexp pairs specified by the user in the global settings. @@ -70,12 +71,22 @@ public boolean isEnabledDefaultRegexp() { return enabledDefaultRegexp; } + public boolean isEnabledDefaultRegexpAWS() { + return enabledDefaultRegexpAWS; + } + @DataBoundSetter public void setEnabledDefaultRegexp(boolean enabledDefaultRegexp) { this.enabledDefaultRegexp = enabledDefaultRegexp; save(); } + @DataBoundSetter + public void setEnabledDefaultRegexpAWS(boolean enabledDefaultRegexpAWS) { + this.enabledDefaultRegexpAWS = enabledDefaultRegexpAWS; + save(); + } + public List getRegexpPairs() { return regexpPairs; } diff --git a/src/main/java/com/tsystems/sbs/LogFileFilterOutputStream.java b/src/main/java/com/tsystems/sbs/LogFileFilterOutputStream.java index 23e9cac..8143a33 100644 --- a/src/main/java/com/tsystems/sbs/LogFileFilterOutputStream.java +++ b/src/main/java/com/tsystems/sbs/LogFileFilterOutputStream.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; @@ -29,6 +30,7 @@ public class LogFileFilterOutputStream extends LineTransformationOutputStream { //Global settings private final boolean isEnabledGlobally; private final boolean isEnabledDefaultRegexp; + private final boolean isEnabledDefaultRegexpAWS; private final List defaultRegexpPairs; private final List customRegexpPairs; private final String jobName; @@ -47,19 +49,27 @@ public LogFileFilterOutputStream(OutputStream out, Charset charset, String jobNa } isEnabledGlobally = config.isEnabledGlobally(); - isEnabledDefaultRegexp = config.isEnabledDefaultRegexp(); - if (isEnabledGlobally) { - //Load regexes - customRegexpPairs = config.getRegexpPairs(); - if (isEnabledDefaultRegexp) { - defaultRegexpPairs = DefaultRegexpPairs.getDefaultRegexes(); - } else { - defaultRegexpPairs = Collections.emptyList(); - } - } else { - customRegexpPairs = Collections.emptyList(); - defaultRegexpPairs = Collections.emptyList(); - } + isEnabledDefaultRegexp = config.isEnabledDefaultRegexp(); + isEnabledDefaultRegexpAWS = config.isEnabledDefaultRegexpAWS(); + + if (isEnabledGlobally) { + // Load regexes + customRegexpPairs = config.getRegexpPairs(); + defaultRegexpPairs = new ArrayList<>(); + if (isEnabledDefaultRegexp) { + defaultRegexpPairs.addAll(DefaultRegexpPairs.getDefaultRegexes()); + } + if (isEnabledDefaultRegexpAWS) { + defaultRegexpPairs.addAll(DefaultRegexpPairs.getDefaultRegexesAWS()); + } + // Log defaultRegexpPairs + for (RegexpPair pair : defaultRegexpPairs) { + LOGGER.log(Level.INFO, pair.toString()); + } + } else { + customRegexpPairs = Collections.emptyList(); + defaultRegexpPairs = Collections.emptyList(); + } } @Override diff --git a/src/main/java/com/tsystems/sbs/RegexpPair.java b/src/main/java/com/tsystems/sbs/RegexpPair.java index 9844f7a..1cfbf40 100644 --- a/src/main/java/com/tsystems/sbs/RegexpPair.java +++ b/src/main/java/com/tsystems/sbs/RegexpPair.java @@ -1,5 +1,6 @@ package com.tsystems.sbs; +import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.model.AbstractDescribableImpl; import hudson.model.Descriptor; @@ -23,6 +24,11 @@ public class RegexpPair extends AbstractDescribableImpl implements S private String replacement; private transient Pattern compiledRegexp; + @Override + public String toString() { + return "RegexpPair{pattern=" + regexp + ", replacement=" + replacement + "}"; + } + @DataBoundConstructor public RegexpPair(String regexp, String replacement) { this.regexp = regexp; diff --git a/src/main/resources/com/tsystems/sbs/LogFileFilterConfig/config.jelly b/src/main/resources/com/tsystems/sbs/LogFileFilterConfig/config.jelly index 79b8f69..ae228e9 100644 --- a/src/main/resources/com/tsystems/sbs/LogFileFilterConfig/config.jelly +++ b/src/main/resources/com/tsystems/sbs/LogFileFilterConfig/config.jelly @@ -24,6 +24,10 @@ + + + + diff --git a/src/main/resources/com/tsystems/sbs/LogFileFilterConfig/help-enabledDefaultRegexpAWS.html b/src/main/resources/com/tsystems/sbs/LogFileFilterConfig/help-enabledDefaultRegexpAWS.html new file mode 100644 index 0000000..19fc5a9 --- /dev/null +++ b/src/main/resources/com/tsystems/sbs/LogFileFilterConfig/help-enabledDefaultRegexpAWS.html @@ -0,0 +1,31 @@ + +
+ + + +

These are the default regular expressions and their respective replacements. These expressions are fixed and come with the plugin.

+ + + + + + + + + + + +
DescriptionRegexpReplacementSample
Masks AWS credential and token(AWS_[a-zA-Z_]+=)(\S+)$1******** +
    +
  • AWS_ACCESS_KEY_ID=A7OTR4HWEGX2SKQMRAXI -> AWS_ACCESS_KEY_ID=********
  • +
  • AWS_SECRET_ACCESS_KEY=agfkjgsakfjhsgad -> AWS_SECRET_ACCESS_KEY=********
  • +
  • AWS_SESSION_TOKEN=ThGHJJHF7jdfnjsdzf -> AWS_SESSION_TOKEN=********
  • +
+
+
\ No newline at end of file diff --git a/src/test/java/com/tsystems/sbs/DefaultRegexpPairsAWSTest.java b/src/test/java/com/tsystems/sbs/DefaultRegexpPairsAWSTest.java new file mode 100644 index 0000000..7fd51d1 --- /dev/null +++ b/src/test/java/com/tsystems/sbs/DefaultRegexpPairsAWSTest.java @@ -0,0 +1,68 @@ +package com.tsystems.sbs; + +import hudson.console.LineTransformationOutputStream; +import org.junit.Test; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.codehaus.groovy.runtime.ResourceGroovyMethods.filterLine; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; + + +public class DefaultRegexpPairsAWSTest { + private List getDefaultRegexpPairs() { + return DefaultRegexpPairs.getDefaultRegexesAWS(); + } + @Test + public void testDefaultPairsList() { + List defaultRegexpPairs = getDefaultRegexpPairs(); + assertThat(defaultRegexpPairs.size(), greaterThan(0)); + + } + + @Test + public void testDefaultPairs() { + List defaultRegexpPairs = getDefaultRegexpPairs(); + + // Define the input string + String input = "AWS_ACCESS_KEY_ID=R2RHTXG7QKSRWMOHEIAMH4A AWS_SECRET_ACCESS_KEY=/lD8T9bXuZUW/F/8MutOB1vDXK2uG/gNHUe/d8bG AWS_SESSION_TOKEN=Z1XKqTnKIHd7eLJhBZb9QWVcG0Rj3f8z1uYgO4Xm6vNiD5F7cM9pAa/2SsPqRrTtEoUyHwC+DxGJlWbVfNkOYK6hI3eX1L0j2+//////////"; + String expected = "AWS_ACCESS_KEY_ID=******** AWS_SECRET_ACCESS_KEY=******** AWS_SESSION_TOKEN=********"; + + + StringBuilder replacedInput = new StringBuilder(input); + + for (RegexpPair pair : defaultRegexpPairs) { + String pattern = pair.getRegexp(); + String replacement = pair.getReplacement(); + + Pattern regexPattern = Pattern.compile(pattern); + Matcher matcher = regexPattern.matcher(replacedInput); + + while (matcher.find()) { + String matchedPattern = matcher.group(); + String replacedString = replacement; + + // Replace all occurrences of $n with the matched groups + for (int i = 1; i <= matcher.groupCount(); i++) { + String group = matcher.group(i); + replacedString = replacedString.replace("$" + i, group); + } + + replacedInput.replace(matcher.start(), matcher.end(), replacedString); + matcher.region(matcher.start() + replacedString.length(), replacedInput.length()); + } + } + + String replacedInputString = replacedInput.toString(); + System.out.println("Replaced input result: " + replacedInputString); + + // Test the behavior + assertEquals(expected, replacedInputString); + } +} +