@@ -7,7 +7,7 @@ const k8sCRDApi = kc.makeApiClient(k8s.CustomObjectsApi);
77const k8sBatchApi = kc . makeApiClient ( k8s . BatchV1Api ) ;
88const k8sPodsApi = kc . makeApiClient ( k8s . CoreV1Api ) ;
99
10- const namespace = "integration-tests" ;
10+ let namespace = "integration-tests" ;
1111
1212const sleep = ( ms ) => new Promise ( ( resolve ) => setTimeout ( resolve , ms * 1000 ) ) ;
1313
@@ -109,6 +109,7 @@ async function disasterRecovery(scanName) {
109109 * @returns {scan.findings } returns findings { categories, severities, count }
110110 */
111111async function scan ( name , scanType , parameters = [ ] , timeout = 180 ) {
112+ namespace = "integration-tests"
112113 const scanDefinition = {
113114 apiVersion : "execution.experimental.securecodebox.io/v1" ,
114115 kind : "Scan" ,
@@ -157,4 +158,116 @@ async function scan(name, scanType, parameters = [], timeout = 180) {
157158 throw new Error ( "timed out while waiting for scan results" ) ;
158159}
159160
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+
160272module . exports . scan = scan ;
273+ module . exports . cascadingScan = cascadingScan ;
0 commit comments