@@ -157,4 +157,125 @@ async function scan(name, scanType, parameters = [], timeout = 180) {
157157 throw new Error ( "timed out while waiting for scan results" ) ;
158158}
159159
160+ /**
161+ *
162+ * @param {string } name name of the scan. Actual name will be sufixed with a random number to avoid conflicts
163+ * @param {string } scanType type of the scan. Must match the name of a ScanType CRD
164+ * @param {string[] } parameters cli argument to be passed to the scanner
165+ * @param {number } timeout in seconds
166+ * @returns {scan.findings } returns findings { categories, severities, count }
167+ */
168+ async function cascadingScan ( name , scanType , parameters = [ ] , nameCascade , scanTypeCascade , parametersCascade , intensive , invasive , timeout = 180 ) {
169+ const cascadingDefinition = {
170+ apiVersion : "cascading.experimental.securecodebox.io/v1" ,
171+ kind : "CascadingRule" ,
172+ metadata : {
173+ generateName : `${ nameCascade } -` ,
174+ labels : {
175+ invasive,
176+ intensive,
177+ } ,
178+ spec : {
179+ matches : {
180+ anyOf : {
181+ category : "Open Port" ,
182+ attributes : {
183+ port : 22 ,
184+ state : "open"
185+ }
186+ }
187+ } ,
188+ scanSpec : {
189+ scanTypeCascade,
190+ parametersCascade
191+ }
192+ }
193+ }
194+ } ;
195+
196+
197+ const scanDefinition = {
198+ apiVersion : "execution.experimental.securecodebox.io/v1" ,
199+ kind : "Scan" ,
200+ metadata : {
201+ // Use `generateName` instead of name to generate a random sufix and avoid name clashes
202+ generateName : `${ name } -` ,
203+ } ,
204+ spec : {
205+ scanType,
206+ parameters,
207+ } ,
208+ cascades : {
209+ matchLabels : {
210+ intensive
211+ }
212+ }
213+ } ;
214+
215+ const { bodyCascade } = await k8sCRDApi . createNamespacedCustomObject (
216+ "cascading.experimental.securecodebox.io" ,
217+ "v1" ,
218+ namespace ,
219+ "scans" ,
220+ cascadingDefinition
221+ ) ;
222+
223+ const { body } = await k8sCRDApi . createNamespacedCustomObject (
224+ "execution.experimental.securecodebox.io" ,
225+ "v1" ,
226+ namespace ,
227+ "scans" ,
228+ scanDefinition
229+ ) ;
230+
231+ const actualName = body . metadata . name ;
232+ const actualNameCascade = bodyCascade . metadata . name ;
233+
234+ for ( let i = 0 ; i < timeout ; i ++ ) {
235+ await sleep ( 1 ) ;
236+ const { status } = await getScan ( actualName ) ;
237+
238+ if ( status && status . state === "Done" ) {
239+ // Wait a couple seconds to give kubernetes more time to update the fields
240+ await sleep ( 2 ) ;
241+
242+ for ( let j = 0 ; j < timeout ; j ++ ) {
243+ await sleep ( 1 )
244+ const { statusCascade } = await getScan ( actualNameCascade ) ;
245+ if ( statusCascade && statusCascade . state === "Done" ) {
246+ await sleep ( 2 ) ;
247+ const { statusCascade } = await getScan ( actualNameCascade ) ;
248+
249+ await deleteScan ( actualName ) ;
250+ await deleteScan ( actualNameCascade ) ;
251+ return statusCascade . findings ;
252+ } else if ( statusCascade && statusCascade . state === "Errored" ) {
253+ console . error ( "Scan Errored" ) ;
254+ await disasterRecovery ( actualNameCascade ) ;
255+ throw new Error (
256+ `Cascade Scan failed with description "${ statusCascade . errorDescription } "`
257+ ) ;
258+ }
259+ console . error ( "Cascade Scan Timed out!" ) ;
260+ await disasterRecovery ( actualNameCascade ) ;
261+
262+ throw new Error ( "timed out while waiting for cascading scan results" ) ;
263+ }
264+
265+ } else if ( status && status . state === "Errored" ) {
266+ console . error ( "Scan Errored" ) ;
267+ await disasterRecovery ( actualName ) ;
268+
269+ throw new Error (
270+ `Scan failed with description "${ status . errorDescription } "`
271+ ) ;
272+ }
273+ }
274+ console . error ( "Scan Timed out!" ) ;
275+ await disasterRecovery ( actualName ) ;
276+
277+ throw new Error ( "timed out while waiting for scan results" ) ;
278+ }
279+
160280module . exports . scan = scan ;
281+ module . exports . cascadingScan = cascadingScan ;
0 commit comments