From 07371204b8e4416d0b4c4c91c6414821b1a5927c Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Fri, 22 Oct 2021 14:36:04 +0200 Subject: [PATCH 1/7] Add hookSelector to ScanSpec in CRD and use it to retrieve hooks Signed-off-by: Jop Zitman --- operator/apis/execution/v1/scan_types.go | 3 ++ .../execution/v1/zz_generated.deepcopy.go | 5 +++ ...ading.securecodebox.io_cascadingrules.yaml | 45 +++++++++++++++++++ .../execution.securecodebox.io_scans.yaml | 45 +++++++++++++++++++ ...ution.securecodebox.io_scheduledscans.yaml | 45 +++++++++++++++++++ .../execution/scans/hook_reconciler.go | 20 ++++++++- ...ading.securecodebox.io_cascadingrules.yaml | 45 +++++++++++++++++++ .../execution.securecodebox.io_scans.yaml | 45 +++++++++++++++++++ ...ution.securecodebox.io_scheduledscans.yaml | 45 +++++++++++++++++++ 9 files changed, 296 insertions(+), 2 deletions(-) diff --git a/operator/apis/execution/v1/scan_types.go b/operator/apis/execution/v1/scan_types.go index 9ddd4baf15..4e88fdb3c5 100644 --- a/operator/apis/execution/v1/scan_types.go +++ b/operator/apis/execution/v1/scan_types.go @@ -62,6 +62,9 @@ type ScanSpec struct { // +kubebuilder:validation:Required Parameters []string `json:"parameters,omitempty"` + // HookSelector allows to specify a LabelSelector with which the hooks are selected. + HookSelector *metav1.LabelSelector `json:"hookSelector,omitempty"` + // Env allows to specify environment vars for the scanner container. These will be merged will the env vars specified for the first container of the pod defined in the ScanType Env []corev1.EnvVar `json:"env,omitempty"` // Volumes allows to specify volumes for the scan container. diff --git a/operator/apis/execution/v1/zz_generated.deepcopy.go b/operator/apis/execution/v1/zz_generated.deepcopy.go index d7d4b10d9a..0e791245d3 100644 --- a/operator/apis/execution/v1/zz_generated.deepcopy.go +++ b/operator/apis/execution/v1/zz_generated.deepcopy.go @@ -424,6 +424,11 @@ func (in *ScanSpec) DeepCopyInto(out *ScanSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.HookSelector != nil { + in, out := &in.HookSelector, &out.HookSelector + *out = new(metav1.LabelSelector) + (*in).DeepCopyInto(*out) + } if in.Env != nil { in, out := &in.Env, &out.Env *out = make([]corev1.EnvVar, len(*in)) diff --git a/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml b/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml index 76e0fecf58..704de6f20c 100644 --- a/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml +++ b/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml @@ -283,6 +283,51 @@ spec: - name type: object type: array + hookSelector: + description: HookSelector allows to specify a LabelSelector with + which the hooks are selected. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: 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. + type: object + type: object initContainers: description: InitContainers allows to specify init containers for the scan container, to pre-load data into them. diff --git a/operator/config/crd/bases/execution.securecodebox.io_scans.yaml b/operator/config/crd/bases/execution.securecodebox.io_scans.yaml index 5f752dc084..3764ff064d 100644 --- a/operator/config/crd/bases/execution.securecodebox.io_scans.yaml +++ b/operator/config/crd/bases/execution.securecodebox.io_scans.yaml @@ -238,6 +238,51 @@ spec: - name type: object type: array + hookSelector: + description: HookSelector allows to specify a LabelSelector with which + the hooks are selected. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: 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. + type: object + type: object initContainers: description: InitContainers allows to specify init containers for the scan container, to pre-load data into them. diff --git a/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml b/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml index 1529f1c120..06dfe264e8 100644 --- a/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml +++ b/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml @@ -265,6 +265,51 @@ spec: - name type: object type: array + hookSelector: + description: HookSelector allows to specify a LabelSelector with + which the hooks are selected. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: 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. + type: object + type: object initContainers: description: InitContainers allows to specify init containers for the scan container, to pre-load data into them. diff --git a/operator/controllers/execution/scans/hook_reconciler.go b/operator/controllers/execution/scans/hook_reconciler.go index 1420e79065..a136e8b90a 100644 --- a/operator/controllers/execution/scans/hook_reconciler.go +++ b/operator/controllers/execution/scans/hook_reconciler.go @@ -23,9 +23,17 @@ import ( func (r *ScanReconciler) setHookStatus(scan *executionv1.Scan) error { // Set (pending) Hook status on the scan ctx := context.Background() + labelSelector, err := metav1.LabelSelectorAsSelector(scan.Spec.HookSelector) + if err != nil { + return err + } + var scanCompletionHooks executionv1.ScanCompletionHookList - if err := r.List(ctx, &scanCompletionHooks, client.InNamespace(scan.Namespace)); err != nil { + if err := r.List(ctx, &scanCompletionHooks, + client.InNamespace(scan.Namespace), + client.MatchingLabelsSelector{Selector: labelSelector}, + ); err != nil { r.Log.V(7).Info("Unable to fetch ScanCompletionHooks") return err } @@ -198,9 +206,17 @@ func containsJobForHook(jobs *batch.JobList, hook executionv1.ScanCompletionHook func (r *ScanReconciler) startReadOnlyHooks(scan *executionv1.Scan) error { ctx := context.Background() + labelSelector, err := metav1.LabelSelectorAsSelector(scan.Spec.HookSelector) + if err != nil { + return err + } + var scanCompletionHooks executionv1.ScanCompletionHookList - if err := r.List(ctx, &scanCompletionHooks, client.InNamespace(scan.Namespace)); err != nil { + if err := r.List(ctx, &scanCompletionHooks, + client.InNamespace(scan.Namespace), + client.MatchingLabelsSelector{Selector: labelSelector}, + ); err != nil { r.Log.V(7).Info("Unable to fetch ScanCompletionHooks") return err } diff --git a/operator/crds/cascading.securecodebox.io_cascadingrules.yaml b/operator/crds/cascading.securecodebox.io_cascadingrules.yaml index 76e0fecf58..704de6f20c 100644 --- a/operator/crds/cascading.securecodebox.io_cascadingrules.yaml +++ b/operator/crds/cascading.securecodebox.io_cascadingrules.yaml @@ -283,6 +283,51 @@ spec: - name type: object type: array + hookSelector: + description: HookSelector allows to specify a LabelSelector with + which the hooks are selected. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: 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. + type: object + type: object initContainers: description: InitContainers allows to specify init containers for the scan container, to pre-load data into them. diff --git a/operator/crds/execution.securecodebox.io_scans.yaml b/operator/crds/execution.securecodebox.io_scans.yaml index 5f752dc084..3764ff064d 100644 --- a/operator/crds/execution.securecodebox.io_scans.yaml +++ b/operator/crds/execution.securecodebox.io_scans.yaml @@ -238,6 +238,51 @@ spec: - name type: object type: array + hookSelector: + description: HookSelector allows to specify a LabelSelector with which + the hooks are selected. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: 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. + type: object + type: object initContainers: description: InitContainers allows to specify init containers for the scan container, to pre-load data into them. diff --git a/operator/crds/execution.securecodebox.io_scheduledscans.yaml b/operator/crds/execution.securecodebox.io_scheduledscans.yaml index 1529f1c120..06dfe264e8 100644 --- a/operator/crds/execution.securecodebox.io_scheduledscans.yaml +++ b/operator/crds/execution.securecodebox.io_scheduledscans.yaml @@ -265,6 +265,51 @@ spec: - name type: object type: array + hookSelector: + description: HookSelector allows to specify a LabelSelector with + which the hooks are selected. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: 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. + type: object + type: object initContainers: description: InitContainers allows to specify init containers for the scan container, to pre-load data into them. From 845b2c657750d78b463db19af76a9b1c1ace3ce9 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Thu, 28 Oct 2021 11:10:40 +0200 Subject: [PATCH 2/7] Select all hooks if HookSelector is not defined Signed-off-by: Jop Zitman --- .../controllers/execution/scans/hook_reconciler.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/operator/controllers/execution/scans/hook_reconciler.go b/operator/controllers/execution/scans/hook_reconciler.go index a136e8b90a..b1f8de9523 100644 --- a/operator/controllers/execution/scans/hook_reconciler.go +++ b/operator/controllers/execution/scans/hook_reconciler.go @@ -7,6 +7,7 @@ package scancontrollers import ( "context" "fmt" + "k8s.io/apimachinery/pkg/labels" executionv1 "github.com/secureCodeBox/secureCodeBox/operator/apis/execution/v1" util "github.com/secureCodeBox/secureCodeBox/operator/utils" @@ -23,7 +24,7 @@ import ( func (r *ScanReconciler) setHookStatus(scan *executionv1.Scan) error { // Set (pending) Hook status on the scan ctx := context.Background() - labelSelector, err := metav1.LabelSelectorAsSelector(scan.Spec.HookSelector) + labelSelector, err := r.getLabelSelector(scan) if err != nil { return err } @@ -206,7 +207,7 @@ func containsJobForHook(jobs *batch.JobList, hook executionv1.ScanCompletionHook func (r *ScanReconciler) startReadOnlyHooks(scan *executionv1.Scan) error { ctx := context.Background() - labelSelector, err := metav1.LabelSelectorAsSelector(scan.Spec.HookSelector) + labelSelector, err := r.getLabelSelector(scan) if err != nil { return err } @@ -482,3 +483,11 @@ func (r *ScanReconciler) updateHookStatus(scan *executionv1.Scan, hookStatus exe } return nil } + +func (r *ScanReconciler) getLabelSelector(scan *executionv1.Scan) (labels.Selector, error) { + hookSelector := scan.Spec.HookSelector + if hookSelector == nil { + hookSelector = &metav1.LabelSelector{} + } + return metav1.LabelSelectorAsSelector(hookSelector) +} From c6ff8f7d70772ff4955f0ffb0cbd2c416609b0ff Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Thu, 28 Oct 2021 12:10:51 +0200 Subject: [PATCH 3/7] Add inheritHookSelector to CRD and cascading scans definition Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook/hook.test.js | 145 ++++++++++++++++++ hooks/cascading-scans/hook/hook.ts | 11 +- .../hook/kubernetes-label-selector.ts | 4 +- hooks/cascading-scans/hook/scan-helpers.ts | 13 ++ operator/apis/execution/v1/scan_types.go | 5 + ...ading.securecodebox.io_cascadingrules.yaml | 5 + .../execution.securecodebox.io_scans.yaml | 5 + ...ution.securecodebox.io_scheduledscans.yaml | 5 + ...ading.securecodebox.io_cascadingrules.yaml | 5 + .../execution.securecodebox.io_scans.yaml | 5 + ...ution.securecodebox.io_scheduledscans.yaml | 5 + 11 files changed, 202 insertions(+), 6 deletions(-) diff --git a/hooks/cascading-scans/hook/hook.test.js b/hooks/cascading-scans/hook/hook.test.js index bbf39004de..0f44dff2b0 100644 --- a/hooks/cascading-scans/hook/hook.test.js +++ b/hooks/cascading-scans/hook/hook.test.js @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 const { getCascadingScans } = require("./hook"); +const {LabelSelectorRequirementOperator} = require("./kubernetes-label-selector"); let parentScan = undefined; let sslyzeCascadingRules = undefined; @@ -104,6 +105,7 @@ test("Should create subsequent scans for open HTTPS ports (NMAP findings)", () = "spec": Object { "cascades": Object {}, "env": Array [], + "hookSelector": Object {}, "initContainers": Array [], "parameters": Array [ "--regular", @@ -241,6 +243,7 @@ test("Should not crash when the annotations are not set", () => { "spec": Object { "cascades": Object {}, "env": Array [], + "hookSelector": Object {}, "initContainers": Array [], "parameters": Array [ "--regular", @@ -372,6 +375,7 @@ test("Should allow wildcards in cascadingRules", () => { "spec": Object { "cascades": Object {}, "env": Array [], + "hookSelector": Object {}, "initContainers": Array [], "parameters": Array [ "--regular", @@ -1128,6 +1132,7 @@ test("Templating should also apply to initContainer commands", () => { "spec": Object { "cascades": Object {}, "env": Array [], + "hookSelector": Object {}, "initContainers": Array [ Object { "command": Array [ @@ -1260,6 +1265,7 @@ test("Templating should not break special encoding (http://...) when using tripl "spec": Object { "cascades": Object {}, "env": Array [], + "hookSelector": Object {}, "initContainers": Array [ Object { "command": Array [ @@ -1301,6 +1307,145 @@ test("Templating should not break special encoding (http://...) when using tripl `); }); +test("should merge hookSelector into cascaded scan", () => { + parentScan.spec.cascades.inheritHookSelector = true + const findings = [ + { + name: "Port 443 is open", + category: "Open Port", + attributes: { + state: "open", + hostname: "foobar.com", + port: 443, + service: "https" + } + } + ]; + + parentScan.spec.hookSelector = {} + parentScan.spec.hookSelector.matchLabels = { + "securecodebox.io/internal": "true", + } + parentScan.spec.hookSelector.matchExpressions = [ + { + key: "securecodebox.io/name", + operator: LabelSelectorRequirementOperator.In, + values: ["cascading-scans"] + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.hookSelector = {}; + sslyzeCascadingRules[0].spec.scanSpec.hookSelector.matchExpressions = [ + { + key: "securecodebox.io/name", + operator: LabelSelectorRequirementOperator.NotIn, + values: ["cascading-scans"] + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.hookSelector.matchLabels = { + "securecodebox.io/internal": "false", + } + + const cascadedScans = getCascadingScans( + parentScan, + findings, + sslyzeCascadingRules + ); + + const cascadedScan = cascadedScans[0]; + + expect(cascadedScan.spec.hookSelector).toMatchInlineSnapshot(` + Object { + "matchExpressions": Array [ + Object { + "key": "securecodebox.io/name", + "operator": "In", + "values": Array [ + "cascading-scans", + ], + }, + Object { + "key": "securecodebox.io/name", + "operator": "NotIn", + "values": Array [ + "cascading-scans", + ], + }, + ], + "matchLabels": Object { + "securecodebox.io/internal": "false", + }, + } + `); +}); + + +test("should not merge hookSelector into cascaded scan if inheritHookSelector is disabled", () => { + parentScan.spec.cascades.inheritHookSelector = false + const findings = [ + { + name: "Port 443 is open", + category: "Open Port", + attributes: { + state: "open", + hostname: "foobar.com", + port: 443, + service: "https" + } + } + ]; + + parentScan.spec.hookSelector = {} + parentScan.spec.hookSelector.matchLabels = { + "securecodebox.io/internal": "true", + } + parentScan.spec.hookSelector.matchExpressions = [ + { + key: "securecodebox.io/name", + operator: LabelSelectorRequirementOperator.In, + values: ["cascading-scans"] + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.hookSelector = {}; + sslyzeCascadingRules[0].spec.scanSpec.hookSelector.matchExpressions = [ + { + key: "securecodebox.io/name", + operator: LabelSelectorRequirementOperator.NotIn, + values: ["cascading-scans"] + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.hookSelector.matchLabels = { + "securecodebox.io/internal": "false", + } + + const cascadedScans = getCascadingScans( + parentScan, + findings, + sslyzeCascadingRules + ); + + const cascadedScan = cascadedScans[0]; + + expect(cascadedScan.spec.hookSelector).toMatchInlineSnapshot(` + Object { + "matchExpressions": Array [ + Object { + "key": "securecodebox.io/name", + "operator": "NotIn", + "values": Array [ + "cascading-scans", + ], + }, + ], + "matchLabels": Object { + "securecodebox.io/internal": "false", + }, + } + `); +}); test("should purge cascaded scan spec from parent scan", () => { parentScan.spec.cascades.inheritEnv = true diff --git a/hooks/cascading-scans/hook/hook.ts b/hooks/cascading-scans/hook/hook.ts index 400affc663..7d8c469673 100644 --- a/hooks/cascading-scans/hook/hook.ts +++ b/hooks/cascading-scans/hook/hook.ts @@ -16,7 +16,8 @@ import { getCascadedRuleForScan, purgeCascadedRuleFromScan, mergeInheritedMap, - mergeInheritedArray + mergeInheritedArray, + mergeInheritedSelector, } from "./scan-helpers"; interface HandleArgs { @@ -110,7 +111,7 @@ function getCascadingScan( let { scanType, parameters } = cascadingRule.spec.scanSpec; - let { annotations, labels, env, volumes, volumeMounts, initContainers } = mergeCascadingRuleWithScan(parentScan, cascadingRule); + let { annotations, labels, env, volumes, volumeMounts, initContainers, hookSelector } = mergeCascadingRuleWithScan(parentScan, cascadingRule); let cascadingChain = getScanChain(parentScan); @@ -142,6 +143,7 @@ function getCascadingScan( ] }, spec: { + hookSelector, scanType, parameters, cascades: parentScan.spec.cascades, @@ -158,8 +160,8 @@ function mergeCascadingRuleWithScan( cascadingRule: CascadingRule ) { const { scanAnnotations, scanLabels } = cascadingRule.spec; - let { env = [], volumes = [], volumeMounts = [], initContainers = [] } = cascadingRule.spec.scanSpec; - let { inheritAnnotations, inheritLabels, inheritEnv, inheritVolumes, inheritInitContainers } = scan.spec.cascades; + let { env = [], volumes = [], volumeMounts = [], initContainers = [], hookSelector = {} } = cascadingRule.spec.scanSpec; + let { inheritAnnotations, inheritLabels, inheritEnv, inheritVolumes, inheritInitContainers, inheritHookSelector } = scan.spec.cascades; return { annotations: mergeInheritedMap(scan.metadata.annotations, scanAnnotations, inheritAnnotations), @@ -168,6 +170,7 @@ function mergeCascadingRuleWithScan( volumes: mergeInheritedArray(scan.spec.volumes, volumes, inheritVolumes), volumeMounts: mergeInheritedArray(scan.spec.volumeMounts, volumeMounts, inheritVolumes), initContainers: mergeInheritedArray(scan.spec.initContainers, initContainers, inheritInitContainers), + hookSelector: mergeInheritedSelector(scan.spec.hookSelector, hookSelector, inheritHookSelector), } } diff --git a/hooks/cascading-scans/hook/kubernetes-label-selector.ts b/hooks/cascading-scans/hook/kubernetes-label-selector.ts index 82122f0a4c..8bbee94b4c 100644 --- a/hooks/cascading-scans/hook/kubernetes-label-selector.ts +++ b/hooks/cascading-scans/hook/kubernetes-label-selector.ts @@ -19,8 +19,8 @@ export interface LabelSelectorRequirement { } export interface LabelSelector { - matchExpressions: Array; - matchLabels: Map; + matchExpressions?: Array; + matchLabels?: Map; } // generateSelectorString transforms a kubernetes labelSelector object in to the string representation diff --git a/hooks/cascading-scans/hook/scan-helpers.ts b/hooks/cascading-scans/hook/scan-helpers.ts index f19d08e6ba..e2ca9fa2e1 100644 --- a/hooks/cascading-scans/hook/scan-helpers.ts +++ b/hooks/cascading-scans/hook/scan-helpers.ts @@ -62,6 +62,7 @@ export interface ScanSpec { volumes?: Array; volumeMounts?: Array; initContainers?: Array; + hookSelector?: LabelSelector; } export interface CascadingInheritance { @@ -70,6 +71,7 @@ export interface CascadingInheritance { inheritEnv: boolean, inheritVolumes: boolean, inheritInitContainers: boolean, + inheritHookSelector: boolean, } export function mergeInheritedMap(parentProps, ruleProps, inherit: boolean = true) { @@ -89,6 +91,17 @@ export function mergeInheritedArray(parentArray, ruleArray, inherit: boolean = f return (parentArray || []).concat(ruleArray) // CascadingRule's env overwrites scan's env } +export function mergeInheritedSelector(parentSelector: LabelSelector = {}, ruleSelector: LabelSelector = {}, inherit: boolean = true): LabelSelector { + let labelSelector: LabelSelector = {}; + if (parentSelector.matchExpressions || ruleSelector.matchExpressions) { + labelSelector.matchExpressions = mergeInheritedArray(parentSelector.matchExpressions, ruleSelector.matchExpressions, inherit); + } + if (parentSelector.matchLabels || ruleSelector.matchLabels) { + labelSelector.matchLabels = mergeInheritedMap(parentSelector.matchLabels, ruleSelector.matchLabels, inherit); + } + return labelSelector +} + export async function startSubsequentSecureCodeBoxScan(scan: Scan) { console.log(`Starting Scan ${scan.metadata.name}`); diff --git a/operator/apis/execution/v1/scan_types.go b/operator/apis/execution/v1/scan_types.go index 4e88fdb3c5..5edb45ef14 100644 --- a/operator/apis/execution/v1/scan_types.go +++ b/operator/apis/execution/v1/scan_types.go @@ -39,6 +39,11 @@ type CascadeSpec struct { // +kubebuilder:default=false InheritInitContainers bool `json:"inheritInitContainers"` + // InheritHookSelector defines whether cascading scans should inherit hookSelector from the parent scan. + // +optional + // +kubebuilder:default=true + InheritHookSelector bool `json:"inheritHookSelector"` + // 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 704de6f20c..1d300e8554 100644 --- a/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml +++ b/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml @@ -114,6 +114,11 @@ spec: description: InheritEnv defines whether cascading scans should inherit environment variables from the parent scan type: boolean + inheritHookSelector: + default: true + description: InheritHookSelector defines whether cascading + scans should inherit hookSelector from the parent scan. + type: boolean inheritInitContainers: default: false description: InheritInitContainers defines whether cascading diff --git a/operator/config/crd/bases/execution.securecodebox.io_scans.yaml b/operator/config/crd/bases/execution.securecodebox.io_scans.yaml index 3764ff064d..9d47107e86 100644 --- a/operator/config/crd/bases/execution.securecodebox.io_scans.yaml +++ b/operator/config/crd/bases/execution.securecodebox.io_scans.yaml @@ -76,6 +76,11 @@ spec: description: InheritEnv defines whether cascading scans should inherit environment variables from the parent scan type: boolean + inheritHookSelector: + default: true + description: InheritHookSelector defines whether cascading scans + should inherit hookSelector from the parent scan. + type: boolean inheritInitContainers: default: false description: InheritInitContainers defines whether cascading scans diff --git a/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml b/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml index 06dfe264e8..5f238dc7ff 100644 --- a/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml +++ b/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml @@ -96,6 +96,11 @@ spec: description: InheritEnv defines whether cascading scans should inherit environment variables from the parent scan type: boolean + inheritHookSelector: + default: true + description: InheritHookSelector defines whether cascading + scans should inherit hookSelector from the parent scan. + type: boolean inheritInitContainers: default: false description: InheritInitContainers defines whether cascading diff --git a/operator/crds/cascading.securecodebox.io_cascadingrules.yaml b/operator/crds/cascading.securecodebox.io_cascadingrules.yaml index 704de6f20c..1d300e8554 100644 --- a/operator/crds/cascading.securecodebox.io_cascadingrules.yaml +++ b/operator/crds/cascading.securecodebox.io_cascadingrules.yaml @@ -114,6 +114,11 @@ spec: description: InheritEnv defines whether cascading scans should inherit environment variables from the parent scan type: boolean + inheritHookSelector: + default: true + description: InheritHookSelector defines whether cascading + scans should inherit hookSelector from the parent scan. + type: boolean inheritInitContainers: default: false description: InheritInitContainers defines whether cascading diff --git a/operator/crds/execution.securecodebox.io_scans.yaml b/operator/crds/execution.securecodebox.io_scans.yaml index 3764ff064d..9d47107e86 100644 --- a/operator/crds/execution.securecodebox.io_scans.yaml +++ b/operator/crds/execution.securecodebox.io_scans.yaml @@ -76,6 +76,11 @@ spec: description: InheritEnv defines whether cascading scans should inherit environment variables from the parent scan type: boolean + inheritHookSelector: + default: true + description: InheritHookSelector defines whether cascading scans + should inherit hookSelector from the parent scan. + type: boolean inheritInitContainers: default: false description: InheritInitContainers defines whether cascading scans diff --git a/operator/crds/execution.securecodebox.io_scheduledscans.yaml b/operator/crds/execution.securecodebox.io_scheduledscans.yaml index 06dfe264e8..5f238dc7ff 100644 --- a/operator/crds/execution.securecodebox.io_scheduledscans.yaml +++ b/operator/crds/execution.securecodebox.io_scheduledscans.yaml @@ -96,6 +96,11 @@ spec: description: InheritEnv defines whether cascading scans should inherit environment variables from the parent scan type: boolean + inheritHookSelector: + default: true + description: InheritHookSelector defines whether cascading + scans should inherit hookSelector from the parent scan. + type: boolean inheritInitContainers: default: false description: InheritInitContainers defines whether cascading From 8e6a22b9214daf59acd5a79b2c2767c7cecd8582 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Thu, 28 Oct 2021 12:28:28 +0200 Subject: [PATCH 4/7] Add hook labels field in the hook values.yaml Signed-off-by: Jop Zitman --- hooks/cascading-scans/templates/cascading-scans-hook.yaml | 3 +++ hooks/cascading-scans/values.yaml | 3 +++ .../templates/finding-post-processing-hook.yaml | 3 +++ hooks/finding-post-processing/values.yaml | 3 +++ hooks/generic-webhook/templates/webhook-hook.yaml | 3 +++ hooks/generic-webhook/values.yaml | 3 +++ hooks/notification/templates/notification-hook.yaml | 5 +++++ hooks/notification/values.yaml | 3 +++ .../templates/persistence-provider.yaml | 3 +++ hooks/persistence-defectdojo/values.yaml | 3 +++ .../persistence-elastic/templates/persistence-provider.yaml | 3 +++ hooks/persistence-elastic/values.yaml | 3 +++ hooks/update-field/templates/update-field-hook.yaml | 3 +++ hooks/update-field/values.yaml | 3 +++ 14 files changed, 44 insertions(+) diff --git a/hooks/cascading-scans/templates/cascading-scans-hook.yaml b/hooks/cascading-scans/templates/cascading-scans-hook.yaml index 167e5fe7f0..dcfcf61adc 100644 --- a/hooks/cascading-scans/templates/cascading-scans-hook.yaml +++ b/hooks/cascading-scans/templates/cascading-scans-hook.yaml @@ -8,6 +8,9 @@ metadata: name: {{ include "cascading-scans.fullname" . }} labels: {{- include "cascading-scans.labels" . | nindent 4 }} + {{- with .Values.hook.labels }} + {{ toYaml . }} + {{- end }} spec: type: ReadOnly image: "{{ .Values.hook.image.repository }}:{{ .Values.hook.image.tag | default .Chart.Version }}" diff --git a/hooks/cascading-scans/values.yaml b/hooks/cascading-scans/values.yaml index 32aa4e38ac..50160bdfe3 100644 --- a/hooks/cascading-scans/values.yaml +++ b/hooks/cascading-scans/values.yaml @@ -14,5 +14,8 @@ hook: # @default -- defaults to the charts version tag: null + # hook.labels -- Add Kubernetes Labels to the hook definition + labels: {} + # hook.ttlSecondsAfterFinished -- Seconds after which the kubernetes job for the hook will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ ttlSecondsAfterFinished: null diff --git a/hooks/finding-post-processing/templates/finding-post-processing-hook.yaml b/hooks/finding-post-processing/templates/finding-post-processing-hook.yaml index bd7bf7eaad..e01efa414f 100644 --- a/hooks/finding-post-processing/templates/finding-post-processing-hook.yaml +++ b/hooks/finding-post-processing/templates/finding-post-processing-hook.yaml @@ -8,6 +8,9 @@ metadata: name: {{ include "finding-post-processing.fullname" . }} labels: {{- include "finding-post-processing.labels" . | nindent 4 }} + {{- with .Values.hook.labels }} + {{ toYaml . }} + {{- end }} spec: type: ReadAndWrite image: "{{ .Values.hook.image.repository }}:{{ .Values.hook.image.tag | default .Chart.Version }}" diff --git a/hooks/finding-post-processing/values.yaml b/hooks/finding-post-processing/values.yaml index 9ae75ea875..4d16d013bf 100644 --- a/hooks/finding-post-processing/values.yaml +++ b/hooks/finding-post-processing/values.yaml @@ -30,5 +30,8 @@ hook: # @default -- defaults to the charts version tag: null + # hook.labels -- Add Kubernetes Labels to the hook definition + labels: {} + # hook.ttlSecondsAfterFinished -- Seconds after which the kubernetes job for the hook will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ ttlSecondsAfterFinished: null diff --git a/hooks/generic-webhook/templates/webhook-hook.yaml b/hooks/generic-webhook/templates/webhook-hook.yaml index 945d97a082..317b476b2a 100644 --- a/hooks/generic-webhook/templates/webhook-hook.yaml +++ b/hooks/generic-webhook/templates/webhook-hook.yaml @@ -8,6 +8,9 @@ metadata: name: {{ include "generic-webhook.fullname" . }} labels: {{- include "generic-webhook.labels" . | nindent 4 }} + {{- with .Values.hook.labels }} + {{ toYaml . }} + {{- end }} spec: type: ReadOnly image: "{{ .Values.hook.image.repository }}:{{ .Values.hook.image.tag | default .Chart.Version }}" diff --git a/hooks/generic-webhook/values.yaml b/hooks/generic-webhook/values.yaml index deae4c2eb3..39da0a067e 100644 --- a/hooks/generic-webhook/values.yaml +++ b/hooks/generic-webhook/values.yaml @@ -17,5 +17,8 @@ hook: # @default -- defaults to the charts version tag: null + # hook.labels -- Add Kubernetes Labels to the hook definition + labels: {} + # hook.ttlSecondsAfterFinished -- Seconds after which the kubernetes job for the hook will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ ttlSecondsAfterFinished: null diff --git a/hooks/notification/templates/notification-hook.yaml b/hooks/notification/templates/notification-hook.yaml index 5d1fd2700a..2961756cf6 100644 --- a/hooks/notification/templates/notification-hook.yaml +++ b/hooks/notification/templates/notification-hook.yaml @@ -6,6 +6,11 @@ apiVersion: "execution.securecodebox.io/v1" kind: ScanCompletionHook metadata: name: {{ include "notification-hook.fullname" . }} + labels: + {{- include "notification-hook.labels" . | nindent 4 }} + {{- with .Values.hook.labels }} + {{ toYaml . }} + {{- end }} spec: type: ReadOnly imagePullPolicy: "{{ .Values.hook.image.pullPolicy }}" diff --git a/hooks/notification/values.yaml b/hooks/notification/values.yaml index b541537e36..5cf9243c90 100644 --- a/hooks/notification/values.yaml +++ b/hooks/notification/values.yaml @@ -16,6 +16,9 @@ hook: # -- Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images pullPolicy: IfNotPresent + # hook.labels -- Add Kubernetes Labels to the hook definition + labels: {} + # hook.ttlSecondsAfterFinished -- seconds after which the kubernetes job for the hook will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ ttlSecondsAfterFinished: null diff --git a/hooks/persistence-defectdojo/templates/persistence-provider.yaml b/hooks/persistence-defectdojo/templates/persistence-provider.yaml index 8d03afccf0..58d374684e 100644 --- a/hooks/persistence-defectdojo/templates/persistence-provider.yaml +++ b/hooks/persistence-defectdojo/templates/persistence-provider.yaml @@ -9,6 +9,9 @@ metadata: labels: {{- include "persistence-defectdojo.labels" . | nindent 4 }} type: Unstructured + {{- with .Values.hook.labels }} + {{ toYaml . }} + {{- end }} spec: {{- if .Values.defectdojo.syncFindingsBack }} type: ReadAndWrite diff --git a/hooks/persistence-defectdojo/values.yaml b/hooks/persistence-defectdojo/values.yaml index 894c82c74b..4ec1a461a2 100644 --- a/hooks/persistence-defectdojo/values.yaml +++ b/hooks/persistence-defectdojo/values.yaml @@ -16,6 +16,9 @@ hook: # -- Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images pullPolicy: IfNotPresent + # hook.labels -- Add Kubernetes Labels to the hook definition + labels: {} + defectdojo: # -- Syncs back (two way sync) all imported findings from DefectDojo to SCB Findings Store. When set to false the hook will only import the findings to DefectDojo (one way sync). syncFindingsBack: true diff --git a/hooks/persistence-elastic/templates/persistence-provider.yaml b/hooks/persistence-elastic/templates/persistence-provider.yaml index 4040c9c37d..6a329759c9 100644 --- a/hooks/persistence-elastic/templates/persistence-provider.yaml +++ b/hooks/persistence-elastic/templates/persistence-provider.yaml @@ -9,6 +9,9 @@ metadata: labels: {{- include "persistence-elastic.labels" . | nindent 4 }} type: Structured + {{- with .Values.hook.labels }} + {{ toYaml . }} + {{- end }} spec: type: ReadOnly image: "{{ .Values.hook.image.repository }}:{{ .Values.hook.image.tag | default .Chart.Version }}" diff --git a/hooks/persistence-elastic/values.yaml b/hooks/persistence-elastic/values.yaml index 10e691287c..ae6c2fa922 100644 --- a/hooks/persistence-elastic/values.yaml +++ b/hooks/persistence-elastic/values.yaml @@ -86,5 +86,8 @@ hook: # @default -- defaults to the charts version tag: null + # hook.labels -- Add Kubernetes Labels to the hook definition + labels: {} + # hook.ttlSecondsAfterFinished -- Seconds after which the kubernetes job for the hook will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ ttlSecondsAfterFinished: null diff --git a/hooks/update-field/templates/update-field-hook.yaml b/hooks/update-field/templates/update-field-hook.yaml index 5acc24e9e3..901116780b 100644 --- a/hooks/update-field/templates/update-field-hook.yaml +++ b/hooks/update-field/templates/update-field-hook.yaml @@ -8,6 +8,9 @@ metadata: name: {{ include "update-field.fullname" . }} labels: {{- include "update-field.labels" . | nindent 4 }} + {{- with .Values.hook.labels }} + {{ toYaml . }} + {{- end }} spec: type: ReadAndWrite image: "{{ .Values.hook.image.repository }}:{{ .Values.hook.image.tag | default .Chart.Version }}" diff --git a/hooks/update-field/values.yaml b/hooks/update-field/values.yaml index 60ad92daec..d4ad8d3609 100644 --- a/hooks/update-field/values.yaml +++ b/hooks/update-field/values.yaml @@ -20,5 +20,8 @@ hook: # @default -- defaults to the charts version tag: null + # hook.labels -- Add Kubernetes Labels to the hook definition + labels: {} + # hook.ttlSecondsAfterFinished -- Seconds after which the kubernetes job for the hook will be deleted. Requires the Kubernetes TTLAfterFinished controller: https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/ ttlSecondsAfterFinished: null From b6de8918a3020ff25b280a1c250198ca1cd8201c Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Thu, 28 Oct 2021 12:30:24 +0200 Subject: [PATCH 5/7] Add internal label to cascading scans hook Signed-off-by: Jop Zitman --- hooks/cascading-scans/templates/cascading-scans-hook.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/hooks/cascading-scans/templates/cascading-scans-hook.yaml b/hooks/cascading-scans/templates/cascading-scans-hook.yaml index dcfcf61adc..87ae80c24b 100644 --- a/hooks/cascading-scans/templates/cascading-scans-hook.yaml +++ b/hooks/cascading-scans/templates/cascading-scans-hook.yaml @@ -8,6 +8,7 @@ metadata: name: {{ include "cascading-scans.fullname" . }} labels: {{- include "cascading-scans.labels" . | nindent 4 }} + securecodebox.io/internal: "true" {{- with .Values.hook.labels }} {{ toYaml . }} {{- end }} From 600ee239a862f77d39b866fbac9f82511f231fa6 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Thu, 28 Oct 2021 17:23:02 +0200 Subject: [PATCH 6/7] Disable inheritHookSelector by default Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook/hook.test.js | 2 +- hooks/cascading-scans/hook/scan-helpers.ts | 2 +- operator/apis/execution/v1/scan_types.go | 2 +- .../crd/bases/cascading.securecodebox.io_cascadingrules.yaml | 2 +- operator/config/crd/bases/execution.securecodebox.io_scans.yaml | 2 +- .../crd/bases/execution.securecodebox.io_scheduledscans.yaml | 2 +- operator/crds/cascading.securecodebox.io_cascadingrules.yaml | 2 +- operator/crds/execution.securecodebox.io_scans.yaml | 2 +- operator/crds/execution.securecodebox.io_scheduledscans.yaml | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hooks/cascading-scans/hook/hook.test.js b/hooks/cascading-scans/hook/hook.test.js index 0f44dff2b0..c3a4cffa4f 100644 --- a/hooks/cascading-scans/hook/hook.test.js +++ b/hooks/cascading-scans/hook/hook.test.js @@ -1307,7 +1307,7 @@ test("Templating should not break special encoding (http://...) when using tripl `); }); -test("should merge hookSelector into cascaded scan", () => { +test("should merge hookSelector into cascaded scan if inheritHookSelector is enabled", () => { parentScan.spec.cascades.inheritHookSelector = true const findings = [ { diff --git a/hooks/cascading-scans/hook/scan-helpers.ts b/hooks/cascading-scans/hook/scan-helpers.ts index e2ca9fa2e1..7dc86b65c2 100644 --- a/hooks/cascading-scans/hook/scan-helpers.ts +++ b/hooks/cascading-scans/hook/scan-helpers.ts @@ -91,7 +91,7 @@ export function mergeInheritedArray(parentArray, ruleArray, inherit: boolean = f return (parentArray || []).concat(ruleArray) // CascadingRule's env overwrites scan's env } -export function mergeInheritedSelector(parentSelector: LabelSelector = {}, ruleSelector: LabelSelector = {}, inherit: boolean = true): LabelSelector { +export function mergeInheritedSelector(parentSelector: LabelSelector = {}, ruleSelector: LabelSelector = {}, inherit: boolean = false): LabelSelector { let labelSelector: LabelSelector = {}; if (parentSelector.matchExpressions || ruleSelector.matchExpressions) { labelSelector.matchExpressions = mergeInheritedArray(parentSelector.matchExpressions, ruleSelector.matchExpressions, inherit); diff --git a/operator/apis/execution/v1/scan_types.go b/operator/apis/execution/v1/scan_types.go index 5edb45ef14..91409b8cdc 100644 --- a/operator/apis/execution/v1/scan_types.go +++ b/operator/apis/execution/v1/scan_types.go @@ -41,7 +41,7 @@ type CascadeSpec struct { // InheritHookSelector defines whether cascading scans should inherit hookSelector from the parent scan. // +optional - // +kubebuilder:default=true + // +kubebuilder:default=false InheritHookSelector bool `json:"inheritHookSelector"` // matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels diff --git a/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml b/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml index 1d300e8554..8df98f340a 100644 --- a/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml +++ b/operator/config/crd/bases/cascading.securecodebox.io_cascadingrules.yaml @@ -115,7 +115,7 @@ spec: inherit environment variables from the parent scan type: boolean inheritHookSelector: - default: true + default: false description: InheritHookSelector defines whether cascading scans should inherit hookSelector from the parent scan. type: boolean diff --git a/operator/config/crd/bases/execution.securecodebox.io_scans.yaml b/operator/config/crd/bases/execution.securecodebox.io_scans.yaml index 9d47107e86..3e24c3b2b0 100644 --- a/operator/config/crd/bases/execution.securecodebox.io_scans.yaml +++ b/operator/config/crd/bases/execution.securecodebox.io_scans.yaml @@ -77,7 +77,7 @@ spec: inherit environment variables from the parent scan type: boolean inheritHookSelector: - default: true + default: false description: InheritHookSelector defines whether cascading scans should inherit hookSelector from the parent scan. type: boolean diff --git a/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml b/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml index 5f238dc7ff..53043f17a2 100644 --- a/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml +++ b/operator/config/crd/bases/execution.securecodebox.io_scheduledscans.yaml @@ -97,7 +97,7 @@ spec: inherit environment variables from the parent scan type: boolean inheritHookSelector: - default: true + default: false description: InheritHookSelector defines whether cascading scans should inherit hookSelector from the parent scan. type: boolean diff --git a/operator/crds/cascading.securecodebox.io_cascadingrules.yaml b/operator/crds/cascading.securecodebox.io_cascadingrules.yaml index 1d300e8554..8df98f340a 100644 --- a/operator/crds/cascading.securecodebox.io_cascadingrules.yaml +++ b/operator/crds/cascading.securecodebox.io_cascadingrules.yaml @@ -115,7 +115,7 @@ spec: inherit environment variables from the parent scan type: boolean inheritHookSelector: - default: true + default: false description: InheritHookSelector defines whether cascading scans should inherit hookSelector from the parent scan. type: boolean diff --git a/operator/crds/execution.securecodebox.io_scans.yaml b/operator/crds/execution.securecodebox.io_scans.yaml index 9d47107e86..3e24c3b2b0 100644 --- a/operator/crds/execution.securecodebox.io_scans.yaml +++ b/operator/crds/execution.securecodebox.io_scans.yaml @@ -77,7 +77,7 @@ spec: inherit environment variables from the parent scan type: boolean inheritHookSelector: - default: true + default: false description: InheritHookSelector defines whether cascading scans should inherit hookSelector from the parent scan. type: boolean diff --git a/operator/crds/execution.securecodebox.io_scheduledscans.yaml b/operator/crds/execution.securecodebox.io_scheduledscans.yaml index 5f238dc7ff..53043f17a2 100644 --- a/operator/crds/execution.securecodebox.io_scheduledscans.yaml +++ b/operator/crds/execution.securecodebox.io_scheduledscans.yaml @@ -97,7 +97,7 @@ spec: inherit environment variables from the parent scan type: boolean inheritHookSelector: - default: true + default: false description: InheritHookSelector defines whether cascading scans should inherit hookSelector from the parent scan. type: boolean From 893e0adaa29ac37900112934fd6731e17a7c72e3 Mon Sep 17 00:00:00 2001 From: Jop Zitman Date: Thu, 28 Oct 2021 17:49:27 +0200 Subject: [PATCH 7/7] Purge matchExpressions and matchLabels from cascaded scan (like env and volumes) Signed-off-by: Jop Zitman --- hooks/cascading-scans/hook/hook.test.js | 38 ++++++++++++++++++++++ hooks/cascading-scans/hook/scan-helpers.ts | 15 ++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/hooks/cascading-scans/hook/hook.test.js b/hooks/cascading-scans/hook/hook.test.js index c3a4cffa4f..c03a6889b3 100644 --- a/hooks/cascading-scans/hook/hook.test.js +++ b/hooks/cascading-scans/hook/hook.test.js @@ -1450,6 +1450,7 @@ test("should not merge hookSelector into cascaded scan if inheritHookSelector is test("should purge cascaded scan spec from parent scan", () => { parentScan.spec.cascades.inheritEnv = true parentScan.spec.cascades.inheritVolumes = true + parentScan.spec.cascades.inheritHookSelector = true const findings = [ { name: "Port 443 is open", @@ -1513,6 +1514,31 @@ test("should purge cascaded scan spec from parent scan", () => { } ] + parentScan.spec.hookSelector = {} + parentScan.spec.hookSelector.matchLabels = { + "securecodebox.io/internal": "true", + } + parentScan.spec.hookSelector.matchExpressions = [ + { + key: "securecodebox.io/name", + operator: LabelSelectorRequirementOperator.In, + values: ["cascading-scans"] + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.hookSelector = {}; + sslyzeCascadingRules[0].spec.scanSpec.hookSelector.matchExpressions = [ + { + key: "securecodebox.io/name", + operator: LabelSelectorRequirementOperator.NotIn, + values: ["cascading-scans"] + } + ] + + sslyzeCascadingRules[0].spec.scanSpec.hookSelector.matchLabels = { + "securecodebox.io/internal": "false", + } + const cascadedScans = getCascadingScans( parentScan, findings, @@ -1595,6 +1621,18 @@ test("should purge cascaded scan spec from parent scan", () => { ] `) + expect(secondCascadedScan.spec.hookSelector.matchExpressions).toMatchInlineSnapshot(` + Array [ + Object { + "key": "securecodebox.io/name", + "operator": "In", + "values": Array [ + "cascading-scans", + ], + }, + ] + `) + expect(secondCascadedScan.spec.hookSelector.matchLabels).toMatchInlineSnapshot(`Object {}`) }); test("should not copy cascaded scan spec from parent scan if inheritance is undefined", () => { diff --git a/hooks/cascading-scans/hook/scan-helpers.ts b/hooks/cascading-scans/hook/scan-helpers.ts index 7dc86b65c2..ae1a84b53c 100644 --- a/hooks/cascading-scans/hook/scan-helpers.ts +++ b/hooks/cascading-scans/hook/scan-helpers.ts @@ -84,7 +84,7 @@ export function mergeInheritedMap(parentProps, ruleProps, inherit: boolean = tru } } -export function mergeInheritedArray(parentArray, ruleArray, inherit: boolean = false) { +export function mergeInheritedArray(parentArray = [], ruleArray = [], inherit: boolean = false) { if (!inherit) { parentArray = []; } @@ -178,6 +178,19 @@ export function purgeCascadedRuleFromScan(scan: Scan, cascadedRuleUsedForParentS ); } + if (scan.spec.hookSelector !== undefined && cascadedRuleUsedForParentScan.spec.scanSpec.hookSelector !== undefined) { + if (scan.spec.hookSelector.matchExpressions !== undefined && cascadedRuleUsedForParentScan.spec.scanSpec.hookSelector.matchExpressions !== undefined) { + scan.spec.hookSelector.matchExpressions = scan.spec.hookSelector.matchExpressions.filter(scanHookSelector => + !cascadedRuleUsedForParentScan.spec.scanSpec.hookSelector.matchExpressions.some(ruleHookSelector => isEqual(scanHookSelector, ruleHookSelector)) + ); + } + if (scan.spec.hookSelector.matchLabels !== undefined && cascadedRuleUsedForParentScan.spec.scanSpec.hookSelector.matchLabels !== undefined) { + for (const label in cascadedRuleUsedForParentScan.spec.scanSpec.hookSelector.matchLabels) { + delete scan.spec.hookSelector.matchLabels[label] + } + } + } + return scan }