github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/analyzer/secret/secret_test.go (about)

     1  package secret_test
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/devseccon/trivy/pkg/fanal/analyzer"
    12  	"github.com/devseccon/trivy/pkg/fanal/analyzer/secret"
    13  	"github.com/devseccon/trivy/pkg/fanal/types"
    14  )
    15  
    16  func TestSecretAnalyzer(t *testing.T) {
    17  	wantFinding1 := types.SecretFinding{
    18  		RuleID:    "rule1",
    19  		Category:  "general",
    20  		Title:     "Generic Rule",
    21  		Severity:  "HIGH",
    22  		StartLine: 2,
    23  		EndLine:   2,
    24  		Match:     "generic secret line secret=\"*********\"",
    25  		Code: types.Code{
    26  			Lines: []types.Line{
    27  				{
    28  					Number:      1,
    29  					Content:     "--- ignore block start ---",
    30  					IsCause:     false,
    31  					Annotation:  "",
    32  					Truncated:   false,
    33  					Highlighted: "--- ignore block start ---",
    34  					FirstCause:  false,
    35  					LastCause:   false,
    36  				},
    37  				{
    38  					Number:      2,
    39  					Content:     "generic secret line secret=\"*********\"",
    40  					IsCause:     true,
    41  					Annotation:  "",
    42  					Truncated:   false,
    43  					Highlighted: "generic secret line secret=\"*********\"",
    44  					FirstCause:  true,
    45  					LastCause:   true,
    46  				},
    47  				{
    48  					Number:      3,
    49  					Content:     "--- ignore block stop ---",
    50  					IsCause:     false,
    51  					Annotation:  "",
    52  					Truncated:   false,
    53  					Highlighted: "--- ignore block stop ---",
    54  					FirstCause:  false,
    55  					LastCause:   false,
    56  				},
    57  			},
    58  		},
    59  	}
    60  	wantFinding2 := types.SecretFinding{
    61  		RuleID:    "rule1",
    62  		Category:  "general",
    63  		Title:     "Generic Rule",
    64  		Severity:  "HIGH",
    65  		StartLine: 4,
    66  		EndLine:   4,
    67  		Match:     "secret=\"**********\"",
    68  		Code: types.Code{
    69  			Lines: []types.Line{
    70  				{
    71  					Number:      2,
    72  					Content:     "generic secret line secret=\"*********\"",
    73  					IsCause:     false,
    74  					Highlighted: "generic secret line secret=\"*********\"",
    75  				},
    76  				{
    77  					Number:      3,
    78  					Content:     "--- ignore block stop ---",
    79  					IsCause:     false,
    80  					Highlighted: "--- ignore block stop ---",
    81  				},
    82  				{
    83  					Number:      4,
    84  					Content:     "secret=\"**********\"",
    85  					IsCause:     true,
    86  					Highlighted: "secret=\"**********\"",
    87  					FirstCause:  true,
    88  					LastCause:   true,
    89  				},
    90  				{
    91  					Number:      5,
    92  					Content:     "credentials: { user: \"username\" password: \"123456789\" }",
    93  					Highlighted: "credentials: { user: \"username\" password: \"123456789\" }",
    94  				},
    95  			},
    96  		},
    97  	}
    98  	tests := []struct {
    99  		name       string
   100  		configPath string
   101  		filePath   string
   102  		dir        string
   103  		want       *analyzer.AnalysisResult
   104  	}{
   105  		{
   106  			name:       "return results",
   107  			configPath: "testdata/config.yaml",
   108  			filePath:   "testdata/secret.txt",
   109  			dir:        ".",
   110  			want: &analyzer.AnalysisResult{
   111  				Secrets: []types.Secret{
   112  					{
   113  						FilePath: "testdata/secret.txt",
   114  						Findings: []types.SecretFinding{wantFinding1, wantFinding2},
   115  					},
   116  				},
   117  			},
   118  		},
   119  		{
   120  			name:       "image scan return result",
   121  			configPath: "testdata/image-config.yaml",
   122  			filePath:   "testdata/secret.txt",
   123  			want: &analyzer.AnalysisResult{
   124  				Secrets: []types.Secret{
   125  					{
   126  						FilePath: "/testdata/secret.txt",
   127  						Findings: []types.SecretFinding{wantFinding1, wantFinding2},
   128  					},
   129  				},
   130  			},
   131  		},
   132  		{
   133  			name:       "image scan return nil",
   134  			configPath: "testdata/image-config.yaml",
   135  			filePath:   "testdata/secret.doc",
   136  			want:       nil,
   137  		},
   138  		{
   139  			name:       "return nil when no results",
   140  			configPath: "",
   141  			filePath:   "testdata/secret.txt",
   142  			want:       nil,
   143  		},
   144  		{
   145  			name:       "skip binary file",
   146  			configPath: "",
   147  			filePath:   "testdata/binaryfile",
   148  			want:       nil,
   149  		},
   150  	}
   151  
   152  	for _, tt := range tests {
   153  		t.Run(tt.name, func(t *testing.T) {
   154  			a := &secret.SecretAnalyzer{}
   155  			err := a.Init(analyzer.AnalyzerOptions{
   156  				SecretScannerOption: analyzer.SecretScannerOption{ConfigPath: tt.configPath},
   157  			})
   158  			require.NoError(t, err)
   159  			content, err := os.Open(tt.filePath)
   160  			require.NoError(t, err)
   161  			fi, err := content.Stat()
   162  			require.NoError(t, err)
   163  
   164  			got, err := a.Analyze(context.TODO(), analyzer.AnalysisInput{
   165  				FilePath: tt.filePath,
   166  				Dir:      tt.dir,
   167  				Content:  content,
   168  				Info:     fi,
   169  			})
   170  
   171  			require.NoError(t, err)
   172  			assert.Equal(t, tt.want, got)
   173  		})
   174  	}
   175  }
   176  
   177  func TestSecretRequire(t *testing.T) {
   178  	tests := []struct {
   179  		name     string
   180  		filePath string
   181  		want     bool
   182  	}{
   183  		{
   184  			name:     "pass regular file",
   185  			filePath: "testdata/secret.txt",
   186  			want:     true,
   187  		},
   188  		{
   189  			name:     "skip small file",
   190  			filePath: "testdata/emptyfile",
   191  			want:     false,
   192  		},
   193  		{
   194  			name:     "skip folder",
   195  			filePath: "testdata/node_modules/secret.txt",
   196  			want:     false,
   197  		},
   198  		{
   199  			name:     "skip file",
   200  			filePath: "testdata/package-lock.json",
   201  			want:     false,
   202  		},
   203  		{
   204  			name:     "skip extension",
   205  			filePath: "testdata/secret.doc",
   206  			want:     false,
   207  		},
   208  	}
   209  
   210  	for _, tt := range tests {
   211  		t.Run(tt.name, func(t *testing.T) {
   212  			a := secret.SecretAnalyzer{}
   213  			err := a.Init(analyzer.AnalyzerOptions{
   214  				SecretScannerOption: analyzer.SecretScannerOption{
   215  					ConfigPath: "testdata/skip-tests-config.yaml",
   216  				},
   217  			})
   218  			require.NoError(t, err)
   219  
   220  			fi, err := os.Stat(tt.filePath)
   221  			require.NoError(t, err)
   222  
   223  			got := a.Required(tt.filePath, fi)
   224  			assert.Equal(t, tt.want, got)
   225  		})
   226  	}
   227  }