diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 86ac2c2f8918..e442c590ccc5 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -63,7 +63,8 @@ trivy filesystem [flags] PATH --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --pkg-types strings comma-separated list of package types (os,library) (default [os,library]) + --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 62e731e14126..cf0e7591b726 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -81,7 +81,8 @@ trivy image [flags] IMAGE_NAME --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --pkg-types strings comma-separated list of package types (os,library) (default [os,library]) + --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-types strings list of package types (os,library) (default [os,library]) --platform string set platform in the form os/arch if image is multi-platform capable --podman-host string unix podman socket path to use for podman scanning --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 2f8539dfeb47..0dea6c93a9fb 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -78,7 +78,8 @@ trivy kubernetes [flags] [CONTEXT] --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --pkg-types strings comma-separated list of package types (os,library) (default [os,library]) + --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-types strings list of package types (os,library) (default [os,library]) --qps float specify the maximum QPS to the master from this client (default 5) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 661381b76ebf..62364d9ba62c 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -63,7 +63,8 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --pkg-types strings comma-separated list of package types (os,library) (default [os,library]) + --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 01ed2ce062c6..e7cec39be469 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -65,7 +65,8 @@ trivy rootfs [flags] ROOTDIR --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. - --pkg-types strings comma-separated list of package types (os,library) (default [os,library]) + --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 0c7508c854e1..6fa70d15ca16 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -43,7 +43,8 @@ trivy sbom [flags] SBOM_PATH --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments - --pkg-types strings comma-separated list of package types (os,library) (default [os,library]) + --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index c250b9bcf06b..b878fc070277 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -56,7 +56,8 @@ trivy vm [flags] VM_IMAGE -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) - --pkg-types strings comma-separated list of package types (os,library) (default [os,library]) + --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/scanner/vulnerability.md b/docs/docs/scanner/vulnerability.md index ba612ee06b28..9df2b43d8b80 100644 --- a/docs/docs/scanner/vulnerability.md +++ b/docs/docs/scanner/vulnerability.md @@ -202,7 +202,8 @@ Currently, specifying a username and password is not supported. This section describes vulnerability-specific configuration. Other common options are documented [here](../configuration/index.md). -### Enabling a subset of package types +### Enabling a Subset of Package Types + It's possible to only enable certain package types if you prefer. You can do so by passing the `--pkg-types` option. This flag takes a comma-separated list of package types. @@ -268,6 +269,45 @@ Total: 7 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 3, CRITICAL: 2) +!!! info + This flag filters the packages themselves, so it also affects the `--list-all-pkgs` option and SBOM generation. + +### Filtering by Package Relationships + + +Trivy supports filtering vulnerabilities based on the relationship of packages within a project. +This is achieved through the `--pkg-relationships` flag. +This feature allows you to focus on vulnerabilities in specific types of dependencies, such as only those in direct dependencies. + +In Trivy, there are four types of package relationships: + +1. `root`: The root package being scanned +2. `direct`: Direct dependencies of the root package +3. `indirect`: Transitive dependencies +4. `unknown`: Packages whose relationship cannot be determined + +The available relationships may vary depending on the ecosystem. +To see which relationships are supported for a particular project, you can use the JSON output format and check the `Relationship` field: + +``` +$ trivy repo -f json --list-all-pkgs /path/to/project +``` + +To scan only the root package and its direct dependencies, you can use the flag as follows: + +``` +$ trivy repo --pkg-relationships root,direct /path/to/project +``` + +By default, all relationships are included in the scan. + +!!! info + This flag filters the packages themselves, so it also affects the `--list-all-pkgs` option and SBOM generation. + +!!! warning + As it may not provide a complete package list, `--pkg-relationships` cannot be used with `--dependency-tree`, `--vex` or SBOM generation. + + [^1]: https://github.com/GoogleContainerTools/distroless [nvd-CVE-2023-0464]: https://nvd.nist.gov/vuln/detail/CVE-2023-0464 diff --git a/pkg/commands/app.go b/pkg/commands/app.go index 4977db6e7ba4..a3bd7b78e6f1 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -243,9 +243,6 @@ func NewRootCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { } func NewImageCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { - scanFlagGroup := flag.NewScanFlagGroup() - scanFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' - reportFlagGroup := flag.NewReportFlagGroup() report := flag.ReportFormatFlag.Clone() report.Default = "summary" // override the default value as the summary is preferred for the compliance report @@ -256,27 +253,28 @@ func NewImageCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { compliance.Values = []string{types.ComplianceDockerCIS160} reportFlagGroup.Compliance = compliance // override usage as the accepted values differ for each subcommand. - misconfFlagGroup := flag.NewMisconfFlagGroup() - misconfFlagGroup.CloudformationParamVars = nil // disable '--cf-params' - misconfFlagGroup.TerraformTFVars = nil // disable '--tf-vars' - imageFlags := &flag.Flags{ GlobalFlagGroup: globalFlags, CacheFlagGroup: flag.NewCacheFlagGroup(), DBFlagGroup: flag.NewDBFlagGroup(), ImageFlagGroup: flag.NewImageFlagGroup(), // container image specific LicenseFlagGroup: flag.NewLicenseFlagGroup(), - MisconfFlagGroup: misconfFlagGroup, + MisconfFlagGroup: flag.NewMisconfFlagGroup(), ModuleFlagGroup: flag.NewModuleFlagGroup(), + PackageFlagGroup: flag.NewPackageFlagGroup(), RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode RegistryFlagGroup: flag.NewRegistryFlagGroup(), RegoFlagGroup: flag.NewRegoFlagGroup(), ReportFlagGroup: reportFlagGroup, - ScanFlagGroup: scanFlagGroup, + ScanFlagGroup: flag.NewScanFlagGroup(), SecretFlagGroup: flag.NewSecretFlagGroup(), VulnerabilityFlagGroup: flag.NewVulnerabilityFlagGroup(), } + imageFlags.PackageFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' + imageFlags.MisconfFlagGroup.CloudformationParamVars = nil // disable '--cf-params' + imageFlags.MisconfFlagGroup.TerraformTFVars = nil // disable '--tf-vars' + cmd := &cobra.Command{ Use: "image [flags] IMAGE_NAME", Aliases: []string{"i"}, @@ -342,6 +340,7 @@ func NewFilesystemCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { LicenseFlagGroup: flag.NewLicenseFlagGroup(), MisconfFlagGroup: flag.NewMisconfFlagGroup(), ModuleFlagGroup: flag.NewModuleFlagGroup(), + PackageFlagGroup: flag.NewPackageFlagGroup(), RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode RegistryFlagGroup: flag.NewRegistryFlagGroup(), RegoFlagGroup: flag.NewRegoFlagGroup(), @@ -400,6 +399,7 @@ func NewRootfsCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { LicenseFlagGroup: flag.NewLicenseFlagGroup(), MisconfFlagGroup: flag.NewMisconfFlagGroup(), ModuleFlagGroup: flag.NewModuleFlagGroup(), + PackageFlagGroup: flag.NewPackageFlagGroup(), RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode RegistryFlagGroup: flag.NewRegistryFlagGroup(), RegoFlagGroup: flag.NewRegoFlagGroup(), @@ -411,7 +411,7 @@ func NewRootfsCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { rootfsFlags.ReportFlagGroup.ReportFormat = nil // TODO: support --report summary rootfsFlags.ReportFlagGroup.Compliance = nil // disable '--compliance' rootfsFlags.ReportFlagGroup.ReportFormat = nil // disable '--report' - rootfsFlags.ScanFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' + rootfsFlags.PackageFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' rootfsFlags.CacheFlagGroup.CacheBackend.Default = string(cache.TypeMemory) // Use memory cache by default cmd := &cobra.Command{ @@ -460,6 +460,7 @@ func NewRepositoryCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { LicenseFlagGroup: flag.NewLicenseFlagGroup(), MisconfFlagGroup: flag.NewMisconfFlagGroup(), ModuleFlagGroup: flag.NewModuleFlagGroup(), + PackageFlagGroup: flag.NewPackageFlagGroup(), RegistryFlagGroup: flag.NewRegistryFlagGroup(), RegoFlagGroup: flag.NewRegoFlagGroup(), RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode @@ -516,7 +517,6 @@ func NewConvertCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { ScanFlagGroup: &flag.ScanFlagGroup{}, ReportFlagGroup: flag.NewReportFlagGroup(), } - convertFlags.ReportFlagGroup.PkgTypes = nil // disable '--pkg-types' cmd := &cobra.Command{ Use: "convert [flags] RESULT_JSON", @@ -685,7 +685,6 @@ func NewConfigCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { configFlags.ReportFlagGroup.ListAllPkgs = nil // disable '--list-all-pkgs' configFlags.ReportFlagGroup.ExitOnEOL = nil // disable '--exit-on-eol' configFlags.ReportFlagGroup.ShowSuppressed = nil // disable '--show-suppressed' - configFlags.ReportFlagGroup.PkgTypes = nil // disable '--pkg-types' configFlags.ReportFlagGroup.ReportFormat.Usage = "specify a compliance report format for the output" // @TODO: support --report summary for non compliance reports configFlags.CacheFlagGroup.CacheBackend.Default = string(cache.TypeMemory) @@ -960,7 +959,6 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { }) scanners.Default = scanners.Values scanFlags.Scanners = scanners - scanFlags.IncludeDevDeps = nil // disable '--include-dev-deps' // required only SourceFlag imageFlags := &flag.ImageFlagGroup{ImageSources: flag.SourceFlag.Clone()} @@ -997,6 +995,7 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { ImageFlagGroup: imageFlags, K8sFlagGroup: flag.NewK8sFlagGroup(), // kubernetes-specific flags MisconfFlagGroup: misconfFlagGroup, + PackageFlagGroup: flag.NewPackageFlagGroup(), RegoFlagGroup: flag.NewRegoFlagGroup(), ReportFlagGroup: reportFlagGroup, ScanFlagGroup: scanFlags, @@ -1004,6 +1003,8 @@ func NewKubernetesCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { RegistryFlagGroup: flag.NewRegistryFlagGroup(), VulnerabilityFlagGroup: flag.NewVulnerabilityFlagGroup(), } + k8sFlags.PackageFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' + cmd := &cobra.Command{ Use: "kubernetes [flags] [CONTEXT]", Aliases: []string{"k8s"}, @@ -1055,6 +1056,7 @@ func NewVMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { DBFlagGroup: flag.NewDBFlagGroup(), MisconfFlagGroup: flag.NewMisconfFlagGroup(), ModuleFlagGroup: flag.NewModuleFlagGroup(), + PackageFlagGroup: flag.NewPackageFlagGroup(), RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode ReportFlagGroup: flag.NewReportFlagGroup(), ScanFlagGroup: flag.NewScanFlagGroup(), @@ -1069,7 +1071,7 @@ func NewVMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { }, } vmFlags.ReportFlagGroup.ReportFormat = nil // disable '--report' - vmFlags.ScanFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' + vmFlags.PackageFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' vmFlags.MisconfFlagGroup.CloudformationParamVars = nil // disable '--cf-params' vmFlags.MisconfFlagGroup.TerraformTFVars = nil // disable '--tf-vars' @@ -1128,9 +1130,8 @@ func NewSBOMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { types.VulnerabilityScanner, }) scanFlagGroup := flag.NewScanFlagGroup() - scanFlagGroup.Scanners = scanners // allow only 'vuln' and 'license' options for '--scanners' - scanFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' - scanFlagGroup.Parallel = nil // disable '--parallel' + scanFlagGroup.Scanners = scanners // allow only 'vuln' and 'license' options for '--scanners' + scanFlagGroup.Parallel = nil // disable '--parallel' licenseFlagGroup := flag.NewLicenseFlagGroup() // License full-scan and confidence-level are for file content only @@ -1141,6 +1142,7 @@ func NewSBOMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { GlobalFlagGroup: globalFlags, CacheFlagGroup: flag.NewCacheFlagGroup(), DBFlagGroup: flag.NewDBFlagGroup(), + PackageFlagGroup: flag.NewPackageFlagGroup(), RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode ReportFlagGroup: reportFlagGroup, ScanFlagGroup: scanFlagGroup, @@ -1150,6 +1152,7 @@ func NewSBOMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { } sbomFlags.CacheFlagGroup.CacheBackend.Default = string(cache.TypeMemory) // Use memory cache by default + sbomFlags.PackageFlagGroup.IncludeDevDeps = nil // disable '--include-dev-deps' cmd := &cobra.Command{ Use: "sbom [flags] SBOM_PATH", diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 043109cc0fd5..e49829e352fb 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -479,6 +479,7 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan 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 @@ -488,18 +489,24 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan } if len(opts.ImageConfigScanners) != 0 { - log.Info("Container image config scanners", log.Any("scanners", opts.ImageConfigScanners)) + log.WithPrefix(log.PrefixContainerImage).Info("Container image config scanners", log.Any("scanners", opts.ImageConfigScanners)) + } + + if opts.Scanners.Enabled(types.SBOMScanner) { + logger := log.WithPrefix(log.PrefixPackage) + logger.Debug("Package types", log.Any("types", scanOptions.PkgTypes)) + logger.Debug("Package relationships", log.Any("relationships", scanOptions.PkgRelationships)) } if opts.Scanners.Enabled(types.VulnerabilityScanner) { - log.Info("Vulnerability scanning is enabled") - log.Debug("Package types", log.Any("types", scanOptions.PkgTypes)) + log.WithPrefix(log.PrefixVulnerability).Info("Vulnerability scanning is enabled") } // ScannerOption is filled only when config scanning is enabled. var configScannerOptions misconf.ScannerOption if opts.Scanners.Enabled(types.MisconfigScanner) || opts.ImageConfigScanners.Enabled(types.MisconfigScanner) { - log.Info("Misconfiguration scanning is enabled") + logger := log.WithPrefix(log.PrefixMisconfiguration) + logger.Info("Misconfiguration scanning is enabled") var downloadedPolicyPaths []string var disableEmbedded bool @@ -507,10 +514,10 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan downloadedPolicyPaths, err := operation.InitBuiltinPolicies(context.Background(), opts.CacheDir, opts.Quiet, opts.SkipCheckUpdate, opts.MisconfOptions.ChecksBundleRepository, opts.RegistryOpts()) if err != nil { if !opts.SkipCheckUpdate { - log.Error("Falling back to embedded checks", log.Err(err)) + logger.Error("Falling back to embedded checks", log.Err(err)) } } else { - log.Debug("Policies successfully loaded from disk") + logger.Debug("Policies successfully loaded from disk") disableEmbedded = true } configScannerOptions = misconf.ScannerOption{ @@ -537,19 +544,21 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan // Do not load config file for secret scanning if opts.Scanners.Enabled(types.SecretScanner) { - log.Info("Secret scanning is enabled") - log.Info("If your scanning is slow, please try '--scanners vuln' to disable secret scanning") + logger := log.WithPrefix(log.PrefixSecret) + logger.Info("Secret scanning is enabled") + logger.Info("If your scanning is slow, please try '--scanners vuln' to disable secret scanning") // e.g. https://aquasecurity.github.io/trivy/latest/docs/scanner/secret/#recommendation - log.Infof("Please see also %s for faster secret detection", doc.URL("/docs/scanner/secret/", "recommendation")) + logger.Info(fmt.Sprintf("Please see also %s for faster secret detection", doc.URL("/docs/scanner/secret/", "recommendation"))) } else { opts.SecretConfigPath = "" } if opts.Scanners.Enabled(types.LicenseScanner) { + logger := log.WithPrefix(log.PrefixLicense) if opts.LicenseFull { - log.Info("Full license scanning is enabled") + logger.Info("Full license scanning is enabled") } else { - log.Info("License scanning is enabled") + logger.Info("License scanning is enabled") } } diff --git a/pkg/fanal/types/package.go b/pkg/fanal/types/package.go index a0734651355d..822291e61c29 100644 --- a/pkg/fanal/types/package.go +++ b/pkg/fanal/types/package.go @@ -20,11 +20,29 @@ const ( RelationshipIndirect ) -var relationshipNames = [...]string{ - "unknown", - "root", - "direct", - "indirect", +var ( + Relationships = []Relationship{ + RelationshipUnknown, + RelationshipRoot, + RelationshipDirect, + RelationshipIndirect, + } + + relationshipNames = [...]string{ + "unknown", + "root", + "direct", + "indirect", + } +) + +func NewRelationship(s string) (Relationship, error) { + for i, name := range relationshipNames { + if s == name { + return Relationship(i), nil + } + } + return RelationshipUnknown, xerrors.Errorf("invalid relationship (%s)", s) } func (r Relationship) String() string { diff --git a/pkg/flag/options.go b/pkg/flag/options.go index 014da145f262..3f48b75ac9b4 100644 --- a/pkg/flag/options.go +++ b/pkg/flag/options.go @@ -320,6 +320,7 @@ type Flags struct { LicenseFlagGroup *LicenseFlagGroup MisconfFlagGroup *MisconfFlagGroup ModuleFlagGroup *ModuleFlagGroup + PackageFlagGroup *PackageFlagGroup RemoteFlagGroup *RemoteFlagGroup RegistryFlagGroup *RegistryFlagGroup RegoFlagGroup *RegoFlagGroup @@ -343,6 +344,7 @@ type Options struct { LicenseOptions MisconfOptions ModuleOptions + PackageOptions RegistryOptions RegoOptions RemoteOptions @@ -370,6 +372,12 @@ func (o *Options) Align(f *Flags) error { o.enableSBOM() } + if f.PackageFlagGroup != nil && f.PackageFlagGroup.PkgRelationships != nil && + slices.Compare(o.PkgRelationships, ftypes.Relationships) != 0 && + (o.DependencyTree || slices.Contains(types.SupportedSBOMFormats, o.Format) || len(o.VEXSources) != 0) { + return xerrors.Errorf("'--pkg-relationships' cannot be used with '--dependency-tree', '--vex' or SBOM formats") + } + if o.Compliance.Spec.ID != "" { if viper.IsSet(ScannersFlag.ConfigName) { log.Info(`The option to change scanners is disabled for scanning with the "--compliance" flag. Default scanners used.`) @@ -568,6 +576,9 @@ func (f *Flags) groups() []FlagGroup { if f.K8sFlagGroup != nil { groups = append(groups, f.K8sFlagGroup) } + if f.PackageFlagGroup != nil { + groups = append(groups, f.PackageFlagGroup) + } if f.RemoteFlagGroup != nil { groups = append(groups, f.RemoteFlagGroup) } @@ -707,6 +718,13 @@ func (f *Flags) ToOptions(args []string) (Options, error) { } } + if f.PackageFlagGroup != nil { + opts.PackageOptions, err = f.PackageFlagGroup.ToOptions() + if err != nil { + return Options{}, xerrors.Errorf("package flag error: %w", err) + } + } + if f.RegoFlagGroup != nil { opts.RegoOptions, err = f.RegoFlagGroup.ToOptions() if err != nil { diff --git a/pkg/flag/package_flags.go b/pkg/flag/package_flags.go new file mode 100644 index 000000000000..17abcbfe81c8 --- /dev/null +++ b/pkg/flag/package_flags.go @@ -0,0 +1,91 @@ +package flag + +import ( + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/types" + xstrings "github.com/aquasecurity/trivy/pkg/x/strings" +) + +var ( + IncludeDevDepsFlag = Flag[bool]{ + Name: "include-dev-deps", + ConfigName: "pkg.include-dev-deps", + Usage: "include development dependencies in the report (supported: npm, yarn)", + } + PkgTypesFlag = Flag[[]string]{ + Name: "pkg-types", + ConfigName: "pkg.types", + Default: types.PkgTypes, + Values: types.PkgTypes, + Usage: "list of package types", + Aliases: []Alias{ + { + Name: "vuln-type", + ConfigName: "vulnerability.type", + Deprecated: true, // --vuln-type was renamed to --pkg-types + }, + }, + } + PkgRelationshipsFlag = Flag[[]string]{ + Name: "pkg-relationships", + ConfigName: "pkg.relationships", + Default: xstrings.ToStringSlice(ftypes.Relationships), + Values: xstrings.ToStringSlice(ftypes.Relationships), + Usage: "list of package relationships", + } +) + +// PackageFlagGroup composes common package flag structs. +// These flags affect both SBOM and vulnerability scanning. +type PackageFlagGroup struct { + IncludeDevDeps *Flag[bool] + PkgTypes *Flag[[]string] + PkgRelationships *Flag[[]string] +} + +type PackageOptions struct { + IncludeDevDeps bool + PkgTypes []string + PkgRelationships []ftypes.Relationship +} + +func NewPackageFlagGroup() *PackageFlagGroup { + return &PackageFlagGroup{ + IncludeDevDeps: IncludeDevDepsFlag.Clone(), + PkgTypes: PkgTypesFlag.Clone(), + PkgRelationships: PkgRelationshipsFlag.Clone(), + } +} + +func (f *PackageFlagGroup) Name() string { + return "Package" +} + +func (f *PackageFlagGroup) Flags() []Flagger { + return []Flagger{ + f.IncludeDevDeps, + f.PkgTypes, + f.PkgRelationships, + } +} + +func (f *PackageFlagGroup) ToOptions() (PackageOptions, error) { + if err := parseFlags(f); err != nil { + return PackageOptions{}, err + } + + var relationships []ftypes.Relationship + for _, r := range f.PkgRelationships.Value() { + relationship, err := ftypes.NewRelationship(r) + if err != nil { + return PackageOptions{}, err + } + relationships = append(relationships, relationship) + } + + return PackageOptions{ + IncludeDevDeps: f.IncludeDevDeps.Value(), + PkgTypes: f.PkgTypes.Value(), + PkgRelationships: relationships, + }, nil +} diff --git a/pkg/flag/package_flags_test.go b/pkg/flag/package_flags_test.go new file mode 100644 index 000000000000..b79a149e3891 --- /dev/null +++ b/pkg/flag/package_flags_test.go @@ -0,0 +1,84 @@ +package flag_test + +import ( + "testing" + + "github.com/spf13/viper" + "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" +) + +func TestPackageFlagGroup_ToOptions(t *testing.T) { + type fields struct { + pkgTypes string + pkgRelationships string + } + tests := []struct { + name string + fields fields + want flag.PackageOptions + wantLogs []string + }{ + { + name: "happy default (without flags)", + fields: fields{}, + want: flag.PackageOptions{}, + }, + { + name: "happy path for OS packages", + fields: fields{ + pkgTypes: "os", + }, + want: flag.PackageOptions{ + PkgTypes: []string{ + types.PkgTypeOS, + }, + }, + }, + { + name: "happy path for library packages", + fields: fields{ + pkgTypes: "library", + }, + want: flag.PackageOptions{ + PkgTypes: []string{ + types.PkgTypeLibrary, + }, + }, + }, + { + name: "root and indirect relationships", + fields: fields{ + pkgRelationships: "root,indirect", + }, + want: flag.PackageOptions{ + PkgRelationships: []ftypes.Relationship{ + ftypes.RelationshipRoot, + ftypes.RelationshipIndirect, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Cleanup(viper.Reset) + + setValue(flag.PkgTypesFlag.ConfigName, tt.fields.pkgTypes) + setValue(flag.PkgRelationshipsFlag.ConfigName, tt.fields.pkgRelationships) + + // Assert options + f := &flag.PackageFlagGroup{ + PkgTypes: flag.PkgTypesFlag.Clone(), + PkgRelationships: flag.PkgRelationshipsFlag.Clone(), + } + + got, err := f.ToOptions() + require.NoError(t, err) + assert.EqualExportedValuesf(t, tt.want, got, "PackageFlagGroup") + }) + } +} diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index b82cc13e706b..ce833cc1b13e 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -106,20 +106,6 @@ var ( ConfigName: "scan.show-suppressed", Usage: "[EXPERIMENTAL] show suppressed vulnerabilities", } - PkgTypesFlag = Flag[[]string]{ - Name: "pkg-types", - ConfigName: "pkg-types", - Default: types.PkgTypes, - Values: types.PkgTypes, - Usage: "comma-separated list of package types", - Aliases: []Alias{ - { - Name: "vuln-type", - ConfigName: "vulnerability.type", - Deprecated: true, // --vuln-type was renamed to --pkg-types - }, - }, - } ) // ReportFlagGroup composes common printer flag structs @@ -139,7 +125,6 @@ type ReportFlagGroup struct { Severity *Flag[[]string] Compliance *Flag[string] ShowSuppressed *Flag[bool] - PkgTypes *Flag[[]string] } type ReportOptions struct { @@ -157,7 +142,6 @@ type ReportOptions struct { Severities []dbTypes.Severity Compliance spec.ComplianceSpec ShowSuppressed bool - PkgTypes []string } func NewReportFlagGroup() *ReportFlagGroup { @@ -176,7 +160,6 @@ func NewReportFlagGroup() *ReportFlagGroup { Severity: SeverityFlag.Clone(), Compliance: ComplianceFlag.Clone(), ShowSuppressed: ShowSuppressedFlag.Clone(), - PkgTypes: PkgTypesFlag.Clone(), } } @@ -200,7 +183,6 @@ func (f *ReportFlagGroup) Flags() []Flagger { f.Severity, f.Compliance, f.ShowSuppressed, - f.PkgTypes, } } @@ -270,7 +252,6 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { Severities: toSeverity(f.Severity.Value()), Compliance: cs, ShowSuppressed: f.ShowSuppressed.Value(), - PkgTypes: f.PkgTypes.Value(), }, nil } diff --git a/pkg/flag/report_flags_test.go b/pkg/flag/report_flags_test.go index 108d95e22a70..9440bf373905 100644 --- a/pkg/flag/report_flags_test.go +++ b/pkg/flag/report_flags_test.go @@ -160,28 +160,6 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { Severities: []dbTypes.Severity{dbTypes.SeverityLow}, }, }, - { - name: "happy path for OS packages", - fields: fields{ - pkgTypes: "os", - }, - want: flag.ReportOptions{ - PkgTypes: []string{ - types.PkgTypeOS, - }, - }, - }, - { - name: "happy path for library packages", - fields: fields{ - pkgTypes: "library", - }, - want: flag.ReportOptions{ - PkgTypes: []string{ - types.PkgTypeLibrary, - }, - }, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -206,7 +184,6 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { setValue(flag.OutputPluginArgFlag.ConfigName, tt.fields.outputPluginArgs) setValue(flag.SeverityFlag.ConfigName, tt.fields.severities) setValue(flag.ComplianceFlag.ConfigName, tt.fields.compliance) - setValue(flag.PkgTypesFlag.ConfigName, tt.fields.pkgTypes) // Assert options f := &flag.ReportFlagGroup{ @@ -222,7 +199,6 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { OutputPluginArg: flag.OutputPluginArgFlag.Clone(), Severity: flag.SeverityFlag.Clone(), Compliance: flag.ComplianceFlag.Clone(), - PkgTypes: flag.PkgTypesFlag.Clone(), } got, err := f.ToOptions() diff --git a/pkg/flag/scan_flags.go b/pkg/flag/scan_flags.go index 07f14a08551a..b413fce01fe9 100644 --- a/pkg/flag/scan_flags.go +++ b/pkg/flag/scan_flags.go @@ -96,51 +96,43 @@ var ( Default: "https://rekor.sigstore.dev", Usage: "[EXPERIMENTAL] address of rekor STL server", } - IncludeDevDepsFlag = Flag[bool]{ - Name: "include-dev-deps", - ConfigName: "scan.include-dev-deps", - Usage: "include development dependencies in the report (supported: npm, yarn)", - } ) type ScanFlagGroup struct { - SkipDirs *Flag[[]string] - SkipFiles *Flag[[]string] - OfflineScan *Flag[bool] - Scanners *Flag[[]string] - FilePatterns *Flag[[]string] - Slow *Flag[bool] // deprecated - Parallel *Flag[int] - SBOMSources *Flag[[]string] - RekorURL *Flag[string] - IncludeDevDeps *Flag[bool] + SkipDirs *Flag[[]string] + SkipFiles *Flag[[]string] + OfflineScan *Flag[bool] + Scanners *Flag[[]string] + FilePatterns *Flag[[]string] + Slow *Flag[bool] // deprecated + Parallel *Flag[int] + SBOMSources *Flag[[]string] + RekorURL *Flag[string] } type ScanOptions struct { - Target string - SkipDirs []string - SkipFiles []string - OfflineScan bool - Scanners types.Scanners - FilePatterns []string - Parallel int - SBOMSources []string - RekorURL string - IncludeDevDeps bool + Target string + SkipDirs []string + SkipFiles []string + OfflineScan bool + Scanners types.Scanners + FilePatterns []string + Parallel int + SBOMSources []string + RekorURL string } func NewScanFlagGroup() *ScanFlagGroup { return &ScanFlagGroup{ - SkipDirs: SkipDirsFlag.Clone(), - SkipFiles: SkipFilesFlag.Clone(), - OfflineScan: OfflineScanFlag.Clone(), - Scanners: ScannersFlag.Clone(), - FilePatterns: FilePatternsFlag.Clone(), - Parallel: ParallelFlag.Clone(), - SBOMSources: SBOMSourcesFlag.Clone(), - RekorURL: RekorURLFlag.Clone(), - IncludeDevDeps: IncludeDevDepsFlag.Clone(), - Slow: SlowFlag.Clone(), + SkipDirs: SkipDirsFlag.Clone(), + SkipFiles: SkipFilesFlag.Clone(), + OfflineScan: OfflineScanFlag.Clone(), + Scanners: ScannersFlag.Clone(), + FilePatterns: FilePatternsFlag.Clone(), + Parallel: ParallelFlag.Clone(), + SBOMSources: SBOMSourcesFlag.Clone(), + RekorURL: RekorURLFlag.Clone(), + Slow: SlowFlag.Clone(), } } @@ -159,7 +151,6 @@ func (f *ScanFlagGroup) Flags() []Flagger { f.Parallel, f.SBOMSources, f.RekorURL, - f.IncludeDevDeps, } } @@ -180,15 +171,14 @@ func (f *ScanFlagGroup) ToOptions(args []string) (ScanOptions, error) { } return ScanOptions{ - Target: target, - SkipDirs: f.SkipDirs.Value(), - SkipFiles: f.SkipFiles.Value(), - OfflineScan: f.OfflineScan.Value(), - Scanners: xstrings.ToTSlice[types.Scanner](f.Scanners.Value()), - FilePatterns: f.FilePatterns.Value(), - Parallel: parallel, - SBOMSources: f.SBOMSources.Value(), - RekorURL: f.RekorURL.Value(), - IncludeDevDeps: f.IncludeDevDeps.Value(), + Target: target, + SkipDirs: f.SkipDirs.Value(), + SkipFiles: f.SkipFiles.Value(), + OfflineScan: f.OfflineScan.Value(), + Scanners: xstrings.ToTSlice[types.Scanner](f.Scanners.Value()), + FilePatterns: f.FilePatterns.Value(), + Parallel: parallel, + SBOMSources: f.SBOMSources.Value(), + RekorURL: f.RekorURL.Value(), }, nil } diff --git a/pkg/log/logger.go b/pkg/log/logger.go index 1f0b8e32e1a2..6eb8bde70dc2 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -17,6 +17,13 @@ const ( LevelWarn = slog.LevelWarn LevelError = slog.LevelError LevelFatal = slog.Level(12) + + PrefixContainerImage = "image" + PrefixPackage = "pkg" + PrefixVulnerability = "vuln" + PrefixMisconfiguration = "misconfig" + PrefixSecret = "secret" + PrefixLicense = "license" ) // Logger is an alias of slog.Logger diff --git a/pkg/rpc/client/client.go b/pkg/rpc/client/client.go index d1ac1d8d829f..9e13db8ded48 100644 --- a/pkg/rpc/client/client.go +++ b/pkg/rpc/client/client.go @@ -83,6 +83,7 @@ func (s Scanner) Scan(ctx context.Context, target, artifactKey string, blobKeys BlobIds: blobKeys, Options: &rpc.ScanOptions{ PkgTypes: opts.PkgTypes, + PkgRelationships: xstrings.ToStringSlice(opts.PkgRelationships), Scanners: xstrings.ToStringSlice(opts.Scanners), LicenseCategories: licenseCategories, IncludeDevDeps: opts.IncludeDevDeps, diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index b0e58f87c0e9..bf4fa2ff5092 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -44,27 +44,44 @@ func teeError(err error) error { // Scan scans and return response func (s *ScanServer) Scan(ctx context.Context, in *rpcScanner.ScanRequest) (*rpcScanner.ScanResponse, error) { - scanners := lo.Map(in.Options.Scanners, func(s string, index int) types.Scanner { + options := s.ToOptions(in.Options) + results, os, err := s.localScanner.Scan(ctx, in.Target, in.ArtifactId, in.BlobIds, options) + if err != nil { + return nil, teeError(xerrors.Errorf("failed scan, %s: %w", in.Target, err)) + } + + return rpc.ConvertToRPCScanResponse(results, os), nil +} + +func (s *ScanServer) ToOptions(in *rpcScanner.ScanOptions) types.ScanOptions { + pkgRelationships := lo.FilterMap(in.PkgRelationships, func(r string, index int) (ftypes.Relationship, bool) { + rel, err := ftypes.NewRelationship(r) + if err != nil { + log.Warnf("Invalid relationship: %s", r) + return ftypes.RelationshipUnknown, false + } + return rel, true + }) + if len(pkgRelationships) == 0 { + pkgRelationships = ftypes.Relationships // For backward compatibility + } + + scanners := lo.Map(in.Scanners, func(s string, index int) types.Scanner { return types.Scanner(s) }) - licenseCategories := lo.MapEntries(in.Options.LicenseCategories, + licenseCategories := lo.MapEntries(in.LicenseCategories, func(k string, v *rpcScanner.Licenses) (ftypes.LicenseCategory, []string) { return ftypes.LicenseCategory(k), v.Names }) - options := types.ScanOptions{ - PkgTypes: in.Options.PkgTypes, + return types.ScanOptions{ + PkgTypes: in.PkgTypes, + PkgRelationships: pkgRelationships, Scanners: scanners, - IncludeDevDeps: in.Options.IncludeDevDeps, + IncludeDevDeps: in.IncludeDevDeps, LicenseCategories: licenseCategories, } - results, os, err := s.localScanner.Scan(ctx, in.Target, in.ArtifactId, in.BlobIds, options) - if err != nil { - return nil, teeError(xerrors.Errorf("failed scan, %s: %w", in.Target, err)) - } - - return rpc.ConvertToRPCScanResponse(results, os), nil } // CacheServer implements the cache diff --git a/pkg/scanner/local/scan.go b/pkg/scanner/local/scan.go index 7526ff48dd4c..3b0c719721e2 100644 --- a/pkg/scanner/local/scan.go +++ b/pkg/scanner/local/scan.go @@ -108,9 +108,8 @@ func (s Scanner) Scan(ctx context.Context, targetName, artifactKey string, blobK func (s Scanner) ScanTarget(ctx context.Context, target types.ScanTarget, options types.ScanOptions) (types.Results, ftypes.OS, error) { var results types.Results - // By default, we need to remove dev dependencies from the result - // IncludeDevDeps option allows you not to remove them - excludeDevDeps(target.Applications, options.IncludeDevDeps) + // Filter packages according to the options + excludePackages(&target, options) // Add packages if needed and scan packages for vulnerabilities vulnResults, eosl, err := s.scanVulnerabilities(ctx, target, options) @@ -395,6 +394,32 @@ func ShouldScanMisconfigOrRbac(scanners types.Scanners) bool { return scanners.AnyEnabled(types.MisconfigScanner, types.RBACScanner) } +func excludePackages(target *types.ScanTarget, options types.ScanOptions) { + // Filter packages by relationship + filterPkgByRelationship(target, options) + + // By default, development packages are removed from the result + // '--include-dev-deps' option allows including them + excludeDevDeps(target.Applications, options.IncludeDevDeps) +} + +func filterPkgByRelationship(target *types.ScanTarget, options types.ScanOptions) { + if slices.Compare(options.PkgRelationships, ftypes.Relationships) == 0 { + return // No need to filter + } + + filter := func(pkgs []ftypes.Package) []ftypes.Package { + return lo.Filter(pkgs, func(pkg ftypes.Package, index int) bool { + return slices.Contains(options.PkgRelationships, pkg.Relationship) + }) + } + + target.Packages = filter(target.Packages) + for i, app := range target.Applications { + target.Applications[i].Packages = filter(app.Packages) + } +} + // excludeDevDeps removes development dependencies from the list of applications func excludeDevDeps(apps []ftypes.Application, include bool) { if include { diff --git a/pkg/scanner/local/scan_test.go b/pkg/scanner/local/scan_test.go index a80a4bd281c8..7d60697fa23a 100644 --- a/pkg/scanner/local/scan_test.go +++ b/pkg/scanner/local/scan_test.go @@ -65,8 +65,17 @@ var ( Licenses: []string{"MIT"}, } laravelPkg = ftypes.Package{ - Name: "laravel/framework", - Version: "6.0.0", + Name: "laravel/framework", + Version: "6.0.0", + Relationship: ftypes.RelationshipDirect, + Layer: ftypes.Layer{ + DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", + }, + } + guzzlePkg = ftypes.Package{ + Name: "guzzlehttp/guzzle", + Version: "7.9.2", + Relationship: ftypes.RelationshipIndirect, Layer: ftypes.Layer{ DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", }, @@ -98,7 +107,8 @@ func TestScanner_Scan(t *testing.T) { types.PkgTypeOS, types.PkgTypeLibrary, }, - Scanners: types.Scanners{types.VulnerabilityScanner}, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.VulnerabilityScanner}, }, }, fixtures: []string{"testdata/fixtures/happy.yaml"}, @@ -198,7 +208,8 @@ func TestScanner_Scan(t *testing.T) { target: "alpine:latest", layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, options: types.ScanOptions{ - Scanners: types.Scanners{types.LicenseScanner}, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.LicenseScanner}, }, }, fixtures: []string{"testdata/fixtures/happy.yaml"}, @@ -298,7 +309,8 @@ func TestScanner_Scan(t *testing.T) { types.PkgTypeOS, types.PkgTypeLibrary, }, - Scanners: types.Scanners{types.VulnerabilityScanner}, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.VulnerabilityScanner}, }, }, fixtures: []string{"testdata/fixtures/happy.yaml"}, @@ -377,8 +389,9 @@ func TestScanner_Scan(t *testing.T) { target: "./result.cdx", layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, options: types.ScanOptions{ - PkgTypes: []string{types.PkgTypeLibrary}, - Scanners: types.Scanners{types.VulnerabilityScanner}, + PkgTypes: []string{types.PkgTypeLibrary}, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.VulnerabilityScanner}, }, }, fixtures: []string{"testdata/fixtures/happy.yaml"}, @@ -477,7 +490,8 @@ func TestScanner_Scan(t *testing.T) { types.PkgTypeOS, types.PkgTypeLibrary, }, - Scanners: types.Scanners{types.VulnerabilityScanner}, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.VulnerabilityScanner}, }, }, fixtures: []string{"testdata/fixtures/happy.yaml"}, @@ -558,7 +572,8 @@ func TestScanner_Scan(t *testing.T) { types.PkgTypeOS, types.PkgTypeLibrary, }, - Scanners: types.Scanners{types.VulnerabilityScanner}, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.VulnerabilityScanner}, }, }, fixtures: []string{"testdata/fixtures/happy.yaml"}, @@ -630,7 +645,8 @@ func TestScanner_Scan(t *testing.T) { types.PkgTypeOS, types.PkgTypeLibrary, }, - Scanners: types.Scanners{types.VulnerabilityScanner}, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.VulnerabilityScanner}, }, }, fixtures: []string{"testdata/fixtures/happy.yaml"}, @@ -645,12 +661,17 @@ func TestScanner_Scan(t *testing.T) { wantResults: nil, }, { - name: "happy path with only language-specific package detection", + name: "happy path with only language-specific package detection, excluding direct packages", args: args{ target: "alpine:latest", layerIDs: []string{"sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33"}, options: types.ScanOptions{ PkgTypes: []string{types.PkgTypeLibrary}, + PkgRelationships: []ftypes.Relationship{ + ftypes.RelationshipUnknown, + ftypes.RelationshipRoot, + ftypes.RelationshipIndirect, + }, Scanners: types.Scanners{types.VulnerabilityScanner}, }, }, @@ -680,7 +701,8 @@ func TestScanner_Scan(t *testing.T) { Type: "composer", FilePath: "/app/composer-lock.json", Packages: []ftypes.Package{ - laravelPkg, + laravelPkg, // will be excluded + guzzlePkg, }, }, }, @@ -721,19 +743,7 @@ func TestScanner_Scan(t *testing.T) { Target: "/app/composer-lock.json", Class: types.ClassLangPkg, Type: ftypes.Composer, - Packages: ftypes.Packages{laravelPkg}, - Vulnerabilities: []types.DetectedVulnerability{ - { - VulnerabilityID: "CVE-2021-21263", - PkgName: laravelPkg.Name, - InstalledVersion: laravelPkg.Version, - FixedVersion: "8.22.1, 7.30.3, 6.20.12", - Status: dbTypes.StatusFixed, - Layer: ftypes.Layer{ - DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", - }, - }, - }, + Packages: ftypes.Packages{guzzlePkg}, }, }, wantOS: ftypes.OS{ @@ -900,7 +910,8 @@ func TestScanner_Scan(t *testing.T) { types.PkgTypeOS, types.PkgTypeLibrary, }, - Scanners: types.Scanners{types.VulnerabilityScanner}, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.VulnerabilityScanner}, }, }, fixtures: []string{"testdata/fixtures/happy.yaml"}, @@ -920,8 +931,9 @@ func TestScanner_Scan(t *testing.T) { target: "alpine:latest", layerIDs: []string{"sha256:5216338b40a7b96416b8b9858974bbe4acc3096ee60acbc4dfb1ee02aecceb10"}, options: types.ScanOptions{ - PkgTypes: []string{types.PkgTypeLibrary}, - Scanners: types.Scanners{types.VulnerabilityScanner}, + PkgTypes: []string{types.PkgTypeLibrary}, + PkgRelationships: ftypes.Relationships, + Scanners: types.Scanners{types.VulnerabilityScanner}, }, }, fixtures: []string{"testdata/fixtures/sad.yaml"}, @@ -1103,8 +1115,7 @@ func TestScanner_Scan(t *testing.T) { s := NewScanner(applier, ospkg.NewScanner(), langpkg.NewScanner(), vulnerability.NewClient(db.Config{})) gotResults, gotOS, err := s.Scan(context.Background(), tt.args.target, "", tt.args.layerIDs, tt.args.options) if tt.wantErr != "" { - require.Error(t, err, tt.name) - require.Contains(t, err.Error(), tt.wantErr, tt.name) + require.ErrorContains(t, err, tt.wantErr, tt.name) return } diff --git a/pkg/types/scan.go b/pkg/types/scan.go index 2151cb9ccd24..09b90e745c58 100644 --- a/pkg/types/scan.go +++ b/pkg/types/scan.go @@ -23,6 +23,7 @@ type ScanTarget struct { // ScanOptions holds the attributes for scanning vulnerabilities type ScanOptions struct { PkgTypes []string + PkgRelationships []types.Relationship Scanners Scanners ImageConfigScanners Scanners // Scanners for container image configuration ScanRemovedPackages bool diff --git a/pkg/x/strings/strings.go b/pkg/x/strings/strings.go index 78c87231605a..43a852f64008 100644 --- a/pkg/x/strings/strings.go +++ b/pkg/x/strings/strings.go @@ -1,17 +1,28 @@ package strings -import "github.com/samber/lo" +import ( + "fmt" + + "github.com/samber/lo" +) type String interface { ~string } -func ToStringSlice[T String](ss []T) []string { - if ss == nil { +func ToStringSlice[T any](ss []T) []string { + if len(ss) == 0 { return nil } return lo.Map(ss, func(s T, _ int) string { - return string(s) + switch v := any(s).(type) { + case string: + return v + case fmt.Stringer: + return v.String() + default: + return fmt.Sprint(v) + } }) } diff --git a/rpc/scanner/service.pb.go b/rpc/scanner/service.pb.go index 2f03d4727662..1e061d5764e1 100644 --- a/rpc/scanner/service.pb.go +++ b/rpc/scanner/service.pb.go @@ -150,6 +150,7 @@ type ScanOptions struct { Scanners []string `protobuf:"bytes,2,rep,name=scanners,proto3" json:"scanners,omitempty"` 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"` } func (x *ScanOptions) Reset() { @@ -212,6 +213,13 @@ func (x *ScanOptions) GetIncludeDevDeps() bool { return false } +func (x *ScanOptions) GetPkgRelationships() []string { + if x != nil { + return x.PkgRelationships + } + return nil +} + type ScanResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -398,7 +406,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, 0xbd, 0x02, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6e, 0x4f, + 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x22, 0xea, 0x02, 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, @@ -411,59 +419,61 @@ var file_rpc_scanner_service_proto_rawDesc = []byte{ 0x79, 0x52, 0x11, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x64, 0x65, 0x70, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, - 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44, 0x65, 0x76, 0x44, 0x65, 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, 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, + 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, + 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 ( diff --git a/rpc/scanner/service.proto b/rpc/scanner/service.proto index 8fc1cdbd46ac..c7ad3748280b 100644 --- a/rpc/scanner/service.proto +++ b/rpc/scanner/service.proto @@ -27,6 +27,7 @@ message ScanOptions { repeated string scanners = 2; map license_categories = 4; bool include_dev_deps = 5; + repeated string pkg_relationships = 6; reserved 3; // deleted 'list_all_packages' } diff --git a/rpc/scanner/service.twirp.go b/rpc/scanner/service.twirp.go index c877fbe34523..83a834536f35 100644 --- a/rpc/scanner/service.twirp.go +++ b/rpc/scanner/service.twirp.go @@ -1094,46 +1094,47 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) } var twirpFileDescriptor0 = []byte{ - // 650 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0xcd, 0x6e, 0xdb, 0x38, - 0x10, 0x86, 0x7f, 0x62, 0xcb, 0xe3, 0xc5, 0xc6, 0x21, 0x76, 0x03, 0xc5, 0xd9, 0x6c, 0x0d, 0x1f, - 0x0a, 0x9f, 0xec, 0xc6, 0x69, 0xd1, 0xbf, 0x5b, 0x93, 0xb4, 0x48, 0xd1, 0x22, 0x01, 0x1d, 0xf4, - 0xd0, 0x8b, 0x4b, 0x53, 0x13, 0x95, 0xb0, 0x2c, 0x29, 0x1c, 0xca, 0x80, 0x5f, 0xa5, 0xef, 0xd2, - 0xc7, 0xe8, 0xfb, 0x14, 0x22, 0x25, 0x23, 0x76, 0x92, 0x9e, 0xc4, 0x99, 0xf9, 0xe6, 0x9b, 0x0f, - 0x9c, 0x4f, 0x84, 0x03, 0x9d, 0xca, 0x11, 0x49, 0x11, 0xc7, 0xa8, 0x47, 0x84, 0x7a, 0xa9, 0x24, - 0x0e, 0x53, 0x9d, 0x98, 0x84, 0x75, 0x8c, 0x56, 0xcb, 0xd5, 0xb0, 0x28, 0x0e, 0x97, 0xc7, 0x5d, - 0x3f, 0x07, 0xcb, 0x64, 0xb1, 0x48, 0xe2, 0x4d, 0x6c, 0xff, 0x47, 0x05, 0xda, 0x13, 0x29, 0x62, - 0x8e, 0xb7, 0x19, 0x92, 0x61, 0xfb, 0xd0, 0x30, 0x42, 0x87, 0x68, 0xfc, 0x4a, 0xaf, 0x32, 0x68, - 0xf1, 0x22, 0x62, 0x4f, 0xa0, 0x2d, 0xb4, 0x51, 0x37, 0x42, 0x9a, 0xa9, 0x0a, 0xfc, 0xaa, 0x2d, - 0x42, 0x99, 0xba, 0x08, 0xd8, 0x01, 0x78, 0xb3, 0x28, 0x99, 0x4d, 0x55, 0x40, 0x7e, 0xad, 0x57, - 0x1b, 0xb4, 0x78, 0x33, 0x8f, 0x2f, 0x02, 0x62, 0x2f, 0xa1, 0x99, 0xa4, 0x46, 0x25, 0x31, 0xf9, - 0xf5, 0x5e, 0x65, 0xd0, 0x1e, 0x1f, 0x0d, 0xb7, 0x15, 0x0e, 0x73, 0x0d, 0x97, 0x0e, 0xc4, 0x4b, - 0x74, 0xbf, 0x07, 0xde, 0x27, 0x25, 0x31, 0x26, 0x24, 0xf6, 0x0f, 0xec, 0xc4, 0x62, 0x81, 0xe4, - 0x57, 0x2c, 0xb9, 0x0b, 0xfa, 0x3f, 0xab, 0x4e, 0x7e, 0xd1, 0xca, 0x0e, 0xa1, 0x95, 0xce, 0xc3, - 0xa9, 0x59, 0xa5, 0x6b, 0xa4, 0x97, 0xce, 0xc3, 0xeb, 0x3c, 0x66, 0x5d, 0xf0, 0x8a, 0x89, 0xe4, - 0x57, 0x5d, 0xad, 0x8c, 0x99, 0x04, 0x16, 0xb9, 0x51, 0x53, 0x29, 0x0c, 0x86, 0x89, 0x56, 0x98, - 0xcb, 0xad, 0x0d, 0xda, 0xe3, 0xe7, 0x7f, 0x94, 0x3b, 0x2c, 0x24, 0x9e, 0xae, 0xdb, 0xce, 0x63, - 0xa3, 0x57, 0x7c, 0x2f, 0xda, 0xce, 0xb3, 0x01, 0x74, 0x54, 0x2c, 0xa3, 0x2c, 0xc0, 0x69, 0x80, - 0xcb, 0x69, 0x80, 0x29, 0xf9, 0x3b, 0xbd, 0xca, 0xc0, 0xe3, 0x7f, 0x17, 0xf9, 0x33, 0x5c, 0x9e, - 0x61, 0x4a, 0xdd, 0x6f, 0xb0, 0xff, 0x30, 0x2d, 0xeb, 0x40, 0x6d, 0x8e, 0xab, 0x62, 0x3b, 0xf9, - 0x91, 0x3d, 0x83, 0x9d, 0xa5, 0x88, 0x32, 0xb4, 0x4b, 0x69, 0x8f, 0xbb, 0xf7, 0xd5, 0x96, 0x97, - 0xc8, 0x1d, 0xf0, 0x4d, 0xf5, 0x55, 0xe5, 0x63, 0xdd, 0xab, 0x75, 0xea, 0xfd, 0x00, 0xfe, 0x72, - 0xdb, 0xa7, 0x34, 0x89, 0x09, 0x59, 0x0f, 0xaa, 0x09, 0x59, 0xf2, 0xf6, 0xb8, 0x53, 0x10, 0x39, - 0xdf, 0x0c, 0x2f, 0x27, 0xbc, 0x9a, 0x10, 0x1b, 0x43, 0x53, 0x23, 0x65, 0x91, 0x71, 0x6b, 0x6e, - 0x8f, 0xfd, 0xfb, 0xf3, 0xb8, 0x05, 0xf0, 0x12, 0xd8, 0xff, 0x55, 0x83, 0x86, 0xcb, 0x3d, 0xea, - 0xaf, 0x73, 0xd8, 0x5d, 0x66, 0x51, 0x8c, 0x5a, 0xcc, 0x54, 0xa4, 0x4c, 0x7e, 0xf9, 0x55, 0x4b, - 0x7f, 0xb8, 0xa9, 0xe2, 0xcb, 0x1d, 0xd0, 0x8a, 0x6f, 0xf7, 0xb0, 0x6b, 0xd8, 0x5b, 0x28, 0x92, - 0x49, 0x7c, 0xa3, 0xc2, 0x4c, 0x8b, 0xd2, 0x74, 0x39, 0xd1, 0xd3, 0x4d, 0xa2, 0x33, 0x34, 0x28, - 0x0d, 0x06, 0x9f, 0xb7, 0xe0, 0xfc, 0x3e, 0x41, 0xee, 0x3d, 0x19, 0x09, 0x22, 0xbf, 0x61, 0x35, - 0xbb, 0x80, 0x31, 0xa8, 0xe7, 0x3e, 0xf3, 0x6b, 0x36, 0x69, 0xcf, 0xec, 0x18, 0xbc, 0x54, 0xc8, - 0xb9, 0x08, 0x31, 0xdf, 0x6c, 0x3e, 0xf6, 0xdf, 0xcd, 0xb1, 0x57, 0xae, 0xca, 0xd7, 0x30, 0xf6, - 0x01, 0x3a, 0x32, 0x23, 0x93, 0x2c, 0xa6, 0x1a, 0x29, 0xc9, 0xb4, 0x44, 0xf2, 0x9b, 0xb6, 0xf5, - 0xbf, 0xcd, 0xd6, 0x53, 0x8b, 0xe2, 0x05, 0x88, 0xef, 0xca, 0x8d, 0x98, 0xd8, 0x0b, 0x68, 0x12, - 0x4a, 0x8d, 0x86, 0x7c, 0xef, 0xa1, 0xab, 0x9b, 0xd8, 0xe2, 0x7b, 0x15, 0x07, 0x2a, 0x0e, 0x79, - 0x89, 0x65, 0xaf, 0xc1, 0x2b, 0x9c, 0x4a, 0x7e, 0xcb, 0xf6, 0x1d, 0x3d, 0x7c, 0x53, 0x85, 0x8b, - 0xf8, 0x1a, 0x3e, 0xbe, 0x82, 0xe6, 0xc4, 0x6d, 0x9d, 0x9d, 0x43, 0x3d, 0x3f, 0xb2, 0x47, 0x7e, - 0xed, 0xe2, 0x79, 0xe9, 0xfe, 0xff, 0x58, 0xd9, 0xf9, 0xef, 0xdd, 0xc9, 0xd7, 0xe3, 0x50, 0x99, - 0xef, 0xd9, 0x2c, 0x1f, 0x3e, 0x12, 0xb7, 0x99, 0x20, 0x94, 0x99, 0x56, 0x66, 0x35, 0xb2, 0x8d, - 0xa3, 0x3b, 0xaf, 0xde, 0xdb, 0xe2, 0x3b, 0x6b, 0xd8, 0xa7, 0xec, 0xe4, 0x77, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x50, 0x58, 0x22, 0xc7, 0x13, 0x05, 0x00, 0x00, + // 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, }