diff --git a/pkg/controller/policies_synthesizer.go b/pkg/controller/policies_synthesizer.go index 6734f2a..c7fe2ef 100644 --- a/pkg/controller/policies_synthesizer.go +++ b/pkg/controller/policies_synthesizer.go @@ -174,7 +174,10 @@ func (ps *PoliciesSynthesizer) extractConnectionsFromInfos(infos []*resource.Inf for _, info := range infos { err := resFinder.parseInfo(info) if err != nil { - kind := info.Object.GetObjectKind().GroupVersionKind().Kind + kind := "" + if info != nil && info.Object != nil { + kind = info.Object.GetObjectKind().GroupVersionKind().Kind + } fileErrors = appendAndLogNewError(fileErrors, failedScanningResource(kind, info.Source, err), ps.logger) } } diff --git a/pkg/controller/policies_synthesizer_test.go b/pkg/controller/policies_synthesizer_test.go index f144c9e..afbc0c5 100644 --- a/pkg/controller/policies_synthesizer_test.go +++ b/pkg/controller/policies_synthesizer_test.go @@ -16,8 +16,11 @@ import ( "strings" "testing" + "github.com/np-guard/netpol-analyzer/pkg/netpol/manifests/fsscanner" "github.com/stretchr/testify/require" core "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/cli-runtime/pkg/resource" ) func TestPoliciesSynthesizerAPI(t *testing.T) { @@ -49,6 +52,49 @@ func TestPoliciesSynthesizerAPI(t *testing.T) { os.Remove(outFile) } +func TestPoliciesSynthesizerAPIWithInfos(t *testing.T) { + dirPath := filepath.Join(getTestsDir(), "k8s_wordpress_example") + infos, errs := fsscanner.GetResourceInfosFromDirPath([]string{dirPath}, true, false) + require.Empty(t, errs) + + synthesizer := NewPoliciesSynthesizer() + policies, err := synthesizer.PoliciesFromInfos(infos) + require.Nil(t, err) + require.Empty(t, synthesizer.Errors()) + require.Len(t, policies, 3) // wordpress, mysql and namespace default deny + + conns, err := synthesizer.ConnectionsFromInfos(infos) + require.Nil(t, err) + require.Empty(t, synthesizer.Errors()) + require.Len(t, conns, 2) // internet->wordpress and wordpress->mysql +} + +func TestPoliciesSynthesizerAPIWithInfosEmptySlice(t *testing.T) { + noInfos := []*resource.Info{} + + synthesizer := NewPoliciesSynthesizer() + _, err := synthesizer.PoliciesFromInfos(noInfos) + require.NotNil(t, err) + + _, err = synthesizer.ConnectionsFromInfos(noInfos) + require.NotNil(t, err) +} + +func TestPoliciesSynthesizerAPIWithInfosBadInfo(t *testing.T) { + badInfo1 := resource.Info{} + badInfo2 := resource.Info{Object: &unstructured.Unstructured{}} + badInfo3 := resource.Info{Object: &unstructured.Unstructured{Object: map[string]interface{}{"kind": "bad"}}} + badInfo4 := resource.Info{Object: &unstructured.Unstructured{Object: map[string]interface{}{"kind": "Service", "spec": []string{}}}} + badInfos := []*resource.Info{&badInfo1, &badInfo2, &badInfo3, &badInfo4} + + synthesizer := NewPoliciesSynthesizer() + _, err := synthesizer.PoliciesFromInfos(badInfos) + require.NotNil(t, err) + + _, err = synthesizer.ConnectionsFromInfos(badInfos) + require.NotNil(t, err) +} + func TestPoliciesSynthesizerAPIMultiplePaths(t *testing.T) { dirPath1 := filepath.Join(getTestsDir(), "k8s_wordpress_example", "mysql-deployment.yaml") dirPath2 := filepath.Join(getTestsDir(), "k8s_wordpress_example", "wordpress-deployment.yaml") @@ -57,6 +103,11 @@ func TestPoliciesSynthesizerAPIMultiplePaths(t *testing.T) { require.Nilf(t, err, "expected no fatal errors, but got %v", err) require.Empty(t, synthesizer.Errors()) require.Len(t, netpols, 3) + + conns, err := synthesizer.ConnectionsFromFolderPath(dirPath2) + require.Nilf(t, err, "expected no fatal errors, but got %v", err) + require.Empty(t, synthesizer.Errors()) + require.Len(t, conns, 1) } func TestPoliciesSynthesizerAPIDnsPort(t *testing.T) { diff --git a/pkg/controller/resource_finder.go b/pkg/controller/resource_finder.go index 8653d9b..d542252 100644 --- a/pkg/controller/resource_finder.go +++ b/pkg/controller/resource_finder.go @@ -116,7 +116,7 @@ func (rf *resourceFinder) searchForManifests(repoDir string) ([]string, []FilePr // parseK8sYaml takes a YAML file and attempts to parse each of its documents into // one of the relevant k8s resources func (rf *resourceFinder) parseK8sYaml(mfp, relMfp string) []FileProcessingError { - infos, errs := fsscanner.GetResourceInfosFromDirPath([]string{mfp}, true, rf.stopOn1stErr) + infos, errs := fsscanner.GetResourceInfosFromDirPath([]string{mfp}, false, rf.stopOn1stErr) fileProcessingErrors := []FileProcessingError{} for _, err := range errs { fileProcessingErrors = appendAndLogNewError(fileProcessingErrors, failedReadingFile(mfp, err), rf.logger) @@ -140,10 +140,18 @@ func (rf *resourceFinder) parseK8sYaml(mfp, relMfp string) []FileProcessingError // the workload resource slice, the Service resource slice and the ConfigMaps resource slice // It also updates the set of services to be exposed when parsing Ingress or OpenShift Routes func (rf *resourceFinder) parseInfo(info *resource.Info) error { + if info == nil || info.Object == nil { + return fmt.Errorf("a bad Info object - Object field is Nil") + } + kind := info.Object.GetObjectKind().GroupVersionKind().Kind if !acceptedK8sTypes.MatchString(kind) { + msg := fmt.Sprintf("skipping object with type: %s", kind) resourcePath := info.Source - rf.logger.Infof("in file: %s, skipping object with type: %s", resourcePath, kind) + if resourcePath != "" { + msg = fmt.Sprintf("in file: %s, %s", resourcePath, msg) + } + rf.logger.Infof(msg) return nil }