Skip to content

Commit

Permalink
[JENKINS-71788] Fix timing of `SecretPatterns.getAggregateSecretPatte…
Browse files Browse the repository at this point in the history
…rn` (#314)

* [JENKINS-71788] Fix timing of `SecretPatterns.getAggregateSecretPattern`

* Protect against possible race condition
  • Loading branch information
jglick authored Sep 11, 2023
1 parent 0a1c04c commit 44fea4f
Showing 1 changed file with 15 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.jenkinsci.plugins.credentialsbinding.masking.SecretPatterns;

Expand All @@ -18,33 +20,37 @@ public class MaskingConsoleLogFilter extends ConsoleLogFilter

private final String charsetName;
private final List<String> valuesToMask;

private Pattern pattern;
private List<String> valuesToMaskInUse;

public MaskingConsoleLogFilter(final String charsetName,
List<String> valuesToMask) {
this.charsetName = charsetName;
this.valuesToMask = valuesToMask;
updatePattern();
}

private synchronized Pattern updatePattern() {
if (!valuesToMask.equals(valuesToMaskInUse)) {
List<String> values = valuesToMask.stream().filter(Objects::nonNull).collect(Collectors.toList());
pattern = values.isEmpty() ? null : SecretPatterns.getAggregateSecretPattern(values);
valuesToMaskInUse = new ArrayList<>(valuesToMask);
}
return pattern;
}

@Override
public OutputStream decorateLogger(Run run,
final OutputStream logger) throws IOException, InterruptedException {
return new SecretPatterns.MaskingOutputStream(logger,
() -> {
// Only return a non-null pattern once there are secrets to mask. When a non-null
// pattern is returned it is cached and not supplied again. In cases like
// VaultBuildWrapper the secrets are added to the "valuesToMasker" list AFTER
// construction AND AFTER the decorateLogger method is initially called, therefore
// the Pattern should only be returned once the secrets have been made available.
// Not to mention it is also a slight optimization when there is are no secrets
// to mask.
List<String> values = valuesToMask.stream().filter(Objects::nonNull).collect(Collectors.toList());
if (!values.isEmpty()) {
return SecretPatterns.getAggregateSecretPattern(values);
} else {
return null;
}
},
this::updatePattern,
charsetName);
}

Expand Down

0 comments on commit 44fea4f

Please sign in to comment.