diff --git a/auto-discovery/kubernetes/controllers/container_scan_controller.go b/auto-discovery/kubernetes/controllers/container_scan_controller.go index b91be41331..736a5f4841 100644 --- a/auto-discovery/kubernetes/controllers/container_scan_controller.go +++ b/auto-discovery/kubernetes/controllers/container_scan_controller.go @@ -82,7 +82,7 @@ func (r *ContainerScanReconciler) Reconcile(ctx context.Context, req ctrl.Reques scanTypesInstalled := r.checkForScanTypes(ctx, pod) if !scanTypesInstalled { - requeueDuration := r.Config.ContainerAutoDiscovery.PassiveReconcileInterval + requeueDuration := r.Config.ContainerAutoDiscovery.PassiveReconcileInterval.Duration return ctrl.Result{Requeue: true, RequeueAfter: requeueDuration}, nil } diff --git a/auto-discovery/kubernetes/controllers/service_scan_controller.go b/auto-discovery/kubernetes/controllers/service_scan_controller.go index 48487fbf97..dde12c9f39 100644 --- a/auto-discovery/kubernetes/controllers/service_scan_controller.go +++ b/auto-discovery/kubernetes/controllers/service_scan_controller.go @@ -187,7 +187,7 @@ func (r *ServiceScanReconciler) Reconcile(ctx context.Context, req ctrl.Request) // Requeue to allow scan to be created when the user installs the scanType return ctrl.Result{ Requeue: true, - RequeueAfter: Config.ServiceAutoDiscovery.PassiveReconcileInterval, + RequeueAfter: r.Config.ServiceAutoDiscovery.PassiveReconcileInterval.Duration, }, nil } else if err != nil { return ctrl.Result{ @@ -242,7 +242,7 @@ func (r *ServiceScanReconciler) Reconcile(ctx context.Context, req ctrl.Request) } return ctrl.Result{ Requeue: true, - RequeueAfter: r.Config.ServiceAutoDiscovery.PassiveReconcileInterval, + RequeueAfter: r.Config.ServiceAutoDiscovery.PassiveReconcileInterval.Duration, }, nil } diff --git a/auto-discovery/kubernetes/controllers/suite_test.go b/auto-discovery/kubernetes/controllers/suite_test.go index 59388589d2..328f3e5743 100644 --- a/auto-discovery/kubernetes/controllers/suite_test.go +++ b/auto-discovery/kubernetes/controllers/suite_test.go @@ -8,7 +8,6 @@ import ( "context" "path/filepath" "testing" - "time" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -21,11 +20,8 @@ import ( ctrl "sigs.k8s.io/controller-runtime" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - //+kubebuilder:scaffold:imports - config "github.com/secureCodeBox/secureCodeBox/auto-discovery/kubernetes/pkg/config" executionv1 "github.com/secureCodeBox/secureCodeBox/operator/apis/execution/v1" ) @@ -72,105 +68,13 @@ var _ = BeforeSuite(func() { }) Expect(err).ToNot(HaveOccurred()) - config := config.AutoDiscoveryConfig{ - Cluster: config.ClusterConfig{ - Name: "test-cluster", - }, - ServiceAutoDiscovery: config.ServiceAutoDiscoveryConfig{ - PassiveReconcileInterval: 1 * time.Second, - ScanConfigs: []config.ScanConfig{ - { - Name: "test-scan-0", - RepeatInterval: time.Hour, - Annotations: map[string]string{}, - Labels: map[string]string{}, - Parameters: []string{"-p", "{{ .Host.Port }}", "{{ .Service.Name }}.{{ .Service.Namespace }}.svc"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "foo": "bar", - }, - }, - }, - { - Name: "test-scan-1", - RepeatInterval: time.Hour, - Annotations: map[string]string{}, - Labels: map[string]string{}, - Parameters: []string{"-p", "{{ .Host.Port }}", "{{ .Service.Name }}.{{ .Service.Namespace }}.svc"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "foo": "bar", - }, - }, - }, - }, - }, - ContainerAutoDiscovery: config.ContainerAutoDiscoveryConfig{ - PassiveReconcileInterval: 1 * time.Second, - ImagePullSecretConfig: config.ImagePullSecretConfig{ - MapImagePullSecretsToEnvironmentVariables: true, - UsernameEnvironmentVariableName: "username", - PasswordNameEnvironmentVariableName: "password", - }, - ScanConfigs: []config.ScanConfig{ - { - Name: "test-scan", - RepeatInterval: time.Hour, - Annotations: map[string]string{"testAnnotation": "{{ .Namespace.Name }}"}, - Labels: map[string]string{"testLabel": "{{ .Namespace.Name }}"}, - Parameters: []string{"-p", "{{ .Namespace.Name }}"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Operator: metav1.LabelSelectorOpIn, - Key: "foo", - Values: []string{"bar", "baz"}, - }, - { - Operator: metav1.LabelSelectorOpDoesNotExist, - Key: "foo", - }, - }, - }, - }, - { - Name: "test-scan-two", - RepeatInterval: time.Hour, - Annotations: map[string]string{"testAnnotation": "{{ .Namespace.Name }}"}, - Labels: map[string]string{"testLabel": "{{ .Namespace.Name }}"}, - Parameters: []string{"-p", "{{ .Namespace.Name }}"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Operator: metav1.LabelSelectorOpIn, - Key: "foo", - Values: []string{"bar", "baz"}, - }, - { - Operator: metav1.LabelSelectorOpDoesNotExist, - Key: "foo", - }, - }, - }, - }, - }, - }, - ResourceInclusion: config.ResourceInclusionConfig{ - Mode: config.EnabledPerResource, - }, - } - // working config err = (&ServiceScanReconciler{ Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), Recorder: k8sManager.GetEventRecorderFor("ServiceScanController"), Log: ctrl.Log.WithName("controllers").WithName("ServiceScanController"), - Config: config, + Config: AutoDiscoveryConfigMock, }).SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) @@ -180,7 +84,7 @@ var _ = BeforeSuite(func() { Scheme: k8sManager.GetScheme(), Recorder: k8sManager.GetEventRecorderFor("ContainerScanController"), Log: ctrl.Log.WithName("controllers").WithName("ContainerScanController"), - Config: config, + Config: AutoDiscoveryConfigMock, }).SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) diff --git a/auto-discovery/kubernetes/controllers/suite_test_util.go b/auto-discovery/kubernetes/controllers/suite_test_util.go index e16ac0f494..c9975960a7 100644 --- a/auto-discovery/kubernetes/controllers/suite_test_util.go +++ b/auto-discovery/kubernetes/controllers/suite_test_util.go @@ -11,174 +11,70 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -var Config = config.AutoDiscoveryConfig{ - Cluster: config.ClusterConfig{ - Name: "test-cluster", - }, - ServiceAutoDiscovery: config.ServiceAutoDiscoveryConfig{ - PassiveReconcileInterval: 1 * time.Second, - ScanConfigs: []config.ScanConfig{ - { - Name: "test-scan-0", - RepeatInterval: time.Hour, - Annotations: map[string]string{}, - Labels: map[string]string{}, - Parameters: []string{"-p", "{{ .Host.Port }}", "{{ .Service.Name }}.{{ .Service.Namespace }}.svc"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "foo": "bar", - }, - }, - }, - { - Name: "test-scan-1", - RepeatInterval: time.Hour, - Annotations: map[string]string{}, - Labels: map[string]string{}, - Parameters: []string{"-p", "{{ .Host.Port }}", "{{ .Service.Name }}.{{ .Service.Namespace }}.svc"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "foo": "bar", - }, - }, +// newServiceScanConfigMock creates a mock scan configuration specifically for service auto-discovery +func newServiceScanConfigMock(name string) config.ScanConfig { + return config.ScanConfig{ + Name: name, + RepeatInterval: metav1.Duration{Duration: time.Hour}, + Annotations: map[string]string{}, + Labels: map[string]string{}, + Parameters: []string{"-p", "{{ .Host.Port }}", "{{ .Service.Name }}.{{ .Service.Namespace }}.svc"}, + ScanType: "nmap", + HookSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "foo": "bar", }, }, - }, - ContainerAutoDiscovery: config.ContainerAutoDiscoveryConfig{ - PassiveReconcileInterval: 1 * time.Second, - ScanConfigs: []config.ScanConfig{ - { - Name: "test-scan", - RepeatInterval: time.Hour, - Annotations: map[string]string{"testAnnotation": "{{ .Namespace.Name }}"}, - Labels: map[string]string{"testLabel": "{{ .Namespace.Name }}"}, - Parameters: []string{"-p", "{{ .Namespace.Name }}"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Operator: metav1.LabelSelectorOpIn, - Key: "foo", - Values: []string{"bar", "baz"}, - }, - { - Operator: metav1.LabelSelectorOpDoesNotExist, - Key: "foo", - }, - }, + } +} + +// newContainerScanConfigMock creates a mock scan configuration specifically for container auto-discovery +func newContainerScanConfigMock(name string) config.ScanConfig { + return config.ScanConfig{ + Name: name, + RepeatInterval: metav1.Duration{Duration: time.Hour}, + Annotations: map[string]string{"testAnnotation": "{{ .Namespace.Name }}"}, + Labels: map[string]string{"testLabel": "{{ .Namespace.Name }}"}, + Parameters: []string{"-p", "{{ .Namespace.Name }}"}, + ScanType: "nmap", + HookSelector: metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + { + Operator: metav1.LabelSelectorOpIn, + Key: "foo", + Values: []string{"bar", "baz"}, }, - }, - { - Name: "test-scan-two", - RepeatInterval: time.Hour, - Annotations: map[string]string{"testAnnotation": "{{ .Namespace.Name }}"}, - Labels: map[string]string{"testLabel": "{{ .Namespace.Name }}"}, - Parameters: []string{"-p", "{{ .Namespace.Name }}"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Operator: metav1.LabelSelectorOpIn, - Key: "foo", - Values: []string{"bar", "baz"}, - }, - { - Operator: metav1.LabelSelectorOpDoesNotExist, - Key: "foo", - }, - }, + { + Operator: metav1.LabelSelectorOpDoesNotExist, + Key: "foo", }, }, }, - }, - ResourceInclusion: config.ResourceInclusionConfig{ - Mode: config.EnabledPerResource, - }, + } } -// broken config has two scans (per autodiscovery) defined with the same name which will trigger an error during controller setup -var BrokenConfig = config.AutoDiscoveryConfig{ +// AutoDiscoveryConfigMock holds the complete mock configuration +var AutoDiscoveryConfigMock = config.AutoDiscoveryConfig{ Cluster: config.ClusterConfig{ Name: "test-cluster", }, ServiceAutoDiscovery: config.ServiceAutoDiscoveryConfig{ - PassiveReconcileInterval: 1 * time.Second, + PassiveReconcileInterval: metav1.Duration{Duration: 1 * time.Second}, ScanConfigs: []config.ScanConfig{ - { - Name: "test-scan", - RepeatInterval: time.Hour, - Annotations: map[string]string{}, - Labels: map[string]string{}, - Parameters: []string{"-p", "{{ .Host.Port }}", "{{ .Service.Name }}.{{ .Service.Namespace }}.svc"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "foo": "bar", - }, - }, - }, - { - Name: "test-scan", - RepeatInterval: time.Hour, - Annotations: map[string]string{}, - Labels: map[string]string{}, - Parameters: []string{"-p", "{{ .Host.Port }}", "{{ .Service.Name }}.{{ .Service.Namespace }}.svc"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{ - "foo": "bar", - }, - }, - }, + newServiceScanConfigMock("test-scan-0"), + newServiceScanConfigMock("test-scan-1"), }, }, ContainerAutoDiscovery: config.ContainerAutoDiscoveryConfig{ - PassiveReconcileInterval: 1 * time.Second, + PassiveReconcileInterval: metav1.Duration{Duration: 1 * time.Second}, + ImagePullSecretConfig: config.ImagePullSecretConfig{ + MapImagePullSecretsToEnvironmentVariables: true, + UsernameEnvironmentVariableName: "username", + PasswordNameEnvironmentVariableName: "password", + }, ScanConfigs: []config.ScanConfig{ - { - Name: "test-scan", - RepeatInterval: time.Hour, - Annotations: map[string]string{"testAnnotation": "{{ .Namespace.Name }}"}, - Labels: map[string]string{"testLabel": "{{ .Namespace.Name }}"}, - Parameters: []string{"-p", "{{ .Namespace.Name }}"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Operator: metav1.LabelSelectorOpIn, - Key: "foo", - Values: []string{"bar", "baz"}, - }, - { - Operator: metav1.LabelSelectorOpDoesNotExist, - Key: "foo", - }, - }, - }, - }, - { - Name: "test-scan", - RepeatInterval: time.Hour, - Annotations: map[string]string{"testAnnotation": "{{ .Namespace.Name }}"}, - Labels: map[string]string{"testLabel": "{{ .Namespace.Name }}"}, - Parameters: []string{"-p", "{{ .Namespace.Name }}"}, - ScanType: "nmap", - HookSelector: metav1.LabelSelector{ - MatchExpressions: []metav1.LabelSelectorRequirement{ - { - Operator: metav1.LabelSelectorOpIn, - Key: "foo", - Values: []string{"bar", "baz"}, - }, - { - Operator: metav1.LabelSelectorOpDoesNotExist, - Key: "foo", - }, - }, - }, - }, + newContainerScanConfigMock("test-scan"), + newContainerScanConfigMock("test-scan-two"), }, }, ResourceInclusion: config.ResourceInclusionConfig{ diff --git a/auto-discovery/kubernetes/go.mod b/auto-discovery/kubernetes/go.mod index 7c8fc9aab1..be97c8e551 100644 --- a/auto-discovery/kubernetes/go.mod +++ b/auto-discovery/kubernetes/go.mod @@ -12,12 +12,12 @@ require ( github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.37.0 github.com/secureCodeBox/secureCodeBox/operator v0.0.0-20250409151104-b2c7b64c9589 - github.com/spf13/viper v1.20.1 k8s.io/api v0.32.3 k8s.io/apimachinery v0.32.3 k8s.io/client-go v0.32.3 k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e sigs.k8s.io/controller-runtime v0.20.4 + sigs.k8s.io/yaml v1.4.0 ) require ( @@ -34,7 +34,6 @@ require ( github.com/go-openapi/jsonpointer v0.21.1 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.1 // indirect - github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect @@ -53,18 +52,12 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nxadm/tail v1.4.8 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.22.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.63.0 // indirect github.com/prometheus/procfs v0.16.0 // indirect - github.com/sagikazarmark/locafero v0.9.0 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.14.0 // indirect - github.com/spf13/cast v1.7.1 // indirect github.com/spf13/pflag v1.0.6 // indirect - github.com/subosito/gotenv v1.6.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect @@ -89,5 +82,4 @@ require ( sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/auto-discovery/kubernetes/go.sum b/auto-discovery/kubernetes/go.sum index ca4638de9d..0b8dacc335 100644 --- a/auto-discovery/kubernetes/go.sum +++ b/auto-discovery/kubernetes/go.sum @@ -18,8 +18,6 @@ github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCv github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= @@ -40,8 +38,6 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8Wd github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= -github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -115,8 +111,6 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -132,27 +126,15 @@ github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2b github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= -github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/secureCodeBox/secureCodeBox/operator v0.0.0-20250409151104-b2c7b64c9589 h1:bA5TfYaqlHXqrDGAZJuIPVpC+BqUU4wKSJzrOH6V6oU= github.com/secureCodeBox/secureCodeBox/operator v0.0.0-20250409151104-b2c7b64c9589/go.mod h1:C2aY0MPPrtn+VkOpWXJKpd+2xmFogMy4sjBH406XrDA= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= -github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/auto-discovery/kubernetes/main.go b/auto-discovery/kubernetes/main.go index 3d65c36170..9ca6b5ee3f 100644 --- a/auto-discovery/kubernetes/main.go +++ b/auto-discovery/kubernetes/main.go @@ -10,7 +10,6 @@ import ( // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) // to ensure that exec-entrypoint and run can make use of them. - "github.com/spf13/viper" _ "k8s.io/client-go/plugin/pkg/client/auth" executionv1 "github.com/secureCodeBox/secureCodeBox/operator/apis/execution/v1" @@ -24,7 +23,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" "github.com/secureCodeBox/secureCodeBox/auto-discovery/kubernetes/controllers" - config "github.com/secureCodeBox/secureCodeBox/auto-discovery/kubernetes/pkg/config" + "github.com/secureCodeBox/secureCodeBox/auto-discovery/kubernetes/pkg/util" //+kubebuilder:scaffold:imports ) @@ -53,18 +52,12 @@ func main() { ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - viper.SetConfigFile(configFile) - if err := viper.ReadInConfig(); err != nil { // Handle errors reading the config file + ctrlConfig, err := util.LoadAutoDiscoveryConfig(configFile) + if err != nil { setupLog.Error(err, "unable to load the config file") os.Exit(1) } - var ctrlConfig config.AutoDiscoveryConfig - if err := viper.Unmarshal(&ctrlConfig); err != nil { - setupLog.Error(err, "unable to decode into struct") - os.Exit(1) - } - setupLog.Info("Got Config", "config", ctrlConfig) mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ diff --git a/auto-discovery/kubernetes/pkg/config/autodiscovery_config.go b/auto-discovery/kubernetes/pkg/config/autodiscovery_config.go index 38f0d4ad14..8bdcdf28ca 100644 --- a/auto-discovery/kubernetes/pkg/config/autodiscovery_config.go +++ b/auto-discovery/kubernetes/pkg/config/autodiscovery_config.go @@ -5,8 +5,6 @@ package config import ( - "time" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -38,15 +36,15 @@ type LeaderElectionConfig struct { } type ServiceAutoDiscoveryConfig struct { - Enabled bool `json:"enabled"` - PassiveReconcileInterval time.Duration `json:"passiveReconcileInterval"` - ScanConfigs []ScanConfig `json:"scanConfigs"` + Enabled bool `json:"enabled"` + PassiveReconcileInterval metav1.Duration `json:"passiveReconcileInterval"` + ScanConfigs []ScanConfig `json:"scanConfigs"` } type ContainerAutoDiscoveryConfig struct { Enabled bool `json:"enabled"` ImagePullSecretConfig ImagePullSecretConfig `json:"imagePullSecretConfig"` - PassiveReconcileInterval time.Duration `json:"passiveReconcileInterval"` + PassiveReconcileInterval metav1.Duration `json:"passiveReconcileInterval"` ScanConfigs []ScanConfig `json:"scanConfigs"` } @@ -75,7 +73,7 @@ type ResourceInclusionConfig struct { type ScanConfig struct { Name string `json:"name"` - RepeatInterval time.Duration `json:"repeatInterval"` + RepeatInterval metav1.Duration `json:"repeatInterval"` Annotations map[string]string `json:"annotations"` Labels map[string]string `json:"labels"` ScanType string `json:"scanType"` diff --git a/auto-discovery/kubernetes/pkg/util/__testfiles__/valid_config_test.yaml b/auto-discovery/kubernetes/pkg/util/__testfiles__/valid_config_test.yaml new file mode 100644 index 0000000000..706a5e8d44 --- /dev/null +++ b/auto-discovery/kubernetes/pkg/util/__testfiles__/valid_config_test.yaml @@ -0,0 +1,167 @@ +# SPDX-FileCopyrightText: the secureCodeBox authors +# +# SPDX-License-Identifier: Apache-2.0 + +# This yaml file should only be used for yaml.Marshal() testing +apiVersion: config.securecodebox.io/v1 +kind: AutoDiscoveryConfig + +cluster: + name: docker-desktop +resourceInclusion: + mode: enabled-per-namespace + +serviceAutoDiscovery: + enabled: true + passiveReconcileInterval: 1m + scanConfigs: + - scanType: zap-advanced-scan + name: "zap" + parameters: + - "-t" + - "{{ .Host.Type }}://{{ .Service.Name }}.{{ .Service.Namespace }}.svc:{{ .Host.Port }}" + repeatInterval: "168h" + labels: {} + annotations: + defectdojo.securecodebox.io/product-name: "{{ .Cluster.Name }} | {{ .Namespace.Name }} | {{ .Target.Name }}" + defectdojo.securecodebox.io/product-tags: "cluster/{{ .Cluster.Name }},namespace/{{ .Namespace.Name }}" + defectdojo.securecodebox.io/engagement-name: "{{ .Target.Name }}" + defectdojo.securecodebox.io/engagement-version: "{{if (index .Target.Labels `app.kubernetes.io/version`) }}{{ index .Target.Labels `app.kubernetes.io/version` }}{{end}}" + volumes: + - name: zap-advanced-scan-config + configMap: + name: zap-advanced-scan-config + optional: true + defaultMode: 420 + items: + - key: "2-zap-advanced-scan.yaml" + path: "2-zap-advanced-scan.yaml" + mode: 420 + - key: "extra-config.yaml" + path: "extra-config.yaml" + mode: 511 + volumeMounts: + - name: zap-advanced-scan-config + readOnly: true + recursiveReadOnly: "Enabled" + mountPath: /home/securecodebox/configs/2-zap-advanced-scan.yaml + subPath: 2-zap-advanced-scan.yaml + mountPropagation: "Bidirectional" + subPathExpr: "$(CONFIG_FILE_NAME)" + hookSelector: + matchLabels: + hook: zap-scan + matchExpressions: + - key: environment + operator: In + values: + - prod + - staging + - key: tier + operator: NotIn + values: + - frontend + env: + - name: ZAP_TARGET + value: "http://example.com" + - name: COMPLEX_ENV + value: "http://example.com" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "metadata.name" + resourceFieldRef: + containerName: "my-container" + resource: "limits.cpu" + divisor: "10" + configMapKeyRef: + name: "my-configmap" + key: "my-key" + optional: false + secretKeyRef: + name: "my-secret" + key: "my-secret-key" + optional: true + +containerAutoDiscovery: + enabled: false + passiveReconcileInterval: 1m + scanConfigs: + - scanType: trivy-image-autodiscovery + name: "trivy" + parameters: + - "{{ .ImageID }}" + repeatInterval: "168h" + labels: {} + annotations: + defectdojo.securecodebox.io/product-name: "{{ .Cluster.Name }} | {{ .Namespace.Name }} | {{ .Target.Name }}" + defectdojo.securecodebox.io/product-tags: "cluster/{{ .Cluster.Name }},namespace/{{ .Namespace.Name }}" + defectdojo.securecodebox.io/engagement-name: "{{ .Target.Name }}" + defectdojo.securecodebox.io/engagement-version: "{{if (index .Target.Labels `app.kubernetes.io/version`) }}{{ index .Target.Labels `app.kubernetes.io/version` }}{{end}}" + volumes: + - name: zap-advanced-scan-config + configMap: + name: zap-advanced-scan-config + optional: true + defaultMode: 420 + items: + - key: "2-zap-advanced-scan.yaml" + path: "2-zap-advanced-scan.yaml" + mode: 420 + - key: "extra-config.yaml" + path: "extra-config.yaml" + mode: 511 + volumeMounts: + - name: zap-advanced-scan-config + readOnly: true + recursiveReadOnly: "Enabled" + mountPath: /home/securecodebox/configs/2-zap-advanced-scan.yaml + subPath: 2-zap-advanced-scan.yaml + mountPropagation: "Bidirectional" + subPathExpr: "$(CONFIG_FILE_NAME)" + hookSelector: + matchLabels: + hook: zap-scan + matchExpressions: + - key: environment + operator: In + values: + - prod + - staging + - key: tier + operator: NotIn + values: + - frontend + env: + - name: ZAP_TARGET + value: "http://example.com" + - name: COMPLEX_ENV + value: "http://example.com" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "metadata.name" + resourceFieldRef: + containerName: "my-container" + resource: "limits.cpu" + divisor: "10" + configMapKeyRef: + name: "my-configmap" + key: "my-key" + optional: false + secretKeyRef: + name: "my-secret" + key: "my-secret-key" + optional: true + imagePullSecretConfig: + mapImagePullSecretsToEnvironmentVariables: true + usernameEnvironmentVariableName: "TRIVY_USERNAME" + passwordEnvironmentVariableName: "TRIVY_PASSWORD" + +health: + healthProbeBindAddress: :8081 +metrics: + bindAddress: 127.0.0.1:8080 +leaderElection: + leaderElect: true + resourceName: 0e41a1f4.securecodebox.io diff --git a/auto-discovery/kubernetes/pkg/util/config_loader.go b/auto-discovery/kubernetes/pkg/util/config_loader.go new file mode 100644 index 0000000000..7ab3b23790 --- /dev/null +++ b/auto-discovery/kubernetes/pkg/util/config_loader.go @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "os" + + "sigs.k8s.io/yaml" + + config "github.com/secureCodeBox/secureCodeBox/auto-discovery/kubernetes/pkg/config" +) + +// LoadAutoDiscoveryConfig reads a YAML config file and unmarshals it into AutoDiscoveryConfig. +func LoadAutoDiscoveryConfig(filename string) (config.AutoDiscoveryConfig, error) { + data, err := os.ReadFile(filename) + if err != nil { + return config.AutoDiscoveryConfig{}, err + } + + var cfg config.AutoDiscoveryConfig + if err = yaml.Unmarshal(data, &cfg); err != nil { + return config.AutoDiscoveryConfig{}, err + } + + return cfg, nil +} diff --git a/auto-discovery/kubernetes/pkg/util/config_loader_test.go b/auto-discovery/kubernetes/pkg/util/config_loader_test.go new file mode 100644 index 0000000000..3d4f4abd2a --- /dev/null +++ b/auto-discovery/kubernetes/pkg/util/config_loader_test.go @@ -0,0 +1,275 @@ +// SPDX-FileCopyrightText: the secureCodeBox authors +// +// SPDX-License-Identifier: Apache-2.0 + +package util + +import ( + "path/filepath" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/secureCodeBox/secureCodeBox/auto-discovery/kubernetes/pkg/config" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("LoadAutoDiscoveryConfig", func() { + Context("With a fully filled valid config file", func() { + It("Should unmarshal all configuration fields as expected", func() { + testFile := filepath.Join("__testfiles__", "valid_config_test.yaml") + + cfg, err := LoadAutoDiscoveryConfig(testFile) + Expect(err).ShouldNot(HaveOccurred()) + Expect(cfg).ShouldNot(BeNil()) + + // Check TypeMeta. + Expect(cfg.APIVersion).To(Equal("config.securecodebox.io/v1")) + Expect(cfg.Kind).To(Equal("AutoDiscoveryConfig")) + + // Check Cluster. + Expect(cfg.Cluster.Name).To(Equal("docker-desktop")) + + // Check ResourceInclusion. + Expect(cfg.ResourceInclusion.Mode).To(Equal(config.EnabledPerNamespace)) + + // Check ServiceAutoDiscovery configuration. + sad := cfg.ServiceAutoDiscovery + Expect(sad.Enabled).To(BeTrue()) + // The YAML specifies "1m" which should parse to time.Minute. + Expect(sad.PassiveReconcileInterval.Duration).To(Equal(time.Minute)) + // Expect one scan configuration. + Expect(sad.ScanConfigs).To(HaveLen(1)) + + sc := sad.ScanConfigs[0] + Expect(sc.Name).To(Equal("zap")) + Expect(sc.ScanType).To(Equal("zap-advanced-scan")) + Expect(sc.RepeatInterval.Duration).To(Equal(168 * time.Hour)) + Expect(sc.Parameters).To(Equal([]string{ + "-t", + "{{ .Host.Type }}://{{ .Service.Name }}.{{ .Service.Namespace }}.svc:{{ .Host.Port }}", + })) + Expect(sc.Labels).To(BeEmpty()) + Expect(sc.Annotations).To(HaveKeyWithValue("defectdojo.securecodebox.io/product-name", "{{ .Cluster.Name }} | {{ .Namespace.Name }} | {{ .Target.Name }}")) + Expect(sc.Annotations).To(HaveKeyWithValue("defectdojo.securecodebox.io/product-tags", "cluster/{{ .Cluster.Name }},namespace/{{ .Namespace.Name }}")) + Expect(sc.Annotations).To(HaveKeyWithValue("defectdojo.securecodebox.io/engagement-name", "{{ .Target.Name }}")) + Expect(sc.Annotations).To(HaveKeyWithValue("defectdojo.securecodebox.io/engagement-version", "{{if (index .Target.Labels `app.kubernetes.io/version`) }}{{ index .Target.Labels `app.kubernetes.io/version` }}{{end}}")) + + // Validate volumes of the service scan config. + Expect(sc.Volumes).To(HaveLen(1)) + vol := sc.Volumes[0] + Expect(vol.Name).To(Equal("zap-advanced-scan-config")) + Expect(vol.ConfigMap).NotTo(BeNil()) + cm := vol.ConfigMap + // The ConfigMap volume source. + Expect(cm.Name).To(Equal("zap-advanced-scan-config")) + // Optional is a pointer. + Expect(*cm.Optional).To(BeTrue()) + Expect(*cm.DefaultMode).To(Equal(int32(420))) + Expect(cm.Items).To(HaveLen(2)) + // First key-to-path mapping. + firstItem := cm.Items[0] + Expect(firstItem.Key).To(Equal("2-zap-advanced-scan.yaml")) + Expect(firstItem.Path).To(Equal("2-zap-advanced-scan.yaml")) + Expect(*firstItem.Mode).To(Equal(int32(420))) + // Second key-to-path mapping. + secondItem := cm.Items[1] + Expect(secondItem.Key).To(Equal("extra-config.yaml")) + Expect(secondItem.Path).To(Equal("extra-config.yaml")) + Expect(*secondItem.Mode).To(Equal(int32(511))) + + // Validate volumeMounts of the service scan config. + Expect(sc.VolumeMounts).To(HaveLen(1)) + vm := sc.VolumeMounts[0] + Expect(vm.Name).To(Equal("zap-advanced-scan-config")) + Expect(vm.ReadOnly).To(BeTrue()) + // recursiveReadOnly is a pointer to a string in the struct. + Expect(*vm.RecursiveReadOnly).To(Equal(corev1.RecursiveReadOnlyEnabled)) + Expect(vm.MountPath).To(Equal("/home/securecodebox/configs/2-zap-advanced-scan.yaml")) + Expect(vm.SubPath).To(Equal("2-zap-advanced-scan.yaml")) + // mountPropagation is also a pointer. + Expect(*vm.MountPropagation).To(Equal(corev1.MountPropagationBidirectional)) + Expect(vm.SubPathExpr).To(Equal("$(CONFIG_FILE_NAME)")) + + // Validate hookSelector: matchLabels and matchExpressions. + Expect(sc.HookSelector.MatchLabels).To(HaveKeyWithValue("hook", "zap-scan")) + Expect(sc.HookSelector.MatchExpressions).To(HaveLen(2)) + + // Validate first matchExpression. + scme1 := sc.HookSelector.MatchExpressions[0] + Expect(scme1.Key).To(Equal("environment")) + Expect(scme1.Operator).To(Equal(metav1.LabelSelectorOpIn)) + Expect(scme1.Values).To(ConsistOf("prod", "staging")) + + // Validate second matchExpression. + scme2 := sc.HookSelector.MatchExpressions[1] + Expect(scme2.Key).To(Equal("tier")) + Expect(scme2.Operator).To(Equal(metav1.LabelSelectorOpNotIn)) + Expect(scme2.Values).To(ConsistOf("frontend")) + + // Validate environment variables. + Expect(sc.Env).To(HaveLen(2)) + + // Validate first environment variable. + scenv1 := sc.Env[0] + Expect(scenv1.Name).To(Equal("ZAP_TARGET")) + Expect(scenv1.Value).To(Equal("http://example.com")) + Expect(scenv1.ValueFrom).To(BeNil()) + + // Validate second environment variable + scenv2 := sc.Env[1] + Expect(scenv2.Name).To(Equal("COMPLEX_ENV")) + Expect(scenv2.Value).To(Equal("http://example.com")) + + Expect(scenv2.ValueFrom).NotTo(BeNil()) + vf := scenv2.ValueFrom + + // Validate fieldRef. + Expect(vf.FieldRef).NotTo(BeNil()) + Expect(vf.FieldRef.APIVersion).To(Equal("v1")) + Expect(vf.FieldRef.FieldPath).To(Equal("metadata.name")) + + // Validate resourceFieldRef. + Expect(vf.ResourceFieldRef).NotTo(BeNil()) + Expect(vf.ResourceFieldRef.ContainerName).To(Equal("my-container")) + Expect(vf.ResourceFieldRef.Resource).To(Equal("limits.cpu")) + // Check that the divisor string is "10". + Expect(vf.ResourceFieldRef.Divisor.String()).To(Equal("10")) + + // Validate configMapKeyRef. + Expect(vf.ConfigMapKeyRef).NotTo(BeNil()) + Expect(vf.ConfigMapKeyRef.Name).To(Equal("my-configmap")) + Expect(vf.ConfigMapKeyRef.Key).To(Equal("my-key")) + Expect(vf.ConfigMapKeyRef.Optional).NotTo(BeNil()) + Expect(*vf.ConfigMapKeyRef.Optional).To(BeFalse()) + + // Validate secretKeyRef. + Expect(vf.SecretKeyRef).NotTo(BeNil()) + Expect(vf.SecretKeyRef.Name).To(Equal("my-secret")) + Expect(vf.SecretKeyRef.Key).To(Equal("my-secret-key")) + Expect(vf.SecretKeyRef.Optional).NotTo(BeNil()) + Expect(*vf.SecretKeyRef.Optional).To(BeTrue()) + + // Check ContainerAutoDiscovery configuration. + cad := cfg.ContainerAutoDiscovery + Expect(cad.Enabled).To(BeFalse()) + Expect(cad.PassiveReconcileInterval.Duration).To(Equal(time.Minute)) + + // Validate ImagePullSecretConfig. + ipc := cad.ImagePullSecretConfig + Expect(ipc.MapImagePullSecretsToEnvironmentVariables).To(BeTrue()) + Expect(ipc.UsernameEnvironmentVariableName).To(Equal("TRIVY_USERNAME")) + Expect(ipc.PasswordNameEnvironmentVariableName).To(Equal("TRIVY_PASSWORD")) + + // Expect one scan configuration. + Expect(cad.ScanConfigs).To(HaveLen(1)) + sc2 := cad.ScanConfigs[0] + Expect(sc2.Name).To(Equal("trivy")) + Expect(sc2.ScanType).To(Equal("trivy-image-autodiscovery")) + Expect(sc2.RepeatInterval.Duration).To(Equal(168 * time.Hour)) + Expect(sc2.Parameters).To(Equal([]string{"{{ .ImageID }}"})) + Expect(sc2.Labels).To(BeEmpty()) + Expect(sc2.Annotations).To(HaveKeyWithValue("defectdojo.securecodebox.io/product-name", "{{ .Cluster.Name }} | {{ .Namespace.Name }} | {{ .Target.Name }}")) + Expect(sc2.Annotations).To(HaveKeyWithValue("defectdojo.securecodebox.io/product-tags", "cluster/{{ .Cluster.Name }},namespace/{{ .Namespace.Name }}")) + Expect(sc2.Annotations).To(HaveKeyWithValue("defectdojo.securecodebox.io/engagement-name", "{{ .Target.Name }}")) + Expect(sc2.Annotations).To(HaveKeyWithValue("defectdojo.securecodebox.io/engagement-version", "{{if (index .Target.Labels `app.kubernetes.io/version`) }}{{ index .Target.Labels `app.kubernetes.io/version` }}{{end}}")) + + // Validate volumes of the container scan config. + Expect(sc2.Volumes).To(HaveLen(1)) + vol2 := sc2.Volumes[0] + Expect(vol2.Name).To(Equal("zap-advanced-scan-config")) + Expect(vol2.ConfigMap).NotTo(BeNil()) + cm2 := vol2.ConfigMap + Expect(cm2.Name).To(Equal("zap-advanced-scan-config")) + Expect(*cm2.Optional).To(BeTrue()) + Expect(*cm2.DefaultMode).To(Equal(int32(420))) + Expect(cm2.Items).To(HaveLen(2)) + firstItem = cm2.Items[0] + Expect(firstItem.Key).To(Equal("2-zap-advanced-scan.yaml")) + Expect(firstItem.Path).To(Equal("2-zap-advanced-scan.yaml")) + Expect(*firstItem.Mode).To(Equal(int32(420))) + secondItem = cm2.Items[1] + Expect(secondItem.Key).To(Equal("extra-config.yaml")) + Expect(secondItem.Path).To(Equal("extra-config.yaml")) + Expect(*secondItem.Mode).To(Equal(int32(511))) + + // Validate volumeMounts of the container scan config. + Expect(sc2.VolumeMounts).To(HaveLen(1)) + vm = sc2.VolumeMounts[0] + Expect(vm.Name).To(Equal("zap-advanced-scan-config")) + Expect(vm.ReadOnly).To(BeTrue()) + Expect(*vm.RecursiveReadOnly).To(Equal(corev1.RecursiveReadOnlyEnabled)) + Expect(vm.MountPath).To(Equal("/home/securecodebox/configs/2-zap-advanced-scan.yaml")) + Expect(vm.SubPath).To(Equal("2-zap-advanced-scan.yaml")) + Expect(*vm.MountPropagation).To(Equal(corev1.MountPropagationBidirectional)) + Expect(vm.SubPathExpr).To(Equal("$(CONFIG_FILE_NAME)")) + + // Validate hookSelector: matchLabels and matchExpressions. + Expect(sc2.HookSelector.MatchLabels).To(HaveKeyWithValue("hook", "zap-scan")) + Expect(sc2.HookSelector.MatchExpressions).To(HaveLen(2)) + + // Validate first matchExpression. + sc2me1 := sc2.HookSelector.MatchExpressions[0] + Expect(sc2me1.Key).To(Equal("environment")) + Expect(sc2me1.Operator).To(Equal(metav1.LabelSelectorOpIn)) + Expect(sc2me1.Values).To(ConsistOf("prod", "staging")) + + // Validate second matchExpression. + sc2me2 := sc2.HookSelector.MatchExpressions[1] + Expect(sc2me2.Key).To(Equal("tier")) + Expect(sc2me2.Operator).To(Equal(metav1.LabelSelectorOpNotIn)) + Expect(sc2me2.Values).To(ConsistOf("frontend")) + + // Validate environment variables. + Expect(sc2.Env).To(HaveLen(2)) + + // Validate first environment variable. + sc2env1 := sc2.Env[0] + Expect(sc2env1.Name).To(Equal("ZAP_TARGET")) + Expect(sc2env1.Value).To(Equal("http://example.com")) + Expect(sc2env1.ValueFrom).To(BeNil()) + + // Validate second environment variable + sc2env2 := sc2.Env[1] + Expect(sc2env2.Name).To(Equal("COMPLEX_ENV")) + Expect(sc2env2.Value).To(Equal("http://example.com")) + + Expect(sc2env2.ValueFrom).NotTo(BeNil()) + vf2 := sc2env2.ValueFrom + + // Validate fieldRef. + Expect(vf2.FieldRef).NotTo(BeNil()) + Expect(vf2.FieldRef.APIVersion).To(Equal("v1")) + Expect(vf2.FieldRef.FieldPath).To(Equal("metadata.name")) + + // Validate resourceFieldRef. + Expect(vf2.ResourceFieldRef).NotTo(BeNil()) + Expect(vf2.ResourceFieldRef.ContainerName).To(Equal("my-container")) + Expect(vf2.ResourceFieldRef.Resource).To(Equal("limits.cpu")) + // Check that the divisor string is "10". + Expect(vf2.ResourceFieldRef.Divisor.String()).To(Equal("10")) + + // Validate configMapKeyRef. + Expect(vf2.ConfigMapKeyRef).NotTo(BeNil()) + Expect(vf2.ConfigMapKeyRef.Name).To(Equal("my-configmap")) + Expect(vf2.ConfigMapKeyRef.Key).To(Equal("my-key")) + Expect(vf2.ConfigMapKeyRef.Optional).NotTo(BeNil()) + Expect(*vf2.ConfigMapKeyRef.Optional).To(BeFalse()) + + // Validate secretKeyRef. + Expect(vf2.SecretKeyRef).NotTo(BeNil()) + Expect(vf2.SecretKeyRef.Name).To(Equal("my-secret")) + Expect(vf2.SecretKeyRef.Key).To(Equal("my-secret-key")) + Expect(vf2.SecretKeyRef.Optional).NotTo(BeNil()) + Expect(*vf2.SecretKeyRef.Optional).To(BeTrue()) + + // Validate top-level metrics, health, and leader election. + Expect(cfg.Metrics.BindAddress).To(Equal("127.0.0.1:8080")) + Expect(cfg.Health.HealthProbeBindAddress).To(Equal(":8081")) + Expect(cfg.LeaderElection.LeaderElect).To(BeTrue()) + Expect(cfg.LeaderElection.ResourceName).To(Equal("0e41a1f4.securecodebox.io")) + }) + }) +}) diff --git a/auto-discovery/kubernetes/pkg/util/gotemplate.go b/auto-discovery/kubernetes/pkg/util/gotemplate.go index 6cfa8b3814..38bb23b652 100644 --- a/auto-discovery/kubernetes/pkg/util/gotemplate.go +++ b/auto-discovery/kubernetes/pkg/util/gotemplate.go @@ -153,7 +153,7 @@ func GenerateScanSpec(scanConfig config.ScanConfig, templateArgs interface{}) ex envVars := generateEnvVars(scanConfig, templateArgs) scheduledScanSpec := executionv1.ScheduledScanSpec{ - Interval: metav1.Duration{Duration: scanConfig.RepeatInterval}, + Interval: scanConfig.RepeatInterval, ScanSpec: &executionv1.ScanSpec{ ScanType: scanConfig.ScanType, Parameters: params, diff --git a/auto-discovery/kubernetes/pkg/util/gotemplate_test.go b/auto-discovery/kubernetes/pkg/util/gotemplate_test.go index e40bee98d9..6001891fbc 100644 --- a/auto-discovery/kubernetes/pkg/util/gotemplate_test.go +++ b/auto-discovery/kubernetes/pkg/util/gotemplate_test.go @@ -81,7 +81,7 @@ var _ = Describe("gotemplate helper util", func() { } scanConfig := config.ScanConfig{ - RepeatInterval: time.Hour, + RepeatInterval: metav1.Duration{Duration: time.Hour}, Annotations: map[string]string{}, Labels: map[string]string{}, Parameters: []string{"-p", "3000", "{{ .Target.Name }}.{{ .Namespace.Name }}.svc"}, @@ -151,7 +151,7 @@ var _ = Describe("gotemplate helper util", func() { It("should work with empty list of matchExpression", func() { scanConfig := config.ScanConfig{ - RepeatInterval: time.Hour, + RepeatInterval: metav1.Duration{Duration: time.Hour}, Annotations: map[string]string{}, Labels: map[string]string{}, Parameters: []string{"-p", "3000", "{{ .Target.Name }}.{{ .Namespace.Name }}.svc"}, @@ -194,7 +194,7 @@ var _ = Describe("gotemplate helper util", func() { It("should work a a list of multiple matchExpressions", func() { scanConfig := config.ScanConfig{ - RepeatInterval: time.Hour, + RepeatInterval: metav1.Duration{Duration: time.Hour}, Annotations: map[string]string{}, Labels: map[string]string{}, Parameters: []string{"-p", "3000", "{{ .Target.Name }}.{{ .Namespace.Name }}.svc"}, @@ -212,7 +212,7 @@ var _ = Describe("gotemplate helper util", func() { It("should template with matchLabels", func() { scanConfig := config.ScanConfig{ - RepeatInterval: time.Hour, + RepeatInterval: metav1.Duration{Duration: time.Hour}, Annotations: map[string]string{}, Labels: map[string]string{}, Parameters: []string{"-p", "3000", "{{ .Target.Name }}.{{ .Namespace.Name }}.svc"}, @@ -257,7 +257,7 @@ var _ = Describe("gotemplate helper util", func() { }, } scanConfig := config.ScanConfig{ - RepeatInterval: time.Hour, + RepeatInterval: metav1.Duration{Duration: time.Hour}, Annotations: map[string]string{}, Labels: map[string]string{}, Parameters: []string{"example.com"}, diff --git a/auto-discovery/kubernetes/tests/__snapshot__/auto-discovery_test.yaml.snap b/auto-discovery/kubernetes/tests/__snapshot__/auto-discovery_test.yaml.snap index a17f466ffb..352a084a9a 100644 --- a/auto-discovery/kubernetes/tests/__snapshot__/auto-discovery_test.yaml.snap +++ b/auto-discovery/kubernetes/tests/__snapshot__/auto-discovery_test.yaml.snap @@ -10,6 +10,11 @@ matches the snapshot: }, "containerAutoDiscovery": { "enabled": false, + "imagePullSecretConfig": { + "mapImagePullSecretsToEnvironmentVariables": true, + "passwordEnvironmentVariableName": "TRIVY_PASSWORD", + "usernameEnvironmentVariableName": "TRIVY_USERNAME" + }, "passiveReconcileInterval": "1m", "scanConfigs": [ { @@ -36,11 +41,6 @@ matches the snapshot: "health": { "healthProbeBindAddress": ":8081" }, - "imagePullSecretConfig": { - "mapImagePullSecretsToEnvironmentVariables": true, - "passwordEnvironmentVariableName": "TRIVY_PASSWORD", - "usernameEnvironmentVariableName": "TRIVY_USERNAME" - }, "kind": "AutoDiscoveryConfig", "leaderElection": { "leaderElect": true, diff --git a/auto-discovery/kubernetes/values.yaml b/auto-discovery/kubernetes/values.yaml index 6fe518bfa9..13520f8fa4 100644 --- a/auto-discovery/kubernetes/values.yaml +++ b/auto-discovery/kubernetes/values.yaml @@ -94,7 +94,7 @@ config: # -- allows to overwrite the env var list of the scan job. # the value field supports templating. env: [] - imagePullSecretConfig: + imagePullSecretConfig: mapImagePullSecretsToEnvironmentVariables: true usernameEnvironmentVariableName: "TRIVY_USERNAME" passwordEnvironmentVariableName: "TRIVY_PASSWORD"