diff --git a/pkg/rego/load.go b/pkg/rego/load.go index 6d26eb50e..de56de597 100644 --- a/pkg/rego/load.go +++ b/pkg/rego/load.go @@ -88,16 +88,16 @@ func (s *Scanner) LoadPolicies(loadEmbedded bool, srcFS fs.FS, paths []string, r s.debug.Log("Overriding filesystem for policies!") srcFS = s.policyFS } + loadedLibs, errLoad := loadEmbeddedLibraries() + if errLoad != nil { + return fmt.Errorf("failed to load embedded rego libraries: %w", errLoad) + } + for name, policy := range loadedLibs { + s.policies[name] = policy + } + s.debug.Log("Loaded %d embedded libraries.", len(loadedLibs)) if loadEmbedded { - loadedLibs, err := loadEmbeddedLibraries() - if err != nil { - return fmt.Errorf("failed to load embedded rego libraries: %w", err) - } - for name, policy := range loadedLibs { - s.policies[name] = policy - } - s.debug.Log("Loaded %d embedded libraries.", len(loadedLibs)) loaded, err := loadEmbeddedPolicies() if err != nil { return fmt.Errorf("failed to load embedded rego policies: %w", err) diff --git a/pkg/scanners/kubernetes/scanner_test.go b/pkg/scanners/kubernetes/scanner_test.go index c68396b21..67edc255a 100644 --- a/pkg/scanners/kubernetes/scanner_test.go +++ b/pkg/scanners/kubernetes/scanner_test.go @@ -31,183 +31,6 @@ spec: - command: ["sh", "-c", "echo 'Hello' && sleep 1h"] image: busybox name: hello -`, - "/rules/lib.k8s.rego": ` -package lib.kubernetes - -default is_gatekeeper = false - -is_gatekeeper { - has_field(input, "review") - has_field(input.review, "object") -} - -object = input { - not is_gatekeeper -} - -object = input.review.object { - is_gatekeeper -} - -format(msg) = gatekeeper_format { - is_gatekeeper - gatekeeper_format = {"msg": msg} -} - -format(msg) = msg { - not is_gatekeeper -} - -name = object.metadata.name - -default namespace = "default" - -namespace = object.metadata.namespace - -#annotations = object.metadata.annotations - -kind = object.kind - -is_pod { - kind = "Pod" -} - -is_cronjob { - kind = "CronJob" -} - -default is_controller = false - -is_controller { - kind = "Deployment" -} - -is_controller { - kind = "StatefulSet" -} - -is_controller { - kind = "DaemonSet" -} - -is_controller { - kind = "ReplicaSet" -} - -is_controller { - kind = "ReplicationController" -} - -is_controller { - kind = "Job" -} - -split_image(image) = [image, "latest"] { - not contains(image, ":") -} - -split_image(image) = [image_name, tag] { - [image_name, tag] = split(image, ":") -} - -pod_containers(pod) = all_containers { - keys = {"containers", "initContainers"} - all_containers = [c | keys[k]; c = pod.spec[k][_]] -} - -containers[container] { - pods[pod] - all_containers = pod_containers(pod) - container = all_containers[_] -} - -containers[container] { - all_containers = pod_containers(object) - container = all_containers[_] -} - -pods[pod] { - is_pod - pod = object -} - -pods[pod] { - is_controller - pod = object.spec.template -} - -pods[pod] { - is_cronjob - pod = object.spec.jobTemplate.spec.template -} - -volumes[volume] { - pods[pod] - volume = pod.spec.volumes[_] -} - -dropped_capability(container, cap) { - container.securityContext.capabilities.drop[_] == cap -} - -added_capability(container, cap) { - container.securityContext.capabilities.add[_] == cap -} - -has_field(obj, field) { - obj[field] -} - -no_read_only_filesystem(c) { - not has_field(c, "securityContext") -} - -no_read_only_filesystem(c) { - has_field(c, "securityContext") - not has_field(c.securityContext, "readOnlyRootFilesystem") -} - -priviledge_escalation_allowed(c) { - not has_field(c, "securityContext") -} - -priviledge_escalation_allowed(c) { - has_field(c, "securityContext") - has_field(c.securityContext, "allowPrivilegeEscalation") -} - -annotations[annotation] { - pods[pod] - annotation = pod.metadata.annotations -} - -host_ipcs[host_ipc] { - pods[pod] - host_ipc = pod.spec.hostIPC -} - -host_networks[host_network] { - pods[pod] - host_network = pod.spec.hostNetwork -} - -host_pids[host_pid] { - pods[pod] - host_pid = pod.spec.hostPID -} - -host_aliases[host_alias] { - pods[pod] - host_alias = pod.spec -} -`, - "/rules/lib.util.rego": ` -package lib.utils - -has_key(x, k) { - _ = x[k] -} `, "/rules/rule.rego": ` package builtin.kubernetes.KSV011 diff --git a/pkg/scanners/rbac/scanner_test.go b/pkg/scanners/rbac/scanner_test.go index 3bcda41c1..0a600ebd0 100644 --- a/pkg/scanners/rbac/scanner_test.go +++ b/pkg/scanners/rbac/scanner_test.go @@ -34,183 +34,6 @@ rules: - secrets verbs: - list -`, - "/rules/lib.k8s.rego": ` -package lib.kubernetes - -default is_gatekeeper = false - -is_gatekeeper { - has_field(input, "review") - has_field(input.review, "object") -} - -object = input { - not is_gatekeeper -} - -object = input.review.object { - is_gatekeeper -} - -format(msg) = gatekeeper_format { - is_gatekeeper - gatekeeper_format = {"msg": msg} -} - -format(msg) = msg { - not is_gatekeeper -} - -name = object.metadata.name - -default namespace = "default" - -namespace = object.metadata.namespace - -#annotations = object.metadata.annotations - -kind = object.kind - -is_pod { - kind = "Pod" -} - -is_cronjob { - kind = "CronJob" -} - -default is_controller = false - -is_controller { - kind = "Deployment" -} - -is_controller { - kind = "StatefulSet" -} - -is_controller { - kind = "DaemonSet" -} - -is_controller { - kind = "ReplicaSet" -} - -is_controller { - kind = "ReplicationController" -} - -is_controller { - kind = "Job" -} - -split_image(image) = [image, "latest"] { - not contains(image, ":") -} - -split_image(image) = [image_name, tag] { - [image_name, tag] = split(image, ":") -} - -pod_containers(pod) = all_containers { - keys = {"containers", "initContainers"} - all_containers = [c | keys[k]; c = pod.spec[k][_]] -} - -containers[container] { - pods[pod] - all_containers = pod_containers(pod) - container = all_containers[_] -} - -containers[container] { - all_containers = pod_containers(object) - container = all_containers[_] -} - -pods[pod] { - is_pod - pod = object -} - -pods[pod] { - is_controller - pod = object.spec.template -} - -pods[pod] { - is_cronjob - pod = object.spec.jobTemplate.spec.template -} - -volumes[volume] { - pods[pod] - volume = pod.spec.volumes[_] -} - -dropped_capability(container, cap) { - container.securityContext.capabilities.drop[_] == cap -} - -added_capability(container, cap) { - container.securityContext.capabilities.add[_] == cap -} - -has_field(obj, field) { - obj[field] -} - -no_read_only_filesystem(c) { - not has_field(c, "securityContext") -} - -no_read_only_filesystem(c) { - has_field(c, "securityContext") - not has_field(c.securityContext, "readOnlyRootFilesystem") -} - -priviledge_escalation_allowed(c) { - not has_field(c, "securityContext") -} - -priviledge_escalation_allowed(c) { - has_field(c, "securityContext") - has_field(c.securityContext, "allowPrivilegeEscalation") -} - -annotations[annotation] { - pods[pod] - annotation = pod.metadata.annotations -} - -host_ipcs[host_ipc] { - pods[pod] - host_ipc = pod.spec.hostIPC -} - -host_networks[host_network] { - pods[pod] - host_network = pod.spec.hostNetwork -} - -host_pids[host_pid] { - pods[pod] - host_pid = pod.spec.hostPID -} - -host_aliases[host_alias] { - pods[pod] - host_alias = pod.spec -} -`, - "/rules/lib.util.rego": ` -package lib.utils - -has_key(x, k) { - _ = x[k] -} `, "/rules/rule.rego": ` package builtin.kubernetes.KSV041 diff --git a/test/docker_test.go b/test/docker_test.go index 44e38c97a..708b91ed6 100644 --- a/test/docker_test.go +++ b/test/docker_test.go @@ -3,9 +3,16 @@ package test import ( "context" "fmt" + "io/ioutil" "os" + "path" + "path/filepath" + "strings" "testing" + "github.com/liamg/memoryfs" + "github.com/open-policy-agent/opa/bundle" + "github.com/aquasecurity/defsec/pkg/scanners/options" "github.com/aquasecurity/defsec/pkg/scan" @@ -21,13 +28,23 @@ func Test_Docker_RegoPoliciesFromDisk(t *testing.T) { entries, err := os.ReadDir("./testdata/dockerfile") require.NoError(t, err) + policiesPath, err := filepath.Abs("../internal/rules") + require.NoError(t, err) scanner := dockerfile.NewScanner( - options.ScannerWithPolicyDirs("internal/rules"), + options.ScannerWithPolicyDirs(filepath.Base(policiesPath)), ) + memfs := memoryfs.New() + // add policies + err = addFilesToMemFS(memfs, true, policiesPath) + require.NoError(t, err) - srcFS := os.DirFS("../") + // add test data + testDataPath, err := filepath.Abs("./testdata/dockerfile") + require.NoError(t, err) + err = addFilesToMemFS(memfs, false, testDataPath) + require.NoError(t, err) - results, err := scanner.ScanFS(context.TODO(), srcFS, "test/testdata/dockerfile") + results, err := scanner.ScanFS(context.TODO(), memfs, filepath.Base(testDataPath)) require.NoError(t, err) for _, entry := range entries { @@ -44,8 +61,7 @@ func Test_Docker_RegoPoliciesFromDisk(t *testing.T) { assert.Greater(t, result.Range().GetStartLine(), 0) assert.Greater(t, result.Range().GetEndLine(), 0) } - expectedFile := fmt.Sprintf("test/testdata/dockerfile/%s/Dockerfile.denied", entry.Name()) - if result.Range().GetFilename() != expectedFile { + if !strings.HasSuffix(result.Range().GetFilename(), entry.Name()) { continue } matched++ @@ -94,3 +110,54 @@ func Test_Docker_RegoPoliciesEmbedded(t *testing.T) { }) } } + +func addFilesToMemFS(memfs *memoryfs.FS, typePolicy bool, folderName string) error { + base := filepath.Base(folderName) + if err := memfs.MkdirAll(base, 0o700); err != nil { + return err + } + err := filepath.Walk(filepath.FromSlash(folderName), + func(fpath string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + if typePolicy && !isRegoFile(info.Name()) { + return nil + } + // ignore embedded lib rego to avoid duplicate default definition + if strings.Contains(fpath, filepath.FromSlash("/lib/")) { + return nil + } + data, err := ioutil.ReadFile(fpath) + if err != nil { + return err + } + fileName := getFileName(fpath, info, typePolicy) + if err := memfs.WriteFile(path.Join(base, fileName), data, 0o644); err != nil { + return err + } + return nil + }) + + if err != nil { + return err + } + return nil +} + +func getFileName(fpath string, info os.FileInfo, typePolicy bool) string { + pathParts := strings.Split(fpath, filepath.FromSlash("/")) + fileName := info.Name() + // append test data folder to input file name example Dockerfile.allowed_DS001 + if len(pathParts) > 2 && !typePolicy { + fileName = fmt.Sprintf("%s_%s", fileName, pathParts[len(pathParts)-2]) + } + return fileName +} + +func isRegoFile(name string) bool { + return strings.HasSuffix(name, bundle.RegoExt) && !strings.HasSuffix(name, "_test"+bundle.RegoExt) +}