Skip to content

Commit f148eb1

Browse files
authored
fix(helm): scan the subcharts once (#6382)
1 parent 97f95c4 commit f148eb1

File tree

7 files changed

+92
-9
lines changed

7 files changed

+92
-9
lines changed

pkg/iac/scanners/helm/scanner.go

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io/fs"
88
"path/filepath"
99
"strings"
10+
"sync"
1011

1112
"github.com/liamg/memoryfs"
1213

@@ -38,6 +39,8 @@ type Scanner struct {
3839
skipRequired bool
3940
frameworks []framework.Framework
4041
spec string
42+
regoScanner *rego.Scanner
43+
mu sync.Mutex
4144
}
4245

4346
func (s *Scanner) SetSpec(spec string) {
@@ -120,6 +123,10 @@ func (s *Scanner) SetRegoErrorLimit(_ int) {}
120123

121124
func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, path string) (scan.Results, error) {
122125

126+
if err := s.initRegoScanner(target); err != nil {
127+
return nil, fmt.Errorf("failed to init rego scanner: %w", err)
128+
}
129+
123130
var results []scan.Result
124131
if err := fs.WalkDir(target, path, func(path string, d fs.DirEntry, err error) error {
125132
select {
@@ -150,6 +157,7 @@ func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, path string) (scan.R
150157
} else {
151158
results = append(results, scanResults...)
152159
}
160+
return fs.SkipDir
153161
}
154162

155163
return nil
@@ -174,14 +182,6 @@ func (s *Scanner) getScanResults(path string, ctx context.Context, target fs.FS)
174182
return nil, nil
175183
}
176184

177-
regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...)
178-
policyFS := target
179-
if s.policyFS != nil {
180-
policyFS = s.policyFS
181-
}
182-
if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, policyFS, s.policyDirs, s.policyReaders); err != nil {
183-
return nil, fmt.Errorf("policies load: %w", err)
184-
}
185185
for _, file := range chartFiles {
186186
file := file
187187
s.debug.Log("Processing rendered chart file: %s", file.TemplateFilePath)
@@ -191,7 +191,7 @@ func (s *Scanner) getScanResults(path string, ctx context.Context, target fs.FS)
191191
return nil, fmt.Errorf("unmarshal yaml: %w", err)
192192
}
193193
for _, manifest := range manifests {
194-
fileResults, err := regoScanner.ScanInput(ctx, rego.Input{
194+
fileResults, err := s.regoScanner.ScanInput(ctx, rego.Input{
195195
Path: file.TemplateFilePath,
196196
Contents: manifest,
197197
FS: target,
@@ -219,3 +219,18 @@ func (s *Scanner) getScanResults(path string, ctx context.Context, target fs.FS)
219219
}
220220
return results, nil
221221
}
222+
223+
func (s *Scanner) initRegoScanner(srcFS fs.FS) error {
224+
s.mu.Lock()
225+
defer s.mu.Unlock()
226+
if s.regoScanner != nil {
227+
return nil
228+
}
229+
regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...)
230+
regoScanner.SetParentDebugLogger(s.debug)
231+
if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil {
232+
return err
233+
}
234+
s.regoScanner = regoScanner
235+
return nil
236+
}

pkg/iac/scanners/helm/test/scanner_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,44 @@ deny[res] {
318318
require.NoError(t, err)
319319
assert.NotNil(t, code)
320320
}
321+
322+
func TestScanSubchartOnce(t *testing.T) {
323+
check := `# METADATA
324+
# title: "Test rego"
325+
# description: "Test rego"
326+
# scope: package
327+
# schemas:
328+
# - input: schema["kubernetes"]
329+
# custom:
330+
# id: ID001
331+
# avd_id: AVD-USR-ID001
332+
# severity: LOW
333+
# input:
334+
# selector:
335+
# - type: kubernetes
336+
# subtypes:
337+
# - kind: pod
338+
package user.kubernetes.ID001
339+
340+
import data.lib.kubernetes
341+
342+
deny[res] {
343+
container := kubernetes.containers[_]
344+
container.securityContext.readOnlyRootFilesystem == false
345+
res := result.new("set 'securityContext.readOnlyRootFilesystem' to true", container)
346+
}
347+
`
348+
349+
scanner := helm.New(
350+
options.ScannerWithEmbeddedPolicies(false),
351+
options.ScannerWithEmbeddedLibraries(true),
352+
options.ScannerWithPolicyNamespaces("user"),
353+
options.ScannerWithPolicyReader(strings.NewReader(check)),
354+
)
355+
356+
results, err := scanner.ScanFS(context.TODO(), os.DirFS("testdata/with-subchart"), ".")
357+
require.NoError(t, err)
358+
require.Len(t, results, 1)
359+
360+
assert.Len(t, results.GetFailed(), 0)
361+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: v2
2+
name: test
3+
description: A Helm chart for Kubernetes
4+
type: application
5+
version: 0.1.0
6+
appVersion: "1.16.0"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: v2
2+
name: nginx
3+
description: A Helm chart for Kubernetes
4+
type: application
5+
version: 0.1.0
6+
appVersion: "1.16.0"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
apiVersion: v1
2+
kind: Pod
3+
metadata:
4+
name: nginx
5+
spec:
6+
containers:
7+
- name: nginx
8+
image: nginx:1.14.2
9+
ports:
10+
- containerPort: 8080
11+
securityContext:
12+
readOnlyRootFilesystem: {{ .Values.readOnlyFs }}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
readOnlyFs: false
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
nginx:
2+
readOnlyFs: true

0 commit comments

Comments
 (0)