mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-21 23:00:42 -08:00
feat(cli): convert JSON reports into a different format (#4452)
Co-authored-by: Aurelien LAJOIE <aurelien.lajoie@kili-technology.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
# Reporting
|
# Reporting
|
||||||
|
|
||||||
|
## Supported Formats
|
||||||
Trivy supports the following formats:
|
Trivy supports the following formats:
|
||||||
|
|
||||||
- Table
|
- Table
|
||||||
@@ -8,7 +9,7 @@ Trivy supports the following formats:
|
|||||||
- Template
|
- Template
|
||||||
- SBOM
|
- SBOM
|
||||||
|
|
||||||
## Table (Default)
|
### Table (Default)
|
||||||
|
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
@@ -21,7 +22,7 @@ Trivy supports the following formats:
|
|||||||
$ trivy image -f table golang:1.12-alpine
|
$ trivy image -f table golang:1.12-alpine
|
||||||
```
|
```
|
||||||
|
|
||||||
### Show origins of vulnerable dependencies
|
#### Show origins of vulnerable dependencies
|
||||||
|
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
@@ -105,7 +106,7 @@ Also, **glob-parent@3.1.0** with some vulnerabilities is included through chain
|
|||||||
|
|
||||||
Then, you can try to update **axios@0.21.4** and **cra-append-sw@2.7.0** to resolve vulnerabilities in **follow-redirects@1.14.6** and **glob-parent@3.1.0**.
|
Then, you can try to update **axios@0.21.4** and **cra-append-sw@2.7.0** to resolve vulnerabilities in **follow-redirects@1.14.6** and **glob-parent@3.1.0**.
|
||||||
|
|
||||||
## JSON
|
### JSON
|
||||||
|
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
@@ -239,7 +240,7 @@ $ trivy image -f json -o results.json golang:1.12-alpine
|
|||||||
|
|
||||||
`VulnerabilityID`, `PkgName`, `InstalledVersion`, and `Severity` in `Vulnerabilities` are always filled with values, but other fields might be empty.
|
`VulnerabilityID`, `PkgName`, `InstalledVersion`, and `Severity` in `Vulnerabilities` are always filled with values, but other fields might be empty.
|
||||||
|
|
||||||
## SARIF
|
### SARIF
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
| Vulnerability | ✓ |
|
| Vulnerability | ✓ |
|
||||||
@@ -255,7 +256,7 @@ $ trivy image --format sarif -o report.sarif golang:1.12-alpine
|
|||||||
|
|
||||||
This SARIF file can be uploaded to GitHub code scanning results, and there is a [Trivy GitHub Action][action] for automating this process.
|
This SARIF file can be uploaded to GitHub code scanning results, and there is a [Trivy GitHub Action][action] for automating this process.
|
||||||
|
|
||||||
## Template
|
### Template
|
||||||
|
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
@@ -264,7 +265,7 @@ This SARIF file can be uploaded to GitHub code scanning results, and there is a
|
|||||||
| Secret | ✓ |
|
| Secret | ✓ |
|
||||||
| License | ✓ |
|
| License | ✓ |
|
||||||
|
|
||||||
### Custom Template
|
#### Custom Template
|
||||||
|
|
||||||
{% raw %}
|
{% raw %}
|
||||||
```
|
```
|
||||||
@@ -301,18 +302,18 @@ Critical: 0, High: 2
|
|||||||
|
|
||||||
For other features of sprig, see the official [sprig][sprig] documentation.
|
For other features of sprig, see the official [sprig][sprig] documentation.
|
||||||
|
|
||||||
### Load templates from a file
|
#### Load templates from a file
|
||||||
You can load templates from a file prefixing the template path with an @.
|
You can load templates from a file prefixing the template path with an @.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ trivy image --format template --template "@/path/to/template" golang:1.12-alpine
|
$ trivy image --format template --template "@/path/to/template" golang:1.12-alpine
|
||||||
```
|
```
|
||||||
|
|
||||||
### Default Templates
|
#### Default Templates
|
||||||
|
|
||||||
If Trivy is installed using rpm then default templates can be found at `/usr/local/share/trivy/templates`.
|
If Trivy is installed using rpm then default templates can be found at `/usr/local/share/trivy/templates`.
|
||||||
|
|
||||||
#### JUnit
|
##### JUnit
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
| Vulnerability | ✓ |
|
| Vulnerability | ✓ |
|
||||||
@@ -325,7 +326,7 @@ In the following example using the template `junit.tpl` XML can be generated.
|
|||||||
$ trivy image --format template --template "@contrib/junit.tpl" -o junit-report.xml golang:1.12-alpine
|
$ trivy image --format template --template "@contrib/junit.tpl" -o junit-report.xml golang:1.12-alpine
|
||||||
```
|
```
|
||||||
|
|
||||||
#### ASFF
|
##### ASFF
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
| Vulnerability | ✓ |
|
| Vulnerability | ✓ |
|
||||||
@@ -335,7 +336,7 @@ $ trivy image --format template --template "@contrib/junit.tpl" -o junit-report.
|
|||||||
|
|
||||||
Trivy also supports an [ASFF template for reporting findings to AWS Security Hub][asff]
|
Trivy also supports an [ASFF template for reporting findings to AWS Security Hub][asff]
|
||||||
|
|
||||||
#### HTML
|
##### HTML
|
||||||
| Scanner | Supported |
|
| Scanner | Supported |
|
||||||
|:----------------:|:---------:|
|
|:----------------:|:---------:|
|
||||||
| Vulnerability | ✓ |
|
| Vulnerability | ✓ |
|
||||||
@@ -353,9 +354,34 @@ The following example shows use of default HTML template when Trivy is installed
|
|||||||
$ trivy image --format template --template "@/usr/local/share/trivy/templates/html.tpl" -o report.html golang:1.12-alpine
|
$ trivy image --format template --template "@/usr/local/share/trivy/templates/html.tpl" -o report.html golang:1.12-alpine
|
||||||
```
|
```
|
||||||
|
|
||||||
## SBOM
|
### SBOM
|
||||||
See [here](../supply-chain/sbom.md) for details.
|
See [here](../supply-chain/sbom.md) for details.
|
||||||
|
|
||||||
|
## Converting
|
||||||
|
To generate multiple reports, you can generate the JSON report first and convert it to other formats with the `convert` subcommand.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ trivy image --format json -o result.json --list-all-pkgs debian:11
|
||||||
|
$ trivy convert --format cyclonedx --output result.cdx result.json
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
Please note that if you want to convert to a format that requires a list of packages,
|
||||||
|
such as SBOM, you need to add the `--list-all-pkgs` flag when outputting in JSON.
|
||||||
|
|
||||||
|
[Filtering options](./filtering.md) such as `--severity` are also available with `convert`.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Output all severities in JSON
|
||||||
|
$ trivy image --format json -o result.json --list-all-pkgs debian:11
|
||||||
|
|
||||||
|
# Output only critical issues in table format
|
||||||
|
$ trivy convert --format table --severity CRITICAL result.json
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
JSON reports from "trivy aws" and "trivy k8s" are not yet supported.
|
||||||
|
|
||||||
[cargo-auditable]: https://github.com/rust-secure-code/cargo-auditable/
|
[cargo-auditable]: https://github.com/rust-secure-code/cargo-auditable/
|
||||||
[action]: https://github.com/aquasecurity/trivy-action
|
[action]: https://github.com/aquasecurity/trivy-action
|
||||||
[asff]: ../../tutorials/integrations/aws-security-hub.md
|
[asff]: ../../tutorials/integrations/aws-security-hub.md
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ trivy [global flags] command [flags] target
|
|||||||
|
|
||||||
* [trivy aws](trivy_aws.md) - [EXPERIMENTAL] Scan AWS account
|
* [trivy aws](trivy_aws.md) - [EXPERIMENTAL] Scan AWS account
|
||||||
* [trivy config](trivy_config.md) - Scan config files for misconfigurations
|
* [trivy config](trivy_config.md) - Scan config files for misconfigurations
|
||||||
|
* [trivy convert](trivy_convert.md) - Convert Trivy JSON report into a different format
|
||||||
* [trivy filesystem](trivy_filesystem.md) - Scan local filesystem
|
* [trivy filesystem](trivy_filesystem.md) - Scan local filesystem
|
||||||
* [trivy image](trivy_image.md) - Scan a container image
|
* [trivy image](trivy_image.md) - Scan a container image
|
||||||
* [trivy kubernetes](trivy_kubernetes.md) - [EXPERIMENTAL] Scan kubernetes cluster
|
* [trivy kubernetes](trivy_kubernetes.md) - [EXPERIMENTAL] Scan kubernetes cluster
|
||||||
|
|||||||
52
docs/docs/references/configuration/cli/trivy_convert.md
Normal file
52
docs/docs/references/configuration/cli/trivy_convert.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
## trivy convert
|
||||||
|
|
||||||
|
Convert Trivy JSON report into a different format
|
||||||
|
|
||||||
|
```
|
||||||
|
trivy convert [flags] RESULT_JSON
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
# report conversion
|
||||||
|
$ trivy image --format json --output result.json --list-all-pkgs debian:11
|
||||||
|
$ trivy convert --format cyclonedx --output result.cdx result.json
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
```
|
||||||
|
--compliance string compliance report to generate
|
||||||
|
--dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages
|
||||||
|
--exit-code int specify exit code when any security issues are found
|
||||||
|
--exit-on-eol int exit with the specified code when the OS reaches end of service/life
|
||||||
|
-f, --format string format (table, json, template, sarif, cyclonedx, spdx, spdx-json, github, cosign-vuln) (default "table")
|
||||||
|
-h, --help help for convert
|
||||||
|
--ignore-policy string specify the Rego file path to evaluate each vulnerability
|
||||||
|
--ignorefile string specify .trivyignore file (default ".trivyignore")
|
||||||
|
--list-all-pkgs enabling the option will output all packages regardless of vulnerability
|
||||||
|
-o, --output string output file name
|
||||||
|
--report string specify a report format for the output. (all,summary) (default "all")
|
||||||
|
-s, --severity string severities of security issues to be displayed (comma separated) (default "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL")
|
||||||
|
-t, --template string output template
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
--cache-dir string cache directory (default "/path/to/cache")
|
||||||
|
-c, --config string config path (default "trivy.yaml")
|
||||||
|
-d, --debug debug mode
|
||||||
|
--generate-default-config write the default config to trivy-default.yaml
|
||||||
|
--insecure allow insecure server connections
|
||||||
|
-q, --quiet suppress progress bar and log output
|
||||||
|
--timeout duration timeout (default 5m0s)
|
||||||
|
-v, --version show version
|
||||||
|
```
|
||||||
|
|
||||||
|
### SEE ALSO
|
||||||
|
|
||||||
|
* [trivy](trivy.md) - Unified security scanner
|
||||||
|
|
||||||
@@ -3,3 +3,9 @@
|
|||||||
### How to pronounce the name "Trivy"?
|
### How to pronounce the name "Trivy"?
|
||||||
|
|
||||||
`tri` is pronounced like **tri**gger, `vy` is pronounced like en**vy**.
|
`tri` is pronounced like **tri**gger, `vy` is pronounced like en**vy**.
|
||||||
|
|
||||||
|
### How to generate multiple reports?
|
||||||
|
See [here](../docs/configuration/reporting.md#converting).
|
||||||
|
|
||||||
|
### How to run Trivy under air-gapped environment?
|
||||||
|
See [here](../docs/advanced/air-gap.md).
|
||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/cloud"
|
"github.com/aquasecurity/trivy/pkg/cloud"
|
||||||
"github.com/aquasecurity/trivy/pkg/cloud/aws/scanner"
|
"github.com/aquasecurity/trivy/pkg/cloud/aws/scanner"
|
||||||
"github.com/aquasecurity/trivy/pkg/cloud/report"
|
"github.com/aquasecurity/trivy/pkg/cloud/report"
|
||||||
cmd "github.com/aquasecurity/trivy/pkg/commands/artifact"
|
"github.com/aquasecurity/trivy/pkg/commands/operation"
|
||||||
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
|
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
|
||||||
"github.com/aquasecurity/trivy/pkg/flag"
|
"github.com/aquasecurity/trivy/pkg/flag"
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
@@ -147,6 +147,6 @@ func Run(ctx context.Context, opt flag.Options) error {
|
|||||||
return fmt.Errorf("unable to write results: %w", err)
|
return fmt.Errorf("unable to write results: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Exit(opt, r.Failed())
|
operation.Exit(opt, r.Failed())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const (
|
|||||||
tableFormat = "table"
|
tableFormat = "table"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Report represents a kubernetes scan report
|
// Report represents an AWS scan report
|
||||||
type Report struct {
|
type Report struct {
|
||||||
Provider string
|
Provider string
|
||||||
AccountID string
|
AccountID string
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
javadb "github.com/aquasecurity/trivy-java-db/pkg/db"
|
javadb "github.com/aquasecurity/trivy-java-db/pkg/db"
|
||||||
awscommands "github.com/aquasecurity/trivy/pkg/cloud/aws/commands"
|
awscommands "github.com/aquasecurity/trivy/pkg/cloud/aws/commands"
|
||||||
"github.com/aquasecurity/trivy/pkg/commands/artifact"
|
"github.com/aquasecurity/trivy/pkg/commands/artifact"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/commands/convert"
|
||||||
"github.com/aquasecurity/trivy/pkg/commands/server"
|
"github.com/aquasecurity/trivy/pkg/commands/server"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
"github.com/aquasecurity/trivy/pkg/fanal/analyzer"
|
||||||
"github.com/aquasecurity/trivy/pkg/flag"
|
"github.com/aquasecurity/trivy/pkg/flag"
|
||||||
@@ -106,6 +107,7 @@ func NewApp(version string) *cobra.Command {
|
|||||||
NewClientCommand(globalFlags),
|
NewClientCommand(globalFlags),
|
||||||
NewServerCommand(globalFlags),
|
NewServerCommand(globalFlags),
|
||||||
NewConfigCommand(globalFlags),
|
NewConfigCommand(globalFlags),
|
||||||
|
NewConvertCommand(globalFlags),
|
||||||
NewPluginCommand(),
|
NewPluginCommand(),
|
||||||
NewModuleCommand(globalFlags),
|
NewModuleCommand(globalFlags),
|
||||||
NewKubernetesCommand(globalFlags),
|
NewKubernetesCommand(globalFlags),
|
||||||
@@ -494,6 +496,47 @@ func NewRepositoryCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewConvertCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||||
|
convertFlags := &flag.Flags{
|
||||||
|
ScanFlagGroup: &flag.ScanFlagGroup{},
|
||||||
|
ReportFlagGroup: flag.NewReportFlagGroup(),
|
||||||
|
}
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "convert [flags] RESULT_JSON",
|
||||||
|
Aliases: []string{"conv"},
|
||||||
|
GroupID: groupUtility,
|
||||||
|
Short: "Convert Trivy JSON report into a different format",
|
||||||
|
Example: ` # report conversion
|
||||||
|
$ trivy image --format json --output result.json --list-all-pkgs debian:11
|
||||||
|
$ trivy convert --format cyclonedx --output result.cdx result.json
|
||||||
|
`,
|
||||||
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if err := convertFlags.Bind(cmd); err != nil {
|
||||||
|
return xerrors.Errorf("flag bind error: %w", err)
|
||||||
|
}
|
||||||
|
return validateArgs(cmd, args)
|
||||||
|
},
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if err := convertFlags.Bind(cmd); err != nil {
|
||||||
|
return xerrors.Errorf("flag bind error: %w", err)
|
||||||
|
}
|
||||||
|
opts, err := convertFlags.ToOptions(cmd.Version, args, globalFlags, outputWriter)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("flag error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return convert.Run(cmd.Context(), opts)
|
||||||
|
},
|
||||||
|
SilenceErrors: true,
|
||||||
|
SilenceUsage: true,
|
||||||
|
}
|
||||||
|
cmd.SetFlagErrorFunc(flagErrorFunc)
|
||||||
|
convertFlags.AddFlags(cmd)
|
||||||
|
cmd.SetUsageTemplate(fmt.Sprintf(usageTemplate, convertFlags.Usages(cmd)))
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
// NewClientCommand returns the 'client' subcommand that is deprecated
|
// NewClientCommand returns the 'client' subcommand that is deprecated
|
||||||
func NewClientCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
func NewClientCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
||||||
remoteFlags := flag.NewClientFlags()
|
remoteFlags := flag.NewClientFlags()
|
||||||
@@ -799,7 +842,7 @@ func NewModuleCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("flag error: %w", err)
|
return xerrors.Errorf("flag error: %w", err)
|
||||||
}
|
}
|
||||||
return module.Install(cmd.Context(), opts.ModuleDir, repo, opts.Quiet, opts.Registry())
|
return module.Install(cmd.Context(), opts.ModuleDir, repo, opts.Quiet, opts.RegistryOpts())
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&cobra.Command{
|
&cobra.Command{
|
||||||
|
|||||||
@@ -4,9 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/aquasecurity/trivy/pkg/policy"
|
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@@ -26,6 +23,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
"github.com/aquasecurity/trivy/pkg/misconf"
|
"github.com/aquasecurity/trivy/pkg/misconf"
|
||||||
"github.com/aquasecurity/trivy/pkg/module"
|
"github.com/aquasecurity/trivy/pkg/module"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/policy"
|
||||||
pkgReport "github.com/aquasecurity/trivy/pkg/report"
|
pkgReport "github.com/aquasecurity/trivy/pkg/report"
|
||||||
"github.com/aquasecurity/trivy/pkg/result"
|
"github.com/aquasecurity/trivy/pkg/result"
|
||||||
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
"github.com/aquasecurity/trivy/pkg/rpc/client"
|
||||||
@@ -273,15 +271,7 @@ func (r *runner) scanArtifact(ctx context.Context, opts flag.Options, initialize
|
|||||||
|
|
||||||
func (r *runner) Filter(ctx context.Context, opts flag.Options, report types.Report) (types.Report, error) {
|
func (r *runner) Filter(ctx context.Context, opts flag.Options, report types.Report) (types.Report, error) {
|
||||||
// Filter results
|
// Filter results
|
||||||
err := result.Filter(ctx, report, result.FilterOption{
|
err := result.Filter(ctx, report, opts.FilterOpts())
|
||||||
Severities: opts.Severities,
|
|
||||||
IgnoreUnfixed: opts.IgnoreUnfixed,
|
|
||||||
IncludeNonFailures: opts.IncludeNonFailures,
|
|
||||||
IgnoreFile: opts.IgnoreFile,
|
|
||||||
PolicyFile: opts.IgnorePolicy,
|
|
||||||
IgnoreLicenses: opts.IgnoredLicenses,
|
|
||||||
VEXPath: opts.VEXPath,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.Report{}, xerrors.Errorf("filtering error: %w", err)
|
return types.Report{}, xerrors.Errorf("filtering error: %w", err)
|
||||||
}
|
}
|
||||||
@@ -290,18 +280,7 @@ func (r *runner) Filter(ctx context.Context, opts flag.Options, report types.Rep
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) Report(opts flag.Options, report types.Report) error {
|
func (r *runner) Report(opts flag.Options, report types.Report) error {
|
||||||
if err := pkgReport.Write(report, pkgReport.Option{
|
if err := pkgReport.Write(report, opts.ReportOpts()); err != nil {
|
||||||
AppVersion: opts.AppVersion,
|
|
||||||
Format: opts.Format,
|
|
||||||
Output: opts.Output,
|
|
||||||
Tree: opts.DependencyTree,
|
|
||||||
Severities: opts.Severities,
|
|
||||||
OutputTemplate: opts.Template,
|
|
||||||
IncludeNonFailures: opts.IncludeNonFailures,
|
|
||||||
Trace: opts.Trace,
|
|
||||||
Report: opts.ReportFormat,
|
|
||||||
Compliance: opts.Compliance,
|
|
||||||
}); err != nil {
|
|
||||||
return xerrors.Errorf("unable to write results: %w", err)
|
return xerrors.Errorf("unable to write results: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +299,7 @@ func (r *runner) initDB(ctx context.Context, opts flag.Options) error {
|
|||||||
|
|
||||||
// download the database file
|
// download the database file
|
||||||
noProgress := opts.Quiet || opts.NoProgress
|
noProgress := opts.Quiet || opts.NoProgress
|
||||||
if err := operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository, noProgress, opts.SkipDBUpdate, opts.Registry()); err != nil {
|
if err := operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository, noProgress, opts.SkipDBUpdate, opts.RegistryOpts()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,8 +454,8 @@ func Run(ctx context.Context, opts flag.Options, targetKind TargetKind) (err err
|
|||||||
return xerrors.Errorf("report error: %w", err)
|
return xerrors.Errorf("report error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
exitOnEOL(opts, report.Metadata)
|
operation.ExitOnEOL(opts, report.Metadata)
|
||||||
Exit(opts, report.Results.Failed())
|
operation.Exit(opts, report.Results.Failed())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -661,7 +640,7 @@ func initScannerConfig(opts flag.Options, cacheClient cache.Cache) (ScannerConfi
|
|||||||
|
|
||||||
// For image scanning
|
// For image scanning
|
||||||
ImageOption: ftypes.ImageOptions{
|
ImageOption: ftypes.ImageOptions{
|
||||||
RegistryOptions: opts.Registry(),
|
RegistryOptions: opts.RegistryOpts(),
|
||||||
DockerOptions: ftypes.DockerOptions{
|
DockerOptions: ftypes.DockerOptions{
|
||||||
Host: opts.DockerHost,
|
Host: opts.DockerHost,
|
||||||
},
|
},
|
||||||
@@ -704,19 +683,6 @@ func scan(ctx context.Context, opts flag.Options, initializeScanner InitializeSc
|
|||||||
return report, nil
|
return report, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Exit(opts flag.Options, failedResults bool) {
|
|
||||||
if opts.ExitCode != 0 && failedResults {
|
|
||||||
os.Exit(opts.ExitCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func exitOnEOL(opts flag.Options, m types.Metadata) {
|
|
||||||
if opts.ExitOnEOL != 0 && m.OS != nil && m.OS.Eosl {
|
|
||||||
log.Logger.Errorf("Detected EOL OS: %s %s", m.OS.Family, m.OS.Name)
|
|
||||||
os.Exit(opts.ExitOnEOL)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func canonicalVersion(ver string) string {
|
func canonicalVersion(ver string) string {
|
||||||
if ver == devVersion {
|
if ver == devVersion {
|
||||||
return ver
|
return ver
|
||||||
|
|||||||
48
pkg/commands/convert/run.go
Normal file
48
pkg/commands/convert/run.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/aquasecurity/trivy/pkg/commands/operation"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/flag"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/report"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/result"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Run(ctx context.Context, opts flag.Options) (err error) {
|
||||||
|
f, err := os.Open(opts.Target)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("file open error: %w", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
var r types.Report
|
||||||
|
if err = json.NewDecoder(f).Decode(&r); err != nil {
|
||||||
|
return xerrors.Errorf("json decode error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// "convert" supports JSON results produced by Trivy scanning other than AWS and Kubernetes
|
||||||
|
if r.ArtifactName == "" && r.ArtifactType == "" {
|
||||||
|
return xerrors.New("AWS and Kubernetes scanning reports are not yet supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = result.Filter(ctx, r, opts.FilterOpts()); err != nil {
|
||||||
|
return xerrors.Errorf("unable to filter results: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logger.Debug("Writing report to output...")
|
||||||
|
if err = report.Write(r, opts.ReportOpts()); err != nil {
|
||||||
|
return xerrors.Errorf("unable to write results: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
operation.ExitOnEOL(opts, r.Metadata)
|
||||||
|
operation.Exit(opts, r.Results.Failed())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -16,10 +16,11 @@ import (
|
|||||||
"github.com/aquasecurity/trivy-db/pkg/metadata"
|
"github.com/aquasecurity/trivy-db/pkg/metadata"
|
||||||
"github.com/aquasecurity/trivy/pkg/db"
|
"github.com/aquasecurity/trivy/pkg/db"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
"github.com/aquasecurity/trivy/pkg/fanal/cache"
|
||||||
"github.com/aquasecurity/trivy/pkg/fanal/types"
|
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/flag"
|
"github.com/aquasecurity/trivy/pkg/flag"
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
"github.com/aquasecurity/trivy/pkg/policy"
|
"github.com/aquasecurity/trivy/pkg/policy"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
"github.com/aquasecurity/trivy/pkg/utils/fsutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -109,7 +110,7 @@ func (c Cache) ClearArtifacts() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DownloadDB downloads the DB
|
// DownloadDB downloads the DB
|
||||||
func DownloadDB(ctx context.Context, appVersion, cacheDir, dbRepository string, quiet, skipUpdate bool, opt types.RegistryOptions) error {
|
func DownloadDB(ctx context.Context, appVersion, cacheDir, dbRepository string, quiet, skipUpdate bool, opt ftypes.RegistryOptions) error {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
@@ -201,3 +202,16 @@ func GetTLSConfig(caCertPath, certPath, keyPath string) (*x509.CertPool, tls.Cer
|
|||||||
|
|
||||||
return caCertPool, cert, nil
|
return caCertPool, cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Exit(opts flag.Options, failedResults bool) {
|
||||||
|
if opts.ExitCode != 0 && failedResults {
|
||||||
|
os.Exit(opts.ExitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExitOnEOL(opts flag.Options, m types.Metadata) {
|
||||||
|
if opts.ExitOnEOL != 0 && m.OS != nil && m.OS.Eosl {
|
||||||
|
log.Logger.Errorf("Detected EOL OS: %s %s", m.OS.Family, m.OS.Name)
|
||||||
|
os.Exit(opts.ExitOnEOL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func Run(ctx context.Context, opts flag.Options) (err error) {
|
|||||||
|
|
||||||
// download the database file
|
// download the database file
|
||||||
if err = operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository,
|
if err = operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository,
|
||||||
true, opts.SkipDBUpdate, opts.Registry()); err != nil {
|
true, opts.SkipDBUpdate, opts.RegistryOpts()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +58,6 @@ func Run(ctx context.Context, opts flag.Options) (err error) {
|
|||||||
m.Register()
|
m.Register()
|
||||||
|
|
||||||
server := rpcServer.NewServer(opts.AppVersion, opts.Listen, opts.CacheDir, opts.Token, opts.TokenHeader,
|
server := rpcServer.NewServer(opts.AppVersion, opts.Listen, opts.CacheDir, opts.Token, opts.TokenHeader,
|
||||||
opts.DBRepository, opts.Registry())
|
opts.DBRepository, opts.RegistryOpts())
|
||||||
return server.ListenAndServe(cache, opts.SkipDBUpdate)
|
return server.ListenAndServe(cache, opts.SkipDBUpdate)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
"github.com/aquasecurity/trivy/pkg/report"
|
"github.com/aquasecurity/trivy/pkg/report"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/result"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Flag struct {
|
type Flag struct {
|
||||||
@@ -122,8 +123,8 @@ func (o *Options) Align() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registry returns options for OCI registries
|
// RegistryOpts returns options for OCI registries
|
||||||
func (o *Options) Registry() ftypes.RegistryOptions {
|
func (o *Options) RegistryOpts() ftypes.RegistryOptions {
|
||||||
return ftypes.RegistryOptions{
|
return ftypes.RegistryOptions{
|
||||||
Credentials: o.Credentials,
|
Credentials: o.Credentials,
|
||||||
RegistryToken: o.RegistryToken,
|
RegistryToken: o.RegistryToken,
|
||||||
@@ -133,6 +134,34 @@ func (o *Options) Registry() ftypes.RegistryOptions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterOpts returns options for filtering
|
||||||
|
func (o *Options) FilterOpts() result.FilterOption {
|
||||||
|
return result.FilterOption{
|
||||||
|
Severities: o.Severities,
|
||||||
|
IgnoreUnfixed: o.IgnoreUnfixed,
|
||||||
|
IncludeNonFailures: o.IncludeNonFailures,
|
||||||
|
IgnoreFile: o.IgnoreFile,
|
||||||
|
PolicyFile: o.IgnorePolicy,
|
||||||
|
IgnoreLicenses: o.IgnoredLicenses,
|
||||||
|
VEXPath: o.VEXPath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Options) ReportOpts() report.Option {
|
||||||
|
return report.Option{
|
||||||
|
AppVersion: o.AppVersion,
|
||||||
|
Format: o.Format,
|
||||||
|
Output: o.Output,
|
||||||
|
Tree: o.DependencyTree,
|
||||||
|
Severities: o.Severities,
|
||||||
|
OutputTemplate: o.Template,
|
||||||
|
IncludeNonFailures: o.IncludeNonFailures,
|
||||||
|
Trace: o.Trace,
|
||||||
|
Report: o.ReportFormat,
|
||||||
|
Compliance: o.Compliance,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func addFlag(cmd *cobra.Command, flag *Flag) {
|
func addFlag(cmd *cobra.Command, flag *Flag) {
|
||||||
if flag == nil || flag.Name == "" {
|
if flag == nil || flag.Name == "" {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
|
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
|
||||||
"github.com/aquasecurity/trivy-kubernetes/pkg/k8s"
|
"github.com/aquasecurity/trivy-kubernetes/pkg/k8s"
|
||||||
cmd "github.com/aquasecurity/trivy/pkg/commands/artifact"
|
cmd "github.com/aquasecurity/trivy/pkg/commands/artifact"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/commands/operation"
|
||||||
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
|
cr "github.com/aquasecurity/trivy/pkg/compliance/report"
|
||||||
"github.com/aquasecurity/trivy/pkg/flag"
|
"github.com/aquasecurity/trivy/pkg/flag"
|
||||||
"github.com/aquasecurity/trivy/pkg/k8s/report"
|
"github.com/aquasecurity/trivy/pkg/k8s/report"
|
||||||
@@ -120,7 +121,7 @@ func (r *runner) run(ctx context.Context, artifacts []*artifacts.Artifact) error
|
|||||||
return xerrors.Errorf("unable to write results: %w", err)
|
return xerrors.Errorf("unable to write results: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Exit(r.flagOpts, rpt.Failed())
|
operation.Exit(r.flagOpts, rpt.Failed())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,6 +139,9 @@ func (m *Marshaler) Marshal(r types.Report) (*spdx.Document, error) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
for _, result := range r.Results {
|
for _, result := range r.Results {
|
||||||
|
if len(result.Packages) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
parentPackage, err := m.resultToSpdxPackage(result, r.Metadata.OS, pkgDownloadLocation)
|
parentPackage, err := m.resultToSpdxPackage(result, r.Metadata.OS, pkgDownloadLocation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to parse result: %w", err)
|
return nil, xerrors.Errorf("failed to parse result: %w", err)
|
||||||
|
|||||||
@@ -761,6 +761,69 @@ func TestMarshaler_Marshal(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "happy path secret",
|
||||||
|
inputReport: types.Report{
|
||||||
|
SchemaVersion: report.SchemaVersion,
|
||||||
|
ArtifactName: "secret",
|
||||||
|
ArtifactType: ftypes.ArtifactFilesystem,
|
||||||
|
Results: types.Results{
|
||||||
|
{
|
||||||
|
Target: "key.pem",
|
||||||
|
Class: types.ClassSecret,
|
||||||
|
Secrets: []ftypes.SecretFinding{
|
||||||
|
{
|
||||||
|
RuleID: "private-key",
|
||||||
|
Category: "AsymmetricPrivateKey",
|
||||||
|
Severity: "HIGH",
|
||||||
|
Title: "Asymmetric Private Key",
|
||||||
|
StartLine: 1,
|
||||||
|
EndLine: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSBOM: &spdx.Document{
|
||||||
|
SPDXVersion: spdx.Version,
|
||||||
|
DataLicense: spdx.DataLicense,
|
||||||
|
SPDXIdentifier: "DOCUMENT",
|
||||||
|
DocumentName: "secret",
|
||||||
|
DocumentNamespace: "http://aquasecurity.github.io/trivy/filesystem/secret-3ff14136-e09f-4df9-80ea-000000000001",
|
||||||
|
|
||||||
|
CreationInfo: &spdx.CreationInfo{
|
||||||
|
Creators: []common.Creator{
|
||||||
|
{
|
||||||
|
Creator: "aquasecurity",
|
||||||
|
CreatorType: "Organization",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Creator: fmt.Sprintf("trivy-0.38.1"),
|
||||||
|
CreatorType: "Tool",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Created: "2021-08-25T12:20:30Z",
|
||||||
|
},
|
||||||
|
Packages: []*spdx.Package{
|
||||||
|
{
|
||||||
|
PackageName: "secret",
|
||||||
|
PackageSPDXIdentifier: "Filesystem-5c08d34162a2c5d3",
|
||||||
|
PackageDownloadLocation: "NONE",
|
||||||
|
PackageAttributionTexts: []string{
|
||||||
|
"SchemaVersion: 2",
|
||||||
|
},
|
||||||
|
PrimaryPackagePurpose: tspdx.PackagePurposeSource,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Relationships: []*spdx.Relationship{
|
||||||
|
{
|
||||||
|
RefA: spdx.DocElementID{ElementRefID: "DOCUMENT"},
|
||||||
|
RefB: spdx.DocElementID{ElementRefID: "Filesystem-5c08d34162a2c5d3"},
|
||||||
|
Relationship: "DESCRIBES",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
clock := fake.NewFakeClock(time.Date(2021, 8, 25, 12, 20, 30, 5, time.UTC))
|
clock := fake.NewFakeClock(time.Date(2021, 8, 25, 12, 20, 30, 5, time.UTC))
|
||||||
|
|||||||
Reference in New Issue
Block a user