github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/test/docker_test.go (about)

     1  package test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"path"
     8  	"path/filepath"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/liamg/memoryfs"
    13  	"github.com/open-policy-agent/opa/bundle"
    14  
    15  	"github.com/khulnasoft-lab/defsec/pkg/scanners/options"
    16  
    17  	"github.com/khulnasoft-lab/defsec/pkg/scan"
    18  	"github.com/khulnasoft-lab/defsec/pkg/scanners/dockerfile"
    19  
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  func Test_Docker_RegoPoliciesFromDisk(t *testing.T) {
    25  	t.Parallel()
    26  
    27  	entries, err := os.ReadDir("./testdata/dockerfile")
    28  	require.NoError(t, err)
    29  
    30  	policiesPath, err := filepath.Abs("../rules")
    31  	require.NoError(t, err)
    32  	scanner := dockerfile.NewScanner(
    33  		options.ScannerWithPolicyDirs(filepath.Base(policiesPath)),
    34  	)
    35  	memfs := memoryfs.New()
    36  	// add policies
    37  	err = addFilesToMemFS(memfs, true, policiesPath)
    38  	require.NoError(t, err)
    39  
    40  	// add test data
    41  	testDataPath, err := filepath.Abs("./testdata/dockerfile")
    42  	require.NoError(t, err)
    43  	err = addFilesToMemFS(memfs, false, testDataPath)
    44  	require.NoError(t, err)
    45  
    46  	results, err := scanner.ScanFS(context.TODO(), memfs, filepath.Base(testDataPath))
    47  	require.NoError(t, err)
    48  
    49  	for _, entry := range entries {
    50  		if !entry.IsDir() {
    51  			continue
    52  		}
    53  		t.Run(entry.Name(), func(t *testing.T) {
    54  			require.NoError(t, err)
    55  			t.Run(entry.Name(), func(t *testing.T) {
    56  				var matched int
    57  				for _, result := range results {
    58  					if result.Rule().HasID(entry.Name()) && result.Status() == scan.StatusFailed {
    59  						if result.Description() != "Specify at least 1 USER command in Dockerfile with non-root user as argument" {
    60  							assert.Greater(t, result.Range().GetStartLine(), 0)
    61  							assert.Greater(t, result.Range().GetEndLine(), 0)
    62  						}
    63  						if !strings.HasSuffix(result.Range().GetFilename(), entry.Name()) {
    64  							continue
    65  						}
    66  						matched++
    67  					}
    68  				}
    69  				assert.Equal(t, 1, matched, "Rule should be matched once")
    70  			})
    71  
    72  		})
    73  	}
    74  }
    75  
    76  func Test_Docker_RegoPoliciesEmbedded(t *testing.T) {
    77  	t.Parallel()
    78  
    79  	entries, err := os.ReadDir("./testdata/dockerfile")
    80  	require.NoError(t, err)
    81  
    82  	scanner := dockerfile.NewScanner(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true))
    83  	srcFS := os.DirFS("../")
    84  
    85  	results, err := scanner.ScanFS(context.TODO(), srcFS, "test/testdata/dockerfile")
    86  	require.NoError(t, err)
    87  
    88  	for _, entry := range entries {
    89  		if !entry.IsDir() {
    90  			continue
    91  		}
    92  		t.Run(entry.Name(), func(t *testing.T) {
    93  			require.NoError(t, err)
    94  			t.Run(entry.Name(), func(t *testing.T) {
    95  				var matched bool
    96  				for _, result := range results {
    97  					if result.Rule().HasID(entry.Name()) && result.Status() == scan.StatusFailed {
    98  						if result.Description() != "Specify at least 1 USER command in Dockerfile with non-root user as argument" {
    99  							assert.Greater(t, result.Range().GetStartLine(), 0)
   100  							assert.Greater(t, result.Range().GetEndLine(), 0)
   101  						}
   102  						assert.Equal(t, fmt.Sprintf("test/testdata/dockerfile/%s/Dockerfile.denied", entry.Name()), result.Range().GetFilename())
   103  						matched = true
   104  					}
   105  				}
   106  				assert.True(t, matched)
   107  			})
   108  
   109  		})
   110  	}
   111  }
   112  
   113  func addFilesToMemFS(memfs *memoryfs.FS, typePolicy bool, folderName string) error {
   114  	base := filepath.Base(folderName)
   115  	if err := memfs.MkdirAll(base, 0o700); err != nil {
   116  		return err
   117  	}
   118  	err := filepath.Walk(filepath.FromSlash(folderName),
   119  		func(fpath string, info os.FileInfo, err error) error {
   120  			if err != nil {
   121  				return err
   122  			}
   123  			if info.IsDir() {
   124  				return nil
   125  			}
   126  			if typePolicy && !isRegoFile(info.Name()) {
   127  				return nil
   128  			}
   129  			data, err := os.ReadFile(fpath)
   130  			if err != nil {
   131  				return err
   132  			}
   133  			fileName := getFileName(fpath, info, typePolicy)
   134  			if err := memfs.WriteFile(path.Join(base, fileName), data, 0o644); err != nil {
   135  				return err
   136  			}
   137  			return nil
   138  		})
   139  
   140  	if err != nil {
   141  		return err
   142  	}
   143  	return nil
   144  }
   145  
   146  func getFileName(fpath string, info os.FileInfo, typePolicy bool) string {
   147  	pathParts := strings.Split(fpath, filepath.FromSlash("/"))
   148  	fileName := info.Name()
   149  	// append test data folder to input file name example Dockerfile.allowed_DS001
   150  	if len(pathParts) > 2 && !typePolicy {
   151  		fileName = fmt.Sprintf("%s_%s", fileName, pathParts[len(pathParts)-2])
   152  	}
   153  	return fileName
   154  }
   155  
   156  func isRegoFile(name string) bool {
   157  	return strings.HasSuffix(name, bundle.RegoExt) && !strings.HasSuffix(name, "_test"+bundle.RegoExt)
   158  }