@@ -7,7 +7,7 @@ const k8sCRDApi = kc.makeApiClient(k8s.CustomObjectsApi);
7
7
const k8sBatchApi = kc . makeApiClient ( k8s . BatchV1Api ) ;
8
8
const k8sPodsApi = kc . makeApiClient ( k8s . CoreV1Api ) ;
9
9
10
- const namespace = "integration-tests" ;
10
+ let namespace = "integration-tests" ;
11
11
12
12
const sleep = ( ms ) => new Promise ( ( resolve ) => setTimeout ( resolve , ms * 1000 ) ) ;
13
13
@@ -109,6 +109,7 @@ async function disasterRecovery(scanName) {
109
109
* @returns {scan.findings } returns findings { categories, severities, count }
110
110
*/
111
111
async function scan ( name , scanType , parameters = [ ] , timeout = 180 ) {
112
+ namespace = "integration-tests"
112
113
const scanDefinition = {
113
114
apiVersion : "execution.experimental.securecodebox.io/v1" ,
114
115
kind : "Scan" ,
@@ -157,4 +158,116 @@ async function scan(name, scanType, parameters = [], timeout = 180) {
157
158
throw new Error ( "timed out while waiting for scan results" ) ;
158
159
}
159
160
161
+ /**
162
+ *
163
+ * @param {string } name name of the scan. Actual name will be sufixed with a random number to avoid conflicts
164
+ * @param {string } scanType type of the scan. Must match the name of a ScanType CRD
165
+ * @param {string[] } parameters cli argument to be passed to the scanner
166
+ * @param {number } timeout in seconds
167
+ * @returns {scan.findings } returns findings { categories, severities, count }
168
+ */
169
+ async function cascadingScan ( name , scanType , parameters = [ ] , { nameCascade, matchLabels } , timeout = 180 ) {
170
+ namespace = "cascading-tests" ;
171
+
172
+ const scanDefinition = {
173
+ apiVersion : "execution.experimental.securecodebox.io/v1" ,
174
+ kind : "Scan" ,
175
+ metadata : {
176
+ // Use `generateName` instead of name to generate a random sufix and avoid name clashes
177
+ generateName : `${ name } -` ,
178
+ } ,
179
+ spec : {
180
+ scanType,
181
+ parameters,
182
+ cascades : {
183
+ matchLabels,
184
+ }
185
+ } ,
186
+ } ;
187
+
188
+ const { body } = await k8sCRDApi . createNamespacedCustomObject (
189
+ "execution.experimental.securecodebox.io" ,
190
+ "v1" ,
191
+ namespace ,
192
+ "scans" ,
193
+ scanDefinition
194
+ ) ;
195
+
196
+ const actualName = body . metadata . name ;
197
+
198
+ for ( let i = 0 ; i < timeout ; i ++ ) {
199
+ await sleep ( 1 ) ;
200
+ const { status } = await getScan ( actualName ) ;
201
+
202
+ if ( status && status . state === "Done" ) {
203
+ // Wait a couple seconds to give kubernetes more time to update the fields
204
+ await sleep ( 2 ) ;
205
+
206
+ break ;
207
+ } else if ( status && status . state === "Errored" ) {
208
+ console . error ( "Scan Errored" ) ;
209
+ await disasterRecovery ( actualName ) ;
210
+ throw new Error (
211
+ `Initial Scan failed with description "${ status . errorDescription } "`
212
+ ) ;
213
+ }
214
+
215
+ if ( i === ( timeout - 1 ) ) {
216
+ throw new Error (
217
+ `Initial Scan timed out failed`
218
+ ) ;
219
+ }
220
+ }
221
+
222
+ console . log ( "First Scan finished" )
223
+
224
+ const { body : scans } = await k8sCRDApi . listNamespacedCustomObject (
225
+ "execution.experimental.securecodebox.io" ,
226
+ "v1" ,
227
+ namespace ,
228
+ "scans"
229
+ ) ;
230
+
231
+ let cascadedScan = null ;
232
+
233
+ for ( const scan of scans . items ) {
234
+ if ( scan . metadata . annotations && scan . metadata . annotations [ "cascading.securecodebox.io/chain" ] === nameCascade ) {
235
+ cascadedScan = scan ;
236
+ break ;
237
+ }
238
+ }
239
+
240
+ if ( cascadedScan === null ) {
241
+ throw new Error ( `Didn't find cascaded Scan for ${ nameCascade } ` )
242
+ }
243
+ const actualNameCascade = cascadedScan . metadata . name ;
244
+
245
+ for ( let j = 0 ; j < timeout ; j ++ ) {
246
+ await sleep ( 1 )
247
+ const { status : statusCascade } = await getScan ( actualNameCascade ) ;
248
+
249
+ if ( statusCascade && statusCascade . state === "Done" ) {
250
+ await sleep ( 2 ) ;
251
+ const { status : statusCascade } = await getScan ( actualNameCascade ) ;
252
+
253
+ await deleteScan ( actualName ) ;
254
+ await deleteScan ( actualNameCascade ) ;
255
+ return statusCascade . findings ;
256
+ } else if ( statusCascade && statusCascade . state === "Errored" ) {
257
+ console . error ( "Scan Errored" ) ;
258
+ await disasterRecovery ( actualName ) ;
259
+ await disasterRecovery ( actualNameCascade ) ;
260
+ throw new Error (
261
+ `Cascade Scan failed with description "${ statusCascade . errorDescription } "`
262
+ ) ;
263
+ }
264
+ }
265
+ console . error ( "Cascade Scan Timed out!" ) ;
266
+ await disasterRecovery ( actualName ) ;
267
+ await disasterRecovery ( actualNameCascade ) ;
268
+
269
+ throw new Error ( "timed out while waiting for scan results" ) ;
270
+ }
271
+
160
272
module . exports . scan = scan ;
273
+ module . exports . cascadingScan = cascadingScan ;
0 commit comments