Skip to content

Commit

Permalink
fix(report): close the file (#4842)
Browse files Browse the repository at this point in the history
* fix(report): close the file

* refactor: add the format type

* fix: return errors in version printing

* fix: lint issues

* fix: do not fail on bogus cache dir

---------

Co-authored-by: DmitriyLewen <dmitriy.lewen@smartforce.io>
  • Loading branch information
knqyf263 and DmitriyLewen committed Jul 23, 2023
1 parent 24a3e54 commit 20c2246
Show file tree
Hide file tree
Showing 38 changed files with 351 additions and 361 deletions.
23 changes: 1 addition & 22 deletions pkg/cloud/aws/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import (
"errors"
"strings"

"golang.org/x/exp/slices"

"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/sts"
"golang.org/x/exp/slices"
"golang.org/x/xerrors"

"github.com/aquasecurity/defsec/pkg/errs"
Expand All @@ -17,10 +16,8 @@ import (
"github.com/aquasecurity/trivy/pkg/cloud/aws/scanner"
"github.com/aquasecurity/trivy/pkg/cloud/report"
"github.com/aquasecurity/trivy/pkg/commands/operation"
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
"github.com/aquasecurity/trivy/pkg/flag"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
)

var allSupportedServicesFunc = awsScanner.AllSupportedServices
Expand Down Expand Up @@ -166,24 +163,6 @@ func Run(ctx context.Context, opt flag.Options) error {
}

log.Logger.Debug("Writing report to output...")
if opt.Compliance.Spec.ID != "" {
convertedResults := report.ConvertResults(results, cloud.ProviderAWS, opt.Services)
var crr []types.Results
for _, r := range convertedResults {
crr = append(crr, r.Results)
}

complianceReport, err := cr.BuildComplianceReport(crr, opt.Compliance)
if err != nil {
return xerrors.Errorf("compliance report build error: %w", err)
}

return cr.Write(complianceReport, cr.Option{
Format: opt.Format,
Report: opt.ReportFormat,
Output: opt.Output,
})
}

res := results.GetFailed()
if opt.MisconfOptions.IncludeNonFailures {
Expand Down
14 changes: 8 additions & 6 deletions pkg/cloud/aws/commands/run_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package commands

import (
"bytes"
"context"
"os"
"path/filepath"
Expand Down Expand Up @@ -1243,8 +1242,8 @@ Summary Report for compliance: my-custom-spec
}()
}

buffer := new(bytes.Buffer)
test.options.Output = buffer
output := filepath.Join(t.TempDir(), "output")
test.options.Output = output
test.options.Debug = true
test.options.GlobalOptions.Timeout = time.Minute
if test.options.Format == "" {
Expand Down Expand Up @@ -1283,10 +1282,13 @@ Summary Report for compliance: my-custom-spec
err := Run(context.Background(), test.options)
if test.expectErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, test.want, buffer.String())
return
}
assert.NoError(t, err)

b, err := os.ReadFile(output)
require.NoError(t, err)
assert.Equal(t, test.want, string(b))
})
}
}
50 changes: 37 additions & 13 deletions pkg/cloud/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package report

import (
"context"
"io"
"os"
"sort"
"time"

"golang.org/x/xerrors"

"github.com/aquasecurity/defsec/pkg/scan"
"github.com/aquasecurity/tml"
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/flag"
pkgReport "github.com/aquasecurity/trivy/pkg/report"
Expand Down Expand Up @@ -55,6 +59,15 @@ func (r *Report) Failed() bool {

// Write writes the results in the give format
func Write(rep *Report, opt flag.Options, fromCache bool) error {
output, err := opt.OutputWriter()
if err != nil {
return xerrors.Errorf("failed to create output file: %w", err)
}
defer output.Close()

if opt.Compliance.Spec.ID != "" {
return writeCompliance(rep, opt, output)
}

var filtered []types.Result

Expand Down Expand Up @@ -91,7 +104,7 @@ func Write(rep *Report, opt flag.Options, fromCache bool) error {

// ensure color/formatting is disabled for pipes/non-pty
var useANSI bool
if opt.Output == os.Stdout {
if opt.Output == "" {
if o, err := os.Stdout.Stat(); err == nil {
useANSI = (o.Mode() & os.ModeCharDevice) == os.ModeCharDevice
}
Expand All @@ -102,33 +115,44 @@ func Write(rep *Report, opt flag.Options, fromCache bool) error {

switch {
case len(opt.Services) == 1 && opt.ARN == "":
if err := writeResourceTable(rep, filtered, opt.Output, opt.Services[0]); err != nil {
if err := writeResourceTable(rep, filtered, output, opt.Services[0]); err != nil {
return err
}
case len(opt.Services) == 1 && opt.ARN != "":
if err := writeResultsForARN(rep, filtered, opt.Output, opt.Services[0], opt.ARN, opt.Severities); err != nil {
if err := writeResultsForARN(rep, filtered, output, opt.Services[0], opt.ARN, opt.Severities); err != nil {
return err
}
default:
if err := writeServiceTable(rep, filtered, opt.Output); err != nil {
if err := writeServiceTable(rep, filtered, output); err != nil {
return err
}
}

// render cache info
if fromCache {
_ = tml.Fprintf(opt.Output, "\n<blue>This scan report was loaded from cached results. If you'd like to run a fresh scan, use --update-cache.</blue>\n")
_ = tml.Fprintf(output, "\n<blue>This scan report was loaded from cached results. If you'd like to run a fresh scan, use --update-cache.</blue>\n")
}

return nil
default:
return pkgReport.Write(base, pkgReport.Option{
Format: opt.Format,
Output: opt.Output,
Severities: opt.Severities,
OutputTemplate: opt.Template,
IncludeNonFailures: opt.IncludeNonFailures,
Trace: opt.Trace,
})
return pkgReport.Write(base, opt)
}
}

func writeCompliance(rep *Report, opt flag.Options, output io.Writer) error {
var crr []types.Results
for _, r := range rep.Results {
crr = append(crr, r.Results)
}

complianceReport, err := cr.BuildComplianceReport(crr, opt.Compliance)
if err != nil {
return xerrors.Errorf("compliance report build error: %w", err)
}

return cr.Write(complianceReport, cr.Option{
Format: opt.Format,
Report: opt.ReportFormat,
Output: output,
})
}
12 changes: 8 additions & 4 deletions pkg/cloud/report/resource_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package report

import (
"bytes"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -109,15 +110,18 @@ No problems detected.
tt.options.AWSOptions.Services,
)

buffer := bytes.NewBuffer([]byte{})
tt.options.Output = buffer
output := filepath.Join(t.TempDir(), "output")
tt.options.Output = output
require.NoError(t, Write(report, tt.options, tt.fromCache))

assert.Equal(t, "AWS", report.Provider)
assert.Equal(t, tt.options.AWSOptions.Account, report.AccountID)
assert.Equal(t, tt.options.AWSOptions.Region, report.Region)
assert.ElementsMatch(t, tt.options.AWSOptions.Services, report.ServicesInScope)
assert.Equal(t, tt.expected, buffer.String())

b, err := os.ReadFile(output)
require.NoError(t, err)
assert.Equal(t, tt.expected, string(b))
})
}
}
12 changes: 8 additions & 4 deletions pkg/cloud/report/result_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package report

import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"

Expand Down Expand Up @@ -68,15 +69,18 @@ See https://avd.aquasec.com/misconfig/avd-aws-9999
tt.options.AWSOptions.Services,
)

buffer := bytes.NewBuffer([]byte{})
tt.options.Output = buffer
output := filepath.Join(t.TempDir(), "output")
tt.options.Output = output
require.NoError(t, Write(report, tt.options, tt.fromCache))

b, err := os.ReadFile(output)
require.NoError(t, err)

assert.Equal(t, "AWS", report.Provider)
assert.Equal(t, tt.options.AWSOptions.Account, report.AccountID)
assert.Equal(t, tt.options.AWSOptions.Region, report.Region)
assert.ElementsMatch(t, tt.options.AWSOptions.Services, report.ServicesInScope)
assert.Equal(t, tt.expected, strings.ReplaceAll(buffer.String(), "\r\n", "\n"))
assert.Equal(t, tt.expected, strings.ReplaceAll(string(b), "\r\n", "\n"))
})
}
}
14 changes: 9 additions & 5 deletions pkg/cloud/report/service_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package report

import (
"bytes"
"os"
"path/filepath"
"testing"

"github.com/aquasecurity/trivy-db/pkg/types"
Expand Down Expand Up @@ -320,19 +321,22 @@ Scan Overview for AWS Account
tt.options.AWSOptions.Services,
)

buffer := bytes.NewBuffer([]byte{})
tt.options.Output = buffer
output := filepath.Join(t.TempDir(), "output")
tt.options.Output = output
require.NoError(t, Write(report, tt.options, tt.fromCache))

assert.Equal(t, "AWS", report.Provider)
assert.Equal(t, tt.options.AWSOptions.Account, report.AccountID)
assert.Equal(t, tt.options.AWSOptions.Region, report.Region)
assert.ElementsMatch(t, tt.options.AWSOptions.Services, report.ServicesInScope)

b, err := os.ReadFile(output)
require.NoError(t, err)
if tt.options.Format == "json" {
// json output can be formatted/ordered differently - we just care that the data matches
assert.JSONEq(t, tt.expected, buffer.String())
assert.JSONEq(t, tt.expected, string(b))
} else {
assert.Equal(t, tt.expected, buffer.String())
assert.Equal(t, tt.expected, string(b))
}
})
}
Expand Down

0 comments on commit 20c2246

Please sign in to comment.