Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Use new defsec options and improve path handling #1696

Merged
merged 3 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.16
require (
github.com/AlecAivazis/survey/v2 v2.3.4
github.com/Masterminds/semver v1.5.0
github.com/aquasecurity/defsec v0.38.0
github.com/aquasecurity/defsec v0.43.0
github.com/hashicorp/go-version v1.4.0
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf
github.com/liamg/clinch v1.5.6
Expand Down
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,20 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/aquasecurity/defsec v0.38.0 h1:jh9XCBIM7eIrYwdI4MpwcFBktB8ua+kc/s5IHCkBXEc=
github.com/aquasecurity/defsec v0.38.0/go.mod h1:/LFRX/+LFRViQPId8Nesgl1oNM6Fo86NH/V9Mu4akDA=
github.com/aquasecurity/defsec v0.38.1-0.20220425105347-2d6144076c6e h1:3IVhGWAPMApugdEZdPAxZOiGSjFYBF1EmmHcWZS+Lm8=
github.com/aquasecurity/defsec v0.38.1-0.20220425105347-2d6144076c6e/go.mod h1:/LFRX/+LFRViQPId8Nesgl1oNM6Fo86NH/V9Mu4akDA=
github.com/aquasecurity/defsec v0.40.0 h1:txQ8M0RGnrvBoHhEDmV53TJq9v/DKYClCFBTsI++wn0=
github.com/aquasecurity/defsec v0.40.0/go.mod h1:/LFRX/+LFRViQPId8Nesgl1oNM6Fo86NH/V9Mu4akDA=
github.com/aquasecurity/defsec v0.41.0 h1:LK4hbuSA6YuOEwp3pi9U/XdfedctENJsolpmZ3m5MUo=
github.com/aquasecurity/defsec v0.41.0/go.mod h1:/LFRX/+LFRViQPId8Nesgl1oNM6Fo86NH/V9Mu4akDA=
github.com/aquasecurity/defsec v0.42.0 h1:dHKEVIXftgJvifr2yGjXDMLR+W4WLtbkJASlObbGS7g=
github.com/aquasecurity/defsec v0.42.0/go.mod h1:/LFRX/+LFRViQPId8Nesgl1oNM6Fo86NH/V9Mu4akDA=
github.com/aquasecurity/defsec v0.42.1 h1:hOmGXUpjjCsZhkNI8SvMnqMKQxU4yclk8rmaDusioqs=
github.com/aquasecurity/defsec v0.42.1/go.mod h1:/LFRX/+LFRViQPId8Nesgl1oNM6Fo86NH/V9Mu4akDA=
github.com/aquasecurity/defsec v0.42.2-0.20220425141632-404c68bfeda9 h1:KDCK+DJ2Ez50apAbMo5baU2nocLm5XZBdHnB1lrL2S8=
github.com/aquasecurity/defsec v0.42.2-0.20220425141632-404c68bfeda9/go.mod h1:/LFRX/+LFRViQPId8Nesgl1oNM6Fo86NH/V9Mu4akDA=
github.com/aquasecurity/defsec v0.43.0 h1:3rnumsRe4liFmfHk43Pr6HaM6fd5lDiXSDijQKNDUAU=
github.com/aquasecurity/defsec v0.43.0/go.mod h1:/LFRX/+LFRViQPId8Nesgl1oNM6Fo86NH/V9Mu4akDA=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
Expand Down
68 changes: 38 additions & 30 deletions internal/app/tfsec/cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"path/filepath"
"strings"

"github.com/aquasecurity/defsec/pkg/scanners/options"

"github.com/aquasecurity/tfsec/internal/pkg/custom"

"github.com/aquasecurity/defsec/pkg/scan"
Expand Down Expand Up @@ -142,79 +144,79 @@ func excludeFunc(excludePaths []string) func(results scan.Results) scan.Results
}
}

func configureOptions(cmd *cobra.Command, fsRoot, dir string) ([]scanner.Option, error) {

var options []scanner.Option
options = append(
options,
scanner.OptionWithSingleThread(singleThreadedMode),
scanner.OptionStopOnHCLError(!ignoreHCLErrors),
scanner.OptionStopOnRuleErrors(stopOnCheckError),
scanner.OptionSkipDownloaded(excludeDownloaded),
scanner.OptionScanAllDirectories(allDirs),
scanner.OptionWithWorkspaceName(workspace),
scanner.OptionWithAlternativeIDProvider(legacy.FindIDs),
scanner.OptionWithPolicyNamespaces("custom"),
scanner.OptionWithDownloads(!noModuleDownloads),
scanner.OptionWithRegoOnly(regoOnly),
func configureOptions(cmd *cobra.Command, fsRoot, dir string) ([]options.ScannerOption, error) {

var scannerOptions []options.ScannerOption
scannerOptions = append(
scannerOptions,
scanner.ScannerWithSingleThread(singleThreadedMode),
scanner.ScannerWithStopOnHCLError(!ignoreHCLErrors),
scanner.ScannerWithStopOnRuleErrors(stopOnCheckError),
scanner.ScannerWithSkipDownloaded(excludeDownloaded),
scanner.ScannerWithAllDirectories(allDirs),
scanner.ScannerWithWorkspaceName(workspace),
scanner.ScannerWithAlternativeIDProvider(legacy.FindIDs),
options.ScannerWithPolicyNamespaces("custom"),
scanner.ScannerWithDownloadsAllowed(!noModuleDownloads),
scanner.ScannerWithRegoOnly(regoOnly),
)

if len(excludePaths) > 0 {
options = append(options, scanner.OptionWithResultsFilter(excludeFunc(excludePaths)))
scannerOptions = append(scannerOptions, scanner.ScannerWithResultsFilter(excludeFunc(excludePaths)))
}

if len(tfvarsPaths) > 0 {
fixedPaths, err := makePathsRelativeToFSRoot(fsRoot, tfvarsPaths)
if err != nil {
return nil, fmt.Errorf("tfvars problem: %w", err)
}
options = append(options, scanner.OptionWithTFVarsPaths(fixedPaths))
scannerOptions = append(scannerOptions, scanner.ScannerWithTFVarsPaths(fixedPaths...))
}

if regoPolicyDir != "" {
fixedPath, err := makePathRelativeToFSRoot(fsRoot, regoPolicyDir)
if err != nil {
return nil, fmt.Errorf("rego policy dir problem: %w", err)
}
options = append(options, scanner.OptionWithPolicyDirs(fixedPath))
scannerOptions = append(scannerOptions, options.ScannerWithPolicyDirs(fixedPath))
}

if disableIgnores {
options = append(options, scanner.OptionNoIgnores())
scannerOptions = append(scannerOptions, scanner.ScannerWithNoIgnores())
}

if minimumSeverity != "" {
sev := severity.StringToSeverity(minimumSeverity)
if sev == severity.None {
return nil, fmt.Errorf("'%s' is not a valid severity - should be one of CRITICAL, HIGH, MEDIUM, LOW", minimumSeverity)
}
options = append(options, scanner.OptionWithMinimumSeverity(sev))
scannerOptions = append(scannerOptions, scanner.ScannerWithMinimumSeverity(sev))
}

if filterResults != "" {
longIDs := strings.Split(filterResults, ",")
options = append(options, scanner.OptionIncludeRules(longIDs))
scannerOptions = append(scannerOptions, scanner.ScannerWithIncludedRules(longIDs))
}

if excludedRuleIDs != "" {
options = append(options, scanner.OptionExcludeRules(strings.Split(excludedRuleIDs, ",")))
scannerOptions = append(scannerOptions, scanner.ScannerWithExcludedRules(strings.Split(excludedRuleIDs, ",")))
}

if debug {
options = append(options, scanner.OptionWithDebug(cmd.ErrOrStderr()))
scannerOptions = append(scannerOptions, options.ScannerWithDebug(cmd.ErrOrStderr()))
}

if printRegoInput {
options = append(options, scanner.OptionWithStateFunc(func(s *state.State) {
scannerOptions = append(scannerOptions, scanner.ScannerWithStateFunc(func(s *state.State) {
data, _ := json.Marshal(s.ToRego())
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "\n%s\n\n", string(data))
}))
}

return applyConfigFiles(options, dir)
return applyConfigFiles(scannerOptions, dir)
}

func applyConfigFiles(options []scanner.Option, dir string) ([]scanner.Option, error) {
func applyConfigFiles(options []options.ScannerOption, dir string) ([]options.ScannerOption, error) {
if configFile == "" {
configDir := filepath.Join(dir, ".tfsec")
for _, filename := range []string{"config.json", "config.yml", "config.yaml"} {
Expand All @@ -231,11 +233,17 @@ func applyConfigFiles(options []scanner.Option, dir string) ([]scanner.Option, e
return nil, fmt.Errorf("minimum tfsec version requirement not satisfied")
}
if conf.MinimumSeverity != "" {
options = append(options, scanner.OptionWithMinimumSeverity(severity.StringToSeverity(conf.MinimumSeverity)))
options = append(options, scanner.ScannerWithMinimumSeverity(severity.StringToSeverity(conf.MinimumSeverity)))
}
if len(conf.SeverityOverrides) > 0 {
options = append(options, scanner.ScannerWithSeverityOverrides(conf.SeverityOverrides))
}
if len(conf.IncludedChecks) > 0 {
options = append(options, scanner.ScannerWithIncludedRules(conf.IncludedChecks))
}
if len(conf.ExcludedChecks) > 0 {
options = append(options, scanner.ScannerWithExcludedRules(append(conf.ExcludedChecks, excludedRuleIDs)))
}
options = append(options, scanner.OptionWithSeverityOverrides(conf.SeverityOverrides))
options = append(options, scanner.OptionIncludeRules(conf.IncludedChecks))
options = append(options, scanner.OptionExcludeRules(append(conf.ExcludedChecks, excludedRuleIDs)))
}
}
if customCheckDir == "" {
Expand Down
18 changes: 8 additions & 10 deletions internal/app/tfsec/cmd/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ import (
"github.com/liamg/tml"
)

func output(cmd *cobra.Command, baseFilename string, formats []string, dir string, results []scan.Result, metrics scanner.Metrics) error {
func output(cmd *cobra.Command, baseFilename string, formats []string, fsRoot, dir string, results []scan.Result, metrics scanner.Metrics) error {
if baseFilename == "" && len(formats) > 1 {
return fmt.Errorf("you must specify a base output filename with --out if you want to use multiple formats")
}

var files []string
for _, format := range formats {
if filename, err := outputFormat(cmd.OutOrStdout(), len(formats) > 1, baseFilename, format, dir, results, metrics); err != nil {
if filename, err := outputFormat(cmd.OutOrStdout(), len(formats) > 1, baseFilename, format, fsRoot, dir, results, metrics); err != nil {
return err
} else if filename != "" {
files = append(files, filename)
Expand Down Expand Up @@ -66,7 +66,7 @@ func gatherLinks(result scan.Result) []string {
return append(docsLink, links...)
}

func outputFormat(w io.Writer, addExtension bool, baseFilename string, format string, dir string, results scan.Results, metrics scanner.Metrics) (string, error) {
func outputFormat(w io.Writer, addExtension bool, baseFilename, format, fsRoot, dir string, results scan.Results, metrics scanner.Metrics) (string, error) {

factory := formatters.New().
WithDebugEnabled(debug).
Expand All @@ -79,28 +79,24 @@ func outputFormat(w io.Writer, addExtension bool, baseFilename string, format st
WithIncludePassed(includePassed)

var alsoStdout bool
var makeRelative bool
makeRelative := true

switch strings.ToLower(format) {
case "lovely", "default":
alsoStdout = true
factory.WithCustomFormatterFunc(formatter.DefaultWithMetrics(metrics, conciseOutput))
case "json":
makeRelative = true
factory.AsJSON()
makeRelative = false
case "csv":
makeRelative = true
factory.AsCSV()
case "checkstyle":
makeRelative = true
factory.AsCheckStyle()
case "junit":
makeRelative = true
factory.AsJUnit()
case "text":
factory.WithCustomFormatterFunc(formatter.DefaultWithMetrics(metrics, conciseOutput)).WithColoursEnabled(false)
case "sarif":
makeRelative = true
factory.AsSARIF()
case "gif":
factory.WithCustomFormatterFunc(formatter.GifWithMetrics(metrics))
Expand All @@ -109,7 +105,9 @@ func outputFormat(w io.Writer, addExtension bool, baseFilename string, format st
}

if makeRelative {
results.SetRelativeTo(dir)
results = results.RelativeTo(fsRoot, dir)
} else {
results = results.Absolute(fsRoot)
}

var outputPath string
Expand Down
2 changes: 1 addition & 1 deletion internal/app/tfsec/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func Root() *cobra.Command {
}

formats := strings.Split(format, ",")
if err := output(cmd, outputFlag, formats, rel, results, metrics); err != nil {
if err := output(cmd, outputFlag, formats, root, dir, results, metrics); err != nil {
return fmt.Errorf("failed to write output: %w", err)
}

Expand Down
24 changes: 18 additions & 6 deletions internal/pkg/formatter/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,7 @@ func makeFilenameNice(first scan.Result, baseDir string) (string, string, []simp
filename := innerRange.GetFilename()
topFilename := filename
var via []simpleLocation
if innerRange.GetSourcePrefix() == "" || strings.HasPrefix(innerRange.GetSourcePrefix(), ".") {
if relative, err := filepath.Rel(baseDir, filename); err == nil && !strings.Contains(relative, "..") {
filename = relative
}
} else {
if strings.HasPrefix(innerRange.GetSourcePrefix(), ".") {
m := first.Metadata()
mod := &m
lastFilename := m.Range().GetFilename()
Expand Down Expand Up @@ -298,6 +294,7 @@ func printCodeLine(w io.Writer, i int, code string) {
)
}

// nolint
func highlightCode(b formatters.ConfigurableFormatter, result scan.Result) error {

srcFS := result.Metadata().Range().GetFS()
Expand All @@ -314,7 +311,22 @@ func highlightCode(b formatters.ConfigurableFormatter, result scan.Result) error
}
}

content, err := fs.ReadFile(srcFS, filepath.ToSlash(innerRange.GetLocalFilename()))
base := b.BaseDir()
if len(base) >= 2 && base[0] != '/' && base[1] == ':' {
base += "/"
}

fullPath := innerRange.GetLocalFilename()
if innerRange.GetSourcePrefix() == "" || strings.HasPrefix(innerRange.GetSourcePrefix(), ".") {
fullPath = filepath.ToSlash(filepath.Join(filepath.ToSlash(base), filepath.ToSlash(innerRange.GetLocalFilename())))
if strings.HasPrefix(fullPath, "/") {
fullPath = fullPath[1:]
} else if len(fullPath) > 2 && fullPath[1] == ':' {
fullPath = fullPath[3:]
}
}

content, err := fs.ReadFile(srcFS, fullPath)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion test/flags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ func Test_Flag_Debug(t *testing.T) {
t.Run(flag, func(t *testing.T) {
out, err, exit := runWithArgs("./testdata/pass", "-f", "json", flag)
_ = parseJSON(t, out)
assert.Contains(t, err, "\n[debug:")
assert.Contains(t, err, "\n[scan:")
assert.Equal(t, 0, exit)
})
}
Expand Down