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: add --distro flag to manually specify OS distribution for vulnerability scanning #8070

Merged
merged 12 commits into from
Dec 9, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ trivy filesystem [flags] PATH
- "precise": Prioritizes precise by minimizing false positives.
- "comprehensive": Aims to detect more security findings at the cost of potential false positives.
(precise,comprehensive) (default "precise")
--distro string [EXPERIMENTAL] specify a distribution, <family>/<version>
--download-db-only download/update vulnerability database but don't run a scan
--download-java-db-only download/update Java index database but don't run a scan
--enable-modules strings [EXPERIMENTAL] module names to enable
Expand Down
1 change: 1 addition & 0 deletions docs/docs/references/configuration/cli/trivy_image.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ trivy image [flags] IMAGE_NAME
- "precise": Prioritizes precise by minimizing false positives.
- "comprehensive": Aims to detect more security findings at the cost of potential false positives.
(precise,comprehensive) (default "precise")
--distro string [EXPERIMENTAL] specify a distribution, <family>/<version>
--docker-host string unix domain socket path to use for docker scanning
--download-db-only download/update vulnerability database but don't run a scan
--download-java-db-only download/update Java index database but don't run a scan
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ trivy kubernetes [flags] [CONTEXT]
- "comprehensive": Aims to detect more security findings at the cost of potential false positives.
(precise,comprehensive) (default "precise")
--disable-node-collector When the flag is activated, the node-collector job will not be executed, thus skipping misconfiguration findings on the node.
--distro string [EXPERIMENTAL] specify a distribution, <family>/<version>
--download-db-only download/update vulnerability database but don't run a scan
--download-java-db-only download/update Java index database but don't run a scan
--exclude-kinds strings indicate the kinds exclude from scanning (example: node)
Expand Down
1 change: 1 addition & 0 deletions docs/docs/references/configuration/cli/trivy_rootfs.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ trivy rootfs [flags] ROOTDIR
- "precise": Prioritizes precise by minimizing false positives.
- "comprehensive": Aims to detect more security findings at the cost of potential false positives.
(precise,comprehensive) (default "precise")
--distro string [EXPERIMENTAL] specify a distribution, <family>/<version>
--download-db-only download/update vulnerability database but don't run a scan
--download-java-db-only download/update Java index database but don't run a scan
--enable-modules strings [EXPERIMENTAL] module names to enable
Expand Down
1 change: 1 addition & 0 deletions docs/docs/references/configuration/cli/trivy_sbom.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ trivy sbom [flags] SBOM_PATH
- "precise": Prioritizes precise by minimizing false positives.
- "comprehensive": Aims to detect more security findings at the cost of potential false positives.
(precise,comprehensive) (default "precise")
--distro string [EXPERIMENTAL] specify a distribution, <family>/<version>
--download-db-only download/update vulnerability database but don't run a scan
--download-java-db-only download/update Java index database but don't run a scan
--exit-code int specify exit code when any security issues are found
Expand Down
1 change: 1 addition & 0 deletions docs/docs/references/configuration/cli/trivy_vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ trivy vm [flags] VM_IMAGE
- "precise": Prioritizes precise by minimizing false positives.
- "comprehensive": Aims to detect more security findings at the cost of potential false positives.
(precise,comprehensive) (default "precise")
--distro string [EXPERIMENTAL] specify a distribution, <family>/<version>
--download-db-only download/update vulnerability database but don't run a scan
--download-java-db-only download/update Java index database but don't run a scan
--enable-modules strings [EXPERIMENTAL] module names to enable
Expand Down
3 changes: 3 additions & 0 deletions docs/docs/references/configuration/config-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,9 @@ scan:
# Same as '--detection-priority'
detection-priority: "precise"

# Same as '--distro'
distro: ""

# Same as '--file-patterns'
file-patterns: []

Expand Down
6 changes: 6 additions & 0 deletions docs/docs/scanner/vulnerability.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,12 @@ Regardless of the chosen mode, user review of detected vulnerabilities is crucia
- `precise`: Review thoroughly, considering potential missed vulnerabilities.
- `comprehensive`: Carefully investigate each reported vulnerability due to increased false positive possibility.

### Overriding OS version
By default, Trivy automatically detects the OS during container image scanning and performs vulnerability detection based on that OS.
However, in some cases, you may want to scan an image with a different OS version than the one detected.
Also, you may want to specify the OS version when OS is not detected.
For these cases, Trivy supports a `--distro` flag using the `<family>/<version>` format (e.g. `alpine/3.20`) to set the desired OS version.

[^1]: https://github.com/GoogleContainerTools/distroless

[nvd-CVE-2023-0464]: https://nvd.nist.gov/vuln/detail/CVE-2023-0464
Expand Down
17 changes: 17 additions & 0 deletions integration/client_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type csArgs struct {
ListAllPackages bool
Target string
secretConfig string
Distro string
}

func TestClientServer(t *testing.T) {
Expand All @@ -52,6 +53,18 @@ func TestClientServer(t *testing.T) {
},
golden: "testdata/alpine-39.json.golden",
},
{
name: "alpine 3.9 as alpine 3.10",
args: csArgs{
Input: "testdata/fixtures/images/alpine-39.tar.gz",
Distro: "alpine/3.10",
},
override: func(t *testing.T, want, got *types.Report) {
want.Metadata.OS.Name = "3.10"
want.Results[0].Target = "testdata/fixtures/images/alpine-39.tar.gz (alpine 3.10)"
},
golden: "testdata/alpine-39.json.golden",
},
{
name: "alpine 3.9 with high and critical severity",
args: csArgs{
Expand Down Expand Up @@ -684,6 +697,10 @@ func setupClient(t *testing.T, c csArgs, addr string, cacheDir string) []string
osArgs = append(osArgs, c.Target)
}

if c.Distro != "" {
osArgs = append(osArgs, "--distro", c.Distro)
}

return osArgs
}

Expand Down
31 changes: 26 additions & 5 deletions integration/standalone_tar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ func TestTar(t *testing.T) {
SkipDirs []string
SkipFiles []string
DetectionPriority ftypes.DetectionPriority
Distro string
}
tests := []struct {
name string
args args
golden string
name string
args args
golden string
override func(t *testing.T, want, got *types.Report)
}{
{
name: "alpine 3.9",
Expand Down Expand Up @@ -159,6 +161,19 @@ func TestTar(t *testing.T) {
},
golden: "testdata/alpine-39-ignore-cveids.json.golden",
},
{
name: "alpine 3.9 as alpine 3.10",
args: args{
Format: types.FormatJSON,
Input: "testdata/fixtures/images/alpine-39.tar.gz",
Distro: "alpine/3.10",
},
override: func(t *testing.T, want, got *types.Report) {
want.Metadata.OS.Name = "3.10"
want.Results[0].Target = "testdata/fixtures/images/alpine-39.tar.gz (alpine 3.10)"
},
golden: "testdata/alpine-39.json.golden",
},
{
name: "alpine 3.10",
args: args{
Expand Down Expand Up @@ -345,7 +360,7 @@ func TestTar(t *testing.T) {
name: "sle micro rancher 5.4",
args: args{
Format: types.FormatJSON,
Input: "testdata/fixtures/images/sle-micro-rancher-5.4_ndb.tar.gz",
Input: "testdata/fixtures/images/sle-micro-rancher-5.4_ndb.tar.gz",
},
golden: "testdata/sl-micro-rancher5.4.json.golden",
},
Expand Down Expand Up @@ -434,8 +449,14 @@ func TestTar(t *testing.T) {
osArgs = append(osArgs, "--detection-priority", string(tt.args.DetectionPriority))
}

if tt.args.Distro != "" {
osArgs = append(osArgs, "--distro", tt.args.Distro)
}

// Run Trivy
runTest(t, osArgs, tt.golden, "", tt.args.Format, runOptions{})
runTest(t, osArgs, tt.golden, "", tt.args.Format, runOptions{
override: overrideFuncs(overrideUID, tt.override),
})
})
}
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,8 @@ func NewRepositoryCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
repoFlags.ReportFlagGroup.Compliance = nil // disable '--compliance'
repoFlags.ReportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol'

repoFlags.ScanFlagGroup.DistroFlag = nil // `repo` subcommand doesn't support scanning OS packages, so we can disable `--distro`

repoFlags.CacheFlagGroup.CacheBackend.Default = string(cache.TypeMemory) // Use memory cache by default

cmd := &cobra.Command{
Expand Down
11 changes: 1 addition & 10 deletions pkg/commands/artifact/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,16 +498,7 @@ func (r *runner) initScannerConfig(ctx context.Context, opts flag.Options) (Scan
target = opts.Input
}

scanOptions := types.ScanOptions{
PkgTypes: opts.PkgTypes,
PkgRelationships: opts.PkgRelationships,
Scanners: opts.Scanners,
ImageConfigScanners: opts.ImageConfigScanners, // this is valid only for 'image' subcommand
ScanRemovedPackages: opts.ScanRemovedPkgs, // this is valid only for 'image' subcommand
LicenseCategories: opts.LicenseCategories,
FilePatterns: opts.FilePatterns,
IncludeDevDeps: opts.IncludeDevDeps,
}
scanOptions := opts.ScanOpts()

if len(opts.ImageConfigScanners) != 0 {
log.WithPrefix(log.PrefixContainerImage).Info("Container image config scanners", log.Any("scanners", opts.ImageConfigScanners))
Expand Down
8 changes: 8 additions & 0 deletions pkg/fanal/types/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ type OS struct {
Extended bool `json:"extended,omitempty"`
}

func (o *OS) String() string {
s := string(o.Family)
if o.Name != "" {
s += "/" + o.Name
}
return s
}

func (o *OS) Detected() bool {
return o.Family != ""
}
Expand Down
53 changes: 53 additions & 0 deletions pkg/fanal/types/artifact_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package types

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestOS_String(t *testing.T) {
type fields struct {
Family OSType
Name string
}
tests := []struct {
name string
fields fields
want string
}{
{
name: "family and name",
fields: fields{
Family: OSType("ubuntu"),
Name: "22.04",
},
want: "ubuntu/22.04",
},
{
name: "empty name",
fields: fields{
Family: OSType("ubuntu"),
Name: "",
},
want: "ubuntu",
},
{
name: "empty",
fields: fields{
Family: "",
Name: "",
},
want: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &OS{
Family: tt.fields.Family,
Name: tt.fields.Name,
}
assert.Equal(t, tt.want, o.String())
})
}
}
38 changes: 31 additions & 7 deletions pkg/fanal/types/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,37 @@ const (
OCP LangType = "ocp" // Red Hat OpenShift Container Platform
)

var AggregatingTypes = []LangType{
PythonPkg,
CondaPkg,
GemSpec,
NodePkg,
Jar,
}
var (
OSTypes = []OSType{
Alma,
Alpine,
Amazon,
Azure,
CBLMariner,
CentOS,
Chainguard,
Debian,
Fedora,
OpenSUSE,
OpenSUSELeap,
OpenSUSETumbleweed,
Oracle,
Photon,
RedHat,
Rocky,
SLEMicro,
SLES,
Ubuntu,
Wolfi,
}
AggregatingTypes = []LangType{
PythonPkg,
CondaPkg,
GemSpec,
NodePkg,
Jar,
}
)

// Config files
const (
Expand Down
15 changes: 15 additions & 0 deletions pkg/flag/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,21 @@ func (o *Options) enableSBOM() {
}
}

// ScanOpts returns options for scanning
func (o *Options) ScanOpts() types.ScanOptions {
return types.ScanOptions{
PkgTypes: o.PkgTypes,
PkgRelationships: o.PkgRelationships,
Scanners: o.Scanners,
ImageConfigScanners: o.ImageConfigScanners, // this is valid only for 'image' subcommand
ScanRemovedPackages: o.ScanRemovedPkgs, // this is valid only for 'image' subcommand
LicenseCategories: o.LicenseCategories,
FilePatterns: o.FilePatterns,
IncludeDevDeps: o.IncludeDevDeps,
Distro: o.Distro,
}
}

// RegistryOpts returns options for OCI registries
func (o *Options) RegistryOpts() ftypes.RegistryOptions {
return ftypes.RegistryOptions{
Expand Down
Loading
Loading