From 80dc575a285974614ce317401bd8e49402703db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sun, 24 Mar 2024 16:48:31 +0100 Subject: [PATCH] misconf: Add helm api-version and kube-version flag --- .../references/configuration/cli/trivy_aws.md | 2 + .../configuration/cli/trivy_config.md | 2 + .../configuration/cli/trivy_filesystem.md | 2 + .../configuration/cli/trivy_image.md | 2 + .../configuration/cli/trivy_kubernetes.md | 2 + .../configuration/cli/trivy_repository.md | 2 + .../configuration/cli/trivy_rootfs.md | 2 + .../references/configuration/cli/trivy_vm.md | 2 + pkg/commands/artifact/run.go | 2 + pkg/flag/misconf_flags.go | 20 +++++ pkg/iac/scanners/helm/options.go | 8 ++ pkg/iac/scanners/helm/parser/option.go | 9 +++ pkg/iac/scanners/helm/parser/parser.go | 19 ++++- pkg/iac/scanners/helm/parser/parser_test.go | 3 +- pkg/iac/scanners/helm/scanner.go | 5 +- pkg/iac/scanners/helm/test/option_test.go | 74 +++++++++++++++++-- pkg/iac/scanners/helm/test/parser_test.go | 15 ++-- .../with-kube-version/templates/pdb.yaml | 17 +++++ .../testdata/with-kube-version/.helmignore | 23 ++++++ .../testdata/with-kube-version/Chart.yaml | 26 +++++++ .../with-kube-version/templates/_helpers.tpl | 62 ++++++++++++++++ .../with-kube-version/templates/pdb.yaml | 11 +++ .../testdata/with-kube-version/values.yaml | 0 pkg/misconf/scanner.go | 10 +++ 24 files changed, 304 insertions(+), 16 deletions(-) create mode 100644 pkg/iac/scanners/helm/test/testdata/expected/options/with-kube-version/templates/pdb.yaml create mode 100644 pkg/iac/scanners/helm/test/testdata/with-kube-version/.helmignore create mode 100644 pkg/iac/scanners/helm/test/testdata/with-kube-version/Chart.yaml create mode 100644 pkg/iac/scanners/helm/test/testdata/with-kube-version/templates/_helpers.tpl create mode 100644 pkg/iac/scanners/helm/test/testdata/with-kube-version/templates/pdb.yaml create mode 100644 pkg/iac/scanners/helm/test/testdata/with-kube-version/values.yaml diff --git a/docs/docs/references/configuration/cli/trivy_aws.md b/docs/docs/references/configuration/cli/trivy_aws.md index af1ebc44a834..b87bfce2bc30 100644 --- a/docs/docs/references/configuration/cli/trivy_aws.md +++ b/docs/docs/references/configuration/cli/trivy_aws.md @@ -76,6 +76,8 @@ trivy aws [flags] --endpoint string AWS Endpoint override --exit-code int specify exit code when any security issues are found -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") + --helm-api-versions strings Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment) + --helm-kube-version string Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command. --helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 865ecb6ba605..070257b4a896 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -20,6 +20,8 @@ trivy config [flags] DIR --exit-code int specify exit code when any security issues are found --file-patterns strings specify config file patterns -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") + --helm-api-versions strings Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment) + --helm-kube-version string Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command. --helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index e26b26df7bfd..7aeb72ca5970 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -35,6 +35,8 @@ trivy filesystem [flags] PATH --exit-code int specify exit code when any security issues are found --file-patterns strings specify config file patterns -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") + --helm-api-versions strings Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment) + --helm-kube-version string Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command. --helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 20be9b459413..e5d91f31eb7c 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -51,6 +51,8 @@ trivy image [flags] IMAGE_NAME --exit-on-eol int exit with the specified code when the OS reaches end of service/life --file-patterns strings specify config file patterns -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") + --helm-api-versions strings Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment) + --helm-kube-version string Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command. --helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index ed22d8299f5b..a1befafeb504 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -46,6 +46,8 @@ trivy kubernetes [flags] { cluster | all | specific resources like kubectl. eg: --exit-code int specify exit code when any security issues are found --file-patterns strings specify config file patterns -f, --format string format (table,json,cyclonedx) (default "table") + --helm-api-versions strings Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment) + --helm-kube-version string Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command. --helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 0a2a614e4a5b..fa4d13bbdeee 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -35,6 +35,8 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --exit-code int specify exit code when any security issues are found --file-patterns strings specify config file patterns -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") + --helm-api-versions strings Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment) + --helm-kube-version string Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command. --helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 571fb009f4f0..088b5deb6d88 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -38,6 +38,8 @@ trivy rootfs [flags] ROOTDIR --exit-on-eol int exit with the specified code when the OS reaches end of service/life --file-patterns strings specify config file patterns -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") + --helm-api-versions strings Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment) + --helm-kube-version string Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command. --helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 6acf6606284b..7b186a505794 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -35,6 +35,8 @@ trivy vm [flags] VM_IMAGE --exit-on-eol int exit with the specified code when the OS reaches end of service/life --file-patterns strings specify config file patterns -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") + --helm-api-versions strings Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment) + --helm-kube-version string Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command. --helm-set strings specify Helm values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) --helm-set-file strings specify Helm values from respective files specified via the command line (can specify multiple or separate values with commas: key1=path1,key2=path2) --helm-set-string strings specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2) diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 4f8be6e1d911..da3b86c0e8b9 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -603,6 +603,8 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi HelmValueFiles: opts.HelmValueFiles, HelmFileValues: opts.HelmFileValues, HelmStringValues: opts.HelmStringValues, + HelmAPIVersions: opts.HelmAPIVersions, + HelmKubeVersion: opts.HelmKubeVersion, TerraformTFVars: opts.TerraformTFVars, CloudFormationParamVars: opts.CloudFormationParamVars, K8sVersion: opts.K8sVersion, diff --git a/pkg/flag/misconf_flags.go b/pkg/flag/misconf_flags.go index 492960b60ff9..57a91820c60d 100644 --- a/pkg/flag/misconf_flags.go +++ b/pkg/flag/misconf_flags.go @@ -45,6 +45,16 @@ var ( ConfigName: "misconfiguration.helm.set-string", Usage: "specify Helm string values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)", } + HelmAPIVersionsFlag = Flag[[]string]{ + Name: "helm-api-versions", + ConfigName: "misconfiguration.helm.api-versions", + Usage: "Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. (can specify multiple or separate values with commas: policy/v1/PodDisruptionBudget,apps/v1/Deployment)", + } + HelmKubeVersionFlag = Flag[string]{ + Name: "helm-kube-version", + ConfigName: "misconfiguration.helm.kube-version", + Usage: "Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command.", + } TfVarsFlag = Flag[[]string]{ Name: "tf-vars", ConfigName: "misconfiguration.terraform.vars", @@ -86,6 +96,8 @@ type MisconfFlagGroup struct { HelmValueFiles *Flag[[]string] HelmFileValues *Flag[[]string] HelmStringValues *Flag[[]string] + HelmAPIVersions *Flag[[]string] + HelmKubeVersion *Flag[string] TerraformTFVars *Flag[[]string] CloudformationParamVars *Flag[[]string] TerraformExcludeDownloaded *Flag[bool] @@ -102,6 +114,8 @@ type MisconfOptions struct { HelmValueFiles []string HelmFileValues []string HelmStringValues []string + HelmAPIVersions []string + HelmKubeVersion string TerraformTFVars []string CloudFormationParamVars []string TfExcludeDownloaded bool @@ -118,6 +132,8 @@ func NewMisconfFlagGroup() *MisconfFlagGroup { HelmFileValues: HelmSetFileFlag.Clone(), HelmStringValues: HelmSetStringFlag.Clone(), HelmValueFiles: HelmValuesFileFlag.Clone(), + HelmAPIVersions: HelmAPIVersionsFlag.Clone(), + HelmKubeVersion: HelmKubeVersionFlag.Clone(), TerraformTFVars: TfVarsFlag.Clone(), CloudformationParamVars: CfParamsFlag.Clone(), TerraformExcludeDownloaded: TerraformExcludeDownloaded.Clone(), @@ -138,6 +154,8 @@ func (f *MisconfFlagGroup) Flags() []Flagger { f.HelmValueFiles, f.HelmFileValues, f.HelmStringValues, + f.HelmAPIVersions, + f.HelmKubeVersion, f.TerraformTFVars, f.TerraformExcludeDownloaded, f.CloudformationParamVars, @@ -158,6 +176,8 @@ func (f *MisconfFlagGroup) ToOptions() (MisconfOptions, error) { HelmValueFiles: f.HelmValueFiles.Value(), HelmFileValues: f.HelmFileValues.Value(), HelmStringValues: f.HelmStringValues.Value(), + HelmAPIVersions: f.HelmAPIVersions.Value(), + HelmKubeVersion: f.HelmKubeVersion.Value(), TerraformTFVars: f.TerraformTFVars.Value(), CloudFormationParamVars: f.CloudformationParamVars.Value(), TfExcludeDownloaded: f.TerraformExcludeDownloaded.Value(), diff --git a/pkg/iac/scanners/helm/options.go b/pkg/iac/scanners/helm/options.go index 009809e734e6..6ac412bf1e34 100644 --- a/pkg/iac/scanners/helm/options.go +++ b/pkg/iac/scanners/helm/options.go @@ -49,3 +49,11 @@ func ScannerWithAPIVersions(values ...string) options.ScannerOption { } } } + +func ScannerWithKubeVersion(values string) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if helmScanner, ok := s.(ConfigurableHelmScanner); ok { + helmScanner.AddParserOptions(parser.OptionWithKubeVersion(values)) + } + } +} diff --git a/pkg/iac/scanners/helm/parser/option.go b/pkg/iac/scanners/helm/parser/option.go index 379cc9460979..6de98d765182 100644 --- a/pkg/iac/scanners/helm/parser/option.go +++ b/pkg/iac/scanners/helm/parser/option.go @@ -9,6 +9,7 @@ type ConfigurableHelmParser interface { SetFileValues(...string) SetStringValues(...string) SetAPIVersions(...string) + SetKubeVersion(string) } func OptionWithValuesFile(paths ...string) options.ParserOption { @@ -50,3 +51,11 @@ func OptionWithAPIVersions(values ...string) options.ParserOption { } } } + +func OptionWithKubeVersion(value string) options.ParserOption { + return func(p options.ConfigurableParser) { + if helmParser, ok := p.(ConfigurableHelmParser); ok { + helmParser.SetKubeVersion(value) + } + } +} diff --git a/pkg/iac/scanners/helm/parser/parser.go b/pkg/iac/scanners/helm/parser/parser.go index 20228258e5d3..7ae69e72eb95 100644 --- a/pkg/iac/scanners/helm/parser/parser.go +++ b/pkg/iac/scanners/helm/parser/parser.go @@ -18,6 +18,7 @@ import ( "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/releaseutil" @@ -41,6 +42,7 @@ type Parser struct { fileValues []string stringValues []string apiVersions []string + kubeVersion string } type ChartFile struct { @@ -76,7 +78,11 @@ func (p *Parser) SetAPIVersions(values ...string) { p.apiVersions = values } -func New(path string, opts ...options.ParserOption) *Parser { +func (p *Parser) SetKubeVersion(value string) { + p.kubeVersion = value +} + +func New(path string, opts ...options.ParserOption) (*Parser, error) { client := action.NewInstall(&action.Configuration{}) client.DryRun = true // don't do anything @@ -96,7 +102,16 @@ func New(path string, opts ...options.ParserOption) *Parser { p.helmClient.APIVersions = p.apiVersions } - return p + if p.kubeVersion != "" { + kubeVersion, err := chartutil.ParseKubeVersion(p.kubeVersion) + if err != nil { + return nil, err + } + + p.helmClient.KubeVersion = kubeVersion + } + + return p, nil } func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) error { diff --git a/pkg/iac/scanners/helm/parser/parser_test.go b/pkg/iac/scanners/helm/parser/parser_test.go index c146b8f9e18f..030b0efbb86f 100644 --- a/pkg/iac/scanners/helm/parser/parser_test.go +++ b/pkg/iac/scanners/helm/parser/parser_test.go @@ -12,7 +12,8 @@ import ( func TestParseFS(t *testing.T) { t.Run("source chart is located next to an same archived chart", func(t *testing.T) { - p := New(".") + p, err := New(".") + require.NoError(t, err) require.NoError(t, p.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", "chart-and-archived-chart")), ".")) expectedFiles := []string{ diff --git a/pkg/iac/scanners/helm/scanner.go b/pkg/iac/scanners/helm/scanner.go index e655932e01fd..b5e9686b3071 100644 --- a/pkg/iac/scanners/helm/scanner.go +++ b/pkg/iac/scanners/helm/scanner.go @@ -162,7 +162,10 @@ func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, path string) (scan.R } func (s *Scanner) getScanResults(path string, ctx context.Context, target fs.FS) (results []scan.Result, err error) { - helmParser := parser.New(path, s.parserOptions...) + helmParser, err := parser.New(path, s.parserOptions...) + if err != nil { + return nil, err + } if err := helmParser.ParseFS(ctx, target, path); err != nil { return nil, err diff --git a/pkg/iac/scanners/helm/test/option_test.go b/pkg/iac/scanners/helm/test/option_test.go index 2ad7efc64008..ab28f508e989 100644 --- a/pkg/iac/scanners/helm/test/option_test.go +++ b/pkg/iac/scanners/helm/test/option_test.go @@ -40,8 +40,9 @@ func Test_helm_parser_with_options_with_values_file(t *testing.T) { opts = append(opts, parser2.OptionWithValuesFile(test.valuesFile)) } - helmParser := parser2.New(chartName, opts...) - err := helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") + helmParser, err := parser2.New(chartName, opts...) + require.NoError(t, err) + err = helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") require.NoError(t, err) manifests, err := helmParser.RenderedChartFiles() require.NoError(t, err) @@ -94,8 +95,9 @@ func Test_helm_parser_with_options_with_set_value(t *testing.T) { opts = append(opts, parser2.OptionWithValues(test.values)) } - helmParser := parser2.New(chartName, opts...) - err := helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") + helmParser, err := parser2.New(chartName, opts...) + require.NoError(t, err) + err = helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") require.NoError(t, err) manifests, err := helmParser.RenderedChartFiles() require.NoError(t, err) @@ -143,8 +145,68 @@ func Test_helm_parser_with_options_with_api_versions(t *testing.T) { opts = append(opts, parser2.OptionWithAPIVersions(test.apiVersions...)) } - helmParser := parser2.New(chartName, opts...) - err := helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") + helmParser, err := parser2.New(chartName, opts...) + require.NoError(t, err) + err = helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") + require.NoError(t, err) + manifests, err := helmParser.RenderedChartFiles() + require.NoError(t, err) + + assert.Len(t, manifests, 1) + + for _, manifest := range manifests { + expectedPath := filepath.Join("testdata", "expected", "options", chartName, manifest.TemplateFilePath) + + expectedContent, err := os.ReadFile(expectedPath) + require.NoError(t, err) + + cleanExpected := strings.TrimSpace(strings.ReplaceAll(string(expectedContent), "\r\n", "\n")) + cleanActual := strings.TrimSpace(strings.ReplaceAll(manifest.ManifestContent, "\r\n", "\n")) + + assert.Equal(t, cleanExpected, cleanActual) + } + }) + } +} + +func Test_helm_parser_with_options_with_kube_versions(t *testing.T) { + + tests := []struct { + testName string + chartName string + kubeVersion string + error string + }{ + { + testName: "Parsing directory 'with-kube-version'", + chartName: "with-kube-version", + kubeVersion: "1.60", + }, + { + testName: "Parsing directory 'with-kube-version' with invalid kube version", + chartName: "with-kube-version", + kubeVersion: "a.b.c", + error: "Invalid Semantic Version", + }, + } + + for _, test := range tests { + t.Run(test.testName, func(t *testing.T) { + chartName := test.chartName + + t.Logf("Running test: %s", test.testName) + + var opts []options.ParserOption + + opts = append(opts, parser2.OptionWithKubeVersion(test.kubeVersion)) + + helmParser, err := parser2.New(chartName, opts...) + if test.error != "" { + require.EqualError(t, err, test.error) + return + } + require.NoError(t, err) + err = helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") require.NoError(t, err) manifests, err := helmParser.RenderedChartFiles() require.NoError(t, err) diff --git a/pkg/iac/scanners/helm/test/parser_test.go b/pkg/iac/scanners/helm/test/parser_test.go index 6d9f5ad0cff3..89667a211f83 100644 --- a/pkg/iac/scanners/helm/test/parser_test.go +++ b/pkg/iac/scanners/helm/test/parser_test.go @@ -35,8 +35,9 @@ func Test_helm_parser(t *testing.T) { t.Logf("Running test: %s", test.testName) - helmParser := parser.New(chartName) - err := helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") + helmParser, err := parser.New(chartName) + require.NoError(t, err) + err = helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") require.NoError(t, err) manifests, err := helmParser.RenderedChartFiles() require.NoError(t, err) @@ -73,8 +74,9 @@ func Test_helm_parser_where_name_non_string(t *testing.T) { t.Logf("Running test: %s", test.testName) - helmParser := parser.New(chartName) - err := helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") + helmParser, err := parser.New(chartName) + require.NoError(t, err) + err = helmParser.ParseFS(context.TODO(), os.DirFS(filepath.Join("testdata", chartName)), ".") require.NoError(t, err) } } @@ -163,8 +165,9 @@ func Test_helm_tarball_parser(t *testing.T) { testFs := os.DirFS(testTemp) - helmParser := parser.New(test.archiveFile) - err := helmParser.ParseFS(context.TODO(), testFs, ".") + helmParser, err := parser.New(test.archiveFile) + require.NoError(t, err) + err = helmParser.ParseFS(context.TODO(), testFs, ".") require.NoError(t, err) manifests, err := helmParser.RenderedChartFiles() diff --git a/pkg/iac/scanners/helm/test/testdata/expected/options/with-kube-version/templates/pdb.yaml b/pkg/iac/scanners/helm/test/testdata/expected/options/with-kube-version/templates/pdb.yaml new file mode 100644 index 000000000000..7c7ef5fd74d7 --- /dev/null +++ b/pkg/iac/scanners/helm/test/testdata/expected/options/with-kube-version/templates/pdb.yaml @@ -0,0 +1,17 @@ +# Source: with-api-version/templates/pdb.yaml +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: with-api-version + labels: + helm.sh/chart: with-api-version-0.1.0 + app.kubernetes.io/name: with-api-version + app.kubernetes.io/instance: with-api-version + app.kubernetes.io/version: "1.16.0" + app.kubernetes.io/managed-by: Helm +spec: + selector: + matchLabels: + app.kubernetes.io/name: with-api-version + app.kubernetes.io/instance: with-api-version + maxUnavailable: 0 diff --git a/pkg/iac/scanners/helm/test/testdata/with-kube-version/.helmignore b/pkg/iac/scanners/helm/test/testdata/with-kube-version/.helmignore new file mode 100644 index 000000000000..0e8a0eb36f4c --- /dev/null +++ b/pkg/iac/scanners/helm/test/testdata/with-kube-version/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/pkg/iac/scanners/helm/test/testdata/with-kube-version/Chart.yaml b/pkg/iac/scanners/helm/test/testdata/with-kube-version/Chart.yaml new file mode 100644 index 000000000000..99c44c125940 --- /dev/null +++ b/pkg/iac/scanners/helm/test/testdata/with-kube-version/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +name: with-api-version +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" + +kubeVersion: ">=1.60.0-0" diff --git a/pkg/iac/scanners/helm/test/testdata/with-kube-version/templates/_helpers.tpl b/pkg/iac/scanners/helm/test/testdata/with-kube-version/templates/_helpers.tpl new file mode 100644 index 000000000000..cab726131dc5 --- /dev/null +++ b/pkg/iac/scanners/helm/test/testdata/with-kube-version/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "with-api-version.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "with-api-version.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "with-api-version.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "with-api-version.labels" -}} +helm.sh/chart: {{ include "with-api-version.chart" . }} +{{ include "with-api-version.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "with-api-version.selectorLabels" -}} +app.kubernetes.io/name: {{ include "with-api-version.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "with-api-version.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "with-api-version.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/pkg/iac/scanners/helm/test/testdata/with-kube-version/templates/pdb.yaml b/pkg/iac/scanners/helm/test/testdata/with-kube-version/templates/pdb.yaml new file mode 100644 index 000000000000..0c063e06df97 --- /dev/null +++ b/pkg/iac/scanners/helm/test/testdata/with-kube-version/templates/pdb.yaml @@ -0,0 +1,11 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: {{ include "with-api-version.fullname" . }} + labels: + {{- include "with-api-version.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "with-api-version.selectorLabels" . | nindent 6 }} + maxUnavailable: 0 diff --git a/pkg/iac/scanners/helm/test/testdata/with-kube-version/values.yaml b/pkg/iac/scanners/helm/test/testdata/with-kube-version/values.yaml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 4c353f22c26e..6a30c9b69ec4 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -59,6 +59,8 @@ type ScannerOption struct { HelmValueFiles []string HelmFileValues []string HelmStringValues []string + HelmAPIVersions []string + HelmKubeVersion string TerraformTFVars []string CloudFormationParamVars []string TfExcludeDownloaded bool @@ -332,6 +334,14 @@ func addHelmOpts(opts []options.ScannerOption, scannerOption ScannerOption) []op opts = append(opts, helm2.ScannerWithStringValues(scannerOption.HelmStringValues...)) } + if len(scannerOption.HelmAPIVersions) > 0 { + opts = append(opts, helm2.ScannerWithAPIVersions(scannerOption.HelmAPIVersions...)) + } + + if scannerOption.HelmKubeVersion != "" { + opts = append(opts, helm2.ScannerWithKubeVersion(scannerOption.HelmKubeVersion)) + } + return opts }