mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
233 lines
6.6 KiB
Go
233 lines
6.6 KiB
Go
package flag
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"golang.org/x/exp/slices"
|
|
"golang.org/x/xerrors"
|
|
|
|
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
|
|
"github.com/aquasecurity/trivy/pkg/log"
|
|
"github.com/aquasecurity/trivy/pkg/report"
|
|
"github.com/aquasecurity/trivy/pkg/result"
|
|
)
|
|
|
|
// e.g. config yaml
|
|
// report:
|
|
// format: table
|
|
// dependency-tree: true
|
|
// exit-code: 1
|
|
// severity: HIGH,CRITICAL
|
|
var (
|
|
FormatFlag = Flag{
|
|
Name: "format",
|
|
ConfigName: "format",
|
|
Shorthand: "f",
|
|
Value: report.FormatTable,
|
|
Usage: "format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github)",
|
|
}
|
|
ReportFormatFlag = Flag{
|
|
Name: "report",
|
|
ConfigName: "report",
|
|
Value: "all",
|
|
Usage: "specify a report format for the output. (all,summary)",
|
|
}
|
|
TemplateFlag = Flag{
|
|
Name: "template",
|
|
ConfigName: "template",
|
|
Shorthand: "t",
|
|
Value: "",
|
|
Usage: "output template",
|
|
}
|
|
DependencyTreeFlag = Flag{
|
|
Name: "dependency-tree",
|
|
ConfigName: "dependency-tree",
|
|
Value: false,
|
|
Usage: "show dependency origin tree (EXPERIMENTAL)",
|
|
}
|
|
ListAllPkgsFlag = Flag{
|
|
Name: "list-all-pkgs",
|
|
ConfigName: "list-all-pkgs",
|
|
Value: false,
|
|
Usage: "enabling the option will output all packages regardless of vulnerability",
|
|
}
|
|
IgnoreFileFlag = Flag{
|
|
Name: "ignorefile",
|
|
ConfigName: "ignorefile",
|
|
Value: result.DefaultIgnoreFile,
|
|
Usage: "specify .trivyignore file",
|
|
}
|
|
IgnorePolicyFlag = Flag{
|
|
Name: "ignore-policy",
|
|
ConfigName: "ignore-policy",
|
|
Value: "",
|
|
Usage: "specify the Rego file path to evaluate each vulnerability",
|
|
}
|
|
ExitCodeFlag = Flag{
|
|
Name: "exit-code",
|
|
ConfigName: "exit-code",
|
|
Value: 0,
|
|
Usage: "specify exit code when any security issues are found",
|
|
}
|
|
OutputFlag = Flag{
|
|
Name: "output",
|
|
ConfigName: "output",
|
|
Shorthand: "o",
|
|
Value: "",
|
|
Usage: "output file name",
|
|
}
|
|
SeverityFlag = Flag{
|
|
Name: "severity",
|
|
ConfigName: "severity",
|
|
Shorthand: "s",
|
|
Value: strings.Join(dbTypes.SeverityNames, ","),
|
|
Usage: "severities of security issues to be displayed (comma separated)",
|
|
}
|
|
)
|
|
|
|
// ReportFlagGroup composes common printer flag structs
|
|
// used for commands requiring reporting logic.
|
|
type ReportFlagGroup struct {
|
|
Format *Flag
|
|
ReportFormat *Flag
|
|
Template *Flag
|
|
DependencyTree *Flag
|
|
ListAllPkgs *Flag
|
|
IgnoreFile *Flag
|
|
IgnorePolicy *Flag
|
|
ExitCode *Flag
|
|
Output *Flag
|
|
Severity *Flag
|
|
}
|
|
|
|
type ReportOptions struct {
|
|
Format string
|
|
ReportFormat string
|
|
Template string
|
|
DependencyTree bool
|
|
ListAllPkgs bool
|
|
IgnoreFile string
|
|
ExitCode int
|
|
IgnorePolicy string
|
|
Output io.Writer
|
|
Severities []dbTypes.Severity
|
|
}
|
|
|
|
func NewReportFlagGroup() *ReportFlagGroup {
|
|
return &ReportFlagGroup{
|
|
Format: &FormatFlag,
|
|
ReportFormat: &ReportFormatFlag,
|
|
Template: &TemplateFlag,
|
|
DependencyTree: &DependencyTreeFlag,
|
|
ListAllPkgs: &ListAllPkgsFlag,
|
|
IgnoreFile: &IgnoreFileFlag,
|
|
IgnorePolicy: &IgnorePolicyFlag,
|
|
ExitCode: &ExitCodeFlag,
|
|
Output: &OutputFlag,
|
|
Severity: &SeverityFlag,
|
|
}
|
|
}
|
|
|
|
func (f *ReportFlagGroup) Name() string {
|
|
return "Report"
|
|
}
|
|
|
|
func (f *ReportFlagGroup) Flags() []*Flag {
|
|
return []*Flag{f.Format, f.ReportFormat, f.Template, f.DependencyTree, f.ListAllPkgs, f.IgnoreFile,
|
|
f.IgnorePolicy, f.ExitCode, f.Output, f.Severity}
|
|
}
|
|
|
|
func (f *ReportFlagGroup) ToOptions(out io.Writer) (ReportOptions, error) {
|
|
format := getString(f.Format)
|
|
template := getString(f.Template)
|
|
dependencyTree := getBool(f.DependencyTree)
|
|
listAllPkgs := getBool(f.ListAllPkgs)
|
|
output := getString(f.Output)
|
|
|
|
if template != "" {
|
|
if format == "" {
|
|
log.Logger.Warn("'--template' is ignored because '--format template' is not specified. Use '--template' option with '--format template' option.")
|
|
} else if format != "template" {
|
|
log.Logger.Warnf("'--template' is ignored because '--format %s' is specified. Use '--template' option with '--format template' option.", format)
|
|
}
|
|
} else {
|
|
if format == report.FormatTemplate {
|
|
log.Logger.Warn("'--format template' is ignored because '--template' is not specified. Specify '--template' option when you use '--format template'.")
|
|
}
|
|
}
|
|
|
|
// "--list-all-pkgs" option is unavailable with "--format table".
|
|
// If user specifies "--list-all-pkgs" with "--format table", we should warn it.
|
|
if listAllPkgs && format == report.FormatTable {
|
|
log.Logger.Warn(`"--list-all-pkgs" cannot be used with "--format table". Try "--format json" or other formats.`)
|
|
}
|
|
|
|
// "--dependency-tree" option is available only with "--format table".
|
|
if dependencyTree {
|
|
log.Logger.Infof(`"--dependency-tree" only shows dependencies for "package-lock.json" files`)
|
|
if format != report.FormatTable {
|
|
log.Logger.Warn(`"--dependency-tree" can be used only with "--format table".`)
|
|
}
|
|
}
|
|
|
|
// Enable '--list-all-pkgs' if needed
|
|
if f.forceListAllPkgs(format, listAllPkgs, dependencyTree) {
|
|
listAllPkgs = true
|
|
}
|
|
|
|
if output != "" {
|
|
var err error
|
|
if out, err = os.Create(output); err != nil {
|
|
return ReportOptions{}, xerrors.Errorf("failed to create an output file: %w", err)
|
|
}
|
|
}
|
|
|
|
return ReportOptions{
|
|
Format: format,
|
|
ReportFormat: getString(f.ReportFormat),
|
|
Template: template,
|
|
DependencyTree: dependencyTree,
|
|
ListAllPkgs: listAllPkgs,
|
|
IgnoreFile: getString(f.IgnoreFile),
|
|
ExitCode: getInt(f.ExitCode),
|
|
IgnorePolicy: getString(f.IgnorePolicy),
|
|
Output: out,
|
|
Severities: splitSeverity(getStringSlice(f.Severity)),
|
|
}, nil
|
|
}
|
|
|
|
func (f *ReportFlagGroup) forceListAllPkgs(format string, listAllPkgs, dependencyTree bool) bool {
|
|
if slices.Contains(report.SupportedSBOMFormats, format) && !listAllPkgs {
|
|
log.Logger.Debugf("%q automatically enables '--list-all-pkgs'.", report.SupportedSBOMFormats)
|
|
return true
|
|
}
|
|
if dependencyTree && !listAllPkgs {
|
|
log.Logger.Debugf("'--dependency-tree' enables '--list-all-pkgs'.")
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func splitSeverity(severity []string) []dbTypes.Severity {
|
|
switch {
|
|
case len(severity) == 0:
|
|
return nil
|
|
case len(severity) == 1 && strings.Contains(severity[0], ","): // get severities from flag
|
|
severity = strings.Split(severity[0], ",")
|
|
}
|
|
|
|
var severities []dbTypes.Severity
|
|
for _, s := range severity {
|
|
sev, err := dbTypes.NewSeverity(strings.ToUpper(s))
|
|
if err != nil {
|
|
log.Logger.Warnf("unknown severity option: %s", err)
|
|
continue
|
|
}
|
|
severities = append(severities, sev)
|
|
}
|
|
log.Logger.Debugf("Severities: %q", severities)
|
|
return severities
|
|
}
|