From da17dc72782cd68b5d2c4314a67936343462b75e Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Mon, 9 Dec 2024 20:46:49 +0900 Subject: [PATCH] feat: add `--distro` flag to manually specify OS distribution for vulnerability scanning (#8070) Signed-off-by: knqyf263 Co-authored-by: DmitriyLewen --- .../configuration/cli/trivy_filesystem.md | 1 + .../configuration/cli/trivy_image.md | 1 + .../configuration/cli/trivy_kubernetes.md | 1 + .../configuration/cli/trivy_rootfs.md | 1 + .../configuration/cli/trivy_sbom.md | 1 + .../references/configuration/cli/trivy_vm.md | 1 + .../references/configuration/config-file.md | 3 + docs/docs/scanner/vulnerability.md | 6 + integration/client_server_test.go | 17 ++ integration/standalone_tar_test.go | 31 +++- pkg/commands/app.go | 2 + pkg/commands/artifact/run.go | 11 +- pkg/fanal/types/artifact.go | 8 + pkg/fanal/types/artifact_test.go | 53 +++++++ pkg/fanal/types/const.go | 38 ++++- pkg/flag/options.go | 15 ++ pkg/flag/scan_flags.go | 25 +++ pkg/flag/scan_flags_test.go | 24 +++ pkg/rpc/client/client.go | 11 ++ pkg/rpc/server/server.go | 7 + pkg/scanner/local/scan.go | 8 +- pkg/scanner/local/scan_test.go | 69 ++++++++ pkg/types/scan.go | 1 + rpc/common/service.proto | 8 +- rpc/scanner/service.pb.go | 148 ++++++++++-------- rpc/scanner/service.proto | 1 + rpc/scanner/service.twirp.go | 87 +++++----- 27 files changed, 441 insertions(+), 138 deletions(-) create mode 100644 pkg/fanal/types/artifact_test.go diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 4bf6aa064999..dab87fc541fc 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -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, / --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 diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 41bc6ce842bc..d9c312602190 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -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, / --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 diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 9290ec0719b8..959532e1c806 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -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, / --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) diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index b84dcc5cd2c3..35cc54ff66a3 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -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, / --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 diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 9456e8883532..63f855b13335 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -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, / --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 diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 1074d878d866..6fe9de30fcd8 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -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, / --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 diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 365d2e5a57a9..fe6332522ee0 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -570,6 +570,9 @@ scan: # Same as '--detection-priority' detection-priority: "precise" + # Same as '--distro' + distro: "" + # Same as '--file-patterns' file-patterns: [] diff --git a/docs/docs/scanner/vulnerability.md b/docs/docs/scanner/vulnerability.md index 9d4e908c667b..26aeacee58e9 100644 --- a/docs/docs/scanner/vulnerability.md +++ b/docs/docs/scanner/vulnerability.md @@ -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 `/` 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 diff --git a/integration/client_server_test.go b/integration/client_server_test.go index 0df09c6ae051..6a9dda6a59f3 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -36,6 +36,7 @@ type csArgs struct { ListAllPackages bool Target string secretConfig string + Distro string } func TestClientServer(t *testing.T) { @@ -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{ @@ -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 } diff --git a/integration/standalone_tar_test.go b/integration/standalone_tar_test.go index 039293cbfd56..4a0027e7743a 100644 --- a/integration/standalone_tar_test.go +++ b/integration/standalone_tar_test.go @@ -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", @@ -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{ @@ -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", }, @@ -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), + }) }) } } diff --git a/pkg/commands/app.go b/pkg/commands/app.go index dbe3d54ba373..922ba6e29ba6 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -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{ diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 798838259ed2..8769ede2b8cb 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -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)) diff --git a/pkg/fanal/types/artifact.go b/pkg/fanal/types/artifact.go index b25aaa954188..c246b8dfbde8 100644 --- a/pkg/fanal/types/artifact.go +++ b/pkg/fanal/types/artifact.go @@ -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 != "" } diff --git a/pkg/fanal/types/artifact_test.go b/pkg/fanal/types/artifact_test.go new file mode 100644 index 000000000000..7da117699c4c --- /dev/null +++ b/pkg/fanal/types/artifact_test.go @@ -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()) + }) + } +} diff --git a/pkg/fanal/types/const.go b/pkg/fanal/types/const.go index 2e746f065782..3544f38b2aa4 100644 --- a/pkg/fanal/types/const.go +++ b/pkg/fanal/types/const.go @@ -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 ( diff --git a/pkg/flag/options.go b/pkg/flag/options.go index 38a36a80ae39..a3bcb0f61ec2 100644 --- a/pkg/flag/options.go +++ b/pkg/flag/options.go @@ -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{ diff --git a/pkg/flag/scan_flags.go b/pkg/flag/scan_flags.go index 544d56691883..15a1e04ce139 100644 --- a/pkg/flag/scan_flags.go +++ b/pkg/flag/scan_flags.go @@ -2,8 +2,11 @@ package flag import ( "runtime" + "slices" + "strings" "github.com/samber/lo" + "golang.org/x/xerrors" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" @@ -110,6 +113,11 @@ var ( - "comprehensive": Aims to detect more security findings at the cost of potential false positives. `, } + DistroFlag = Flag[string]{ + Name: "distro", + ConfigName: "scan.distro", + Usage: "[EXPERIMENTAL] specify a distribution, /", + } ) type ScanFlagGroup struct { @@ -123,6 +131,7 @@ type ScanFlagGroup struct { SBOMSources *Flag[[]string] RekorURL *Flag[string] DetectionPriority *Flag[string] + DistroFlag *Flag[string] } type ScanOptions struct { @@ -136,6 +145,7 @@ type ScanOptions struct { SBOMSources []string RekorURL string DetectionPriority ftypes.DetectionPriority + Distro ftypes.OS } func NewScanFlagGroup() *ScanFlagGroup { @@ -150,6 +160,7 @@ func NewScanFlagGroup() *ScanFlagGroup { RekorURL: RekorURLFlag.Clone(), Slow: SlowFlag.Clone(), DetectionPriority: DetectionPriority.Clone(), + DistroFlag: DistroFlag.Clone(), } } @@ -169,6 +180,7 @@ func (f *ScanFlagGroup) Flags() []Flagger { f.SBOMSources, f.RekorURL, f.DetectionPriority, + f.DistroFlag, } } @@ -188,6 +200,18 @@ func (f *ScanFlagGroup) ToOptions(args []string) (ScanOptions, error) { parallel = runtime.NumCPU() } + var distro ftypes.OS + if f.DistroFlag != nil && f.DistroFlag.Value() != "" { + family, version, _ := strings.Cut(f.DistroFlag.Value(), "/") + if !slices.Contains(ftypes.OSTypes, ftypes.OSType(family)) { + return ScanOptions{}, xerrors.Errorf("unknown OS family: %s, must be %q", family, ftypes.OSTypes) + } + distro = ftypes.OS{ + Family: ftypes.OSType(family), + Name: version, + } + } + return ScanOptions{ Target: target, SkipDirs: f.SkipDirs.Value(), @@ -199,5 +223,6 @@ func (f *ScanFlagGroup) ToOptions(args []string) (ScanOptions, error) { SBOMSources: f.SBOMSources.Value(), RekorURL: f.RekorURL.Value(), DetectionPriority: ftypes.DetectionPriority(f.DetectionPriority.Value()), + Distro: distro, }, nil } diff --git a/pkg/flag/scan_flags_test.go b/pkg/flag/scan_flags_test.go index d3ad792ae948..e0f8ffb9deb6 100644 --- a/pkg/flag/scan_flags_test.go +++ b/pkg/flag/scan_flags_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/flag" "github.com/aquasecurity/trivy/pkg/types" ) @@ -17,6 +18,7 @@ func TestScanFlagGroup_ToOptions(t *testing.T) { skipFiles []string offlineScan bool scanners string + distro string } tests := []struct { name string @@ -105,6 +107,26 @@ func TestScanFlagGroup_ToOptions(t *testing.T) { }, assertion: require.NoError, }, + { + name: "happy path `distro` flag", + fields: fields{ + distro: "alpine/3.20", + }, + want: flag.ScanOptions{ + Distro: ftypes.OS{ + Family: "alpine", + Name: "3.20", + }, + }, + assertion: require.NoError, + }, + { + name: "sad distro flag", + fields: fields{ + distro: "sad", + }, + assertion: require.Error, + }, } for _, tt := range tests { @@ -114,6 +136,7 @@ func TestScanFlagGroup_ToOptions(t *testing.T) { setSliceValue(flag.SkipFilesFlag.ConfigName, tt.fields.skipFiles) setValue(flag.OfflineScanFlag.ConfigName, tt.fields.offlineScan) setValue(flag.ScannersFlag.ConfigName, tt.fields.scanners) + setValue(flag.DistroFlag.ConfigName, tt.fields.distro) // Assert options f := &flag.ScanFlagGroup{ @@ -121,6 +144,7 @@ func TestScanFlagGroup_ToOptions(t *testing.T) { SkipFiles: flag.SkipFilesFlag.Clone(), OfflineScan: flag.OfflineScanFlag.Clone(), Scanners: flag.ScannersFlag.Clone(), + DistroFlag: flag.DistroFlag.Clone(), } got, err := f.ToOptions(tt.args) diff --git a/pkg/rpc/client/client.go b/pkg/rpc/client/client.go index ed7d130dcb06..dd13b145878f 100644 --- a/pkg/rpc/client/client.go +++ b/pkg/rpc/client/client.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "net/http" + "github.com/samber/lo" "github.com/twitchtv/twirp" "golang.org/x/xerrors" @@ -12,6 +13,7 @@ import ( r "github.com/aquasecurity/trivy/pkg/rpc" "github.com/aquasecurity/trivy/pkg/types" xstrings "github.com/aquasecurity/trivy/pkg/x/strings" + "github.com/aquasecurity/trivy/rpc/common" rpc "github.com/aquasecurity/trivy/rpc/scanner" ) @@ -75,6 +77,14 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys licenseCategories[string(category)] = &rpc.Licenses{Names: names} } + var distro *common.OS + if !lo.IsEmpty(opts.Distro) { + distro = &common.OS{ + Family: string(opts.Distro.Family), + Name: opts.Distro.Name, + } + } + var res *rpc.ScanResponse err := r.Retry(func() error { var err error @@ -88,6 +98,7 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys Scanners: xstrings.ToStringSlice(opts.Scanners), LicenseCategories: licenseCategories, IncludeDevDeps: opts.IncludeDevDeps, + Distro: distro, }, }) return err diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index bf4fa2ff5092..0bc7492783d8 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -75,12 +75,19 @@ func (s *ScanServer) ToOptions(in *rpcScanner.ScanOptions) types.ScanOptions { return ftypes.LicenseCategory(k), v.Names }) + var distro ftypes.OS + if in.Distro != nil { + distro.Family = ftypes.OSType(in.Distro.Family) + distro.Name = in.Distro.Name + } + return types.ScanOptions{ PkgTypes: in.PkgTypes, PkgRelationships: pkgRelationships, Scanners: scanners, IncludeDevDeps: in.IncludeDevDeps, LicenseCategories: licenseCategories, + Distro: distro, } } diff --git a/pkg/scanner/local/scan.go b/pkg/scanner/local/scan.go index 58cd4cc00167..7fd36fbb2643 100644 --- a/pkg/scanner/local/scan.go +++ b/pkg/scanner/local/scan.go @@ -90,10 +90,16 @@ func (s Scanner) Scan(ctx context.Context, targetName, artifactKey string, blobK return nil, ftypes.OS{}, xerrors.Errorf("failed to apply layers: %w", err) } + if !lo.IsEmpty(options.Distro) && !lo.IsEmpty(detail.OS) { + log.Info("Overriding detected OS with provided distro", log.String("detected", detail.OS.String()), + log.String("provided", options.Distro.String())) + detail.OS = options.Distro + } + target := types.ScanTarget{ Name: targetName, OS: detail.OS, - Repository: detail.Repository, + Repository: lo.Ternary(lo.IsEmpty(options.Distro), detail.Repository, nil), Packages: mergePkgs(detail.Packages, detail.ImageConfig.Packages, options), Applications: detail.Applications, Misconfigurations: mergeMisconfigurations(targetName, detail), diff --git a/pkg/scanner/local/scan_test.go b/pkg/scanner/local/scan_test.go index bdeb5166a2fa..0e904806fbd4 100644 --- a/pkg/scanner/local/scan_test.go +++ b/pkg/scanner/local/scan_test.go @@ -221,6 +221,75 @@ func TestScanner_Scan(t *testing.T) { Eosl: true, }, }, + { + name: "happy path with OS rewriting", + args: args{ + target: "alpine:latest", + layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, + options: types.ScanOptions{ + PkgTypes: []string{ + types.PkgTypeOS, + types.PkgTypeLibrary, + }, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.VulnerabilityScanner}, + Distro: ftypes.OS{ + Family: "alpine", + Name: "3.11", + }, + }, + }, + fixtures: []string{"testdata/fixtures/happy.yaml"}, + applyLayersExpectation: ApplierApplyLayersExpectation{ + Args: ApplierApplyLayersArgs{ + BlobIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, + }, + Returns: ApplierApplyLayersReturns{ + Detail: ftypes.ArtifactDetail{ + OS: ftypes.OS{ + Family: ftypes.Alpine, + Name: "3.10", + }, + Packages: []ftypes.Package{ + muslPkg, + }, + }, + }, + }, + wantResults: types.Results{ + { + Target: "alpine:latest (alpine 3.11)", + Class: types.ClassOSPkg, + Type: ftypes.Alpine, + Packages: ftypes.Packages{ + muslPkg, + }, + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2020-9999", + PkgName: muslPkg.Name, + InstalledVersion: muslPkg.Version, + FixedVersion: "1.2.4", + Status: dbTypes.StatusFixed, + Layer: ftypes.Layer{ + DiffID: "sha256:ebf12965380b39889c99a9c02e82ba465f887b45975b6e389d42e9e6a3857888", + }, + PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-9999", + Vulnerability: dbTypes.Vulnerability{ + Title: "dos", + Description: "dos vulnerability", + Severity: "HIGH", + }, + }, + }, + }, + }, + wantOS: ftypes.OS{ + Family: "alpine", + Name: "3.11", + Eosl: true, + }, + }, { name: "happy path license scanner", args: args{ diff --git a/pkg/types/scan.go b/pkg/types/scan.go index 0fef0028bef3..4dedbce6fcf1 100644 --- a/pkg/types/scan.go +++ b/pkg/types/scan.go @@ -121,4 +121,5 @@ type ScanOptions struct { LicenseCategories map[types.LicenseCategory][]string FilePatterns []string IncludeDevDeps bool + Distro types.OS // Forced OS } diff --git a/rpc/common/service.proto b/rpc/common/service.proto index f9ab77df4e47..7be5c0d04bb4 100644 --- a/rpc/common/service.proto +++ b/rpc/common/service.proto @@ -173,10 +173,10 @@ enum Severity { } message CVSS { - string v2_vector = 1; - string v3_vector = 2; - double v2_score = 3; - double v3_score = 4; + string v2_vector = 1; + string v3_vector = 2; + double v2_score = 3; + double v3_score = 4; string v40_vector = 5; double v40_score = 6; } diff --git a/rpc/scanner/service.pb.go b/rpc/scanner/service.pb.go index 1e061d5764e1..00ff3485240c 100644 --- a/rpc/scanner/service.pb.go +++ b/rpc/scanner/service.pb.go @@ -151,6 +151,7 @@ type ScanOptions struct { LicenseCategories map[string]*Licenses `protobuf:"bytes,4,rep,name=license_categories,json=licenseCategories,proto3" json:"license_categories,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` IncludeDevDeps bool `protobuf:"varint,5,opt,name=include_dev_deps,json=includeDevDeps,proto3" json:"include_dev_deps,omitempty"` PkgRelationships []string `protobuf:"bytes,6,rep,name=pkg_relationships,json=pkgRelationships,proto3" json:"pkg_relationships,omitempty"` + Distro *common.OS `protobuf:"bytes,7,opt,name=distro,proto3" json:"distro,omitempty"` } func (x *ScanOptions) Reset() { @@ -220,6 +221,13 @@ func (x *ScanOptions) GetPkgRelationships() []string { return nil } +func (x *ScanOptions) GetDistro() *common.OS { + if x != nil { + return x.Distro + } + return nil +} + type ScanResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -406,7 +414,7 @@ var file_rpc_scanner_service_proto_rawDesc = []byte{ 0x53, 0x63, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x20, 0x0a, 0x08, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0xea, 0x02, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6e, 0x4f, + 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0x94, 0x03, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x6b, 0x67, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6b, 0x67, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x18, @@ -422,58 +430,61 @@ var file_rpc_scanner_service_proto_rawDesc = []byte{ 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44, 0x65, 0x76, 0x44, 0x65, 0x70, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x6b, 0x67, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x70, 0x6b, 0x67, 0x52, 0x65, - 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x73, 0x1a, 0x60, 0x0a, 0x16, 0x4c, - 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, - 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, - 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, - 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, - 0x03, 0x10, 0x04, 0x22, 0x64, 0x0a, 0x0c, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x02, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x10, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, - 0x53, 0x52, 0x02, 0x6f, 0x73, 0x12, 0x32, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, - 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0xd5, 0x03, 0x0a, 0x06, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x45, 0x0a, 0x0f, - 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x52, 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, - 0x69, 0x65, 0x73, 0x12, 0x54, 0x0a, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, - 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6c, 0x61, - 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x08, 0x70, 0x61, - 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, - 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0f, - 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, - 0x35, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, - 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, + 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x73, 0x12, 0x28, 0x0a, 0x06, 0x64, + 0x69, 0x73, 0x74, 0x72, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x72, + 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x53, 0x52, 0x06, 0x64, + 0x69, 0x73, 0x74, 0x72, 0x6f, 0x1a, 0x60, 0x0a, 0x16, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, + 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x64, 0x0a, + 0x0c, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, + 0x02, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4f, 0x53, 0x52, 0x02, 0x6f, 0x73, 0x12, + 0x32, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x22, 0xd5, 0x03, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x45, 0x0a, 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, + 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0f, 0x76, 0x75, + 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x54, 0x0a, + 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, - 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x52, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, - 0x73, 0x32, 0x50, 0x0a, 0x07, 0x53, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x45, 0x0a, 0x04, - 0x53, 0x63, 0x61, 0x6e, 0x12, 0x1d, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, - 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, - 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, - 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, - 0x3b, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x11, 0x6d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x31, 0x0a, + 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, + 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, + 0x12, 0x47, 0x0a, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x07, 0x73, 0x65, 0x63, + 0x72, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, + 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, + 0x12, 0x39, 0x0a, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, + 0x65, 0x52, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x32, 0x50, 0x0a, 0x07, 0x53, + 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x45, 0x0a, 0x04, 0x53, 0x63, 0x61, 0x6e, 0x12, 0x1d, + 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, + 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x63, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x33, 0x5a, + 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, + 0x70, 0x63, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x3b, 0x73, 0x63, 0x61, 0x6e, 0x6e, + 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -507,22 +518,23 @@ var file_rpc_scanner_service_proto_goTypes = []interface{}{ var file_rpc_scanner_service_proto_depIdxs = []int32{ 2, // 0: trivy.scanner.v1.ScanRequest.options:type_name -> trivy.scanner.v1.ScanOptions 5, // 1: trivy.scanner.v1.ScanOptions.license_categories:type_name -> trivy.scanner.v1.ScanOptions.LicenseCategoriesEntry - 6, // 2: trivy.scanner.v1.ScanResponse.os:type_name -> trivy.common.OS - 4, // 3: trivy.scanner.v1.ScanResponse.results:type_name -> trivy.scanner.v1.Result - 7, // 4: trivy.scanner.v1.Result.vulnerabilities:type_name -> trivy.common.Vulnerability - 8, // 5: trivy.scanner.v1.Result.misconfigurations:type_name -> trivy.common.DetectedMisconfiguration - 9, // 6: trivy.scanner.v1.Result.packages:type_name -> trivy.common.Package - 10, // 7: trivy.scanner.v1.Result.custom_resources:type_name -> trivy.common.CustomResource - 11, // 8: trivy.scanner.v1.Result.secrets:type_name -> trivy.common.SecretFinding - 12, // 9: trivy.scanner.v1.Result.licenses:type_name -> trivy.common.DetectedLicense - 1, // 10: trivy.scanner.v1.ScanOptions.LicenseCategoriesEntry.value:type_name -> trivy.scanner.v1.Licenses - 0, // 11: trivy.scanner.v1.Scanner.Scan:input_type -> trivy.scanner.v1.ScanRequest - 3, // 12: trivy.scanner.v1.Scanner.Scan:output_type -> trivy.scanner.v1.ScanResponse - 12, // [12:13] is the sub-list for method output_type - 11, // [11:12] is the sub-list for method input_type - 11, // [11:11] is the sub-list for extension type_name - 11, // [11:11] is the sub-list for extension extendee - 0, // [0:11] is the sub-list for field type_name + 6, // 2: trivy.scanner.v1.ScanOptions.distro:type_name -> trivy.common.OS + 6, // 3: trivy.scanner.v1.ScanResponse.os:type_name -> trivy.common.OS + 4, // 4: trivy.scanner.v1.ScanResponse.results:type_name -> trivy.scanner.v1.Result + 7, // 5: trivy.scanner.v1.Result.vulnerabilities:type_name -> trivy.common.Vulnerability + 8, // 6: trivy.scanner.v1.Result.misconfigurations:type_name -> trivy.common.DetectedMisconfiguration + 9, // 7: trivy.scanner.v1.Result.packages:type_name -> trivy.common.Package + 10, // 8: trivy.scanner.v1.Result.custom_resources:type_name -> trivy.common.CustomResource + 11, // 9: trivy.scanner.v1.Result.secrets:type_name -> trivy.common.SecretFinding + 12, // 10: trivy.scanner.v1.Result.licenses:type_name -> trivy.common.DetectedLicense + 1, // 11: trivy.scanner.v1.ScanOptions.LicenseCategoriesEntry.value:type_name -> trivy.scanner.v1.Licenses + 0, // 12: trivy.scanner.v1.Scanner.Scan:input_type -> trivy.scanner.v1.ScanRequest + 3, // 13: trivy.scanner.v1.Scanner.Scan:output_type -> trivy.scanner.v1.ScanResponse + 13, // [13:14] is the sub-list for method output_type + 12, // [12:13] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_rpc_scanner_service_proto_init() } diff --git a/rpc/scanner/service.proto b/rpc/scanner/service.proto index c7ad3748280b..d809d36610ee 100644 --- a/rpc/scanner/service.proto +++ b/rpc/scanner/service.proto @@ -28,6 +28,7 @@ message ScanOptions { map license_categories = 4; bool include_dev_deps = 5; repeated string pkg_relationships = 6; + common.OS distro = 7; reserved 3; // deleted 'list_all_packages' } diff --git a/rpc/scanner/service.twirp.go b/rpc/scanner/service.twirp.go index 83a834536f35..d7525d23c45e 100644 --- a/rpc/scanner/service.twirp.go +++ b/rpc/scanner/service.twirp.go @@ -1094,47 +1094,48 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) } var twirpFileDescriptor0 = []byte{ - // 671 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0xdd, 0x6e, 0xd3, 0x4c, - 0x10, 0x55, 0x7e, 0x9a, 0x38, 0x93, 0x4f, 0x5f, 0xd3, 0x15, 0x54, 0x6e, 0x4a, 0x21, 0xca, 0x05, - 0x8a, 0x84, 0x94, 0xd0, 0x14, 0xc4, 0xdf, 0x1d, 0x6d, 0x41, 0x45, 0xa0, 0x56, 0x9b, 0x8a, 0x0b, - 0x6e, 0xc2, 0x66, 0x3d, 0x75, 0x57, 0x71, 0x6c, 0x77, 0x67, 0x1d, 0x29, 0xaf, 0xc2, 0x7b, 0xf1, - 0x12, 0x3c, 0x05, 0xda, 0xb5, 0x13, 0x35, 0x69, 0xcb, 0x95, 0x77, 0x66, 0xce, 0xcc, 0x39, 0xde, - 0x39, 0x5a, 0xd8, 0xd3, 0xa9, 0x1c, 0x90, 0x14, 0x71, 0x8c, 0x7a, 0x40, 0xa8, 0xe7, 0x4a, 0x62, - 0x3f, 0xd5, 0x89, 0x49, 0x58, 0xcb, 0x68, 0x35, 0x5f, 0xf4, 0x8b, 0x62, 0x7f, 0x7e, 0xd8, 0xf6, - 0x2d, 0x58, 0x26, 0xb3, 0x59, 0x12, 0xaf, 0x63, 0xbb, 0xbf, 0x4a, 0xd0, 0x1c, 0x49, 0x11, 0x73, - 0xbc, 0xc9, 0x90, 0x0c, 0xdb, 0x85, 0x9a, 0x11, 0x3a, 0x44, 0xe3, 0x97, 0x3a, 0xa5, 0x5e, 0x83, - 0x17, 0x11, 0x7b, 0x06, 0x4d, 0xa1, 0x8d, 0xba, 0x12, 0xd2, 0x8c, 0x55, 0xe0, 0x97, 0x5d, 0x11, - 0x96, 0xa9, 0xb3, 0x80, 0xed, 0x81, 0x37, 0x89, 0x92, 0xc9, 0x58, 0x05, 0xe4, 0x57, 0x3a, 0x95, - 0x5e, 0x83, 0xd7, 0x6d, 0x7c, 0x16, 0x10, 0x7b, 0x03, 0xf5, 0x24, 0x35, 0x2a, 0x89, 0xc9, 0xaf, - 0x76, 0x4a, 0xbd, 0xe6, 0xf0, 0xa0, 0xbf, 0xa9, 0xb0, 0x6f, 0x35, 0x9c, 0xe7, 0x20, 0xbe, 0x44, - 0x77, 0x3b, 0xe0, 0x7d, 0x55, 0x12, 0x63, 0x42, 0x62, 0x8f, 0x60, 0x2b, 0x16, 0x33, 0x24, 0xbf, - 0xe4, 0x86, 0xe7, 0x41, 0xf7, 0x4f, 0x39, 0x97, 0x5f, 0xb4, 0xb2, 0x7d, 0x68, 0xa4, 0xd3, 0x70, - 0x6c, 0x16, 0xe9, 0x0a, 0xe9, 0xa5, 0xd3, 0xf0, 0xd2, 0xc6, 0xac, 0x0d, 0x5e, 0xc1, 0x48, 0x7e, - 0x39, 0xaf, 0x2d, 0x63, 0x26, 0x81, 0x45, 0x39, 0xd5, 0x58, 0x0a, 0x83, 0x61, 0xa2, 0x15, 0x5a, - 0xb9, 0x95, 0x5e, 0x73, 0xf8, 0xea, 0x9f, 0x72, 0xfb, 0x85, 0xc4, 0xe3, 0x55, 0xdb, 0x69, 0x6c, - 0xf4, 0x82, 0xef, 0x44, 0x9b, 0x79, 0xd6, 0x83, 0x96, 0x8a, 0x65, 0x94, 0x05, 0x38, 0x0e, 0x70, - 0x3e, 0x0e, 0x30, 0x25, 0x7f, 0xab, 0x53, 0xea, 0x79, 0xfc, 0xff, 0x22, 0x7f, 0x82, 0xf3, 0x13, - 0x4c, 0x89, 0xbd, 0x80, 0x1d, 0xfb, 0x1f, 0x1a, 0x23, 0xe1, 0x48, 0xae, 0x55, 0x4a, 0x7e, 0xcd, - 0x69, 0x6e, 0xa5, 0xd3, 0x90, 0xdf, 0xce, 0xb7, 0x7f, 0xc2, 0xee, 0xfd, 0x1a, 0x58, 0x0b, 0x2a, - 0x53, 0x5c, 0x14, 0xab, 0xb4, 0x47, 0xf6, 0x12, 0xb6, 0xe6, 0x22, 0xca, 0xd0, 0x6d, 0xb0, 0x39, - 0x6c, 0xdf, 0xfd, 0xb5, 0xe5, 0x8d, 0xf3, 0x1c, 0xf8, 0xbe, 0xfc, 0xb6, 0xf4, 0xa5, 0xea, 0x55, - 0x5a, 0xd5, 0x6e, 0x00, 0xff, 0xe5, 0x56, 0xa1, 0x34, 0x89, 0x09, 0x59, 0x07, 0xca, 0x09, 0xb9, - 0xe1, 0xcd, 0x61, 0xab, 0x18, 0x94, 0x9b, 0xac, 0x7f, 0x3e, 0xe2, 0xe5, 0x84, 0xd8, 0x10, 0xea, - 0x1a, 0x29, 0x8b, 0x4c, 0xee, 0x89, 0xe6, 0xd0, 0xbf, 0xcb, 0xc7, 0x1d, 0x80, 0x2f, 0x81, 0xdd, - 0xdf, 0x15, 0xa8, 0xe5, 0xb9, 0x07, 0xcd, 0x78, 0x0a, 0xdb, 0xf3, 0x2c, 0x8a, 0x51, 0x8b, 0x89, - 0x8a, 0x94, 0xb1, 0x9b, 0x2a, 0xbb, 0xf1, 0xfb, 0xeb, 0x2a, 0xbe, 0xdf, 0x02, 0x2d, 0xf8, 0x66, - 0x0f, 0xbb, 0x84, 0x9d, 0x99, 0x22, 0x99, 0xc4, 0x57, 0x2a, 0xcc, 0xb4, 0x58, 0x3a, 0xd4, 0x0e, - 0x7a, 0xbe, 0x3e, 0xe8, 0x04, 0x0d, 0x4a, 0x83, 0xc1, 0xb7, 0x0d, 0x38, 0xbf, 0x3b, 0xc0, 0x1a, - 0x55, 0x46, 0x82, 0xec, 0xba, 0xac, 0xe6, 0x3c, 0x60, 0x0c, 0xaa, 0xd6, 0x94, 0x7e, 0xc5, 0x25, - 0xdd, 0x99, 0x1d, 0x82, 0x97, 0x0a, 0x39, 0x15, 0x21, 0x5a, 0x1b, 0x58, 0xda, 0xc7, 0xeb, 0xb4, - 0x17, 0x79, 0x95, 0xaf, 0x60, 0xec, 0x33, 0xb4, 0x64, 0x46, 0x26, 0x99, 0x8d, 0x35, 0x52, 0x92, - 0x69, 0x89, 0xe4, 0xd7, 0x5d, 0xeb, 0x93, 0xf5, 0xd6, 0x63, 0x87, 0xe2, 0x05, 0x88, 0x6f, 0xcb, - 0xb5, 0x98, 0xd8, 0x6b, 0xa8, 0x13, 0x4a, 0x8d, 0x86, 0x7c, 0xef, 0xbe, 0xab, 0x1b, 0xb9, 0xe2, - 0x27, 0x15, 0x07, 0x2a, 0x0e, 0xf9, 0x12, 0xcb, 0xde, 0x81, 0x57, 0xd8, 0x9a, 0xfc, 0x86, 0xeb, - 0x3b, 0xb8, 0xff, 0xa6, 0x0a, 0x17, 0xf1, 0x15, 0x7c, 0x78, 0x01, 0xf5, 0x51, 0xbe, 0x75, 0x76, - 0x0a, 0x55, 0x7b, 0x64, 0x0f, 0xbc, 0x03, 0xc5, 0x5b, 0xd4, 0x7e, 0xfa, 0x50, 0x39, 0xf7, 0xdf, - 0xc7, 0xa3, 0x1f, 0x87, 0xa1, 0x32, 0xd7, 0xd9, 0xc4, 0x92, 0x0f, 0xc4, 0x4d, 0x26, 0x08, 0x65, - 0xa6, 0x95, 0x59, 0x0c, 0x5c, 0xe3, 0xe0, 0xd6, 0x13, 0xf9, 0xa1, 0xf8, 0x4e, 0x6a, 0xee, 0xdd, - 0x3b, 0xfa, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x66, 0x86, 0x78, 0x40, 0x05, 0x00, 0x00, + // 685 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0x51, 0x6f, 0x1a, 0x47, + 0x10, 0x16, 0x1c, 0x86, 0x63, 0xa8, 0x6a, 0xbc, 0x6a, 0xad, 0x35, 0xae, 0x5b, 0xc4, 0x43, 0x85, + 0x54, 0x09, 0x6a, 0xdc, 0xaa, 0x4d, 0xf2, 0x16, 0xdb, 0x89, 0x1c, 0x25, 0xb2, 0xb5, 0x58, 0x79, + 0xc8, 0x0b, 0x59, 0xf6, 0xc6, 0xe7, 0x15, 0xc7, 0xed, 0x79, 0x77, 0x0f, 0x89, 0xff, 0x91, 0xa7, + 0xfc, 0xaf, 0xfc, 0x9f, 0x68, 0xf7, 0x0e, 0x64, 0x30, 0xce, 0x13, 0x3b, 0x33, 0xdf, 0xcc, 0x7c, + 0xcc, 0x7c, 0x37, 0x70, 0xa4, 0x33, 0x31, 0x34, 0x82, 0xa7, 0x29, 0xea, 0xa1, 0x41, 0xbd, 0x90, + 0x02, 0x07, 0x99, 0x56, 0x56, 0x91, 0xb6, 0xd5, 0x72, 0xb1, 0x1c, 0x94, 0xc1, 0xc1, 0xe2, 0xb4, + 0x43, 0x1d, 0x58, 0xa8, 0xf9, 0x5c, 0xa5, 0x9b, 0xd8, 0xde, 0xd7, 0x0a, 0xb4, 0xc6, 0x82, 0xa7, + 0x0c, 0x1f, 0x72, 0x34, 0x96, 0x1c, 0x42, 0xdd, 0x72, 0x1d, 0xa3, 0xa5, 0x95, 0x6e, 0xa5, 0xdf, + 0x64, 0xa5, 0x45, 0xfe, 0x80, 0x16, 0xd7, 0x56, 0xde, 0x71, 0x61, 0x27, 0x32, 0xa2, 0x55, 0x1f, + 0x84, 0x95, 0xeb, 0x2a, 0x22, 0x47, 0x10, 0x4e, 0x13, 0x35, 0x9d, 0xc8, 0xc8, 0xd0, 0xa0, 0x1b, + 0xf4, 0x9b, 0xac, 0xe1, 0xec, 0xab, 0xc8, 0x90, 0xff, 0xa0, 0xa1, 0x32, 0x2b, 0x55, 0x6a, 0x68, + 0xad, 0x5b, 0xe9, 0xb7, 0x46, 0x27, 0x83, 0x6d, 0x86, 0x03, 0xc7, 0xe1, 0xba, 0x00, 0xb1, 0x15, + 0xba, 0xd7, 0x85, 0xf0, 0xbd, 0x14, 0x98, 0x1a, 0x34, 0xe4, 0x17, 0xd8, 0x4b, 0xf9, 0x1c, 0x0d, + 0xad, 0xf8, 0xe2, 0x85, 0xd1, 0xfb, 0x12, 0x14, 0xf4, 0xcb, 0x54, 0x72, 0x0c, 0xcd, 0x6c, 0x16, + 0x4f, 0xec, 0x32, 0x5b, 0x23, 0xc3, 0x6c, 0x16, 0xdf, 0x3a, 0x9b, 0x74, 0x20, 0x2c, 0x3b, 0x1a, + 0x5a, 0x2d, 0x62, 0x2b, 0x9b, 0x08, 0x20, 0x49, 0xd1, 0x6a, 0x22, 0xb8, 0xc5, 0x58, 0x69, 0x89, + 0x8e, 0x6e, 0xd0, 0x6f, 0x8d, 0xfe, 0xf9, 0x21, 0xdd, 0x41, 0x49, 0xf1, 0x7c, 0x9d, 0x76, 0x99, + 0x5a, 0xbd, 0x64, 0x07, 0xc9, 0xb6, 0x9f, 0xf4, 0xa1, 0x2d, 0x53, 0x91, 0xe4, 0x11, 0x4e, 0x22, + 0x5c, 0x4c, 0x22, 0xcc, 0x0c, 0xdd, 0xeb, 0x56, 0xfa, 0x21, 0xfb, 0xb9, 0xf4, 0x5f, 0xe0, 0xe2, + 0x02, 0x33, 0x43, 0xfe, 0x82, 0x03, 0xf7, 0x3f, 0x34, 0x26, 0xdc, 0x37, 0xb9, 0x97, 0x99, 0xa1, + 0x75, 0xcf, 0xb9, 0x9d, 0xcd, 0x62, 0xf6, 0xd8, 0x4f, 0xfa, 0x50, 0x8f, 0xa4, 0xb1, 0x5a, 0xd1, + 0x86, 0x1f, 0x6f, 0xbb, 0xe4, 0x5b, 0x2c, 0x7c, 0x70, 0x3d, 0x66, 0x65, 0xbc, 0xf3, 0x19, 0x0e, + 0x77, 0xb3, 0x25, 0x6d, 0x08, 0x66, 0xb8, 0x2c, 0x97, 0xee, 0x9e, 0xe4, 0x6f, 0xd8, 0x5b, 0xf0, + 0x24, 0x47, 0xbf, 0xeb, 0xd6, 0xa8, 0xf3, 0x74, 0x08, 0xab, 0xdd, 0xb0, 0x02, 0xf8, 0xb2, 0xfa, + 0x7f, 0xe5, 0x5d, 0x2d, 0x0c, 0xda, 0xb5, 0x5e, 0x04, 0x3f, 0x15, 0xa2, 0x32, 0x99, 0x4a, 0x0d, + 0x92, 0x2e, 0x54, 0x95, 0xf1, 0xc5, 0x77, 0xb1, 0xab, 0x2a, 0x43, 0x46, 0xd0, 0xd0, 0x68, 0xf2, + 0xc4, 0x16, 0xea, 0x69, 0x8d, 0xe8, 0xd3, 0x7e, 0xcc, 0x03, 0xd8, 0x0a, 0xd8, 0xfb, 0x16, 0x40, + 0xbd, 0xf0, 0x3d, 0x2b, 0xdb, 0x4b, 0xd8, 0x5f, 0xe4, 0x49, 0x8a, 0x9a, 0x4f, 0x65, 0x22, 0xad, + 0xdb, 0x69, 0xd5, 0x97, 0x3f, 0xde, 0x64, 0xf1, 0xf1, 0x11, 0x68, 0xc9, 0xb6, 0x73, 0xc8, 0x2d, + 0x1c, 0xcc, 0xa5, 0x11, 0x2a, 0xbd, 0x93, 0x71, 0xae, 0xf9, 0x4a, 0xcb, 0xae, 0xd0, 0x9f, 0x9b, + 0x85, 0x2e, 0xd0, 0xa2, 0xb0, 0x18, 0x7d, 0xd8, 0x82, 0xb3, 0xa7, 0x05, 0x9c, 0xa4, 0x45, 0xc2, + 0x8d, 0x5b, 0xac, 0xe3, 0x5c, 0x18, 0x84, 0x40, 0xcd, 0xc9, 0x97, 0x06, 0xde, 0xe9, 0xdf, 0xe4, + 0x14, 0xc2, 0x8c, 0x8b, 0x19, 0x8f, 0xd1, 0x09, 0xc6, 0xb5, 0xfd, 0x75, 0xb3, 0xed, 0x4d, 0x11, + 0x65, 0x6b, 0x18, 0x79, 0x0b, 0x6d, 0x91, 0x1b, 0xab, 0xe6, 0x13, 0x8d, 0x46, 0xe5, 0x5a, 0xa0, + 0xa1, 0x0d, 0x9f, 0xfa, 0xdb, 0x66, 0xea, 0xb9, 0x47, 0xb1, 0x12, 0xc4, 0xf6, 0xc5, 0x86, 0x6d, + 0xc8, 0xbf, 0xd0, 0x30, 0x28, 0x34, 0x5a, 0x43, 0xc3, 0x5d, 0xa3, 0x1b, 0xfb, 0xe0, 0x1b, 0x99, + 0x46, 0x32, 0x8d, 0xd9, 0x0a, 0x4b, 0x5e, 0x40, 0x58, 0x7e, 0x00, 0x86, 0x36, 0x7d, 0xde, 0xc9, + 0xee, 0x49, 0x95, 0x2a, 0x62, 0x6b, 0xf8, 0xe8, 0x06, 0x1a, 0xe3, 0x62, 0xeb, 0xe4, 0x12, 0x6a, + 0xee, 0x49, 0x9e, 0xb9, 0x18, 0xe5, 0xd5, 0xea, 0xfc, 0xfe, 0x5c, 0xb8, 0xd0, 0xdf, 0xeb, 0xb3, + 0x4f, 0xa7, 0xb1, 0xb4, 0xf7, 0xf9, 0xd4, 0x35, 0x1f, 0xf2, 0x87, 0x9c, 0x1b, 0x14, 0xb9, 0x96, + 0x76, 0x39, 0xf4, 0x89, 0xc3, 0x47, 0xc7, 0xf4, 0x55, 0xf9, 0x3b, 0xad, 0xfb, 0x0b, 0x79, 0xf6, + 0x3d, 0x00, 0x00, 0xff, 0xff, 0x40, 0xd0, 0xe7, 0xda, 0x6a, 0x05, 0x00, 0x00, }