mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 07:10:41 -08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa8a8ba7dc | ||
|
|
769ed554b0 | ||
|
|
5f9a963ef6 | ||
|
|
d93a997800 | ||
|
|
f9be138aab | ||
|
|
c7f0bc92ae | ||
|
|
c2f3731873 | ||
|
|
7b4f2dc72f | ||
|
|
84677903a6 | ||
|
|
e1e02d785f |
2
.github/workflows/test.yaml
vendored
2
.github/workflows/test.yaml
vendored
@@ -11,7 +11,7 @@ on:
|
||||
pull_request:
|
||||
env:
|
||||
GO_VERSION: "1.18"
|
||||
TINYGO_VERSION: "0.23.0"
|
||||
TINYGO_VERSION: "0.24.0"
|
||||
jobs:
|
||||
test:
|
||||
name: Test
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/commands"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/plugin"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -10,8 +16,26 @@ var (
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := commands.NewApp(version)
|
||||
if err := app.Execute(); err != nil {
|
||||
if err := run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func run() error {
|
||||
// Trivy behaves as the specified plugin.
|
||||
if runAsPlugin := os.Getenv("TRIVY_RUN_AS_PLUGIN"); runAsPlugin != "" {
|
||||
if !plugin.IsPredefined(runAsPlugin) {
|
||||
return xerrors.Errorf("unknown plugin: %s", runAsPlugin)
|
||||
}
|
||||
if err := plugin.RunWithArgs(context.Background(), runAsPlugin, os.Args); err != nil {
|
||||
return xerrors.Errorf("plugin error: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
app := commands.NewApp(version)
|
||||
if err := app.Execute(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
2
docs/build/Dockerfile
vendored
2
docs/build/Dockerfile
vendored
@@ -1,4 +1,4 @@
|
||||
FROM squidfunk/mkdocs-material:8.2.10
|
||||
FROM squidfunk/mkdocs-material:8.3.9
|
||||
|
||||
## If you want to see exactly the same version as is published to GitHub pages
|
||||
## use a private image for insiders, which requires authentication.
|
||||
|
||||
6
docs/build/requirements.txt
vendored
6
docs/build/requirements.txt
vendored
@@ -11,13 +11,13 @@ mergedeep==1.3.4
|
||||
mike==1.1.2
|
||||
mkdocs==1.3.0
|
||||
mkdocs-macros-plugin==0.7.0
|
||||
mkdocs-material==8.2.10
|
||||
mkdocs-material==8.3.9
|
||||
mkdocs-material-extensions==1.0.3
|
||||
mkdocs-minify-plugin==0.5.0
|
||||
mkdocs-redirects==1.0.4
|
||||
packaging==21.3
|
||||
Pygments==2.11.2
|
||||
pymdown-extensions==9.3
|
||||
Pygments==2.12.0
|
||||
pymdown-extensions==9.5
|
||||
pyparsing==3.0.8
|
||||
python-dateutil==2.8.2
|
||||
PyYAML==6.0
|
||||
|
||||
@@ -5,14 +5,34 @@ Trivy can be used in air-gapped environments. Note that an allowlist is [here][a
|
||||
## Air-Gapped Environment for vulnerabilities
|
||||
|
||||
### Download the vulnerability database
|
||||
At first, you need to download the vulnerability database for use in air-gapped environments.
|
||||
Please follow [oras installation instruction][oras].
|
||||
=== "Trivy"
|
||||
|
||||
Download `db.tar.gz`:
|
||||
```
|
||||
TRIVY_TEMP_DIR=$(mktemp -d)
|
||||
trivy --cache-dir $TRIVY_TEMP_DIR image --download-db-only
|
||||
tar -cf ./db.tar.gz -C $TRIVY_TEMP_DIR/db metadata.json trivy.db
|
||||
rm -rf $TRIVY_TEMP_DIR
|
||||
```
|
||||
|
||||
```
|
||||
$ oras pull ghcr.io/aquasecurity/trivy-db:2 -a
|
||||
```
|
||||
=== "oras >= v0.13.0"
|
||||
At first, you need to download the vulnerability database for use in air-gapped environments.
|
||||
Please follow [oras installation instruction][oras].
|
||||
|
||||
Download `db.tar.gz`:
|
||||
|
||||
```
|
||||
$ oras pull ghcr.io/aquasecurity/trivy-db:2
|
||||
```
|
||||
|
||||
=== "oras < v0.13.0"
|
||||
At first, you need to download the vulnerability database for use in air-gapped environments.
|
||||
Please follow [oras installation instruction][oras].
|
||||
|
||||
Download `db.tar.gz`:
|
||||
|
||||
```
|
||||
$ oras pull -a ghcr.io/aquasecurity/trivy-db:2
|
||||
```
|
||||
|
||||
### Transfer the DB file into the air-gapped environment
|
||||
The way of transfer depends on the environment.
|
||||
|
||||
@@ -13,8 +13,8 @@ Cosign can generate key pairs and use them for signing and verification. Read mo
|
||||
In the following example, Trivy generates an SBOM in the spdx format, and then Cosign attaches an attestation of the SBOM to a container image with a local key pair.
|
||||
|
||||
```
|
||||
$ trivy image --format spdx -o predicate <IMAGE>
|
||||
$ cosign attest --key /path/to/cosign.key --type spdx --predicate predicate <IMAGE>
|
||||
$ trivy image --format spdx -o sbom.spdx <IMAGE>
|
||||
$ cosign attest --key /path/to/cosign.key --type spdx --predicate sbom.spdx <IMAGE>
|
||||
```
|
||||
|
||||
Then, you can verify attestations on the image.
|
||||
@@ -27,12 +27,12 @@ You can also create attestations of other formatted SBOM.
|
||||
|
||||
```
|
||||
# spdx-json
|
||||
$ trivy image --format spdx-json -o predicate <IMAGE>
|
||||
$ cosign attest --key /path/to/cosign.key --type spdx --predicate predicate <IMAGE>
|
||||
$ trivy image --format spdx-json -o sbom.spdx.json <IMAGE>
|
||||
$ cosign attest --key /path/to/cosign.key --type spdx --predicate sbom.spdx.json <IMAGE>
|
||||
|
||||
# cyclonedx
|
||||
$ trivy image --format cyclonedx -o predicate <IMAGE>
|
||||
$ cosign attest --key /path/to/cosign.key --type https://cyclonedx.org/schema --predicate predicate <IMAGE>
|
||||
$ trivy image --format cyclonedx -o sbom.cdx.json <IMAGE>
|
||||
$ cosign attest --key /path/to/cosign.key --type https://cyclonedx.org/schema --predicate sbom.cdx.json <IMAGE>
|
||||
```
|
||||
|
||||
## Keyless signing
|
||||
@@ -40,8 +40,8 @@ $ cosign attest --key /path/to/cosign.key --type https://cyclonedx.org/schema --
|
||||
You can use Cosign to sign without keys by authenticating with an OpenID Connect protocol supported by sigstore (Google, GitHub, or Microsoft).
|
||||
|
||||
```
|
||||
$ trivy image --format spdx -o predicate <IMAGE>
|
||||
$ COSIGN_EXPERIMENTAL=1 cosign attest --type spdx --predicate predicate <IMAGE>
|
||||
$ trivy image --format spdx -o sbom.spdx <IMAGE>
|
||||
$ COSIGN_EXPERIMENTAL=1 cosign attest --type spdx --predicate sbom.spdx <IMAGE>
|
||||
```
|
||||
|
||||
You can verify attestations.
|
||||
|
||||
@@ -276,6 +276,6 @@ $ trivy image --format template --template "@/usr/local/share/trivy/templates/ht
|
||||
|
||||
[new-json]: https://github.com/aquasecurity/trivy/discussions/1050
|
||||
[action]: https://github.com/aquasecurity/trivy-action
|
||||
[asff]: https://github.com/aquasecurity/trivy/blob/main/docs/advanced/integrations/aws-security-hub.md
|
||||
[asff]: https://github.com/aquasecurity/trivy/blob/main/docs/docs/integrations/aws-security-hub.md
|
||||
[sarif]: https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/managing-results-from-code-scanning
|
||||
[sprig]: http://masterminds.github.io/sprig/
|
||||
|
||||
@@ -138,6 +138,7 @@ theme:
|
||||
- navigation.tabs
|
||||
- navigation.tabs.sticky
|
||||
- navigation.sections
|
||||
- content.tabs.link
|
||||
|
||||
markdown_extensions:
|
||||
- pymdownx.highlight
|
||||
@@ -145,7 +146,8 @@ markdown_extensions:
|
||||
- admonition
|
||||
- footnotes
|
||||
- attr_list
|
||||
- pymdownx.tabbed
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- def_list
|
||||
- pymdownx.details
|
||||
- pymdownx.emoji:
|
||||
|
||||
@@ -68,15 +68,6 @@ func SetOut(out io.Writer) {
|
||||
func NewApp(version string) *cobra.Command {
|
||||
globalFlags := flag.NewGlobalFlagGroup()
|
||||
rootCmd := NewRootCommand(version, globalFlags)
|
||||
|
||||
if runAsPlugin := os.Getenv("TRIVY_RUN_AS_PLUGIN"); runAsPlugin != "" {
|
||||
rootCmd.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
return plugin.RunWithArgs(cmd.Context(), runAsPlugin, args)
|
||||
}
|
||||
rootCmd.DisableFlagParsing = true
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
rootCmd.AddCommand(
|
||||
NewImageCommand(globalFlags),
|
||||
NewFilesystemCommand(globalFlags),
|
||||
|
||||
26
pkg/db/db.go
26
pkg/db/db.go
@@ -149,15 +149,16 @@ func (c *Client) Download(ctx context.Context, dst string) error {
|
||||
log.Logger.Debug("no metadata file")
|
||||
}
|
||||
|
||||
if err := c.populateOCIArtifact(); err != nil {
|
||||
art, err := c.initOCIArtifact()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("OCI artifact error: %w", err)
|
||||
}
|
||||
|
||||
if err := c.artifact.Download(ctx, db.Dir(dst)); err != nil {
|
||||
if err = art.Download(ctx, db.Dir(dst)); err != nil {
|
||||
return xerrors.Errorf("database download error: %w", err)
|
||||
}
|
||||
|
||||
if err := c.updateDownloadedAt(dst); err != nil {
|
||||
if err = c.updateDownloadedAt(dst); err != nil {
|
||||
return xerrors.Errorf("failed to update downloaded_at: %w", err)
|
||||
}
|
||||
return nil
|
||||
@@ -182,14 +183,15 @@ func (c *Client) updateDownloadedAt(dst string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) populateOCIArtifact() error {
|
||||
if c.artifact == nil {
|
||||
repo := fmt.Sprintf("%s:%d", c.dbRepository, db.SchemaVersion)
|
||||
art, err := oci.NewArtifact(repo, dbMediaType, c.quiet, c.insecureSkipTLSVerify)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("OCI artifact error: %w", err)
|
||||
}
|
||||
c.artifact = art
|
||||
func (c *Client) initOCIArtifact() (*oci.Artifact, error) {
|
||||
if c.artifact != nil {
|
||||
return c.artifact, nil
|
||||
}
|
||||
return nil
|
||||
|
||||
repo := fmt.Sprintf("%s:%d", c.dbRepository, db.SchemaVersion)
|
||||
art, err := oci.NewArtifact(repo, dbMediaType, c.quiet, c.insecureSkipTLSVerify)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("OCI artifact error: %w", err)
|
||||
}
|
||||
return art, nil
|
||||
}
|
||||
|
||||
@@ -104,16 +104,17 @@ const (
|
||||
var (
|
||||
// TypeOSes has all OS-related analyzers
|
||||
TypeOSes = []Type{
|
||||
TypeAlpine, TypeAmazon, TypeDebian, TypePhoton, TypeCentOS,
|
||||
TypeOSRelease, TypeAlpine, TypeAmazon, TypeCBLMariner, TypeDebian, TypePhoton, TypeCentOS,
|
||||
TypeRocky, TypeAlma, TypeFedora, TypeOracle, TypeRedHatBase, TypeSUSE, TypeUbuntu,
|
||||
TypeApk, TypeDpkg, TypeRpm,
|
||||
TypeApk, TypeDpkg, TypeDpkgLicense, TypeRpm, TypeRpmqa,
|
||||
TypeApkRepo,
|
||||
}
|
||||
|
||||
// TypeLanguages has all language analyzers
|
||||
TypeLanguages = []Type{
|
||||
TypeBundler, TypeGemSpec, TypeCargo, TypeComposer, TypeJar, TypePom,
|
||||
TypeNpmPkgLock, TypeNodePkg, TypeYarn, TypePnpm, TypeNuget, TypePythonPkg, TypePip, TypePipenv,
|
||||
TypePoetry, TypeGoBinary, TypeGoMod,
|
||||
TypeNpmPkgLock, TypeNodePkg, TypeYarn, TypePnpm, TypeNuget, TypeDotNetDeps,
|
||||
TypePythonPkg, TypePip, TypePipenv, TypePoetry, TypeGoBinary, TypeGoMod,
|
||||
}
|
||||
|
||||
// TypeLockfiles has all lock file analyzers
|
||||
|
||||
@@ -220,7 +220,7 @@ func splitSeverity(severity []string) []dbTypes.Severity {
|
||||
|
||||
var severities []dbTypes.Severity
|
||||
for _, s := range severity {
|
||||
sev, err := dbTypes.NewSeverity(s)
|
||||
sev, err := dbTypes.NewSeverity(strings.ToUpper(s))
|
||||
if err != nil {
|
||||
log.Logger.Warnf("unknown severity option: %s", err)
|
||||
continue
|
||||
|
||||
@@ -43,6 +43,18 @@ func TestReportFlagGroup_ToOptions(t *testing.T) {
|
||||
Output: os.Stdout,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with a low case severity",
|
||||
fields: fields{
|
||||
severities: "critical",
|
||||
},
|
||||
want: flag.ReportOptions{
|
||||
Output: os.Stdout,
|
||||
Severities: []dbTypes.Severity{
|
||||
dbTypes.SeverityCritical,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with an unknown severity",
|
||||
fields: fields{
|
||||
|
||||
@@ -71,6 +71,7 @@ func run(ctx context.Context, opts flag.Options, cluster string, artifacts []*ar
|
||||
if err != nil {
|
||||
return xerrors.Errorf("k8s scan error: %w", err)
|
||||
}
|
||||
|
||||
if err := report.Write(r, report.Option{
|
||||
Format: opts.Format,
|
||||
Report: opts.ReportFormat,
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/aquasecurity/trivy-kubernetes/pkg/artifacts"
|
||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
)
|
||||
|
||||
@@ -129,6 +130,8 @@ type Writer interface {
|
||||
|
||||
// Write writes the results in the give format
|
||||
func Write(report Report, option Option, securityChecks []string, showEmpty bool) error {
|
||||
report.printErrors()
|
||||
|
||||
switch option.Format {
|
||||
case jsonFormat:
|
||||
jwriter := JSONWriter{Output: option.Output, Report: option.Report}
|
||||
@@ -220,3 +223,17 @@ func CreateResource(artifact *artifacts.Artifact, report types.Report, err error
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (r Report) printErrors() {
|
||||
for _, resource := range r.Vulnerabilities {
|
||||
if resource.Error != "" {
|
||||
log.Logger.Errorf("Error during vulnerabilities scan: %s", resource.Error)
|
||||
}
|
||||
}
|
||||
|
||||
for _, resource := range r.Misconfigurations {
|
||||
if resource.Error != "" {
|
||||
log.Logger.Errorf("Error during misconfiguration scan: %s", resource.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func (s *Scanner) scanVulns(ctx context.Context, artifact *artifacts.Artifact) (
|
||||
imageReport, err := s.runner.ScanImage(ctx, s.opts)
|
||||
|
||||
if err != nil {
|
||||
log.Logger.Debugf("failed to scan image %s: %s", image, err)
|
||||
log.Logger.Warnf("failed to scan image %s: %s", image, err)
|
||||
resources = append(resources, report.CreateResource(artifact, imageReport, err))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -84,8 +84,15 @@ type Manager struct {
|
||||
func NewManager(ctx context.Context) (*Manager, error) {
|
||||
m := &Manager{}
|
||||
|
||||
// The runtime must enable the following features because Tinygo uses these features to build.
|
||||
// cf. https://github.com/tinygo-org/tinygo/blob/b65447c7d567eea495805656f45472cc3c483e03/targets/wasi.json#L4
|
||||
c := wazero.NewRuntimeConfig().
|
||||
WithFeatureBulkMemoryOperations(true).
|
||||
WithFeatureNonTrappingFloatToIntConversion(true).
|
||||
WithFeatureSignExtensionOps(true)
|
||||
|
||||
// Create a new WebAssembly Runtime.
|
||||
m.runtime = wazero.NewRuntime()
|
||||
m.runtime = wazero.NewRuntimeWithConfig(c)
|
||||
|
||||
// Load WASM modules in local
|
||||
if err := m.loadModules(ctx); err != nil {
|
||||
|
||||
@@ -293,6 +293,11 @@ func RunWithArgs(ctx context.Context, url string, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsPredefined(name string) bool {
|
||||
_, ok := officialPlugins[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
func loadMetadata(dir string) (Plugin, error) {
|
||||
filePath := filepath.Join(dir, configFile)
|
||||
f, err := os.Open(filePath)
|
||||
|
||||
@@ -114,6 +114,9 @@ func (results Results) Failed() bool {
|
||||
if len(r.Secrets) > 0 {
|
||||
return true
|
||||
}
|
||||
if len(r.Licenses) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user