Skip to content

Commit de7eb13

Browse files
authored
fix(misconf): do not skip loading documents from subdirectories (#8526)
Signed-off-by: nikpivkin <[email protected]>
1 parent f07030d commit de7eb13

File tree

2 files changed

+67
-14
lines changed

2 files changed

+67
-14
lines changed

pkg/iac/rego/store.go

+31-14
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,43 @@ package rego
33
import (
44
"fmt"
55
"io/fs"
6-
"os"
7-
"path/filepath"
6+
"path"
87
"slices"
98
"strings"
109

1110
"github.com/open-policy-agent/opa/v1/loader"
1211
"github.com/open-policy-agent/opa/v1/storage"
12+
13+
"github.com/aquasecurity/trivy/pkg/log"
14+
"github.com/aquasecurity/trivy/pkg/set"
1315
)
1416

1517
// initialize a store populated with OPA data files found in dataPaths
1618
func initStore(dataFS fs.FS, dataPaths, namespaces []string) (storage.Store, error) {
17-
// FilteredPaths will recursively find all file paths that contain a valid document
18-
// extension from the given list of data paths.
19-
allDocumentPaths, _ := loader.FilteredPathsFS(dataFS, dataPaths,
20-
func(abspath string, info os.FileInfo, depth int) bool {
21-
return !isDataFile(info)
22-
},
23-
)
24-
25-
documents, err := loader.NewFileLoader().WithFS(dataFS).All(allDocumentPaths)
19+
dataFiles := set.New[string]()
20+
21+
// The virtual file system uses a slash ('/') as a path separator,
22+
// but OPA uses the filepath package, which is OS-dependent.
23+
// Therefore, we need to collect all the paths ourselves and pass them to OPA.
24+
for _, root := range dataPaths {
25+
if err := fs.WalkDir(dataFS, root, func(path string, d fs.DirEntry, err error) error {
26+
if err != nil {
27+
return err
28+
}
29+
if d.IsDir() {
30+
return nil
31+
}
32+
33+
if isDataFile(path) {
34+
dataFiles.Append(path)
35+
}
36+
return nil
37+
}); err != nil {
38+
log.Error("Failed to collect data file paths", log.String("root", root), log.Err(err))
39+
}
40+
}
41+
42+
documents, err := loader.NewFileLoader().WithFS(dataFS).All(dataFiles.Items())
2643
if err != nil {
2744
return nil, fmt.Errorf("load documents: %w", err)
2845
}
@@ -37,10 +54,10 @@ func initStore(dataFS fs.FS, dataPaths, namespaces []string) (storage.Store, err
3754
return store, nil
3855
}
3956

40-
func isDataFile(fi fs.FileInfo) bool {
41-
return !fi.IsDir() && slices.Contains([]string{
57+
func isDataFile(filePath string) bool {
58+
return slices.Contains([]string{
4259
".yaml",
4360
".yml",
4461
".json",
45-
}, strings.ToLower(filepath.Ext(fi.Name())))
62+
}, strings.ToLower(path.Ext(filePath)))
4663
}

pkg/iac/rego/store_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package rego
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
"testing/fstest"
7+
8+
"github.com/open-policy-agent/opa/v1/storage"
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestInitStore(t *testing.T) {
14+
fsys := fstest.MapFS{
15+
"test1.yml": &fstest.MapFile{Data: []byte("foo: 1")},
16+
"test2.yaml": &fstest.MapFile{Data: []byte("bar: 2")},
17+
"test3.json": &fstest.MapFile{Data: []byte(`{"baz": 3}`)},
18+
"dir/test4.yaml": &fstest.MapFile{Data: []byte("qux: 4")},
19+
}
20+
store, err := initStore(fsys, []string{"."}, []string{"builtin.aws.test", "user.test"})
21+
require.NoError(t, err)
22+
23+
tx, err := store.NewTransaction(t.Context())
24+
require.NoError(t, err)
25+
doc, err := store.Read(t.Context(), tx, storage.MustParsePath("/"))
26+
require.NoError(t, err)
27+
28+
expected := map[string]any{
29+
"foo": json.Number("1"),
30+
"bar": json.Number("2"),
31+
"baz": json.Number("3"),
32+
"qux": json.Number("4"),
33+
"namespaces": []any{"builtin.aws.test", "user.test"},
34+
}
35+
assert.Equal(t, expected, doc)
36+
}

0 commit comments

Comments
 (0)