1
1
package com .splunk .splunkjenkins ;
2
2
3
3
import com .splunk .splunkjenkins .console .ConsoleRecordCacheUtils ;
4
+ import hudson .console .LineTransformationOutputStream ;
5
+ import hudson .model .AbstractBuild ;
4
6
import org .jenkinsci .plugins .workflow .cps .CpsFlowDefinition ;
5
7
import org .jenkinsci .plugins .workflow .job .WorkflowJob ;
6
8
import org .jenkinsci .plugins .workflow .job .WorkflowRun ;
10
12
import org .junit .Rule ;
11
13
import org .junit .Test ;
12
14
import org .jvnet .hudson .test .BuildWatcher ;
15
+ import org .jvnet .hudson .test .Issue ;
13
16
import org .jvnet .hudson .test .JenkinsRule ;
17
+ import org .jvnet .hudson .test .TestExtension ;
18
+ import org .kohsuke .stapler .DataBoundConstructor ;
19
+ import org .jenkinsci .plugins .workflow .steps .*;
20
+ import hudson .console .ConsoleLogFilter ;
14
21
22
+ import java .io .IOException ;
23
+ import java .io .OutputStream ;
24
+ import java .io .Serializable ;
25
+ import java .util .Collections ;
26
+ import java .util .Set ;
15
27
import java .util .UUID ;
16
28
17
29
import static com .splunk .splunkjenkins .SplunkConfigUtil .checkTokenAvailable ;
@@ -25,6 +37,8 @@ public class SplunkConsoleTaskListenerDecoratorTest {
25
37
String id = UUID .randomUUID ().toString ();
26
38
@ Rule
27
39
public JenkinsRule r = new JenkinsRule ();
40
+ private static final String TEST_SECRET = "secret" ;
41
+ private static final String TEST_REPLACEMENT = "xxxx" ;
28
42
private String jobScript = "node{\n " +
29
43
" parallel first: {sh \" echo SplunkConsoleTaskListenerDecoratorTest\" },\n " +
30
44
" second: {sh \" echo " + id + "\" }\n " +
@@ -57,4 +71,93 @@ public void testSendConsole() throws Exception {
57
71
verifySplunkSearchResult ("source=" + b1 .getUrl () + "console " + id , startTime , 2 );
58
72
verifySplunkSearchResult ("source=" + b1 .getUrl () + "console parallel_label=first" , startTime , 1 );
59
73
}
74
+
75
+
76
+ @ Issue ("SECURITY-2128" )
77
+ @ Test
78
+ public void testDataFilter () throws Exception {
79
+ WorkflowJob p = r .jenkins .createProject (WorkflowJob .class , "mask-job" );
80
+ p .setDefinition (new CpsFlowDefinition ("withTestMaskFilter {node {echo 'hello" + TEST_SECRET + "'}}" , false ));
81
+ long startTime = System .currentTimeMillis ();
82
+ WorkflowRun b1 = r .assertBuildStatusSuccess (p .scheduleBuild2 (0 ));
83
+ assertFalse (b1 .isBuilding ());
84
+ String testStr = "hello" + TEST_REPLACEMENT ;
85
+ r .assertLogContains (testStr , b1 );
86
+ verifySplunkSearchResult ("source=" + b1 .getUrl () + "console " + testStr , startTime , 1 );
87
+ }
88
+
89
+ /**
90
+ * simply replace secret with xxxx
91
+ */
92
+ public static final class FilterStep extends Step {
93
+ @ DataBoundConstructor
94
+ public FilterStep () {
95
+ }
96
+
97
+ @ Override
98
+ public StepExecution start (StepContext context ) throws Exception {
99
+ return new Execution (context );
100
+ }
101
+
102
+ private static final class Execution extends StepExecution {
103
+ private static final long serialVersionUID = 1L ;
104
+
105
+ Execution (StepContext context ) {
106
+ super (context );
107
+ }
108
+
109
+ @ Override
110
+ public boolean start () throws Exception {
111
+ getContext ().newBodyInvoker ().withContext (new Filter ()).withCallback (BodyExecutionCallback .wrap (getContext ())).start ();
112
+ return false ;
113
+ }
114
+ }
115
+
116
+ private static final class Filter extends ConsoleLogFilter implements Serializable {
117
+ private static final long serialVersionUID = 1L ;
118
+
119
+ @ SuppressWarnings ("rawtypes" )
120
+ @ Override
121
+ public OutputStream decorateLogger (AbstractBuild _ignore , OutputStream logger ) throws IOException , InterruptedException {
122
+ return new MaskingOutputStream (logger );
123
+ }
124
+ }
125
+
126
+ public static class MaskingOutputStream extends LineTransformationOutputStream .Delegating {
127
+
128
+
129
+ protected MaskingOutputStream (OutputStream out ) {
130
+ super (out );
131
+ }
132
+
133
+ @ Override
134
+ protected void eol (byte [] b , int len ) throws IOException {
135
+ if (len < TEST_SECRET .length ()) {
136
+ out .write (b , 0 , len );
137
+ return ;
138
+ }
139
+ String content = new String (b , 0 , len , "utf-8" );
140
+ out .write (content .replaceAll (TEST_SECRET , TEST_REPLACEMENT ).getBytes ());
141
+ }
142
+ }
143
+
144
+ @ TestExtension
145
+ public static final class DescriptorImpl extends StepDescriptor {
146
+ @ Override
147
+ public Set <? extends Class <?>> getRequiredContext () {
148
+ return Collections .emptySet ();
149
+ }
150
+
151
+ @ Override
152
+ public String getFunctionName () {
153
+ return "withTestMaskFilter" ;
154
+ }
155
+
156
+ @ Override
157
+ public boolean takesImplicitBlockArgument () {
158
+ return true ;
159
+ }
160
+ }
161
+ }
162
+
60
163
}
0 commit comments