mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
fix(misconf): do not skip loading documents from subdirectories (#8526)
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
@@ -3,26 +3,43 @@ package rego
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/open-policy-agent/opa/v1/loader"
|
||||
"github.com/open-policy-agent/opa/v1/storage"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/set"
|
||||
)
|
||||
|
||||
// initialize a store populated with OPA data files found in dataPaths
|
||||
func initStore(dataFS fs.FS, dataPaths, namespaces []string) (storage.Store, error) {
|
||||
// FilteredPaths will recursively find all file paths that contain a valid document
|
||||
// extension from the given list of data paths.
|
||||
allDocumentPaths, _ := loader.FilteredPathsFS(dataFS, dataPaths,
|
||||
func(abspath string, info os.FileInfo, depth int) bool {
|
||||
return !isDataFile(info)
|
||||
},
|
||||
)
|
||||
dataFiles := set.New[string]()
|
||||
|
||||
documents, err := loader.NewFileLoader().WithFS(dataFS).All(allDocumentPaths)
|
||||
// The virtual file system uses a slash ('/') as a path separator,
|
||||
// but OPA uses the filepath package, which is OS-dependent.
|
||||
// Therefore, we need to collect all the paths ourselves and pass them to OPA.
|
||||
for _, root := range dataPaths {
|
||||
if err := fs.WalkDir(dataFS, root, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if isDataFile(path) {
|
||||
dataFiles.Append(path)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
log.Error("Failed to collect data file paths", log.String("root", root), log.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
documents, err := loader.NewFileLoader().WithFS(dataFS).All(dataFiles.Items())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load documents: %w", err)
|
||||
}
|
||||
@@ -37,10 +54,10 @@ func initStore(dataFS fs.FS, dataPaths, namespaces []string) (storage.Store, err
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func isDataFile(fi fs.FileInfo) bool {
|
||||
return !fi.IsDir() && slices.Contains([]string{
|
||||
func isDataFile(filePath string) bool {
|
||||
return slices.Contains([]string{
|
||||
".yaml",
|
||||
".yml",
|
||||
".json",
|
||||
}, strings.ToLower(filepath.Ext(fi.Name())))
|
||||
}, strings.ToLower(path.Ext(filePath)))
|
||||
}
|
||||
|
||||
36
pkg/iac/rego/store_test.go
Normal file
36
pkg/iac/rego/store_test.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package rego
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/open-policy-agent/opa/v1/storage"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInitStore(t *testing.T) {
|
||||
fsys := fstest.MapFS{
|
||||
"test1.yml": &fstest.MapFile{Data: []byte("foo: 1")},
|
||||
"test2.yaml": &fstest.MapFile{Data: []byte("bar: 2")},
|
||||
"test3.json": &fstest.MapFile{Data: []byte(`{"baz": 3}`)},
|
||||
"dir/test4.yaml": &fstest.MapFile{Data: []byte("qux: 4")},
|
||||
}
|
||||
store, err := initStore(fsys, []string{"."}, []string{"builtin.aws.test", "user.test"})
|
||||
require.NoError(t, err)
|
||||
|
||||
tx, err := store.NewTransaction(t.Context())
|
||||
require.NoError(t, err)
|
||||
doc, err := store.Read(t.Context(), tx, storage.MustParsePath("/"))
|
||||
require.NoError(t, err)
|
||||
|
||||
expected := map[string]any{
|
||||
"foo": json.Number("1"),
|
||||
"bar": json.Number("2"),
|
||||
"baz": json.Number("3"),
|
||||
"qux": json.Number("4"),
|
||||
"namespaces": []any{"builtin.aws.test", "user.test"},
|
||||
}
|
||||
assert.Equal(t, expected, doc)
|
||||
}
|
||||
Reference in New Issue
Block a user