diff --git a/e2e/.snapshots/TestCache b/e2e/.snapshots/TestCache new file mode 100644 index 000000000..b28022bb8 --- /dev/null +++ b/e2e/.snapshots/TestCache @@ -0,0 +1,39 @@ +critical: + - rule: + cwe_ids: + - "42" + id: test_ruby_logger + title: Ruby logger + description: Ruby logger + documentation_url: "" + line_number: 1 + full_filename: e2e/testdata/logger/main.rb + filename: main.rb + data_type: + category_uuid: cef587dd-76db-430b-9e18-7b031e1a193b + name: Email Address + category_groups: + - PII + - Personal Data + source: + location: + start: 1 + end: 1 + column: + start: 26 + end: 36 + sink: + location: + start: 1 + end: 1 + column: + start: 1 + end: 37 + content: logger.info("user info", user.email) + parent_line_number: 1 + snippet: logger.info("user info", user.email) + fingerprint: fa5e03644738e4c17cbbd04a580506b1_0 + old_fingerprint: 16c8aedf4ee6fe1f129aec2a9c14310c_0 + code_extract: logger.info("user info", user.email) + + diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go new file mode 100644 index 000000000..695446a29 --- /dev/null +++ b/e2e/e2e_test.go @@ -0,0 +1,49 @@ +package e2e_test + +import ( + "testing" + + "github.com/bearer/bearer/e2e/internal/testhelper" + "github.com/bradleyjkemp/cupaloy" + "github.com/stretchr/testify/assert" +) + +func TestCache(t *testing.T) { + arguments := []string{ + "scan", + "e2e/testdata/logger", + "--format", "yaml", + "--disable-version-check", + "--disable-default-rules", + "--external-rule-dir", "e2e/testdata/rules", + "--exit-code=0", + } + + noCacheStdOut, noCacheStdErr := testhelper.ExecuteTest( + testhelper.NewTestCase( + "no_cache", + arguments, + testhelper.TestCaseOptions{ + DisplayStdErr: true, + }, + ), + t, + ) + + withCacheStdOut, withCacheStdErr := testhelper.ExecuteTest( + testhelper.NewTestCase( + "with_cache", + arguments, + testhelper.TestCaseOptions{ + DisplayStdErr: true, + IgnoreForce: true, + }, + ), + t, + ) + + assert.NotContains(t, noCacheStdErr, "Cached data used") + assert.Contains(t, withCacheStdErr, "Cached data used") + assert.Equal(t, noCacheStdOut, withCacheStdOut) + cupaloy.SnapshotT(t, withCacheStdOut) +} diff --git a/e2e/internal/testhelper/testhelper.go b/e2e/internal/testhelper/testhelper.go index d49a363aa..4a718172b 100644 --- a/e2e/internal/testhelper/testhelper.go +++ b/e2e/internal/testhelper/testhelper.go @@ -3,6 +3,7 @@ package testhelper import ( "bytes" "context" + "fmt" "os" "os/exec" "strings" @@ -42,7 +43,7 @@ func NewTestCase(name string, arguments []string, options TestCaseOptions) TestC } } -func executeApp(t *testing.T, arguments []string) (string, error) { +func executeApp(t *testing.T, arguments []string) (string, string, error) { cmd, cancel := CreateCommand(arguments) buffOut := bytes.NewBuffer(nil) @@ -54,12 +55,6 @@ func executeApp(t *testing.T, arguments []string) (string, error) { timer := time.NewTimer(TestTimeout) commandFinished := make(chan struct{}, 1) - combinedOutput := func() string { - errStr := buffErr.String() - // trim exit status - errStr = strings.TrimSuffix(errStr, "exit status 1\n") - return buffOut.String() + "\n--\n" + errStr - } go func() { err = cmd.Start() @@ -76,12 +71,21 @@ func executeApp(t *testing.T, arguments []string) (string, error) { select { case <-timer.C: cancel() - t.Fatalf("command failed to complete on time 'bearer %s':\n%s", strings.Join(arguments, " "), combinedOutput()) + t.Fatalf( + "command failed to complete on time 'bearer %s':\n%s\n--\n%s", + strings.Join(arguments, " "), + buffOut, + buffErr, + ) case <-commandFinished: cancel() } - return combinedOutput(), err + errStr := buffErr.String() + // make output from `go run` match a compiled executable + errStr = strings.TrimSuffix(errStr, "exit status 1\n") + + return buffOut.String(), errStr, err } func CreateCommand(arguments []string) (*exec.Cmd, context.CancelFunc) { @@ -129,18 +133,9 @@ func GetCWD() string { func RunTestsWithSnapshotSubdirectory(t *testing.T, tests []TestCase, snapshotSubdirectory string) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - combinedOutput, err := executeTest(test, t) - - if test.ShouldSucceed && err != nil { - t.Fatalf("command completed with error %s %s", err, combinedOutput) - } - - if !test.ShouldSucceed && err == nil { - t.Fatal("expected command to fail but it succeeded instead") - } - + stdOut, stdErr := ExecuteTest(test, t) cupaloyCopy := cupaloy.NewDefaultConfig().WithOptions(cupaloy.SnapshotSubdirectory(snapshotSubdirectory)) - cupaloyCopy.SnapshotT(t, combinedOutput) + cupaloyCopy.SnapshotT(t, combineOutput(stdOut, stdErr)) }) } } @@ -148,22 +143,13 @@ func RunTestsWithSnapshotSubdirectory(t *testing.T, tests []TestCase, snapshotSu func RunTests(t *testing.T, tests []TestCase) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - combinedOutput, err := executeTest(test, t) - - if test.ShouldSucceed && err != nil { - t.Fatalf("command completed with error %s %s", err, combinedOutput) - } - - if !test.ShouldSucceed && err == nil { - t.Fatal("expected command to fail but it succeeded instead") - } - - cupaloy.SnapshotT(t, combinedOutput) + stdOut, stdErr := ExecuteTest(test, t) + cupaloy.SnapshotT(t, combineOutput(stdOut, stdErr)) }) } } -func executeTest(test TestCase, t *testing.T) (string, error) { +func ExecuteTest(test TestCase, t *testing.T) (string, string) { arguments := test.arguments if !test.displayProgressBar { @@ -178,5 +164,18 @@ func executeTest(test TestCase, t *testing.T) (string, error) { arguments = append(arguments, "--force") } - return executeApp(t, arguments) + stdOut, stdErr, err := executeApp(t, arguments) + if test.ShouldSucceed && err != nil { + t.Fatalf("command completed with error %s %s", err, combineOutput(stdOut, stdErr)) + } + + if !test.ShouldSucceed && err == nil { + t.Fatal("expected command to fail but it succeeded instead") + } + + return stdOut, stdErr +} + +func combineOutput(stdOut, stdErr string) string { + return fmt.Sprintf("%s\n--\n%s", stdOut, stdErr) } diff --git a/e2e/testdata/logger/main.rb b/e2e/testdata/logger/main.rb new file mode 100644 index 000000000..2024596d0 --- /dev/null +++ b/e2e/testdata/logger/main.rb @@ -0,0 +1 @@ +logger.info("user info", user.email) \ No newline at end of file diff --git a/e2e/testdata/rules/logger.yml b/e2e/testdata/rules/logger.yml new file mode 100644 index 000000000..91d9b8ae3 --- /dev/null +++ b/e2e/testdata/rules/logger.yml @@ -0,0 +1,15 @@ +patterns: + - pattern: logger.$<_>($<...>$$<...>) + filters: + - variable: DATA_TYPE + detection: datatype + scope: result +languages: + - ruby +severity: high +metadata: + description: Ruby logger + remediation_message: Ruby logger + cwe_id: + - 42 + id: test_ruby_logger diff --git a/internal/commands/artifact/run.go b/internal/commands/artifact/run.go index e9ec79e16..b84018bd6 100644 --- a/internal/commands/artifact/run.go +++ b/internal/commands/artifact/run.go @@ -374,7 +374,11 @@ func (r *runner) Report( startTime := time.Now() cacheUsed := r.CacheUsed() - report := types.Report{Path: r.reportPath, Inputgocloc: r.goclocResult, HasFiles: len(files) != 0} + report := types.Report{ + Path: r.reportPath, + Inputgocloc: r.goclocResult, + HasFiles: r.CacheUsed() || len(files) != 0, + } // if output is defined we want to write only to file logger := outputhandler.StdOutLog