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

     1  package secret_test
     2  
     3  import (
     4  	"bytes"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  	"go.uber.org/zap"
    12  	"go.uber.org/zap/zapcore"
    13  
    14  	"github.com/devseccon/trivy/pkg/fanal/log"
    15  	"github.com/devseccon/trivy/pkg/fanal/secret"
    16  	"github.com/devseccon/trivy/pkg/fanal/types"
    17  )
    18  
    19  func TestMain(m *testing.M) {
    20  	logger, _ := zap.NewDevelopment(zap.IncreaseLevel(zapcore.FatalLevel))
    21  	log.SetLogger(logger.Sugar())
    22  	os.Exit(m.Run())
    23  }
    24  
    25  func TestSecretScanner(t *testing.T) {
    26  	wantFinding1 := types.SecretFinding{
    27  		RuleID:    "rule1",
    28  		Category:  "general",
    29  		Title:     "Generic Rule",
    30  		Severity:  "HIGH",
    31  		StartLine: 2,
    32  		EndLine:   2,
    33  		Match:     "generic secret line secret=\"*********\"",
    34  		Code: types.Code{
    35  			Lines: []types.Line{
    36  				{
    37  					Number:      1,
    38  					Content:     "--- ignore block start ---",
    39  					Highlighted: "--- ignore block start ---",
    40  				},
    41  				{
    42  					Number:      2,
    43  					Content:     "generic secret line secret=\"*********\"",
    44  					Highlighted: "generic secret line secret=\"*********\"",
    45  					IsCause:     true,
    46  					FirstCause:  true,
    47  					LastCause:   true,
    48  				},
    49  				{
    50  					Number:      3,
    51  					Content:     "--- ignore block stop ---",
    52  					Highlighted: "--- ignore block stop ---",
    53  				},
    54  			},
    55  		},
    56  	}
    57  	wantFinding2 := types.SecretFinding{
    58  		RuleID:    "rule1",
    59  		Category:  "general",
    60  		Title:     "Generic Rule",
    61  		Severity:  "HIGH",
    62  		StartLine: 4,
    63  		EndLine:   4,
    64  		Match:     "secret=\"**********\"",
    65  		Code: types.Code{
    66  			Lines: []types.Line{
    67  				{
    68  					Number:      2,
    69  					Content:     "generic secret line secret=\"*********\"",
    70  					Highlighted: "generic secret line secret=\"*********\"",
    71  				},
    72  				{
    73  					Number:      3,
    74  					Content:     "--- ignore block stop ---",
    75  					Highlighted: "--- ignore block stop ---",
    76  				},
    77  				{
    78  					Number:      4,
    79  					Content:     "secret=\"**********\"",
    80  					Highlighted: "secret=\"**********\"",
    81  					IsCause:     true,
    82  					FirstCause:  true,
    83  					LastCause:   true,
    84  				},
    85  				{
    86  					Number:      5,
    87  					Content:     "credentials: { user: \"username\" password: \"123456789\" }",
    88  					Highlighted: "credentials: { user: \"username\" password: \"123456789\" }",
    89  				},
    90  			},
    91  		},
    92  	}
    93  	wantFindingRegexDisabled := types.SecretFinding{
    94  		RuleID:    "rule1",
    95  		Category:  "general",
    96  		Title:     "Generic Rule",
    97  		Severity:  "HIGH",
    98  		StartLine: 4,
    99  		EndLine:   4,
   100  		Match:     "secret=\"**********\"",
   101  		Code: types.Code{
   102  			Lines: []types.Line{
   103  				{
   104  					Number:      2,
   105  					Content:     "generic secret line secret=\"somevalue\"",
   106  					Highlighted: "generic secret line secret=\"somevalue\"",
   107  				},
   108  				{
   109  					Number:      3,
   110  					Content:     "--- ignore block stop ---",
   111  					Highlighted: "--- ignore block stop ---",
   112  				},
   113  				{
   114  					Number:      4,
   115  					Content:     "secret=\"**********\"",
   116  					Highlighted: "secret=\"**********\"",
   117  					IsCause:     true,
   118  					FirstCause:  true,
   119  					LastCause:   true,
   120  				},
   121  				{
   122  					Number:      5,
   123  					Content:     "credentials: { user: \"username\" password: \"123456789\" }",
   124  					Highlighted: "credentials: { user: \"username\" password: \"123456789\" }",
   125  				},
   126  			},
   127  		},
   128  	}
   129  	wantFinding3 := types.SecretFinding{
   130  		RuleID:    "rule1",
   131  		Category:  "general",
   132  		Title:     "Generic Rule",
   133  		Severity:  "HIGH",
   134  		StartLine: 5,
   135  		EndLine:   5,
   136  		Match:     "credentials: { user: \"********\" password: \"*********\" }",
   137  		Code: types.Code{
   138  			Lines: []types.Line{
   139  				{
   140  					Number:      3,
   141  					Content:     "--- ignore block stop ---",
   142  					Highlighted: "--- ignore block stop ---",
   143  				},
   144  				{
   145  					Number:      4,
   146  					Content:     "secret=\"othervalue\"",
   147  					Highlighted: "secret=\"othervalue\"",
   148  				},
   149  				{
   150  					Number:      5,
   151  					Content:     "credentials: { user: \"********\" password: \"*********\" }",
   152  					Highlighted: "credentials: { user: \"********\" password: \"*********\" }",
   153  					IsCause:     true,
   154  					FirstCause:  true,
   155  					LastCause:   true,
   156  				},
   157  			},
   158  		},
   159  	}
   160  	wantFinding4 := types.SecretFinding{
   161  		RuleID:    "rule1",
   162  		Category:  "general",
   163  		Title:     "Generic Rule",
   164  		Severity:  "HIGH",
   165  		StartLine: 5,
   166  		EndLine:   5,
   167  		Match:     "credentials: { user: \"********\" password: \"*********\" }",
   168  		Code: types.Code{
   169  			Lines: []types.Line{
   170  				{
   171  					Number:      3,
   172  					Content:     "--- ignore block stop ---",
   173  					Highlighted: "--- ignore block stop ---",
   174  				},
   175  				{
   176  					Number:      4,
   177  					Content:     "secret=\"othervalue\"",
   178  					Highlighted: "secret=\"othervalue\"",
   179  				},
   180  				{
   181  					Number:      5,
   182  					Content:     "credentials: { user: \"********\" password: \"*********\" }",
   183  					Highlighted: "credentials: { user: \"********\" password: \"*********\" }",
   184  					IsCause:     true,
   185  					FirstCause:  true,
   186  					LastCause:   true,
   187  				},
   188  			},
   189  		},
   190  	}
   191  	wantFinding5 := types.SecretFinding{
   192  		RuleID:    "aws-access-key-id",
   193  		Category:  secret.CategoryAWS,
   194  		Title:     "AWS Access Key ID",
   195  		Severity:  "CRITICAL",
   196  		StartLine: 2,
   197  		EndLine:   2,
   198  		Match:     "AWS_ACCESS_KEY_ID=********************",
   199  		Code: types.Code{
   200  			Lines: []types.Line{
   201  				{
   202  					Number:      1,
   203  					Content:     "'AWS_secret_KEY'=\"****************************************\"",
   204  					Highlighted: "'AWS_secret_KEY'=\"****************************************\"",
   205  				},
   206  				{
   207  					Number:      2,
   208  					Content:     "AWS_ACCESS_KEY_ID=********************",
   209  					Highlighted: "AWS_ACCESS_KEY_ID=********************",
   210  					IsCause:     true,
   211  					FirstCause:  true,
   212  					LastCause:   true,
   213  				},
   214  				{
   215  					Number:      3,
   216  					Content:     "\"aws_account_ID\":'1234-5678-9123'",
   217  					Highlighted: "\"aws_account_ID\":'1234-5678-9123'",
   218  				},
   219  			},
   220  		},
   221  	}
   222  	wantFinding5a := types.SecretFinding{
   223  		RuleID:    "aws-access-key-id",
   224  		Category:  secret.CategoryAWS,
   225  		Title:     "AWS Access Key ID",
   226  		Severity:  "CRITICAL",
   227  		StartLine: 2,
   228  		EndLine:   2,
   229  		Match:     "AWS_ACCESS_KEY_ID=********************",
   230  		Code: types.Code{
   231  			Lines: []types.Line{
   232  				{
   233  					Number:      1,
   234  					Content:     "GITHUB_PAT=****************************************",
   235  					Highlighted: "GITHUB_PAT=****************************************",
   236  				},
   237  				{
   238  					Number:      2,
   239  					Content:     "AWS_ACCESS_KEY_ID=********************",
   240  					Highlighted: "AWS_ACCESS_KEY_ID=********************",
   241  					IsCause:     true,
   242  					FirstCause:  true,
   243  					LastCause:   true,
   244  				},
   245  			},
   246  		},
   247  	}
   248  	wantFindingPATDisabled := types.SecretFinding{
   249  		RuleID:    "aws-access-key-id",
   250  		Category:  secret.CategoryAWS,
   251  		Title:     "AWS Access Key ID",
   252  		Severity:  "CRITICAL",
   253  		StartLine: 2,
   254  		EndLine:   2,
   255  		Match:     "AWS_ACCESS_KEY_ID=********************",
   256  		Code: types.Code{
   257  			Lines: []types.Line{
   258  				{
   259  					Number:      1,
   260  					Content:     "GITHUB_PAT=ghp_012345678901234567890123456789abcdef",
   261  					Highlighted: "GITHUB_PAT=ghp_012345678901234567890123456789abcdef",
   262  				},
   263  				{
   264  					Number:      2,
   265  					Content:     "AWS_ACCESS_KEY_ID=********************",
   266  					Highlighted: "AWS_ACCESS_KEY_ID=********************",
   267  					IsCause:     true,
   268  					FirstCause:  true,
   269  					LastCause:   true,
   270  				},
   271  			},
   272  		},
   273  	}
   274  	wantFinding6 := types.SecretFinding{
   275  		RuleID:    "github-pat",
   276  		Category:  secret.CategoryGitHub,
   277  		Title:     "GitHub Personal Access Token",
   278  		Severity:  "CRITICAL",
   279  		StartLine: 1,
   280  		EndLine:   1,
   281  		Match:     "GITHUB_PAT=****************************************",
   282  		Code: types.Code{
   283  			Lines: []types.Line{
   284  				{
   285  					Number:      1,
   286  					Content:     "GITHUB_PAT=****************************************",
   287  					Highlighted: "GITHUB_PAT=****************************************",
   288  					IsCause:     true,
   289  					FirstCause:  true,
   290  					LastCause:   true,
   291  				},
   292  				{
   293  					Number:      2,
   294  					Content:     "AWS_ACCESS_KEY_ID=********************",
   295  					Highlighted: "AWS_ACCESS_KEY_ID=********************",
   296  				},
   297  			},
   298  		},
   299  	}
   300  	wantFindingGHButDisableAWS := types.SecretFinding{
   301  		RuleID:    "github-pat",
   302  		Category:  secret.CategoryGitHub,
   303  		Title:     "GitHub Personal Access Token",
   304  		Severity:  "CRITICAL",
   305  		StartLine: 1,
   306  		EndLine:   1,
   307  		Match:     "GITHUB_PAT=****************************************",
   308  		Code: types.Code{
   309  			Lines: []types.Line{
   310  				{
   311  					Number:      1,
   312  					Content:     "GITHUB_PAT=****************************************",
   313  					Highlighted: "GITHUB_PAT=****************************************",
   314  					IsCause:     true,
   315  					FirstCause:  true,
   316  					LastCause:   true,
   317  				},
   318  				{
   319  					Number:      2,
   320  					Content:     "AWS_ACCESS_KEY_ID=AKIA0123456789ABCDEF",
   321  					Highlighted: "AWS_ACCESS_KEY_ID=AKIA0123456789ABCDEF",
   322  				},
   323  			},
   324  		},
   325  	}
   326  	wantFinding7 := types.SecretFinding{
   327  		RuleID:    "github-pat",
   328  		Category:  secret.CategoryGitHub,
   329  		Title:     "GitHub Personal Access Token",
   330  		Severity:  "CRITICAL",
   331  		StartLine: 1,
   332  		EndLine:   1,
   333  		Match:     "aaaaaaaaaaaaaaaaaa GITHUB_PAT=**************************************** bbbbbbbbbbbbbbbbbbb",
   334  		Code: types.Code{
   335  			Lines: []types.Line{
   336  				{
   337  					Number:      1,
   338  					Content:     "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa GITHUB_PAT=**************************************** bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
   339  					Highlighted: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa GITHUB_PAT=**************************************** bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
   340  					IsCause:     true,
   341  					FirstCause:  true,
   342  					LastCause:   true,
   343  				},
   344  			},
   345  		},
   346  	}
   347  	wantFinding8 := types.SecretFinding{
   348  		RuleID:    "rule1",
   349  		Category:  "general",
   350  		Title:     "Generic Rule",
   351  		Severity:  "UNKNOWN",
   352  		StartLine: 2,
   353  		EndLine:   2,
   354  		Match:     "generic secret line secret=\"*********\"",
   355  		Code: types.Code{
   356  			Lines: []types.Line{
   357  				{
   358  					Number:      1,
   359  					Content:     "--- ignore block start ---",
   360  					Highlighted: "--- ignore block start ---",
   361  				},
   362  				{
   363  					Number:      2,
   364  					Content:     "generic secret line secret=\"*********\"",
   365  					Highlighted: "generic secret line secret=\"*********\"",
   366  					IsCause:     true,
   367  					FirstCause:  true,
   368  					LastCause:   true,
   369  				},
   370  				{
   371  					Number:      3,
   372  					Content:     "--- ignore block stop ---",
   373  					Highlighted: "--- ignore block stop ---",
   374  				},
   375  			},
   376  		},
   377  	}
   378  	wantFinding9 := types.SecretFinding{
   379  		RuleID:    "aws-secret-access-key",
   380  		Category:  secret.CategoryAWS,
   381  		Title:     "AWS Secret Access Key",
   382  		Severity:  "CRITICAL",
   383  		StartLine: 1,
   384  		EndLine:   1,
   385  		Match:     `'AWS_secret_KEY'="****************************************"`,
   386  		Code: types.Code{
   387  			Lines: []types.Line{
   388  				{
   389  					Number:      1,
   390  					Content:     "'AWS_secret_KEY'=\"****************************************\"",
   391  					Highlighted: "'AWS_secret_KEY'=\"****************************************\"",
   392  					IsCause:     true,
   393  					FirstCause:  true,
   394  					LastCause:   true,
   395  				},
   396  				{
   397  					Number:      2,
   398  					Content:     "AWS_ACCESS_KEY_ID=********************",
   399  					Highlighted: "AWS_ACCESS_KEY_ID=********************",
   400  				},
   401  			},
   402  		},
   403  	}
   404  	wantFindingAsymmetricPrivateKeyJson := types.SecretFinding{
   405  		RuleID:    "private-key",
   406  		Category:  secret.CategoryAsymmetricPrivateKey,
   407  		Title:     "Asymmetric Private Key",
   408  		Severity:  "HIGH",
   409  		StartLine: 1,
   410  		EndLine:   1,
   411  		Match:     "----BEGIN RSA PRIVATE KEY-----**************************************************************************************************************************-----END RSA PRIVATE",
   412  		Code: types.Code{
   413  			Lines: []types.Line{
   414  				{
   415  					Number:      1,
   416  					Content:     "{\"key\": \"-----BEGIN RSA PRIVATE KEY-----**************************************************************************************************************************-----END RSA PRIVATE KEY-----\\n\"}",
   417  					Highlighted: "{\"key\": \"-----BEGIN RSA PRIVATE KEY-----**************************************************************************************************************************-----END RSA PRIVATE KEY-----\\n\"}",
   418  					IsCause:     true,
   419  					FirstCause:  true,
   420  					LastCause:   true,
   421  				},
   422  			},
   423  		},
   424  	}
   425  	wantFindingAsymmetricPrivateKey := types.SecretFinding{
   426  		RuleID:    "private-key",
   427  		Category:  secret.CategoryAsymmetricPrivateKey,
   428  		Title:     "Asymmetric Private Key",
   429  		Severity:  "HIGH",
   430  		StartLine: 1,
   431  		EndLine:   1,
   432  		Match:     "----BEGIN RSA PRIVATE KEY-----****************************************************************************************************************************************************************************************-----END RSA PRIVATE",
   433  		Code: types.Code{
   434  			Lines: []types.Line{
   435  				{
   436  					Number:      1,
   437  					Content:     "-----BEGIN RSA PRIVATE KEY-----****************************************************************************************************************************************************************************************-----END RSA PRIVATE KEY-----",
   438  					Highlighted: "-----BEGIN RSA PRIVATE KEY-----****************************************************************************************************************************************************************************************-----END RSA PRIVATE KEY-----",
   439  					IsCause:     true,
   440  					FirstCause:  true,
   441  					LastCause:   true,
   442  				},
   443  			},
   444  		},
   445  	}
   446  	wantFindingAsymmSecretKey := types.SecretFinding{
   447  		RuleID:    "private-key",
   448  		Category:  secret.CategoryAsymmetricPrivateKey,
   449  		Title:     "Asymmetric Private Key",
   450  		Severity:  "HIGH",
   451  		StartLine: 1,
   452  		EndLine:   1,
   453  		Match:     "----BEGIN RSA PRIVATE KEY-----**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************-----END RSA PRIVATE",
   454  		Code: types.Code{
   455  			Lines: []types.Line{
   456  				{
   457  					Number:      1,
   458  					Content:     "-----BEGIN RSA PRIVATE KEY-----**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************-----END RSA PRIVATE KEY-----",
   459  					Highlighted: "-----BEGIN RSA PRIVATE KEY-----**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************-----END RSA PRIVATE KEY-----",
   460  					IsCause:     true,
   461  					FirstCause:  true,
   462  					LastCause:   true,
   463  				},
   464  			},
   465  		},
   466  	}
   467  	wantFindingAlibabaAccessKeyId := types.SecretFinding{
   468  		RuleID:    "alibaba-access-key-id",
   469  		Category:  secret.CategoryAlibaba,
   470  		Title:     "Alibaba AccessKey ID",
   471  		Severity:  "HIGH",
   472  		StartLine: 2,
   473  		EndLine:   2,
   474  		Match:     "key = ************************,",
   475  		Code: types.Code{
   476  			Lines: []types.Line{
   477  				{
   478  					Number:      1,
   479  					Content:     "key : LTAI1234567890ABCDEFG123asd",
   480  					Highlighted: "key : LTAI1234567890ABCDEFG123asd",
   481  				},
   482  				{
   483  					Number:      2,
   484  					Content:     "key = ************************,",
   485  					Highlighted: "key = ************************,",
   486  					IsCause:     true,
   487  					FirstCause:  true,
   488  					LastCause:   true,
   489  				},
   490  				{
   491  					Number:      3,
   492  					Content:     "asdLTAI1234567890ABCDEFG123",
   493  					Highlighted: "asdLTAI1234567890ABCDEFG123",
   494  				},
   495  			},
   496  		},
   497  	}
   498  	wantMultiLine := types.SecretFinding{
   499  		RuleID:    "multi-line-secret",
   500  		Category:  "general",
   501  		Title:     "Generic Rule",
   502  		Severity:  "HIGH",
   503  		StartLine: 2,
   504  		EndLine:   2,
   505  		Match:     "***************",
   506  		Code: types.Code{
   507  			Lines: []types.Line{
   508  				{
   509  					Number:      1,
   510  					Content:     "123",
   511  					Highlighted: "123",
   512  				},
   513  				{
   514  					Number:      2,
   515  					Content:     "***************",
   516  					Highlighted: "***************",
   517  					IsCause:     true,
   518  					FirstCause:  true,
   519  					LastCause:   true,
   520  				},
   521  				{
   522  					Number:      3,
   523  					Content:     "123",
   524  					Highlighted: "123",
   525  				},
   526  			},
   527  		},
   528  	}
   529  
   530  	tests := []struct {
   531  		name          string
   532  		configPath    string
   533  		inputFilePath string
   534  		want          types.Secret
   535  	}{
   536  		{
   537  			name:          "find match",
   538  			configPath:    filepath.Join("testdata", "config.yaml"),
   539  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   540  			want: types.Secret{
   541  				FilePath: filepath.Join("testdata", "secret.txt"),
   542  				Findings: []types.SecretFinding{wantFinding1, wantFinding2},
   543  			},
   544  		},
   545  		{
   546  			name:          "find aws secrets",
   547  			configPath:    filepath.Join("testdata", "config.yaml"),
   548  			inputFilePath: filepath.Join("testdata", "aws-secrets.txt"),
   549  			want: types.Secret{
   550  				FilePath: filepath.Join("testdata", "aws-secrets.txt"),
   551  				Findings: []types.SecretFinding{wantFinding5, wantFinding9},
   552  			},
   553  		},
   554  		{
   555  			name:          "find Asymmetric Private Key secrets",
   556  			configPath:    filepath.Join("testdata", "skip-test.yaml"),
   557  			inputFilePath: filepath.Join("testdata", "asymmetric-private-secret.txt"),
   558  			want: types.Secret{
   559  				FilePath: filepath.Join("testdata", "asymmetric-private-secret.txt"),
   560  				Findings: []types.SecretFinding{wantFindingAsymmetricPrivateKey},
   561  			},
   562  		},
   563  		{
   564  			name:          "find Alibaba AccessKey ID txt",
   565  			configPath:    filepath.Join("testdata", "skip-test.yaml"),
   566  			inputFilePath: "testdata/alibaba-access-key-id.txt",
   567  			want: types.Secret{
   568  				FilePath: "testdata/alibaba-access-key-id.txt",
   569  				Findings: []types.SecretFinding{wantFindingAlibabaAccessKeyId},
   570  			},
   571  		},
   572  		{
   573  			name:          "find Asymmetric Private Key secrets json",
   574  			configPath:    filepath.Join("testdata", "skip-test.yaml"),
   575  			inputFilePath: filepath.Join("testdata", "asymmetric-private-secret.json"),
   576  			want: types.Secret{
   577  				FilePath: filepath.Join("testdata", "asymmetric-private-secret.json"),
   578  				Findings: []types.SecretFinding{wantFindingAsymmetricPrivateKeyJson},
   579  			},
   580  		},
   581  		{
   582  			name:          "include when keyword found",
   583  			configPath:    filepath.Join("testdata", "config-happy-keywords.yaml"),
   584  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   585  			want: types.Secret{
   586  				FilePath: filepath.Join("testdata", "secret.txt"),
   587  				Findings: []types.SecretFinding{wantFinding1, wantFinding2},
   588  			},
   589  		},
   590  		{
   591  			name:          "exclude when no keyword found",
   592  			configPath:    filepath.Join("testdata", "config-sad-keywords.yaml"),
   593  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   594  			want:          types.Secret{},
   595  		},
   596  		{
   597  			name:          "should ignore .md files by default",
   598  			configPath:    filepath.Join("testdata", "config.yaml"),
   599  			inputFilePath: filepath.Join("testdata", "secret.md"),
   600  			want: types.Secret{
   601  				FilePath: filepath.Join("testdata", "secret.md"),
   602  			},
   603  		},
   604  		{
   605  			name:          "should disable .md allow rule",
   606  			configPath:    filepath.Join("testdata", "config-disable-allow-rule-md.yaml"),
   607  			inputFilePath: filepath.Join("testdata", "secret.md"),
   608  			want: types.Secret{
   609  				FilePath: filepath.Join("testdata", "secret.md"),
   610  				Findings: []types.SecretFinding{wantFinding1, wantFinding2},
   611  			},
   612  		},
   613  		{
   614  			name:          "should find ghp builtin secret",
   615  			configPath:    filepath.Join("testdata", "skip-test.yaml"),
   616  			inputFilePath: filepath.Join("testdata", "builtin-rule-secret.txt"),
   617  			want: types.Secret{
   618  				FilePath: filepath.Join("testdata", "builtin-rule-secret.txt"),
   619  				Findings: []types.SecretFinding{wantFinding5a, wantFinding6},
   620  			},
   621  		},
   622  		{
   623  			name:          "should enable github-pat builtin rule, but disable aws-access-key-id rule",
   624  			configPath:    filepath.Join("testdata", "config-enable-ghp.yaml"),
   625  			inputFilePath: filepath.Join("testdata", "builtin-rule-secret.txt"),
   626  			want: types.Secret{
   627  				FilePath: filepath.Join("testdata", "builtin-rule-secret.txt"),
   628  				Findings: []types.SecretFinding{wantFindingGHButDisableAWS},
   629  			},
   630  		},
   631  		{
   632  			name:          "should disable github-pat builtin rule",
   633  			configPath:    filepath.Join("testdata", "config-disable-ghp.yaml"),
   634  			inputFilePath: filepath.Join("testdata", "builtin-rule-secret.txt"),
   635  			want: types.Secret{
   636  				FilePath: filepath.Join("testdata", "builtin-rule-secret.txt"),
   637  				Findings: []types.SecretFinding{wantFindingPATDisabled},
   638  			},
   639  		},
   640  		{
   641  			name:          "should disable custom rule",
   642  			configPath:    filepath.Join("testdata", "config-disable-rule1.yaml"),
   643  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   644  			want:          types.Secret{},
   645  		},
   646  		{
   647  			name:          "allow-rule path",
   648  			configPath:    filepath.Join("testdata", "allow-path.yaml"),
   649  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   650  			want:          types.Secret{},
   651  		},
   652  		{
   653  			name:          "allow-rule regex inside group",
   654  			configPath:    filepath.Join("testdata", "allow-regex.yaml"),
   655  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   656  			want: types.Secret{
   657  				FilePath: filepath.Join("testdata", "secret.txt"),
   658  				Findings: []types.SecretFinding{wantFinding1},
   659  			},
   660  		},
   661  		{
   662  			name:          "allow-rule regex outside group",
   663  			configPath:    filepath.Join("testdata", "allow-regex-outside-group.yaml"),
   664  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   665  			want:          types.Secret{},
   666  		},
   667  		{
   668  			name:          "exclude-block regexes",
   669  			configPath:    filepath.Join("testdata", "exclude-block.yaml"),
   670  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   671  			want: types.Secret{
   672  				FilePath: filepath.Join("testdata", "secret.txt"),
   673  				Findings: []types.SecretFinding{wantFindingRegexDisabled},
   674  			},
   675  		},
   676  		{
   677  			name:          "skip examples file",
   678  			configPath:    filepath.Join("testdata", "skip-test.yaml"),
   679  			inputFilePath: filepath.Join("testdata", "example-secret.txt"),
   680  			want: types.Secret{
   681  				FilePath: filepath.Join("testdata", "example-secret.txt"),
   682  			},
   683  		},
   684  		{
   685  			name:          "global allow-rule path",
   686  			configPath:    filepath.Join("testdata", "global-allow-path.yaml"),
   687  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   688  			want: types.Secret{
   689  				FilePath: filepath.Join("testdata", "secret.txt"),
   690  				Findings: nil,
   691  			},
   692  		},
   693  		{
   694  			name:          "global allow-rule regex",
   695  			configPath:    filepath.Join("testdata", "global-allow-regex.yaml"),
   696  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   697  			want: types.Secret{
   698  				FilePath: filepath.Join("testdata", "secret.txt"),
   699  				Findings: []types.SecretFinding{wantFinding1},
   700  			},
   701  		},
   702  		{
   703  			name:          "global exclude-block regexes",
   704  			configPath:    filepath.Join("testdata", "global-exclude-block.yaml"),
   705  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   706  			want: types.Secret{
   707  				FilePath: filepath.Join("testdata", "secret.txt"),
   708  				Findings: []types.SecretFinding{wantFindingRegexDisabled},
   709  			},
   710  		},
   711  		{
   712  			name:          "multiple secret groups",
   713  			configPath:    filepath.Join("testdata", "multiple-secret-groups.yaml"),
   714  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   715  			want: types.Secret{
   716  				FilePath: filepath.Join("testdata", "secret.txt"),
   717  				Findings: []types.SecretFinding{wantFinding3, wantFinding4},
   718  			},
   719  		},
   720  		{
   721  			name:          "truncate long line",
   722  			configPath:    filepath.Join("testdata", "skip-test.yaml"),
   723  			inputFilePath: filepath.Join("testdata", "long-line-secret.txt"),
   724  			want: types.Secret{
   725  				FilePath: filepath.Join("testdata", "long-line-secret.txt"),
   726  				Findings: []types.SecretFinding{wantFinding7},
   727  			},
   728  		},
   729  		{
   730  			name:          "add unknown severity when rule has no severity",
   731  			configPath:    filepath.Join("testdata", "config-without-severity.yaml"),
   732  			inputFilePath: filepath.Join("testdata", "secret.txt"),
   733  			want: types.Secret{
   734  				FilePath: filepath.Join("testdata", "secret.txt"),
   735  				Findings: []types.SecretFinding{wantFinding8},
   736  			},
   737  		},
   738  		{
   739  			name:          "invalid aws secrets",
   740  			configPath:    filepath.Join("testdata", "skip-test.yaml"),
   741  			inputFilePath: filepath.Join("testdata", "invalid-aws-secrets.txt"),
   742  			want:          types.Secret{},
   743  		},
   744  		{
   745  			name:          "asymmetric file",
   746  			configPath:    filepath.Join("testdata", "skip-test.yaml"),
   747  			inputFilePath: "testdata/asymmetric-private-key.txt",
   748  			want: types.Secret{
   749  				FilePath: "testdata/asymmetric-private-key.txt",
   750  				Findings: []types.SecretFinding{wantFindingAsymmSecretKey},
   751  			},
   752  		},
   753  		{
   754  			name:          "begin/end line symbols without multi-line mode",
   755  			configPath:    filepath.Join("testdata", "multi-line-off.yaml"),
   756  			inputFilePath: "testdata/multi-line.txt",
   757  			want:          types.Secret{},
   758  		},
   759  		{
   760  			name:          "begin/end line symbols with multi-line mode",
   761  			configPath:    filepath.Join("testdata", "multi-line-on.yaml"),
   762  			inputFilePath: "testdata/multi-line.txt",
   763  			want: types.Secret{
   764  				FilePath: "testdata/multi-line.txt",
   765  				Findings: []types.SecretFinding{wantMultiLine},
   766  			},
   767  		},
   768  	}
   769  
   770  	for _, tt := range tests {
   771  		t.Run(tt.name, func(t *testing.T) {
   772  			content, err := os.ReadFile(tt.inputFilePath)
   773  			require.NoError(t, err)
   774  
   775  			content = bytes.ReplaceAll(content, []byte("\r"), []byte(""))
   776  
   777  			c, err := secret.ParseConfig(tt.configPath)
   778  			require.NoError(t, err)
   779  
   780  			s := secret.NewScanner(c)
   781  			got := s.Scan(secret.ScanArgs{
   782  				FilePath: tt.inputFilePath,
   783  				Content:  content,
   784  			},
   785  			)
   786  			assert.Equal(t, tt.want, got)
   787  		})
   788  	}
   789  }