From 499c077cd35ce56151c418a1048ebafdb921e75d Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Thu, 24 Jun 2021 16:16:04 +0200 Subject: [PATCH 01/17] Cascading Scans: merge environment variables from parent scan and cascading rule Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.test.js | 101 ++++++++++++++++++++++++-- hooks/cascading-scans/hook.ts | 2 +- hooks/cascading-scans/scan-helpers.ts | 2 +- 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/hooks/cascading-scans/hook.test.js b/hooks/cascading-scans/hook.test.js index 4477164309..2506a725bc 100644 --- a/hooks/cascading-scans/hook.test.js +++ b/hooks/cascading-scans/hook.test.js @@ -81,7 +81,7 @@ test("Should create subsequent scans for open HTTPS ports (NMAP findings)", () = Array [ Object { "cascades": Object {}, - "env": undefined, + "env": Array [], "finding": Object { "attributes": Object { "hostname": "foobar.com", @@ -154,7 +154,7 @@ test("Should not try to do magic to the scan name if its something random", () = Array [ Object { "cascades": Object {}, - "env": undefined, + "env": Array [], "finding": Object { "attributes": Object { "hostname": undefined, @@ -232,7 +232,7 @@ test("Should not crash when the annotations are not set", () => { Array [ Object { "cascades": Object {}, - "env": undefined, + "env": Array [], "finding": Object { "attributes": Object { "hostname": "foobar.com", @@ -374,7 +374,7 @@ test("Should allow wildcards in cascadingRules", () => { Array [ Object { "cascades": Object {}, - "env": undefined, + "env": Array [], "finding": Object { "attributes": Object { "hostname": "foobar.com", @@ -642,7 +642,7 @@ test("should copy scanLabels from CascadingRule to cascading scan", () => { Array [ Object { "cascades": Object {}, - "env": undefined, + "env": Array [], "finding": Object { "attributes": Object { "hostname": "foobar.com", @@ -707,7 +707,7 @@ test("should copy scanAnnotations from CascadingRule to cascading scan", () => { Array [ Object { "cascades": Object {}, - "env": undefined, + "env": Array [], "finding": Object { "attributes": Object { "hostname": "foobar.com", @@ -825,7 +825,7 @@ test("should copy proper finding ID into annotations", () => { Array [ Object { "cascades": Object {}, - "env": undefined, + "env": Array [], "finding": Object { "attributes": Object { "hostname": "foobar.com", @@ -859,3 +859,90 @@ test("should copy proper finding ID into annotations", () => { } )).toBe(true) }); + +test("should merge environment variables into cascaded scan", () => { + const findings = [ + { + name: "Port 443 is open", + category: "Open Port", + attributes: { + state: "open", + hostname: "foobar.com", + port: 443, + service: "https" + } + } + ]; + + parentScan.spec.env = [ + { + "name": "parent_environment_variable_name", + "value": "parent_environment_variable_value" + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.env = [ + { + "name": "rule_environment_variable_name", + "value": "rule_environment_variable_value" + } + ] + + const cascadedScans = getCascadingScans( + parentScan, + findings, + sslyzeCascadingRules + ); + + const cascadedScan = cascadedScans[0] + + expect(cascadedScans).toMatchInlineSnapshot(` + Array [ + Object { + "cascades": Object {}, + "env": Array [ + Object { + "name": "rule_environment_variable_name", + "value": "rule_environment_variable_value", + }, + ], + "finding": Object { + "attributes": Object { + "hostname": "foobar.com", + "port": 443, + "service": "https", + "state": "open", + }, + "category": "Open Port", + "name": "Port 443 is open", + }, + "generatedBy": "tls-scans", + "name": "sslyze-foobar.com-tls-scans", + "parameters": Array [ + "--regular", + "foobar.com:443", + ], + "scanAnnotations": Object {}, + "scanLabels": Object {}, + "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], + }, + ] + `); + + const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); + + expect(cascadingScanDefinition.spec.env).toMatchInlineSnapshot(` + Array [ + Object { + "name": "rule_environment_variable_name", + "value": "rule_environment_variable_value", + }, + Object { + "name": "parent_environment_variable_name", + "value": "parent_environment_variable_value", + }, + ] + `); +}); diff --git a/hooks/cascading-scans/hook.ts b/hooks/cascading-scans/hook.ts index 260826b680..b92879f481 100644 --- a/hooks/cascading-scans/hook.ts +++ b/hooks/cascading-scans/hook.ts @@ -100,7 +100,7 @@ function getCascadingScan( finding: Finding, cascadingRule: CascadingRule ) { - const { scanType, parameters, env } = cascadingRule.spec.scanSpec; + const { scanType, parameters, env = [] } = cascadingRule.spec.scanSpec; const templateArgs = { ...finding, diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index 34f3b280af..60b286b0db 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -153,7 +153,7 @@ export function getCascadingScanDefinition({ scanType, parameters, cascades, - env, + env: env.concat(parentScan.spec.env || []), } }; } From 0f224fa99d223713b82924b1b1b7335bf87401fd Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Thu, 24 Jun 2021 16:17:57 +0200 Subject: [PATCH 02/17] Cascading Scans: merge volumes and volumeMounts from parent scan and cascading rule Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.test.js | 210 ++++++++++++++++++++++++++ hooks/cascading-scans/hook.ts | 4 +- hooks/cascading-scans/scan-helpers.ts | 6 + 3 files changed, 219 insertions(+), 1 deletion(-) diff --git a/hooks/cascading-scans/hook.test.js b/hooks/cascading-scans/hook.test.js index 2506a725bc..61c4709500 100644 --- a/hooks/cascading-scans/hook.test.js +++ b/hooks/cascading-scans/hook.test.js @@ -101,6 +101,8 @@ test("Should create subsequent scans for open HTTPS ports (NMAP findings)", () = "scanAnnotations": Object {}, "scanLabels": Object {}, "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, ] `); @@ -175,6 +177,8 @@ test("Should not try to do magic to the scan name if its something random", () = "scanAnnotations": Object {}, "scanLabels": Object {}, "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, ] `); @@ -252,6 +256,8 @@ test("Should not crash when the annotations are not set", () => { "scanAnnotations": Object {}, "scanLabels": Object {}, "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, ] `); @@ -318,6 +324,8 @@ test("Should copy ENV fields from cascadingRule to created scan", () => { "scanAnnotations": Object {}, "scanLabels": Object {}, "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, ] `); @@ -394,6 +402,8 @@ test("Should allow wildcards in cascadingRules", () => { "scanAnnotations": Object {}, "scanLabels": Object {}, "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, ] `); @@ -665,6 +675,8 @@ test("should copy scanLabels from CascadingRule to cascading scan", () => { "k_two": "v_two", }, "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, ] `); @@ -730,6 +742,8 @@ test("should copy scanAnnotations from CascadingRule to cascading scan", () => { }, "scanLabels": Object {}, "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, ] `); @@ -846,6 +860,8 @@ test("should copy proper finding ID into annotations", () => { "scanAnnotations": Object {}, "scanLabels": Object {}, "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, ] `); @@ -946,3 +962,197 @@ test("should merge environment variables into cascaded scan", () => { ] `); }); + +test("should merge volumeMounts into cascaded scan", () => { + const findings = [ + { + name: "Port 443 is open", + category: "Open Port", + attributes: { + state: "open", + hostname: "foobar.com", + port: 443, + service: "https" + } + } + ]; + + parentScan.spec.volumeMounts = [ + { + "mountPath": "/etc/ssl/certs/ca-cert.cer", + "name": "ca-certificate", + "readOnly": true, + "subPath": "ca-cert.cer" + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.volumeMounts = [ + { + "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", + "name": "ca-certificate-sslyze", + "readOnly": true, + "subPath": "ca-cert-sslyze.cer" + } + ] + + const cascadedScans = getCascadingScans( + parentScan, + findings, + sslyzeCascadingRules + ); + + const cascadedScan = cascadedScans[0] + + expect(cascadedScans).toMatchInlineSnapshot(` + Array [ + Object { + "cascades": Object {}, + "env": Array [], + "finding": Object { + "attributes": Object { + "hostname": "foobar.com", + "port": 443, + "service": "https", + "state": "open", + }, + "category": "Open Port", + "name": "Port 443 is open", + }, + "generatedBy": "tls-scans", + "name": "sslyze-foobar.com-tls-scans", + "parameters": Array [ + "--regular", + "foobar.com:443", + ], + "scanAnnotations": Object {}, + "scanLabels": Object {}, + "scanType": "sslyze", + "volumeMounts": Array [ + Object { + "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", + "name": "ca-certificate-sslyze", + "readOnly": true, + "subPath": "ca-cert-sslyze.cer", + }, + ], + "volumes": Array [], + }, + ] + `); + + const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); + + expect(cascadingScanDefinition.spec.volumeMounts).toMatchInlineSnapshot(` + Array [ + Object { + "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", + "name": "ca-certificate-sslyze", + "readOnly": true, + "subPath": "ca-cert-sslyze.cer", + }, + Object { + "mountPath": "/etc/ssl/certs/ca-cert.cer", + "name": "ca-certificate", + "readOnly": true, + "subPath": "ca-cert.cer", + }, + ] + `); +}); + +test("should merge volumes into cascaded scan", () => { + const findings = [ + { + name: "Port 443 is open", + category: "Open Port", + attributes: { + state: "open", + hostname: "foobar.com", + port: 443, + service: "https" + } + } + ]; + + parentScan.spec.volumes = [ + { + "name": "ca-certificate", + "configMap": { + "name": "ca-certificate" + } + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.volumes = [ + { + "name": "ca-certificate-sslyze", + "configMap": { + "name": "ca-certificate-sslyze" + } + } + ] + + const cascadedScans = getCascadingScans( + parentScan, + findings, + sslyzeCascadingRules + ); + + const cascadedScan = cascadedScans[0] + + expect(cascadedScans).toMatchInlineSnapshot(` + Array [ + Object { + "cascades": Object {}, + "env": Array [], + "finding": Object { + "attributes": Object { + "hostname": "foobar.com", + "port": 443, + "service": "https", + "state": "open", + }, + "category": "Open Port", + "name": "Port 443 is open", + }, + "generatedBy": "tls-scans", + "name": "sslyze-foobar.com-tls-scans", + "parameters": Array [ + "--regular", + "foobar.com:443", + ], + "scanAnnotations": Object {}, + "scanLabels": Object {}, + "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [ + Object { + "configMap": Object { + "name": "ca-certificate-sslyze", + }, + "name": "ca-certificate-sslyze", + }, + ], + }, + ] + `); + + const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); + + expect(cascadingScanDefinition.spec.volumes).toMatchInlineSnapshot(` + Array [ + Object { + "configMap": Object { + "name": "ca-certificate-sslyze", + }, + "name": "ca-certificate-sslyze", + }, + Object { + "configMap": Object { + "name": "ca-certificate", + }, + "name": "ca-certificate", + }, + ] + `); +}); diff --git a/hooks/cascading-scans/hook.ts b/hooks/cascading-scans/hook.ts index b92879f481..f29feb7e12 100644 --- a/hooks/cascading-scans/hook.ts +++ b/hooks/cascading-scans/hook.ts @@ -100,7 +100,7 @@ function getCascadingScan( finding: Finding, cascadingRule: CascadingRule ) { - const { scanType, parameters, env = [] } = cascadingRule.spec.scanSpec; + const { scanType, parameters, env = [], volumes = [], volumeMounts = [] } = cascadingRule.spec.scanSpec; const templateArgs = { ...finding, @@ -121,6 +121,8 @@ function getCascadingScan( cascades: parentScan.spec.cascades, generatedBy: cascadingRule.metadata.name, env, + volumes, + volumeMounts, scanLabels: cascadingRule.spec.scanLabels === undefined ? {} : mapValues(cascadingRule.spec.scanLabels, value => Mustache.render(value, templateArgs)), scanAnnotations: cascadingRule.spec.scanAnnotations === undefined ? {} : diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index 60b286b0db..51127914eb 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -57,6 +57,8 @@ export interface ScanSpec { parameters: Array; cascades: LabelSelector & CascadingInheritance; env?: Array; + volumes?: Array; + volumeMounts?: Array; } export interface CascadingInheritance { @@ -92,6 +94,8 @@ export function getCascadingScanDefinition({ parameters, generatedBy, env, + volumes, + volumeMounts, cascades, scanLabels, scanAnnotations, @@ -154,6 +158,8 @@ export function getCascadingScanDefinition({ parameters, cascades, env: env.concat(parentScan.spec.env || []), + volumes: volumes.concat(parentScan.spec.volumes || []), + volumeMounts: volumeMounts.concat(parentScan.spec.volumeMounts || []), } }; } From 3391d747c25a89117b1c659a3d50c6a61b6fedec Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Fri, 25 Jun 2021 10:24:20 +0200 Subject: [PATCH 03/17] Cascading Scans: CascadingRule's spec overwrites scan's spec Signed-off-by: Jop Zitman --- hooks/cascading-scans/scan-helpers.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index 51127914eb..1f71305520 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -157,9 +157,9 @@ export function getCascadingScanDefinition({ scanType, parameters, cascades, - env: env.concat(parentScan.spec.env || []), - volumes: volumes.concat(parentScan.spec.volumes || []), - volumeMounts: volumeMounts.concat(parentScan.spec.volumeMounts || []), + env: (parentScan.spec.env || []).concat(env), // CascadingRule's env overwrites scan's env + volumes: (parentScan.spec.volumes || []).concat(volumes), + volumeMounts: (parentScan.spec.volumeMounts || []).concat(volumeMounts), } }; } From b7b1856d5cf48748f71ed10e4f8fad3f1548bb5b Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Fri, 25 Jun 2021 10:33:49 +0200 Subject: [PATCH 04/17] Cascading Scans: purge cascaded rules spec from parent scan Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.test.js | 202 ++++++++++++++++++++++++++ hooks/cascading-scans/hook.ts | 17 ++- hooks/cascading-scans/scan-helpers.ts | 45 ++++++ 3 files changed, 261 insertions(+), 3 deletions(-) diff --git a/hooks/cascading-scans/hook.test.js b/hooks/cascading-scans/hook.test.js index 61c4709500..d4e1c736b0 100644 --- a/hooks/cascading-scans/hook.test.js +++ b/hooks/cascading-scans/hook.test.js @@ -1156,3 +1156,205 @@ test("should merge volumes into cascaded scan", () => { ] `); }); + + +test("should purge cascaded scan spec from parent scan", () => { + const findings = [ + { + name: "Port 443 is open", + category: "Open Port", + attributes: { + state: "open", + hostname: "foobar.com", + port: 443, + service: "https" + } + } + ]; + + parentScan.spec.volumes = [ + { + "name": "ca-certificate", + "configMap": { + "name": "ca-certificate" + } + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.volumes = [ + { + "name": "ca-certificate-sslyze", + "configMap": { + "name": "ca-certificate-sslyze" + } + } + ] + + parentScan.spec.volumeMounts = [ + { + "mountPath": "/etc/ssl/certs/ca-cert.cer", + "name": "ca-certificate", + "readOnly": true, + "subPath": "ca-cert.cer" + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.volumeMounts = [ + { + "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", + "name": "ca-certificate-sslyze", + "readOnly": true, + "subPath": "ca-cert-sslyze.cer" + } + ] + + parentScan.spec.env = [ + { + "name": "parent_environment_variable_name", + "value": "parent_environment_variable_value" + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.env = [ + { + "name": "rule_environment_variable_name", + "value": "rule_environment_variable_value" + } + ] + + const cascadedScans = getCascadingScans( + parentScan, + findings, + sslyzeCascadingRules + ); + + const cascadedScan = cascadedScans[0] + + expect(cascadedScans).toMatchInlineSnapshot(` + Array [ + Object { + "cascades": Object {}, + "env": Array [ + Object { + "name": "rule_environment_variable_name", + "value": "rule_environment_variable_value", + }, + ], + "finding": Object { + "attributes": Object { + "hostname": "foobar.com", + "port": 443, + "service": "https", + "state": "open", + }, + "category": "Open Port", + "name": "Port 443 is open", + }, + "generatedBy": "tls-scans", + "name": "sslyze-foobar.com-tls-scans", + "parameters": Array [ + "--regular", + "foobar.com:443", + ], + "scanAnnotations": Object {}, + "scanLabels": Object {}, + "scanType": "sslyze", + "volumeMounts": Array [ + Object { + "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", + "name": "ca-certificate-sslyze", + "readOnly": true, + "subPath": "ca-cert-sslyze.cer", + }, + ], + "volumes": Array [ + Object { + "configMap": Object { + "name": "ca-certificate-sslyze", + }, + "name": "ca-certificate-sslyze", + }, + ], + }, + ] + `); + + const cascadedScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan) + + // Create a second cascading rule + sslyzeCascadingRules[1] = { + apiVersion: "cascading.securecodebox.io/v1", + kind: "CascadingRule", + metadata: { + name: "tls-scans-second" + }, + spec: { + matches: { + anyOf: [ + { + category: "Open Port", + attributes: { + port: 443, + service: "https" + } + }, + { + category: "Open Port", + attributes: { + service: "https" + } + } + ] + }, + scanSpec: { + scanType: "sslyze", + parameters: ["--regular", "{{$.hostOrIP}}:{{attributes.port}}"] + } + } + } + + cascadedScanDefinition.metadata.name = cascadedScanDefinition.metadata.generateName + + const secondCascadedScans = getCascadingScans( + cascadedScanDefinition, + findings, + sslyzeCascadingRules, + sslyzeCascadingRules[0] // cascaded rule on parent + ); + + const secondCascadedScan = secondCascadedScans[0]; + + const secondCascadedScanDefinition = getCascadingScanDefinition(secondCascadedScan, cascadedScanDefinition); + + expect(secondCascadedScanDefinition.spec.env).toMatchInlineSnapshot(` + Array [ + Object { + "name": "parent_environment_variable_name", + "value": "parent_environment_variable_value", + }, + ] + `) + + expect(secondCascadedScanDefinition.spec.volumes).toMatchInlineSnapshot(` + Array [ + Object { + "configMap": Object { + "name": "ca-certificate", + }, + "name": "ca-certificate", + }, + ] + `) + + expect(secondCascadedScanDefinition.spec.volumeMounts).toMatchInlineSnapshot(` + Array [ + Object { + "mountPath": "/etc/ssl/certs/ca-cert.cer", + "name": "ca-certificate", + "readOnly": true, + "subPath": "ca-cert.cer", + }, + ] + `) + +}); diff --git a/hooks/cascading-scans/hook.ts b/hooks/cascading-scans/hook.ts index f29feb7e12..a17c2b17f8 100644 --- a/hooks/cascading-scans/hook.ts +++ b/hooks/cascading-scans/hook.ts @@ -14,7 +14,9 @@ import { Scan, Finding, CascadingRule, - ExtendedScanSpec + ExtendedScanSpec, + getCascadedRuleForScan, + purgeCascadedRuleFromScan } from "./scan-helpers"; interface HandleArgs { @@ -25,8 +27,9 @@ interface HandleArgs { export async function handle({ scan, getFindings }: HandleArgs) { const findings = await getFindings(); const cascadingRules = await getCascadingRules(scan); + const cascadedRule = await getCascadedRule(scan); - const cascadingScans = getCascadingScans(scan, findings, cascadingRules); + const cascadingScans = getCascadingScans(scan, findings, cascadingRules, cascadedRule); for (const cascadingScan of cascadingScans) { const cascadingScanDefinition = getCascadingScanDefinition(cascadingScan, scan); @@ -39,6 +42,11 @@ async function getCascadingRules(scan: Scan): Promise> { return >await getCascadingRulesForScan(scan); } +async function getCascadedRule(scan: Scan): Promise { + // Explicit Cast to the proper Type + return await getCascadedRuleForScan(scan); +} + /** * Goes thought the Findings and the CascadingRules * and returns a List of Scans which should be started based on both. @@ -46,11 +54,14 @@ async function getCascadingRules(scan: Scan): Promise> { export function getCascadingScans( parentScan: Scan, findings: Array, - cascadingRules: Array + cascadingRules: Array, + cascadedRule: CascadingRule ): Array { let cascadingScans: Array = []; const cascadingRuleChain = getScanChain(parentScan); + parentScan = purgeCascadedRuleFromScan(parentScan, cascadedRule); + for (const cascadingRule of cascadingRules) { // Check if the Same CascadingRule was already applied in the Cascading Chain // If it has already been used skip this rule as it could potentially lead to loops diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index 1f71305520..e5b8ce1c5a 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -8,6 +8,7 @@ import { generateSelectorString, LabelSelector } from "./kubernetes-label-selector"; +import {isEqual} from "lodash"; // configure k8s client const kc = new k8s.KubeConfig(); @@ -215,3 +216,47 @@ export async function getCascadingRulesForScan(scan: Scan) { process.exit(1); } } + +export function purgeCascadedRuleFromScan(scan: Scan, cascadedRule?: CascadingRule) : Scan { + if (cascadedRule === undefined) return scan; + + scan.spec.env = scan.spec.env.filter(scanEnv => + !cascadedRule.spec.scanSpec.env.some(ruleEnv => isEqual(scanEnv, ruleEnv)) + ); + + scan.spec.volumes = scan.spec.volumes.filter(scanVolume => + !cascadedRule.spec.scanSpec.volumes.some(ruleVolume => isEqual(scanVolume, ruleVolume)) + ); + + scan.spec.volumeMounts = scan.spec.volumeMounts.filter(scanVolumeMount => + !cascadedRule.spec.scanSpec.volumeMounts.some(ruleVolumeMount => isEqual(scanVolumeMount, ruleVolumeMount)) + ); + + return scan +} + +export async function getCascadedRuleForScan(scan: Scan) { + if (scan.metadata.generation === 1) return undefined; + + const cascadingChain = scan.metadata.annotations["cascading.securecodebox.io/chain"].split(",") + return await getCascadingRule(cascadingChain[cascadingChain.length - 1]); +} + +async function getCascadingRule(ruleName) { + try { + const response: any = await k8sApiCRD.getNamespacedCustomObject( + "cascading.securecodebox.io", + "v1", + namespace, + "cascadingrules", + ruleName + ); + + console.log(`Fetched CascadingRule "${ruleName}" that triggered parent scan`); + return response.body; + } catch (err) { + console.error(`Failed to get CascadingRule "${ruleName}" from the kubernetes api`); + console.error(err); + process.exit(1); + } +} From 5307a1a0b733aee3f71700a878915c53d73f03a2 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Wed, 30 Jun 2021 13:44:26 +0200 Subject: [PATCH 05/17] Cascading Scans: fix error when cascadingRule has no spec Signed-off-by: Jop Zitman --- hooks/cascading-scans/scan-helpers.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index e5b8ce1c5a..f2f69073fc 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -220,17 +220,23 @@ export async function getCascadingRulesForScan(scan: Scan) { export function purgeCascadedRuleFromScan(scan: Scan, cascadedRule?: CascadingRule) : Scan { if (cascadedRule === undefined) return scan; - scan.spec.env = scan.spec.env.filter(scanEnv => - !cascadedRule.spec.scanSpec.env.some(ruleEnv => isEqual(scanEnv, ruleEnv)) - ); + if (scan.spec.env !== undefined && cascadedRule.spec.scanSpec.env !== undefined) { + scan.spec.env = scan.spec.env.filter(scanEnv => + !cascadedRule.spec.scanSpec.env.some(ruleEnv => isEqual(scanEnv, ruleEnv)) + ); + } - scan.spec.volumes = scan.spec.volumes.filter(scanVolume => - !cascadedRule.spec.scanSpec.volumes.some(ruleVolume => isEqual(scanVolume, ruleVolume)) - ); + if (scan.spec.volumes !== undefined && cascadedRule.spec.scanSpec.volumes !== undefined) { + scan.spec.volumes = scan.spec.volumes.filter(scanVolume => + !cascadedRule.spec.scanSpec.volumes.some(ruleVolume => isEqual(scanVolume, ruleVolume)) + ); + } - scan.spec.volumeMounts = scan.spec.volumeMounts.filter(scanVolumeMount => - !cascadedRule.spec.scanSpec.volumeMounts.some(ruleVolumeMount => isEqual(scanVolumeMount, ruleVolumeMount)) - ); + if (scan.spec.volumeMounts !== undefined && cascadedRule.spec.scanSpec.volumeMounts !== undefined) { + scan.spec.volumeMounts = scan.spec.volumeMounts.filter(scanVolumeMount => + !cascadedRule.spec.scanSpec.volumeMounts.some(ruleVolumeMount => isEqual(scanVolumeMount, ruleVolumeMount)) + ); + } return scan } From 94bed3af79101d95be5a77db966028a8560c098b Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Mon, 12 Jul 2021 10:25:24 +0200 Subject: [PATCH 06/17] Cascading Scans: fix tests when running with ts-jest Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.test.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/hooks/cascading-scans/hook.test.js b/hooks/cascading-scans/hook.test.js index d4e1c736b0..f0c12f3a50 100644 --- a/hooks/cascading-scans/hook.test.js +++ b/hooks/cascading-scans/hook.test.js @@ -951,14 +951,14 @@ test("should merge environment variables into cascaded scan", () => { expect(cascadingScanDefinition.spec.env).toMatchInlineSnapshot(` Array [ - Object { - "name": "rule_environment_variable_name", - "value": "rule_environment_variable_value", - }, Object { "name": "parent_environment_variable_name", "value": "parent_environment_variable_value", }, + Object { + "name": "rule_environment_variable_name", + "value": "rule_environment_variable_value", + }, ] `); }); @@ -1044,18 +1044,18 @@ test("should merge volumeMounts into cascaded scan", () => { expect(cascadingScanDefinition.spec.volumeMounts).toMatchInlineSnapshot(` Array [ - Object { - "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", - "name": "ca-certificate-sslyze", - "readOnly": true, - "subPath": "ca-cert-sslyze.cer", - }, Object { "mountPath": "/etc/ssl/certs/ca-cert.cer", "name": "ca-certificate", "readOnly": true, "subPath": "ca-cert.cer", }, + Object { + "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", + "name": "ca-certificate-sslyze", + "readOnly": true, + "subPath": "ca-cert-sslyze.cer", + }, ] `); }); @@ -1143,15 +1143,15 @@ test("should merge volumes into cascaded scan", () => { Array [ Object { "configMap": Object { - "name": "ca-certificate-sslyze", + "name": "ca-certificate", }, - "name": "ca-certificate-sslyze", + "name": "ca-certificate", }, Object { "configMap": Object { - "name": "ca-certificate", + "name": "ca-certificate-sslyze", }, - "name": "ca-certificate", + "name": "ca-certificate-sslyze", }, ] `); From 8312973bec17005f5ca0ec1a8393de2157ed1771 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Mon, 12 Jul 2021 10:33:12 +0200 Subject: [PATCH 07/17] Cascading Scans: add inheritEnv & inheritVolumes (disabled by default) Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.test.js | 199 +++++++++++++++++++++++++- hooks/cascading-scans/scan-helpers.ts | 29 +++- 2 files changed, 216 insertions(+), 12 deletions(-) diff --git a/hooks/cascading-scans/hook.test.js b/hooks/cascading-scans/hook.test.js index f0c12f3a50..a031a8cb88 100644 --- a/hooks/cascading-scans/hook.test.js +++ b/hooks/cascading-scans/hook.test.js @@ -877,6 +877,7 @@ test("should copy proper finding ID into annotations", () => { }); test("should merge environment variables into cascaded scan", () => { + parentScan.spec.cascades.inheritEnv = true const findings = [ { name: "Port 443 is open", @@ -915,7 +916,9 @@ test("should merge environment variables into cascaded scan", () => { expect(cascadedScans).toMatchInlineSnapshot(` Array [ Object { - "cascades": Object {}, + "cascades": Object { + "inheritEnv": true, + }, "env": Array [ Object { "name": "rule_environment_variable_name", @@ -964,6 +967,7 @@ test("should merge environment variables into cascaded scan", () => { }); test("should merge volumeMounts into cascaded scan", () => { + parentScan.spec.cascades.inheritVolumes = true const findings = [ { name: "Port 443 is open", @@ -1006,7 +1010,9 @@ test("should merge volumeMounts into cascaded scan", () => { expect(cascadedScans).toMatchInlineSnapshot(` Array [ Object { - "cascades": Object {}, + "cascades": Object { + "inheritVolumes": true, + }, "env": Array [], "finding": Object { "attributes": Object { @@ -1061,6 +1067,7 @@ test("should merge volumeMounts into cascaded scan", () => { }); test("should merge volumes into cascaded scan", () => { + parentScan.spec.cascades.inheritVolumes = true const findings = [ { name: "Port 443 is open", @@ -1103,7 +1110,9 @@ test("should merge volumes into cascaded scan", () => { expect(cascadedScans).toMatchInlineSnapshot(` Array [ Object { - "cascades": Object {}, + "cascades": Object { + "inheritVolumes": true, + }, "env": Array [], "finding": Object { "attributes": Object { @@ -1157,8 +1166,9 @@ test("should merge volumes into cascaded scan", () => { `); }); - test("should purge cascaded scan spec from parent scan", () => { + parentScan.spec.cascades.inheritEnv = true + parentScan.spec.cascades.inheritVolumes = true const findings = [ { name: "Port 443 is open", @@ -1233,7 +1243,10 @@ test("should purge cascaded scan spec from parent scan", () => { expect(cascadedScans).toMatchInlineSnapshot(` Array [ Object { - "cascades": Object {}, + "cascades": Object { + "inheritEnv": true, + "inheritVolumes": true, + }, "env": Array [ Object { "name": "rule_environment_variable_name", @@ -1358,3 +1371,179 @@ test("should purge cascaded scan spec from parent scan", () => { `) }); + +test("should not copy cascaded scan spec from parent scan if inheritance is undefined", () => { + const findings = [ + { + name: "Port 443 is open", + category: "Open Port", + attributes: { + state: "open", + hostname: "foobar.com", + port: 443, + service: "https" + } + } + ]; + + parentScan.spec.volumes = [ + { + "name": "ca-certificate", + "configMap": { + "name": "ca-certificate" + } + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.volumes = [ + { + "name": "ca-certificate-sslyze", + "configMap": { + "name": "ca-certificate-sslyze" + } + } + ] + + parentScan.spec.volumeMounts = [ + { + "mountPath": "/etc/ssl/certs/ca-cert.cer", + "name": "ca-certificate", + "readOnly": true, + "subPath": "ca-cert.cer" + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.volumeMounts = [ + { + "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", + "name": "ca-certificate-sslyze", + "readOnly": true, + "subPath": "ca-cert-sslyze.cer" + } + ] + + parentScan.spec.env = [ + { + "name": "parent_environment_variable_name", + "value": "parent_environment_variable_value" + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.env = [ + { + "name": "rule_environment_variable_name", + "value": "rule_environment_variable_value" + } + ] + + const cascadedScans = getCascadingScans( + parentScan, + findings, + sslyzeCascadingRules + ); + + const cascadedScan = cascadedScans[0] + + expect(cascadedScans).toMatchInlineSnapshot(` + Array [ + Object { + "cascades": Object {}, + "env": Array [ + Object { + "name": "rule_environment_variable_name", + "value": "rule_environment_variable_value", + }, + ], + "finding": Object { + "attributes": Object { + "hostname": "foobar.com", + "port": 443, + "service": "https", + "state": "open", + }, + "category": "Open Port", + "name": "Port 443 is open", + }, + "generatedBy": "tls-scans", + "name": "sslyze-foobar.com-tls-scans", + "parameters": Array [ + "--regular", + "foobar.com:443", + ], + "scanAnnotations": Object {}, + "scanLabels": Object {}, + "scanType": "sslyze", + "volumeMounts": Array [ + Object { + "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", + "name": "ca-certificate-sslyze", + "readOnly": true, + "subPath": "ca-cert-sslyze.cer", + }, + ], + "volumes": Array [ + Object { + "configMap": Object { + "name": "ca-certificate-sslyze", + }, + "name": "ca-certificate-sslyze", + }, + ], + }, + ] + `); + + const cascadedScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan) + + // Create a second cascading rule + sslyzeCascadingRules[1] = { + apiVersion: "cascading.securecodebox.io/v1", + kind: "CascadingRule", + metadata: { + name: "tls-scans-second" + }, + spec: { + matches: { + anyOf: [ + { + category: "Open Port", + attributes: { + port: 443, + service: "https" + } + }, + { + category: "Open Port", + attributes: { + service: "https" + } + } + ] + }, + scanSpec: { + scanType: "sslyze", + parameters: ["--regular", "{{$.hostOrIP}}:{{attributes.port}}"] + } + } + } + + cascadedScanDefinition.metadata.name = cascadedScanDefinition.metadata.generateName + + const secondCascadedScans = getCascadingScans( + cascadedScanDefinition, + findings, + sslyzeCascadingRules, + sslyzeCascadingRules[0] // cascaded rule on parent + ); + + const secondCascadedScan = secondCascadedScans[0]; + + const secondCascadedScanDefinition = getCascadingScanDefinition(secondCascadedScan, cascadedScanDefinition); + + expect(secondCascadedScanDefinition.spec.env).toMatchInlineSnapshot(`Array []`) + + expect(secondCascadedScanDefinition.spec.volumes).toMatchInlineSnapshot(`Array []`) + + expect(secondCascadedScanDefinition.spec.volumeMounts).toMatchInlineSnapshot(`Array []`) + +}); diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index f2f69073fc..2c9a7da23f 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -64,7 +64,9 @@ export interface ScanSpec { export interface CascadingInheritance { inheritLabels: boolean, - inheritAnnotations: boolean + inheritAnnotations: boolean, + inheritEnv: boolean, + inheritVolumes: boolean } export interface ExtendedScanSpec extends ScanSpec { @@ -102,7 +104,7 @@ export function getCascadingScanDefinition({ scanAnnotations, finding }: ExtendedScanSpec, parentScan: Scan) { - function mergeInherited(parentProps, ruleProps, inherit: boolean = true) { + function mergeInheritedMap(parentProps, ruleProps, inherit: boolean = true) { if (!inherit) { parentProps = {}; } @@ -112,10 +114,23 @@ export function getCascadingScanDefinition({ } } - let annotations = mergeInherited( + function mergeInheritedArray(parentArray, ruleArray, inherit: boolean = false) { + if (!inherit) { + parentArray = []; + } + return (parentArray || []).concat(ruleArray) // CascadingRule's env overwrites scan's env + } + + let annotations = mergeInheritedMap( parentScan.metadata.annotations, scanAnnotations, parentScan.spec.cascades.inheritAnnotations); - let labels = mergeInherited( + let labels = mergeInheritedMap( parentScan.metadata.labels, scanLabels, parentScan.spec.cascades.inheritLabels); + env = mergeInheritedArray( + parentScan.spec.env, env, parentScan.spec.cascades.inheritEnv); + volumes = mergeInheritedArray( + parentScan.spec.volumes, volumes, parentScan.spec.cascades.inheritVolumes); + volumeMounts = mergeInheritedArray( + parentScan.spec.volumeMounts, volumeMounts, parentScan.spec.cascades.inheritVolumes); let cascadingChain: Array = []; @@ -158,9 +173,9 @@ export function getCascadingScanDefinition({ scanType, parameters, cascades, - env: (parentScan.spec.env || []).concat(env), // CascadingRule's env overwrites scan's env - volumes: (parentScan.spec.volumes || []).concat(volumes), - volumeMounts: (parentScan.spec.volumeMounts || []).concat(volumeMounts), + env, + volumes, + volumeMounts, } }; } From 1979c3aab1fb84a6cff5f9a89fda4d26e1b43426 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Mon, 12 Jul 2021 10:34:17 +0200 Subject: [PATCH 08/17] Operator: add inheritVolumes and inheritEnv to CRDs Signed-off-by: Jop Zitman --- operator/apis/execution/v1/scan_types.go | 8 ++++++++ .../bases/cascading.securecodebox.io_cascadingrules.yaml | 9 +++++++++ .../crd/bases/execution.securecodebox.io_scans.yaml | 8 ++++++++ .../bases/execution.securecodebox.io_scheduledscans.yaml | 9 +++++++++ 4 files changed, 34 insertions(+) diff --git a/operator/apis/execution/v1/scan_types.go b/operator/apis/execution/v1/scan_types.go index 11a624c276..db0650dffc 100644 --- a/operator/apis/execution/v1/scan_types.go +++ b/operator/apis/execution/v1/scan_types.go @@ -22,6 +22,14 @@ type CascadeSpec struct { // +optional InheritAnnotations bool `json:"inheritAnnotations,omitempty"` + // InheritEnv defines whether cascading scans should inherit environment variables from the parent scan + // +optional + InheritEnv bool `json:"inheritEnv,omitempty"` + + // InheritVolumes defines whether cascading scans should inherit volumes and volume mounts from the parent scan + // +optional + InheritVolumes bool `json:"inheritVolumes,omitempty"` + // matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels // map is equivalent to an element of matchExpressions, whose key field is "key", the // operator is "In", and the values array contains only "value". The requirements are ANDed. diff --git a/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml b/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml index 1bd877e6a4..e181c76b28 100644 --- a/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml +++ b/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml @@ -108,10 +108,19 @@ spec: description: InheritAnnotations defines whether cascading scans should inherit annotations from the parent scan type: boolean + inheritEnv: + description: InheritEnv defines whether cascading scans should + inherit environment variables from the parent scan + type: boolean inheritLabels: description: InheritLabels defines whether cascading scans should inherit labels from the parent scan type: boolean + inheritVolumes: + description: InheritVolumes defines whether cascading scans + should inherit volumes and volume mounts from the parent + scan + type: boolean matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. diff --git a/operator/config/crd/bases/execution.securecodebox.io_scans.yaml b/operator/config/crd/bases/execution.securecodebox.io_scans.yaml index 68444c933a..cc38bfe839 100644 --- a/operator/config/crd/bases/execution.securecodebox.io_scans.yaml +++ b/operator/config/crd/bases/execution.securecodebox.io_scans.yaml @@ -70,10 +70,18 @@ spec: description: InheritAnnotations defines whether cascading scans should inherit annotations from the parent scan type: boolean + inheritEnv: + description: InheritEnv defines whether cascading scans should + inherit environment variables from the parent scan + type: boolean inheritLabels: description: InheritLabels defines whether cascading scans should inherit labels from the parent scan type: boolean + inheritVolumes: + description: InheritVolumes defines whether cascading scans should + inherit volumes and volume mounts from the parent scan + type: boolean matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. diff --git a/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml b/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml index 9445cd79cf..3264a249a8 100644 --- a/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml +++ b/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml @@ -84,10 +84,19 @@ spec: description: InheritAnnotations defines whether cascading scans should inherit annotations from the parent scan type: boolean + inheritEnv: + description: InheritEnv defines whether cascading scans should + inherit environment variables from the parent scan + type: boolean inheritLabels: description: InheritLabels defines whether cascading scans should inherit labels from the parent scan type: boolean + inheritVolumes: + description: InheritVolumes defines whether cascading scans + should inherit volumes and volume mounts from the parent + scan + type: boolean matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. From d15f02e52d604b172743078d12559ef7ed45b5c9 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Mon, 12 Jul 2021 10:42:50 +0200 Subject: [PATCH 09/17] Cascading Scans: extract functions to make codeclimate happy Signed-off-by: Jop Zitman --- hooks/cascading-scans/scan-helpers.ts | 34 +++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index 2c9a7da23f..6e2a2f1608 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -91,6 +91,23 @@ export interface ExtendedScanSpec extends ScanSpec { finding: Finding } +function mergeInheritedMap(parentProps, ruleProps, inherit: boolean = true) { + if (!inherit) { + parentProps = {}; + } + return { + ...parentProps, + ...ruleProps // ruleProps overwrites any duplicate keys from parentProps + } +} + +function mergeInheritedArray(parentArray, ruleArray, inherit: boolean = false) { + if (!inherit) { + parentArray = []; + } + return (parentArray || []).concat(ruleArray) // CascadingRule's env overwrites scan's env +} + export function getCascadingScanDefinition({ name, scanType, @@ -104,23 +121,6 @@ export function getCascadingScanDefinition({ scanAnnotations, finding }: ExtendedScanSpec, parentScan: Scan) { - function mergeInheritedMap(parentProps, ruleProps, inherit: boolean = true) { - if (!inherit) { - parentProps = {}; - } - return { - ...parentProps, - ...ruleProps // ruleProps overwrites any duplicate keys from parentProps - } - } - - function mergeInheritedArray(parentArray, ruleArray, inherit: boolean = false) { - if (!inherit) { - parentArray = []; - } - return (parentArray || []).concat(ruleArray) // CascadingRule's env overwrites scan's env - } - let annotations = mergeInheritedMap( parentScan.metadata.annotations, scanAnnotations, parentScan.spec.cascades.inheritAnnotations); let labels = mergeInheritedMap( From 8501b73848d1e4ec39b49eb385b2a6e58327522e Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Wed, 21 Jul 2021 10:07:14 +0200 Subject: [PATCH 10/17] Cascading Scans: updates from code reviews Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.ts | 13 ++++--------- hooks/cascading-scans/scan-helpers.ts | 26 ++++++++++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/hooks/cascading-scans/hook.ts b/hooks/cascading-scans/hook.ts index a17c2b17f8..023c04358d 100644 --- a/hooks/cascading-scans/hook.ts +++ b/hooks/cascading-scans/hook.ts @@ -27,9 +27,9 @@ interface HandleArgs { export async function handle({ scan, getFindings }: HandleArgs) { const findings = await getFindings(); const cascadingRules = await getCascadingRules(scan); - const cascadedRule = await getCascadedRule(scan); + const cascadedRuleUsedForParentScan = await getCascadedRuleForScan(scan); - const cascadingScans = getCascadingScans(scan, findings, cascadingRules, cascadedRule); + const cascadingScans = getCascadingScans(scan, findings, cascadingRules, cascadedRuleUsedForParentScan); for (const cascadingScan of cascadingScans) { const cascadingScanDefinition = getCascadingScanDefinition(cascadingScan, scan); @@ -42,11 +42,6 @@ async function getCascadingRules(scan: Scan): Promise> { return >await getCascadingRulesForScan(scan); } -async function getCascadedRule(scan: Scan): Promise { - // Explicit Cast to the proper Type - return await getCascadedRuleForScan(scan); -} - /** * Goes thought the Findings and the CascadingRules * and returns a List of Scans which should be started based on both. @@ -55,12 +50,12 @@ export function getCascadingScans( parentScan: Scan, findings: Array, cascadingRules: Array, - cascadedRule: CascadingRule + cascadedRuleUsedForParentScan: CascadingRule ): Array { let cascadingScans: Array = []; const cascadingRuleChain = getScanChain(parentScan); - parentScan = purgeCascadedRuleFromScan(parentScan, cascadedRule); + parentScan = purgeCascadedRuleFromScan(parentScan, cascadedRuleUsedForParentScan); for (const cascadingRule of cascadingRules) { // Check if the Same CascadingRule was already applied in the Cascading Chain diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index 6e2a2f1608..1619ee55dc 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -232,24 +232,27 @@ export async function getCascadingRulesForScan(scan: Scan) { } } -export function purgeCascadedRuleFromScan(scan: Scan, cascadedRule?: CascadingRule) : Scan { - if (cascadedRule === undefined) return scan; +// To ensure that the environment variables and volumes from the cascading rule are only applied to the matched scan +// (and not its children), this function purges the cascading rule spec from the parent scan when inheriting them. +export function purgeCascadedRuleFromScan(scan: Scan, cascadedRuleUsedForParentScan?: CascadingRule) : Scan { + // If there was no cascading rule applied to the parent scan, then ignore no purging is necessary. + if (cascadedRuleUsedForParentScan === undefined) return scan; - if (scan.spec.env !== undefined && cascadedRule.spec.scanSpec.env !== undefined) { + if (scan.spec.env !== undefined && cascadedRuleUsedForParentScan.spec.scanSpec.env !== undefined) { scan.spec.env = scan.spec.env.filter(scanEnv => - !cascadedRule.spec.scanSpec.env.some(ruleEnv => isEqual(scanEnv, ruleEnv)) + !cascadedRuleUsedForParentScan.spec.scanSpec.env.some(ruleEnv => isEqual(scanEnv, ruleEnv)) ); } - if (scan.spec.volumes !== undefined && cascadedRule.spec.scanSpec.volumes !== undefined) { + if (scan.spec.volumes !== undefined && cascadedRuleUsedForParentScan.spec.scanSpec.volumes !== undefined) { scan.spec.volumes = scan.spec.volumes.filter(scanVolume => - !cascadedRule.spec.scanSpec.volumes.some(ruleVolume => isEqual(scanVolume, ruleVolume)) + !cascadedRuleUsedForParentScan.spec.scanSpec.volumes.some(ruleVolume => isEqual(scanVolume, ruleVolume)) ); } - if (scan.spec.volumeMounts !== undefined && cascadedRule.spec.scanSpec.volumeMounts !== undefined) { + if (scan.spec.volumeMounts !== undefined && cascadedRuleUsedForParentScan.spec.scanSpec.volumeMounts !== undefined) { scan.spec.volumeMounts = scan.spec.volumeMounts.filter(scanVolumeMount => - !cascadedRule.spec.scanSpec.volumeMounts.some(ruleVolumeMount => isEqual(scanVolumeMount, ruleVolumeMount)) + !cascadedRuleUsedForParentScan.spec.scanSpec.volumeMounts.some(ruleVolumeMount => isEqual(scanVolumeMount, ruleVolumeMount)) ); } @@ -257,10 +260,13 @@ export function purgeCascadedRuleFromScan(scan: Scan, cascadedRule?: CascadingRu } export async function getCascadedRuleForScan(scan: Scan) { - if (scan.metadata.generation === 1) return undefined; + if (typeof scan.metadata.annotations["cascading.securecodebox.io/chain"] === "undefined") return undefined; const cascadingChain = scan.metadata.annotations["cascading.securecodebox.io/chain"].split(",") - return await getCascadingRule(cascadingChain[cascadingChain.length - 1]); + + if (cascadingChain.length === 0) return undefined; + + return await getCascadingRule(cascadingChain[cascadingChain.length - 1]); } async function getCascadingRule(ruleName) { From 2ded643a5b5bcaca665e1e2984f6bf78c73adcd4 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Wed, 21 Jul 2021 10:28:10 +0200 Subject: [PATCH 11/17] Cascading Scans: tests remove intermediate assertions on cascadedScans Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.test.js | 321 ----------------------------- 1 file changed, 321 deletions(-) diff --git a/hooks/cascading-scans/hook.test.js b/hooks/cascading-scans/hook.test.js index a031a8cb88..bf408331b3 100644 --- a/hooks/cascading-scans/hook.test.js +++ b/hooks/cascading-scans/hook.test.js @@ -647,40 +647,6 @@ test("should copy scanLabels from CascadingRule to cascading scan", () => { ); const cascadedScan = cascadedScans[0] - - expect(cascadedScans).toMatchInlineSnapshot(` - Array [ - Object { - "cascades": Object {}, - "env": Array [], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", - }, - "category": "Open Port", - "name": "Port 443 is open", - }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object { - "k_one": "v_one", - "k_two": "v_two", - }, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [], - }, - ] - `); - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); expect(Object.entries(sslyzeCascadingRules[0].spec.scanLabels).every(([label, value]) => @@ -714,40 +680,6 @@ test("should copy scanAnnotations from CascadingRule to cascading scan", () => { ); const cascadedScan = cascadedScans[0] - - expect(cascadedScans).toMatchInlineSnapshot(` - Array [ - Object { - "cascades": Object {}, - "env": Array [], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", - }, - "category": "Open Port", - "name": "Port 443 is open", - }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object { - "k_one": "v_one", - "k_two": "v_two", - }, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [], - }, - ] - `); - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); expect(Object.entries(sslyzeCascadingRules[0].spec.scanAnnotations).every(([label, value]) => @@ -834,38 +766,6 @@ test("should copy proper finding ID into annotations", () => { ); const cascadedScan = cascadedScans[0] - - expect(cascadedScans).toMatchInlineSnapshot(` - Array [ - Object { - "cascades": Object {}, - "env": Array [], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", - }, - "category": "Open Port", - "id": "f0c718bd-9987-42c8-2259-73794e61dd5a", - "name": "Port 443 is open", - }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [], - }, - ] - `); - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); expect(Object.entries(cascadingScanDefinition.metadata.annotations).every(([label, value]) => { @@ -912,44 +812,6 @@ test("should merge environment variables into cascaded scan", () => { ); const cascadedScan = cascadedScans[0] - - expect(cascadedScans).toMatchInlineSnapshot(` - Array [ - Object { - "cascades": Object { - "inheritEnv": true, - }, - "env": Array [ - Object { - "name": "rule_environment_variable_name", - "value": "rule_environment_variable_value", - }, - ], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", - }, - "category": "Open Port", - "name": "Port 443 is open", - }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [], - }, - ] - `); - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); expect(cascadingScanDefinition.spec.env).toMatchInlineSnapshot(` @@ -1006,46 +868,6 @@ test("should merge volumeMounts into cascaded scan", () => { ); const cascadedScan = cascadedScans[0] - - expect(cascadedScans).toMatchInlineSnapshot(` - Array [ - Object { - "cascades": Object { - "inheritVolumes": true, - }, - "env": Array [], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", - }, - "category": "Open Port", - "name": "Port 443 is open", - }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [ - Object { - "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", - "name": "ca-certificate-sslyze", - "readOnly": true, - "subPath": "ca-cert-sslyze.cer", - }, - ], - "volumes": Array [], - }, - ] - `); - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); expect(cascadingScanDefinition.spec.volumeMounts).toMatchInlineSnapshot(` @@ -1106,46 +928,6 @@ test("should merge volumes into cascaded scan", () => { ); const cascadedScan = cascadedScans[0] - - expect(cascadedScans).toMatchInlineSnapshot(` - Array [ - Object { - "cascades": Object { - "inheritVolumes": true, - }, - "env": Array [], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", - }, - "category": "Open Port", - "name": "Port 443 is open", - }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [ - Object { - "configMap": Object { - "name": "ca-certificate-sslyze", - }, - "name": "ca-certificate-sslyze", - }, - ], - }, - ] - `); - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); expect(cascadingScanDefinition.spec.volumes).toMatchInlineSnapshot(` @@ -1239,59 +1021,6 @@ test("should purge cascaded scan spec from parent scan", () => { ); const cascadedScan = cascadedScans[0] - - expect(cascadedScans).toMatchInlineSnapshot(` - Array [ - Object { - "cascades": Object { - "inheritEnv": true, - "inheritVolumes": true, - }, - "env": Array [ - Object { - "name": "rule_environment_variable_name", - "value": "rule_environment_variable_value", - }, - ], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", - }, - "category": "Open Port", - "name": "Port 443 is open", - }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [ - Object { - "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", - "name": "ca-certificate-sslyze", - "readOnly": true, - "subPath": "ca-cert-sslyze.cer", - }, - ], - "volumes": Array [ - Object { - "configMap": Object { - "name": "ca-certificate-sslyze", - }, - "name": "ca-certificate-sslyze", - }, - ], - }, - ] - `); - const cascadedScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan) // Create a second cascading rule @@ -1443,56 +1172,6 @@ test("should not copy cascaded scan spec from parent scan if inheritance is unde ); const cascadedScan = cascadedScans[0] - - expect(cascadedScans).toMatchInlineSnapshot(` - Array [ - Object { - "cascades": Object {}, - "env": Array [ - Object { - "name": "rule_environment_variable_name", - "value": "rule_environment_variable_value", - }, - ], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", - }, - "category": "Open Port", - "name": "Port 443 is open", - }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [ - Object { - "mountPath": "/etc/ssl/certs/ca-cert-sslyze.cer", - "name": "ca-certificate-sslyze", - "readOnly": true, - "subPath": "ca-cert-sslyze.cer", - }, - ], - "volumes": Array [ - Object { - "configMap": Object { - "name": "ca-certificate-sslyze", - }, - "name": "ca-certificate-sslyze", - }, - ], - }, - ] - `); - const cascadedScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan) // Create a second cascading rule From ffa294f1d839baf3551e9e02e8ef899f01fe5834 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Wed, 21 Jul 2021 13:15:17 +0200 Subject: [PATCH 12/17] Cascading Scans: create scan definition in `getCascadingScans` and update the tests accordingly. Also replaces intermediate checks on the scan definition by only the test's specific assertion (e.g. random name test). Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.test.js | 323 +++++++++++--------------- hooks/cascading-scans/hook.ts | 117 ++++++++-- hooks/cascading-scans/scan-helpers.ts | 76 +----- 3 files changed, 233 insertions(+), 283 deletions(-) diff --git a/hooks/cascading-scans/hook.test.js b/hooks/cascading-scans/hook.test.js index bf408331b3..36528afc6b 100644 --- a/hooks/cascading-scans/hook.test.js +++ b/hooks/cascading-scans/hook.test.js @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: Apache-2.0 -const { getCascadingScanDefinition } = require("./scan-helpers"); const { getCascadingScans } = require("./hook"); let parentScan = undefined; @@ -80,29 +79,39 @@ test("Should create subsequent scans for open HTTPS ports (NMAP findings)", () = expect(cascadedScans).toMatchInlineSnapshot(` Array [ Object { - "cascades": Object {}, - "env": Array [], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", + "apiVersion": "execution.securecodebox.io/v1", + "kind": "Scan", + "metadata": Object { + "annotations": Object { + "cascading.securecodebox.io/chain": "tls-scans", + "cascading.securecodebox.io/matched-finding": undefined, + "cascading.securecodebox.io/parent-scan": "nmap-foobar.com", + "securecodebox.io/hook": "cascading-scans", }, - "category": "Open Port", - "name": "Port 443 is open", + "generateName": "sslyze-foobar.com-tls-scans-", + "labels": Object {}, + "ownerReferences": Array [ + Object { + "apiVersion": "execution.securecodebox.io/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Scan", + "name": "nmap-foobar.com", + "uid": undefined, + }, + ], + }, + "spec": Object { + "cascades": Object {}, + "env": Array [], + "parameters": Array [ + "--regular", + "foobar.com:443", + ], + "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [], }, ] `); @@ -152,36 +161,7 @@ test("Should not try to do magic to the scan name if its something random", () = sslyzeCascadingRules ); - expect(cascadedScans).toMatchInlineSnapshot(` - Array [ - Object { - "cascades": Object {}, - "env": Array [], - "finding": Object { - "attributes": Object { - "hostname": undefined, - "ip_address": "10.42.42.42", - "port": 443, - "service": "https", - "state": "open", - }, - "category": "Open Port", - "name": "Port 443 is open", - }, - "generatedBy": "tls-scans", - "name": "foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "10.42.42.42:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [], - }, - ] - `); + expect(cascadedScans[0].metadata.generateName).toEqual("foobar.com-tls-scans-"); }); test("Should not start a new scan when the corresponding cascadingRule is already in the chain", () => { @@ -235,29 +215,39 @@ test("Should not crash when the annotations are not set", () => { expect(cascadedScans).toMatchInlineSnapshot(` Array [ Object { - "cascades": Object {}, - "env": Array [], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", + "apiVersion": "execution.securecodebox.io/v1", + "kind": "Scan", + "metadata": Object { + "annotations": Object { + "cascading.securecodebox.io/chain": "tls-scans", + "cascading.securecodebox.io/matched-finding": undefined, + "cascading.securecodebox.io/parent-scan": "nmap-foobar.com", + "securecodebox.io/hook": "cascading-scans", }, - "category": "Open Port", - "name": "Port 443 is open", + "generateName": "sslyze-foobar.com-tls-scans-", + "labels": Object {}, + "ownerReferences": Array [ + Object { + "apiVersion": "execution.securecodebox.io/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Scan", + "name": "nmap-foobar.com", + "uid": undefined, + }, + ], + }, + "spec": Object { + "cascades": Object {}, + "env": Array [], + "parameters": Array [ + "--regular", + "foobar.com:443", + ], + "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [], }, ] `); @@ -290,42 +280,16 @@ test("Should copy ENV fields from cascadingRule to created scan", () => { sslyzeCascadingRules ); - expect(cascadedScans).toMatchInlineSnapshot(` + expect(cascadedScans[0].spec.env).toMatchInlineSnapshot(` Array [ Object { - "cascades": Object {}, - "env": Array [ - Object { - "name": "FOOBAR", - "valueFrom": Object { - "secretKeyRef": Object { - "key": "token", - "name": "foobar-token", - }, - }, - }, - ], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 443, - "service": "https", - "state": "open", + "name": "FOOBAR", + "valueFrom": Object { + "secretKeyRef": Object { + "key": "token", + "name": "foobar-token", }, - "category": "Open Port", - "name": "Port 443 is open", }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [], }, ] `); @@ -381,29 +345,39 @@ test("Should allow wildcards in cascadingRules", () => { expect(cascadedScans).toMatchInlineSnapshot(` Array [ Object { - "cascades": Object {}, - "env": Array [], - "finding": Object { - "attributes": Object { - "hostname": "foobar.com", - "port": 8443, - "service": "https-alt", - "state": "open", + "apiVersion": "execution.securecodebox.io/v1", + "kind": "Scan", + "metadata": Object { + "annotations": Object { + "cascading.securecodebox.io/chain": "tls-scans", + "cascading.securecodebox.io/matched-finding": undefined, + "cascading.securecodebox.io/parent-scan": "nmap-foobar.com", + "securecodebox.io/hook": "cascading-scans", }, - "category": "Open Port", - "name": "Port 8443 is open", + "generateName": "sslyze-foobar.com-tls-scans-", + "labels": Object {}, + "ownerReferences": Array [ + Object { + "apiVersion": "execution.securecodebox.io/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Scan", + "name": "nmap-foobar.com", + "uid": undefined, + }, + ], + }, + "spec": Object { + "cascades": Object {}, + "env": Array [], + "parameters": Array [ + "--regular", + "foobar.com:8443", + ], + "scanType": "sslyze", + "volumeMounts": Array [], + "volumes": Array [], }, - "generatedBy": "tls-scans", - "name": "sslyze-foobar.com-tls-scans", - "parameters": Array [ - "--regular", - "foobar.com:8443", - ], - "scanAnnotations": Object {}, - "scanLabels": Object {}, - "scanType": "sslyze", - "volumeMounts": Array [], - "volumes": Array [], }, ] `); @@ -437,10 +411,8 @@ test("should not copy labels if inheritLabels is set to false", () => { ); for (const cascadedScan of cascadedScans) { - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - expect(Object.entries(parentScan.metadata.labels).every(([label, value]) => - cascadingScanDefinition.metadata.labels[label] === value + cascadedScan.metadata.labels[label] === value )).toBe(false) } }); @@ -472,10 +444,8 @@ test("should copy labels if inheritLabels is not set", () => { ); for (const cascadedScan of cascadedScans) { - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - expect(Object.entries(parentScan.metadata.labels).every(([label, value]) => - cascadingScanDefinition.metadata.labels[label] === value + cascadedScan.metadata.labels[label] === value )).toBe(true) } }); @@ -509,10 +479,8 @@ test("should copy labels if inheritLabels is set to true", () => { ); for (const cascadedScan of cascadedScans) { - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - expect(Object.entries(parentScan.metadata.labels).every(([label, value]) => - cascadingScanDefinition.metadata.labels[label] === value + cascadedScan.metadata.labels[label] === value )).toBe(true) } }); @@ -544,10 +512,8 @@ test("should not copy annotations if inheritAnnotations is set to false", () => ); for (const cascadedScan of cascadedScans) { - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - expect(Object.entries(parentScan.metadata.annotations).every(([label, value]) => - cascadingScanDefinition.metadata.annotations[label] === value + cascadedScan.metadata.annotations[label] === value )).toBe(false) } }); @@ -578,10 +544,8 @@ test("should copy annotations if inheritAnnotations is not set", () => { ); for (const cascadedScan of cascadedScans) { - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - expect(Object.entries(parentScan.metadata.annotations).every(([label, value]) => - cascadingScanDefinition.metadata.annotations[label] === value + cascadedScan.metadata.annotations[label] === value )).toBe(true) } }); @@ -613,10 +577,8 @@ test("should copy annotations if inheritAnnotations is set to true", () => { ); for (const cascadedScan of cascadedScans) { - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - expect(Object.entries(parentScan.metadata.annotations).every(([label, value]) => - cascadingScanDefinition.metadata.annotations[label] === value + cascadedScan.metadata.annotations[label] === value )).toBe(true) } }); @@ -647,10 +609,8 @@ test("should copy scanLabels from CascadingRule to cascading scan", () => { ); const cascadedScan = cascadedScans[0] - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - expect(Object.entries(sslyzeCascadingRules[0].spec.scanLabels).every(([label, value]) => - cascadingScanDefinition.metadata.labels[label] === value + cascadedScan.metadata.labels[label] === value )).toBe(true) }); @@ -680,10 +640,8 @@ test("should copy scanAnnotations from CascadingRule to cascading scan", () => { ); const cascadedScan = cascadedScans[0] - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - expect(Object.entries(sslyzeCascadingRules[0].spec.scanAnnotations).every(([label, value]) => - cascadingScanDefinition.metadata.annotations[label] === value + cascadedScan.metadata.annotations[label] === value )).toBe(true) }); @@ -716,21 +674,32 @@ test("should properly parse template values in scanLabels and scanAnnotations", const cascadedScans = getCascadingScans( parentScan, findings, - sslyzeCascadingRules + sslyzeCascadingRules, + sslyzeCascadingRules[0] ); - const { scanLabels, scanAnnotations } = cascadedScans[0] + const { labels, annotations } = cascadedScans[0].metadata; // No snapshots as scanLabels/scanAnnotations can be in any order - const result = { + const labelResults = { "k_one": "nmap-foobar.com", "k_two": "", "k_three": "foobar.com", } - expect(scanLabels).toEqual(result) + expect(labels).toEqual(labelResults) - expect(scanAnnotations).toEqual(result) + const annotationsResults = { + "cascading.securecodebox.io/chain": "tls-scans", + "cascading.securecodebox.io/matched-finding": undefined, + "cascading.securecodebox.io/parent-scan": "nmap-foobar.com", + "securecodebox.io/hook": "cascading-scans", + "k_one": "nmap-foobar.com", + "k_two": "", + "k_three": "foobar.com", + }; + + expect(annotations).toEqual(annotationsResults) }) test("should copy proper finding ID into annotations", () => { @@ -766,9 +735,7 @@ test("should copy proper finding ID into annotations", () => { ); const cascadedScan = cascadedScans[0] - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - - expect(Object.entries(cascadingScanDefinition.metadata.annotations).every(([label, value]) => { + expect(Object.entries(cascadedScan.metadata.annotations).every(([label, value]) => { if (label === "cascading.securecodebox.io/matched-finding") { return value === "f0c718bd-9987-42c8-2259-73794e61dd5a"; } else return true; @@ -812,9 +779,7 @@ test("should merge environment variables into cascaded scan", () => { ); const cascadedScan = cascadedScans[0] - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - - expect(cascadingScanDefinition.spec.env).toMatchInlineSnapshot(` + expect(cascadedScan.spec.env).toMatchInlineSnapshot(` Array [ Object { "name": "parent_environment_variable_name", @@ -868,9 +833,7 @@ test("should merge volumeMounts into cascaded scan", () => { ); const cascadedScan = cascadedScans[0] - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); - - expect(cascadingScanDefinition.spec.volumeMounts).toMatchInlineSnapshot(` + expect(cascadedScan.spec.volumeMounts).toMatchInlineSnapshot(` Array [ Object { "mountPath": "/etc/ssl/certs/ca-cert.cer", @@ -927,10 +890,9 @@ test("should merge volumes into cascaded scan", () => { sslyzeCascadingRules ); - const cascadedScan = cascadedScans[0] - const cascadingScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan); + const cascadedScan = cascadedScans[0]; - expect(cascadingScanDefinition.spec.volumes).toMatchInlineSnapshot(` + expect(cascadedScan.spec.volumes).toMatchInlineSnapshot(` Array [ Object { "configMap": Object { @@ -1021,7 +983,6 @@ test("should purge cascaded scan spec from parent scan", () => { ); const cascadedScan = cascadedScans[0] - const cascadedScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan) // Create a second cascading rule sslyzeCascadingRules[1] = { @@ -1055,10 +1016,10 @@ test("should purge cascaded scan spec from parent scan", () => { } } - cascadedScanDefinition.metadata.name = cascadedScanDefinition.metadata.generateName + cascadedScan.metadata.name = cascadedScan.metadata.generateName const secondCascadedScans = getCascadingScans( - cascadedScanDefinition, + cascadedScan, findings, sslyzeCascadingRules, sslyzeCascadingRules[0] // cascaded rule on parent @@ -1066,9 +1027,7 @@ test("should purge cascaded scan spec from parent scan", () => { const secondCascadedScan = secondCascadedScans[0]; - const secondCascadedScanDefinition = getCascadingScanDefinition(secondCascadedScan, cascadedScanDefinition); - - expect(secondCascadedScanDefinition.spec.env).toMatchInlineSnapshot(` + expect(secondCascadedScan.spec.env).toMatchInlineSnapshot(` Array [ Object { "name": "parent_environment_variable_name", @@ -1077,7 +1036,7 @@ test("should purge cascaded scan spec from parent scan", () => { ] `) - expect(secondCascadedScanDefinition.spec.volumes).toMatchInlineSnapshot(` + expect(secondCascadedScan.spec.volumes).toMatchInlineSnapshot(` Array [ Object { "configMap": Object { @@ -1088,7 +1047,7 @@ test("should purge cascaded scan spec from parent scan", () => { ] `) - expect(secondCascadedScanDefinition.spec.volumeMounts).toMatchInlineSnapshot(` + expect(secondCascadedScan.spec.volumeMounts).toMatchInlineSnapshot(` Array [ Object { "mountPath": "/etc/ssl/certs/ca-cert.cer", @@ -1172,8 +1131,6 @@ test("should not copy cascaded scan spec from parent scan if inheritance is unde ); const cascadedScan = cascadedScans[0] - const cascadedScanDefinition = getCascadingScanDefinition(cascadedScan, parentScan) - // Create a second cascading rule sslyzeCascadingRules[1] = { apiVersion: "cascading.securecodebox.io/v1", @@ -1206,10 +1163,10 @@ test("should not copy cascaded scan spec from parent scan if inheritance is unde } } - cascadedScanDefinition.metadata.name = cascadedScanDefinition.metadata.generateName + cascadedScan.metadata.name = cascadedScan.metadata.generateName const secondCascadedScans = getCascadingScans( - cascadedScanDefinition, + cascadedScan, findings, sslyzeCascadingRules, sslyzeCascadingRules[0] // cascaded rule on parent @@ -1217,12 +1174,10 @@ test("should not copy cascaded scan spec from parent scan if inheritance is unde const secondCascadedScan = secondCascadedScans[0]; - const secondCascadedScanDefinition = getCascadingScanDefinition(secondCascadedScan, cascadedScanDefinition); - - expect(secondCascadedScanDefinition.spec.env).toMatchInlineSnapshot(`Array []`) + expect(secondCascadedScan.spec.env).toMatchInlineSnapshot(`Array []`) - expect(secondCascadedScanDefinition.spec.volumes).toMatchInlineSnapshot(`Array []`) + expect(secondCascadedScan.spec.volumes).toMatchInlineSnapshot(`Array []`) - expect(secondCascadedScanDefinition.spec.volumeMounts).toMatchInlineSnapshot(`Array []`) + expect(secondCascadedScan.spec.volumeMounts).toMatchInlineSnapshot(`Array []`) }); diff --git a/hooks/cascading-scans/hook.ts b/hooks/cascading-scans/hook.ts index 023c04358d..bb6fbae9a7 100644 --- a/hooks/cascading-scans/hook.ts +++ b/hooks/cascading-scans/hook.ts @@ -9,14 +9,15 @@ import * as Mustache from "mustache"; import { startSubsequentSecureCodeBoxScan, getCascadingRulesForScan, - getCascadingScanDefinition, // types Scan, Finding, CascadingRule, ExtendedScanSpec, getCascadedRuleForScan, - purgeCascadedRuleFromScan + purgeCascadedRuleFromScan, + mergeInheritedMap, + mergeInheritedArray } from "./scan-helpers"; interface HandleArgs { @@ -32,8 +33,7 @@ export async function handle({ scan, getFindings }: HandleArgs) { const cascadingScans = getCascadingScans(scan, findings, cascadingRules, cascadedRuleUsedForParentScan); for (const cascadingScan of cascadingScans) { - const cascadingScanDefinition = getCascadingScanDefinition(cascadingScan, scan); - await startSubsequentSecureCodeBoxScan(cascadingScanDefinition); + await startSubsequentSecureCodeBoxScan(cascadingScan); } } @@ -51,8 +51,8 @@ export function getCascadingScans( findings: Array, cascadingRules: Array, cascadedRuleUsedForParentScan: CascadingRule -): Array { - let cascadingScans: Array = []; +): Array { + let cascadingScans: Array = []; const cascadingRuleChain = getScanChain(parentScan); parentScan = purgeCascadedRuleFromScan(parentScan, cascadedRuleUsedForParentScan); @@ -87,7 +87,7 @@ function getScanChain(parentScan: Scan) { } function getScansMatchingRule(parentScan: Scan, findings: Array, cascadingRule: CascadingRule) { - const cascadingScans: Array = []; + const cascadingScans: Array = []; for (const finding of findings) { // Check if one (ore more) of the CascadingRule matchers apply to the finding const matches = cascadingRule.spec.matches.anyOf.some(matchesRule => @@ -106,8 +106,79 @@ function getCascadingScan( finding: Finding, cascadingRule: CascadingRule ) { - const { scanType, parameters, env = [], volumes = [], volumeMounts = [] } = cascadingRule.spec.scanSpec; + cascadingRule = templateCascadingRule(parentScan, finding, cascadingRule); + let { scanType, parameters } = cascadingRule.spec.scanSpec; + + let { annotations, labels, env, volumes, volumeMounts } = mergeCascadingRuleWithScan(parentScan, cascadingRule); + + let cascadingChain: Array = []; + if (parentScan.metadata.annotations && parentScan.metadata.annotations["cascading.securecodebox.io/chain"]) { + cascadingChain = parentScan.metadata.annotations[ + "cascading.securecodebox.io/chain" + ].split(","); + } + + return { + apiVersion: "execution.securecodebox.io/v1", + kind: "Scan", + metadata: { + generateName: `${generateCascadingScanName(parentScan, cascadingRule)}-`, + labels, + annotations: { + "securecodebox.io/hook": "cascading-scans", + "cascading.securecodebox.io/parent-scan": parentScan.metadata.name, + "cascading.securecodebox.io/matched-finding": finding.id, + "cascading.securecodebox.io/chain": [ + ...cascadingChain, + cascadingRule.metadata.name + ].join(","), + ...annotations, + }, + ownerReferences: [ + { + apiVersion: "execution.securecodebox.io/v1", + blockOwnerDeletion: true, + controller: true, + kind: "Scan", + name: parentScan.metadata.name, + uid: parentScan.metadata.uid + } + ] + }, + spec: { + scanType, + parameters, + cascades: parentScan.spec.cascades, + env, + volumes, + volumeMounts, + } + }; +} + +function mergeCascadingRuleWithScan( + scan: Scan, + cascadingRule: CascadingRule +) { + const { scanAnnotations, scanLabels } = cascadingRule.spec; + let { env = [], volumes = [], volumeMounts = [] } = cascadingRule.spec.scanSpec; + let { inheritAnnotations, inheritLabels, inheritEnv, inheritVolumes } = scan.spec.cascades; + + return { + annotations: mergeInheritedMap(scan.metadata.annotations, scanAnnotations, inheritAnnotations), + labels: mergeInheritedMap(scan.metadata.labels, scanLabels, inheritLabels), + env: mergeInheritedArray(scan.spec.env, env, inheritEnv), + volumes: mergeInheritedArray(scan.spec.volumes, volumes, inheritVolumes), + volumeMounts: mergeInheritedArray(scan.spec.volumeMounts, volumeMounts, inheritVolumes) + } +} + +function templateCascadingRule( + parentScan: Scan, + finding: Finding, + cascadingRule: CascadingRule +): CascadingRule { const templateArgs = { ...finding, ...parentScan, @@ -118,23 +189,19 @@ function getCascadingScan( } }; - return { - name: generateCascadingScanName(parentScan, cascadingRule), - scanType: Mustache.render(scanType, templateArgs), - parameters: parameters.map(parameter => - Mustache.render(parameter, templateArgs) - ), - cascades: parentScan.spec.cascades, - generatedBy: cascadingRule.metadata.name, - env, - volumes, - volumeMounts, - scanLabels: cascadingRule.spec.scanLabels === undefined ? {} : - mapValues(cascadingRule.spec.scanLabels, value => Mustache.render(value, templateArgs)), - scanAnnotations: cascadingRule.spec.scanAnnotations === undefined ? {} : - mapValues(cascadingRule.spec.scanAnnotations, value => Mustache.render(value, templateArgs)), - finding - }; + const { scanSpec, scanAnnotations, scanLabels } = cascadingRule.spec; + const { scanType, parameters } = scanSpec; + + cascadingRule.spec.scanSpec.scanType = + Mustache.render(scanType, templateArgs); + cascadingRule.spec.scanSpec.parameters = + parameters.map(parameter => Mustache.render(parameter, templateArgs)) + cascadingRule.spec.scanAnnotations = + scanAnnotations === undefined ? {} :mapValues(scanAnnotations, value => Mustache.render(value, templateArgs)) + cascadingRule.spec.scanLabels = + scanLabels === undefined ? {} : mapValues(scanLabels, value => Mustache.render(value, templateArgs)) + + return cascadingRule; } function generateCascadingScanName( diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index 1619ee55dc..ab34baebac 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -91,7 +91,7 @@ export interface ExtendedScanSpec extends ScanSpec { finding: Finding } -function mergeInheritedMap(parentProps, ruleProps, inherit: boolean = true) { +export function mergeInheritedMap(parentProps, ruleProps, inherit: boolean = true) { if (!inherit) { parentProps = {}; } @@ -101,85 +101,13 @@ function mergeInheritedMap(parentProps, ruleProps, inherit: boolean = true) { } } -function mergeInheritedArray(parentArray, ruleArray, inherit: boolean = false) { +export function mergeInheritedArray(parentArray, ruleArray, inherit: boolean = false) { if (!inherit) { parentArray = []; } return (parentArray || []).concat(ruleArray) // CascadingRule's env overwrites scan's env } -export function getCascadingScanDefinition({ - name, - scanType, - parameters, - generatedBy, - env, - volumes, - volumeMounts, - cascades, - scanLabels, - scanAnnotations, - finding - }: ExtendedScanSpec, parentScan: Scan) { - let annotations = mergeInheritedMap( - parentScan.metadata.annotations, scanAnnotations, parentScan.spec.cascades.inheritAnnotations); - let labels = mergeInheritedMap( - parentScan.metadata.labels, scanLabels, parentScan.spec.cascades.inheritLabels); - env = mergeInheritedArray( - parentScan.spec.env, env, parentScan.spec.cascades.inheritEnv); - volumes = mergeInheritedArray( - parentScan.spec.volumes, volumes, parentScan.spec.cascades.inheritVolumes); - volumeMounts = mergeInheritedArray( - parentScan.spec.volumeMounts, volumeMounts, parentScan.spec.cascades.inheritVolumes); - - let cascadingChain: Array = []; - - if (parentScan.metadata.annotations && parentScan.metadata.annotations["cascading.securecodebox.io/chain"]) { - cascadingChain = parentScan.metadata.annotations[ - "cascading.securecodebox.io/chain" - ].split(","); - } - - return { - apiVersion: "execution.securecodebox.io/v1", - kind: "Scan", - metadata: { - generateName: `${name}-`, - labels: { - ...labels - }, - annotations: { - "securecodebox.io/hook": "cascading-scans", - "cascading.securecodebox.io/parent-scan": parentScan.metadata.name, - "cascading.securecodebox.io/matched-finding": finding.id, - "cascading.securecodebox.io/chain": [ - ...cascadingChain, - generatedBy - ].join(","), - ...annotations, - }, - ownerReferences: [ - { - apiVersion: "execution.securecodebox.io/v1", - blockOwnerDeletion: true, - controller: true, - kind: "Scan", - name: parentScan.metadata.name, - uid: parentScan.metadata.uid - } - ] - }, - spec: { - scanType, - parameters, - cascades, - env, - volumes, - volumeMounts, - } - }; -} - export async function startSubsequentSecureCodeBoxScan(scan: Scan) { console.log(`Starting Scan ${scan.metadata.name}`); From c538866722dd6ce10ba9affef1aee38dce3a74ea Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Wed, 21 Jul 2021 13:22:28 +0200 Subject: [PATCH 13/17] Cascading Scans: update getCascadedRuleForScan to use existing chain method Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.ts | 2 +- hooks/cascading-scans/scan-helpers.ts | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hooks/cascading-scans/hook.ts b/hooks/cascading-scans/hook.ts index bb6fbae9a7..95a0bd2b39 100644 --- a/hooks/cascading-scans/hook.ts +++ b/hooks/cascading-scans/hook.ts @@ -73,7 +73,7 @@ export function getCascadingScans( return cascadingScans; } -function getScanChain(parentScan: Scan) { +export function getScanChain(parentScan: Scan) { // Get the current Scan Chain (meaning which CascadingRules were used to start this scan and its parents) and convert it to a set, which makes it easier to query. if ( parentScan.metadata.annotations && diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index ab34baebac..62c3a1111e 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -9,6 +9,7 @@ import { LabelSelector } from "./kubernetes-label-selector"; import {isEqual} from "lodash"; +import {getScanChain} from "./hook"; // configure k8s client const kc = new k8s.KubeConfig(); @@ -188,13 +189,11 @@ export function purgeCascadedRuleFromScan(scan: Scan, cascadedRuleUsedForParentS } export async function getCascadedRuleForScan(scan: Scan) { - if (typeof scan.metadata.annotations["cascading.securecodebox.io/chain"] === "undefined") return undefined; + const chain = getScanChain(scan) - const cascadingChain = scan.metadata.annotations["cascading.securecodebox.io/chain"].split(",") + if (chain.length === 0) return undefined; - if (cascadingChain.length === 0) return undefined; - - return await getCascadingRule(cascadingChain[cascadingChain.length - 1]); + return await getCascadingRule(chain[chain.length - 1]); } async function getCascadingRule(ruleName) { From 934941b61cc432fc086c5815e6ef7a5dde05c2ea Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Wed, 21 Jul 2021 13:58:03 +0200 Subject: [PATCH 14/17] Cascading Scans: get rid of redundant ExtendedScanSpec Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook.ts | 1 - hooks/cascading-scans/scan-helpers.ts | 22 ---------------------- 2 files changed, 23 deletions(-) diff --git a/hooks/cascading-scans/hook.ts b/hooks/cascading-scans/hook.ts index 95a0bd2b39..df69548f79 100644 --- a/hooks/cascading-scans/hook.ts +++ b/hooks/cascading-scans/hook.ts @@ -13,7 +13,6 @@ import { Scan, Finding, CascadingRule, - ExtendedScanSpec, getCascadedRuleForScan, purgeCascadedRuleFromScan, mergeInheritedMap, diff --git a/hooks/cascading-scans/scan-helpers.ts b/hooks/cascading-scans/scan-helpers.ts index 62c3a1111e..c777eed87c 100644 --- a/hooks/cascading-scans/scan-helpers.ts +++ b/hooks/cascading-scans/scan-helpers.ts @@ -70,28 +70,6 @@ export interface CascadingInheritance { inheritVolumes: boolean } -export interface ExtendedScanSpec extends ScanSpec { - // This is the name of the scan. Its not "really" part of the scan spec - // But this makes the object smaller - name: string; - - // Indicates which CascadingRule was used to generate the resulting Scan - generatedBy: string; - - // Additional label to be added to the resulting scan - scanLabels: { - [key: string]: string; - }; - - // Additional annotations to be added to the resulting scan - scanAnnotations: { - [key: string]: string; - }; - - // Finding that triggered the scan - finding: Finding -} - export function mergeInheritedMap(parentProps, ruleProps, inherit: boolean = true) { if (!inherit) { parentProps = {}; From c99094d76187bfcc319f6cf0ae0381ac284215e8 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Wed, 21 Jul 2021 14:03:01 +0200 Subject: [PATCH 15/17] Operator: update Helm CRD's Signed-off-by: Jop Zitman --- .../crds/cascading.securecodebox.io_cascadingrules.yaml | 9 +++++++++ operator/crds/execution.securecodebox.io_scans.yaml | 8 ++++++++ .../crds/execution.securecodebox.io_scheduledscans.yaml | 9 +++++++++ 3 files changed, 26 insertions(+) diff --git a/operator/crds/cascading.securecodebox.io_cascadingrules.yaml b/operator/crds/cascading.securecodebox.io_cascadingrules.yaml index d7884f860d..2982914c46 100644 --- a/operator/crds/cascading.securecodebox.io_cascadingrules.yaml +++ b/operator/crds/cascading.securecodebox.io_cascadingrules.yaml @@ -108,10 +108,19 @@ spec: description: InheritAnnotations defines whether cascading scans should inherit annotations from the parent scan type: boolean + inheritEnv: + description: InheritEnv defines whether cascading scans should + inherit environment variables from the parent scan + type: boolean inheritLabels: description: InheritLabels defines whether cascading scans should inherit labels from the parent scan type: boolean + inheritVolumes: + description: InheritVolumes defines whether cascading scans + should inherit volumes and volume mounts from the parent + scan + type: boolean matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. diff --git a/operator/crds/execution.securecodebox.io_scans.yaml b/operator/crds/execution.securecodebox.io_scans.yaml index dda21a180d..1b27eb2650 100644 --- a/operator/crds/execution.securecodebox.io_scans.yaml +++ b/operator/crds/execution.securecodebox.io_scans.yaml @@ -70,10 +70,18 @@ spec: description: InheritAnnotations defines whether cascading scans should inherit annotations from the parent scan type: boolean + inheritEnv: + description: InheritEnv defines whether cascading scans should + inherit environment variables from the parent scan + type: boolean inheritLabels: description: InheritLabels defines whether cascading scans should inherit labels from the parent scan type: boolean + inheritVolumes: + description: InheritVolumes defines whether cascading scans should + inherit volumes and volume mounts from the parent scan + type: boolean matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. diff --git a/operator/crds/execution.securecodebox.io_scheduledscans.yaml b/operator/crds/execution.securecodebox.io_scheduledscans.yaml index 00af99d3c7..49745f32d6 100644 --- a/operator/crds/execution.securecodebox.io_scheduledscans.yaml +++ b/operator/crds/execution.securecodebox.io_scheduledscans.yaml @@ -84,10 +84,19 @@ spec: description: InheritAnnotations defines whether cascading scans should inherit annotations from the parent scan type: boolean + inheritEnv: + description: InheritEnv defines whether cascading scans should + inherit environment variables from the parent scan + type: boolean inheritLabels: description: InheritLabels defines whether cascading scans should inherit labels from the parent scan type: boolean + inheritVolumes: + description: InheritVolumes defines whether cascading scans + should inherit volumes and volume mounts from the parent + scan + type: boolean matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. From e410e6ac1ddce2c12667a5387ab8bb6fa84f6196 Mon Sep 17 00:00:00 2001 From: Jannik Hollenbach Date: Thu, 22 Jul 2021 11:19:35 +0200 Subject: [PATCH 16/17] Fix incorrect expected / actual ordering in assertions Signed-off-by: Jannik Hollenbach --- ...ectDojoFindingToSecureCodeBoxMapperTest.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/DefectDojoFindingToSecureCodeBoxMapperTest.java b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/DefectDojoFindingToSecureCodeBoxMapperTest.java index b6d8fcc2a2..0066ae8edb 100644 --- a/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/DefectDojoFindingToSecureCodeBoxMapperTest.java +++ b/hooks/persistence-defectdojo/hook/src/test/java/io/securecodebox/persistence/mapping/DefectDojoFindingToSecureCodeBoxMapperTest.java @@ -15,6 +15,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.time.LocalDateTime; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -54,23 +55,23 @@ public void shouldMapBasicFindings(){ var actualFinding = this.mapper.fromDefectDojoFinding(ddFinding); assertEquals( - actualFinding.getName(), - "Content Security Policy (CSP) Header Not Set" + "Content Security Policy (CSP) Header Not Set", + actualFinding.getName() ); assertEquals( - actualFinding.getCategory(), - "DefectDojo Imported Finding" + "DefectDojo Imported Finding", + actualFinding.getCategory() ); assertEquals( - actualFinding.getSeverity(), - SecureCodeBoxFinding.Severities.MEDIUM + SecureCodeBoxFinding.Severities.MEDIUM, + actualFinding.getSeverity() ); assertEquals( - actualFinding.getLocation(), - "http://juice-shop.securecodebox-test.svc:3000" + "http://juice-shop.securecodebox-test.svc:3000", + actualFinding.getLocation() ); } From d4856d8d444f2e61da621e6471000a9412280dc0 Mon Sep 17 00:00:00 2001 From: Jannik Hollenbach Date: Thu, 22 Jul 2021 15:48:02 +0200 Subject: [PATCH 17/17] Trigger CI Signed-off-by: Jannik Hollenbach