mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
Add Linux Kernel cataloger (#1694)
* add kernel handler Signed-off-by: Avi Deitcher <avi@deitcher.net> * [wip] combine kernel and kernel module cataloging Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * [wip] combine kernel and kernel module cataloging Signed-off-by: Alex Goodman <alex.goodman@anchore.com> Signed-off-by: Avi Deitcher <avi@deitcher.net> * rename Kernel package to LinuxKernel package Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * split kernel and module packages within cataloger Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * wire up application configuration with kernel cataloger options Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * dont use references for packages on relationships Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * fix linting and tests Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * kernel cataloger should be resistent to partial failure Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * log upon kernel module metadata missing Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * add tests for linux kernel cataloger Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update integration tests Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update cli package test counts Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * add evidence annotations for kernel packages Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * reduce noise in cli test output Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * missed cli test to reduce noise for Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * fix package counts Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * update docs with linux kernel cataloging refs Signed-off-by: Alex Goodman <alex.goodman@anchore.com> * bump json schema with new metadata fields Signed-off-by: Alex Goodman <alex.goodman@anchore.com> --------- Signed-off-by: Avi Deitcher <avi@deitcher.net> Signed-off-by: Alex Goodman <alex.goodman@anchore.com> Signed-off-by: <> Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
5d156b8241
commit
cc731c7b19
@ -45,6 +45,8 @@ For commercial support options with Syft or Grype, please [contact Anchore](http
|
|||||||
- Java (jar, ear, war, par, sar, nar, native-image)
|
- Java (jar, ear, war, par, sar, nar, native-image)
|
||||||
- JavaScript (npm, yarn)
|
- JavaScript (npm, yarn)
|
||||||
- Jenkins Plugins (jpi, hpi)
|
- Jenkins Plugins (jpi, hpi)
|
||||||
|
- Linux kernel archives (vmlinz)
|
||||||
|
- Linux kernel modules (ko)
|
||||||
- Nix (outputs in /nix/store)
|
- Nix (outputs in /nix/store)
|
||||||
- PHP (composer)
|
- PHP (composer)
|
||||||
- Python (wheel, egg, poetry, requirements.txt)
|
- Python (wheel, egg, poetry, requirements.txt)
|
||||||
@ -513,6 +515,11 @@ golang:
|
|||||||
# SYFT_GOLANG_LOCAL_MOD_CACHE_DIR env var
|
# SYFT_GOLANG_LOCAL_MOD_CACHE_DIR env var
|
||||||
local-mod-cache-dir: ""
|
local-mod-cache-dir: ""
|
||||||
|
|
||||||
|
linux-kernel:
|
||||||
|
# whether to catalog linux kernel modules found within lib/modules/** directories
|
||||||
|
# SYFT_LINUX_KERNEL_CATALOG_MODULES env var
|
||||||
|
catalog-modules: true
|
||||||
|
|
||||||
# cataloging file contents is exposed through the power-user subcommand
|
# cataloging file contents is exposed through the power-user subcommand
|
||||||
file-contents:
|
file-contents:
|
||||||
cataloger:
|
cataloger:
|
||||||
|
|||||||
1
go.mod
1
go.mod
@ -53,6 +53,7 @@ require (
|
|||||||
github.com/Masterminds/sprig/v3 v3.2.3
|
github.com/Masterminds/sprig/v3 v3.2.3
|
||||||
github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8
|
github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8
|
||||||
github.com/anchore/stereoscope v0.0.0-20230406143206-e95d60a265e3
|
github.com/anchore/stereoscope v0.0.0-20230406143206-e95d60a265e3
|
||||||
|
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
|
||||||
github.com/docker/docker v23.0.3+incompatible
|
github.com/docker/docker v23.0.3+incompatible
|
||||||
github.com/google/go-containerregistry v0.14.0
|
github.com/google/go-containerregistry v0.14.0
|
||||||
github.com/google/licensecheck v0.3.1
|
github.com/google/licensecheck v0.3.1
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -145,6 +145,8 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da h1:ZOjWpVsFZ06eIhnh4mkaceTiVoktdU67+M7KDHJ268M=
|
||||||
|
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=
|
||||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||||
github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM=
|
github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM=
|
||||||
github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/anchore/syft/internal/log"
|
"github.com/anchore/syft/internal/log"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger"
|
"github.com/anchore/syft/syft/pkg/cataloger"
|
||||||
golangCataloger "github.com/anchore/syft/syft/pkg/cataloger/golang"
|
golangCataloger "github.com/anchore/syft/syft/pkg/cataloger/golang"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -50,6 +51,7 @@ type Application struct {
|
|||||||
Catalogers []string `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
|
Catalogers []string `yaml:"catalogers" json:"catalogers" mapstructure:"catalogers"`
|
||||||
Package pkg `yaml:"package" json:"package" mapstructure:"package"`
|
Package pkg `yaml:"package" json:"package" mapstructure:"package"`
|
||||||
Golang golang `yaml:"golang" json:"golang" mapstructure:"golang"`
|
Golang golang `yaml:"golang" json:"golang" mapstructure:"golang"`
|
||||||
|
LinuxKernel linuxKernel `yaml:"linux-kernel" json:"linux-kernel" mapstructure:"linux-kernel"`
|
||||||
Attest attest `yaml:"attest" json:"attest" mapstructure:"attest"`
|
Attest attest `yaml:"attest" json:"attest" mapstructure:"attest"`
|
||||||
FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
|
FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
|
||||||
FileClassification fileClassification `yaml:"file-classification" json:"file-classification" mapstructure:"file-classification"`
|
FileClassification fileClassification `yaml:"file-classification" json:"file-classification" mapstructure:"file-classification"`
|
||||||
@ -76,6 +78,9 @@ func (cfg Application) ToCatalogerConfig() cataloger.Config {
|
|||||||
SearchLocalModCacheLicenses: cfg.Golang.SearchLocalModCacheLicenses,
|
SearchLocalModCacheLicenses: cfg.Golang.SearchLocalModCacheLicenses,
|
||||||
LocalModCacheDir: cfg.Golang.LocalModCacheDir,
|
LocalModCacheDir: cfg.Golang.LocalModCacheDir,
|
||||||
},
|
},
|
||||||
|
LinuxKernel: kernel.LinuxCatalogerConfig{
|
||||||
|
CatalogModules: cfg.LinuxKernel.CatalogModules,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
internal/config/linux_kernel.go
Normal file
11
internal/config/linux_kernel.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import "github.com/spf13/viper"
|
||||||
|
|
||||||
|
type linuxKernel struct {
|
||||||
|
CatalogModules bool `json:"catalog-modules" yaml:"catalog-modules" mapstructure:"catalog-modules"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg linuxKernel) loadDefaultValues(v *viper.Viper) {
|
||||||
|
v.SetDefault("linux-kernel.catalog-modules", true)
|
||||||
|
}
|
||||||
@ -6,5 +6,5 @@ const (
|
|||||||
|
|
||||||
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
// JSONSchemaVersion is the current schema version output by the JSON encoder
|
||||||
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
|
||||||
JSONSchemaVersion = "7.1.2"
|
JSONSchemaVersion = "7.1.3"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -45,6 +45,8 @@ type artifactMetadataContainer struct {
|
|||||||
Hackage pkg.HackageMetadata
|
Hackage pkg.HackageMetadata
|
||||||
Java pkg.JavaMetadata
|
Java pkg.JavaMetadata
|
||||||
KbPackage pkg.KbPackageMetadata
|
KbPackage pkg.KbPackageMetadata
|
||||||
|
LinuxKernel pkg.LinuxKernelMetadata
|
||||||
|
LinuxKernelModule pkg.LinuxKernelModuleMetadata
|
||||||
Nix pkg.NixStoreMetadata
|
Nix pkg.NixStoreMetadata
|
||||||
NpmPackage pkg.NpmPackageJSONMetadata
|
NpmPackage pkg.NpmPackageJSONMetadata
|
||||||
NpmPackageLock pkg.NpmPackageLockJSONMetadata
|
NpmPackageLock pkg.NpmPackageLockJSONMetadata
|
||||||
|
|||||||
1768
schema/json/schema-7.1.3.json
Normal file
1768
schema/json/schema-7.1.3.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:funlen
|
||||||
func SourceInfo(p pkg.Package) string {
|
func SourceInfo(p pkg.Package) string {
|
||||||
answer := ""
|
answer := ""
|
||||||
switch p.Type {
|
switch p.Type {
|
||||||
@ -45,6 +46,10 @@ func SourceInfo(p pkg.Package) string {
|
|||||||
answer = "acquired package info from cabal or stack manifest files"
|
answer = "acquired package info from cabal or stack manifest files"
|
||||||
case pkg.HexPkg:
|
case pkg.HexPkg:
|
||||||
answer = "acquired package info from rebar3 or mix manifest file"
|
answer = "acquired package info from rebar3 or mix manifest file"
|
||||||
|
case pkg.LinuxKernelPkg:
|
||||||
|
answer = "acquired package info from linux kernel archive"
|
||||||
|
case pkg.LinuxKernelModulePkg:
|
||||||
|
answer = "acquired package info from linux kernel module files"
|
||||||
case pkg.NixPkg:
|
case pkg.NixPkg:
|
||||||
answer = "acquired package info from nix store path"
|
answer = "acquired package info from nix store path"
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -199,6 +199,22 @@ func Test_SourceInfo(t *testing.T) {
|
|||||||
"from rebar3 or mix manifest file",
|
"from rebar3 or mix manifest file",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
input: pkg.Package{
|
||||||
|
Type: pkg.LinuxKernelPkg,
|
||||||
|
},
|
||||||
|
expected: []string{
|
||||||
|
"from linux kernel archive",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: pkg.Package{
|
||||||
|
Type: pkg.LinuxKernelModulePkg,
|
||||||
|
},
|
||||||
|
expected: []string{
|
||||||
|
"from linux kernel module files",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
input: pkg.Package{
|
input: pkg.Package{
|
||||||
Type: pkg.NixPkg,
|
Type: pkg.NixPkg,
|
||||||
|
|||||||
@ -89,7 +89,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schema": {
|
"schema": {
|
||||||
"version": "7.1.2",
|
"version": "7.1.3",
|
||||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-7.1.2.json"
|
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-7.1.3.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -185,7 +185,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schema": {
|
"schema": {
|
||||||
"version": "7.1.2",
|
"version": "7.1.3",
|
||||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-7.1.2.json"
|
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-7.1.3.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,7 +112,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schema": {
|
"schema": {
|
||||||
"version": "7.1.2",
|
"version": "7.1.3",
|
||||||
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-7.1.2.json"
|
"url": "https://raw.githubusercontent.com/anchore/syft/main/schema/json/schema-7.1.3.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/anchore/syft/syft/pkg/cataloger/haskell"
|
"github.com/anchore/syft/syft/pkg/cataloger/haskell"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/nix"
|
"github.com/anchore/syft/syft/pkg/cataloger/nix"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/php"
|
"github.com/anchore/syft/syft/pkg/cataloger/php"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/portage"
|
"github.com/anchore/syft/syft/pkg/cataloger/portage"
|
||||||
@ -55,6 +56,7 @@ func ImageCatalogers(cfg Config) []pkg.Cataloger {
|
|||||||
nix.NewStoreCataloger(),
|
nix.NewStoreCataloger(),
|
||||||
sbom.NewSBOMCataloger(),
|
sbom.NewSBOMCataloger(),
|
||||||
binary.NewCataloger(),
|
binary.NewCataloger(),
|
||||||
|
kernel.NewLinuxKernelCataloger(cfg.Kernel()),
|
||||||
}, cfg.Catalogers)
|
}, cfg.Catalogers)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +90,7 @@ func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
|
|||||||
binary.NewCataloger(),
|
binary.NewCataloger(),
|
||||||
elixir.NewMixLockCataloger(),
|
elixir.NewMixLockCataloger(),
|
||||||
erlang.NewRebarLockCataloger(),
|
erlang.NewRebarLockCataloger(),
|
||||||
|
kernel.NewLinuxKernelCataloger(cfg.Kernel()),
|
||||||
nix.NewStoreCataloger(),
|
nix.NewStoreCataloger(),
|
||||||
}, cfg.Catalogers)
|
}, cfg.Catalogers)
|
||||||
}
|
}
|
||||||
@ -126,6 +129,7 @@ func AllCatalogers(cfg Config) []pkg.Cataloger {
|
|||||||
binary.NewCataloger(),
|
binary.NewCataloger(),
|
||||||
elixir.NewMixLockCataloger(),
|
elixir.NewMixLockCataloger(),
|
||||||
erlang.NewRebarLockCataloger(),
|
erlang.NewRebarLockCataloger(),
|
||||||
|
kernel.NewLinuxKernelCataloger(cfg.Kernel()),
|
||||||
nix.NewStoreCataloger(),
|
nix.NewStoreCataloger(),
|
||||||
}, cfg.Catalogers)
|
}, cfg.Catalogers)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,11 +3,15 @@ package cataloger
|
|||||||
import (
|
import (
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/golang"
|
"github.com/anchore/syft/syft/pkg/cataloger/golang"
|
||||||
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: these field naming vs helper function naming schemes are inconsistent.
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Search SearchConfig
|
Search SearchConfig
|
||||||
Golang golang.GoCatalogerOpts
|
Golang golang.GoCatalogerOpts
|
||||||
|
LinuxKernel kernel.LinuxCatalogerConfig
|
||||||
Catalogers []string
|
Catalogers []string
|
||||||
Parallelism int
|
Parallelism int
|
||||||
}
|
}
|
||||||
@ -16,6 +20,7 @@ func DefaultConfig() Config {
|
|||||||
return Config{
|
return Config{
|
||||||
Search: DefaultSearchConfig(),
|
Search: DefaultSearchConfig(),
|
||||||
Parallelism: 1,
|
Parallelism: 1,
|
||||||
|
LinuxKernel: kernel.DefaultLinuxCatalogerConfig(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,3 +34,7 @@ func (c Config) Java() java.Config {
|
|||||||
func (c Config) Go() golang.GoCatalogerOpts {
|
func (c Config) Go() golang.GoCatalogerOpts {
|
||||||
return c.Golang
|
return c.Golang
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Config) Kernel() kernel.LinuxCatalogerConfig {
|
||||||
|
return c.LinuxKernel
|
||||||
|
}
|
||||||
|
|||||||
127
syft/pkg/cataloger/kernel/cataloger.go
Normal file
127
syft/pkg/cataloger/kernel/cataloger.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
Package kernel provides a concrete Cataloger implementation for linux kernel and module files.
|
||||||
|
*/
|
||||||
|
package kernel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ pkg.Cataloger = (*LinuxKernelCataloger)(nil)
|
||||||
|
|
||||||
|
type LinuxCatalogerConfig struct {
|
||||||
|
CatalogModules bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinuxKernelCataloger struct {
|
||||||
|
cfg LinuxCatalogerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultLinuxCatalogerConfig() LinuxCatalogerConfig {
|
||||||
|
return LinuxCatalogerConfig{
|
||||||
|
CatalogModules: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var kernelArchiveGlobs = []string{
|
||||||
|
"**/kernel",
|
||||||
|
"**/kernel-*",
|
||||||
|
"**/vmlinux",
|
||||||
|
"**/vmlinux-*",
|
||||||
|
"**/vmlinuz",
|
||||||
|
"**/vmlinuz-*",
|
||||||
|
}
|
||||||
|
|
||||||
|
var kernelModuleGlobs = []string{
|
||||||
|
"**/lib/modules/**/*.ko",
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLinuxKernelCataloger returns a new kernel files cataloger object.
|
||||||
|
func NewLinuxKernelCataloger(cfg LinuxCatalogerConfig) *LinuxKernelCataloger {
|
||||||
|
return &LinuxKernelCataloger{
|
||||||
|
cfg: cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LinuxKernelCataloger) Name() string {
|
||||||
|
return "linux-kernel-cataloger"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LinuxKernelCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
var allPackages []pkg.Package
|
||||||
|
var allRelationships []artifact.Relationship
|
||||||
|
var errs error
|
||||||
|
|
||||||
|
kernelPackages, kernelRelationships, err := generic.NewCataloger(l.Name()).WithParserByGlobs(parseLinuxKernelFile, kernelArchiveGlobs...).Catalog(resolver)
|
||||||
|
if err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
allRelationships = append(allRelationships, kernelRelationships...)
|
||||||
|
allPackages = append(allPackages, kernelPackages...)
|
||||||
|
|
||||||
|
if l.cfg.CatalogModules {
|
||||||
|
modulePackages, moduleRelationships, err := generic.NewCataloger(l.Name()).WithParserByGlobs(parseLinuxKernelModuleFile, kernelModuleGlobs...).Catalog(resolver)
|
||||||
|
if err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
allPackages = append(allPackages, modulePackages...)
|
||||||
|
|
||||||
|
moduleToKernelRelationships := createKernelToModuleRelationships(kernelPackages, modulePackages)
|
||||||
|
allRelationships = append(allRelationships, moduleRelationships...)
|
||||||
|
allRelationships = append(allRelationships, moduleToKernelRelationships...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return allPackages, allRelationships, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func createKernelToModuleRelationships(kernelPackages, modulePackages []pkg.Package) []artifact.Relationship {
|
||||||
|
// organize kernel and module packages by kernel version
|
||||||
|
kernelPackagesByVersion := make(map[string][]*pkg.Package)
|
||||||
|
for idx, p := range kernelPackages {
|
||||||
|
kernelPackagesByVersion[p.Version] = append(kernelPackagesByVersion[p.Version], &kernelPackages[idx])
|
||||||
|
}
|
||||||
|
|
||||||
|
modulesByKernelVersion := make(map[string][]*pkg.Package)
|
||||||
|
for idx, p := range modulePackages {
|
||||||
|
m, ok := p.Metadata.(pkg.LinuxKernelModuleMetadata)
|
||||||
|
if !ok {
|
||||||
|
log.Debug("linux-kernel-module package found without metadata: %s@%s", p.Name, p.Version)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
modulesByKernelVersion[m.KernelVersion] = append(modulesByKernelVersion[m.KernelVersion], &modulePackages[idx])
|
||||||
|
}
|
||||||
|
|
||||||
|
// create relationships between kernel and modules: [module] --(depends on)--> [kernel]
|
||||||
|
// since we try to use singular directions for relationships, we'll use "dependency of" here instead:
|
||||||
|
// [kernel] --(dependency of)--> [module]
|
||||||
|
var moduleToKernelRelationships []artifact.Relationship
|
||||||
|
for kernelVersion, modules := range modulesByKernelVersion {
|
||||||
|
kps, ok := kernelPackagesByVersion[kernelVersion]
|
||||||
|
if !ok {
|
||||||
|
// it's ok if there is a module that has no installed kernel...
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// we don't know which kernel is the "right" one, so we'll create a relationship for each one
|
||||||
|
for _, kp := range kps {
|
||||||
|
for _, mp := range modules {
|
||||||
|
moduleToKernelRelationships = append(moduleToKernelRelationships, artifact.Relationship{
|
||||||
|
// note: relationships should have Package objects, not pointers
|
||||||
|
From: *kp,
|
||||||
|
To: *mp,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return moduleToKernelRelationships
|
||||||
|
}
|
||||||
92
syft/pkg/cataloger/kernel/cataloger_test.go
Normal file
92
syft/pkg/cataloger/kernel/cataloger_test.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package kernel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_JavascriptCataloger(t *testing.T) {
|
||||||
|
kernelPkg := pkg.Package{
|
||||||
|
Name: "linux-kernel",
|
||||||
|
Version: "6.2.9-200.fc37.x86_64",
|
||||||
|
FoundBy: "linux-kernel-cataloger",
|
||||||
|
Locations: source.NewLocationSet(
|
||||||
|
source.NewVirtualLocation(
|
||||||
|
"/lib/modules/6.2.9-200.fc37.x86_64/vmlinuz",
|
||||||
|
"/lib/modules/6.2.9-200.fc37.x86_64/vmlinuz",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Type: pkg.LinuxKernelPkg,
|
||||||
|
PURL: "pkg:generic/linux-kernel@6.2.9-200.fc37.x86_64",
|
||||||
|
MetadataType: pkg.LinuxKernelMetadataType,
|
||||||
|
Metadata: pkg.LinuxKernelMetadata{
|
||||||
|
Name: "",
|
||||||
|
Architecture: "x86",
|
||||||
|
Version: "6.2.9-200.fc37.x86_64",
|
||||||
|
ExtendedVersion: "6.2.9-200.fc37.x86_64 (mockbuild@bkernel02.iad2.fedoraproject.org) #1 SMP PREEMPT_DYNAMIC Thu Mar 30 22:31:57 UTC 2023",
|
||||||
|
BuildTime: "",
|
||||||
|
Author: "",
|
||||||
|
Format: "bzImage",
|
||||||
|
RWRootFS: false,
|
||||||
|
SwapDevice: 0,
|
||||||
|
RootDevice: 0,
|
||||||
|
VideoMode: "Video mode 65535",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
kernelModulePkg := pkg.Package{
|
||||||
|
Name: "fsa4480",
|
||||||
|
Version: "",
|
||||||
|
FoundBy: "linux-kernel-cataloger",
|
||||||
|
Locations: source.NewLocationSet(
|
||||||
|
source.NewVirtualLocation("/lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko",
|
||||||
|
"/lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Licenses: []string{
|
||||||
|
"GPL v2",
|
||||||
|
},
|
||||||
|
Type: pkg.LinuxKernelModulePkg,
|
||||||
|
PURL: "pkg:generic/fsa4480",
|
||||||
|
MetadataType: pkg.LinuxKernelModuleMetadataType,
|
||||||
|
Metadata: pkg.LinuxKernelModuleMetadata{
|
||||||
|
Name: "fsa4480",
|
||||||
|
Version: "",
|
||||||
|
SourceVersion: "",
|
||||||
|
License: "GPL v2",
|
||||||
|
Path: "/lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko",
|
||||||
|
Description: "ON Semiconductor FSA4480 driver",
|
||||||
|
KernelVersion: "6.2.9-200.fc37.x86_64",
|
||||||
|
VersionMagic: "6.2.9-200.fc37.x86_64 SMP preempt mod_unload ",
|
||||||
|
Parameters: map[string]pkg.LinuxKernelModuleParameter{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedPkgs := []pkg.Package{
|
||||||
|
kernelPkg,
|
||||||
|
kernelModulePkg,
|
||||||
|
}
|
||||||
|
expectedRelationships := []artifact.Relationship{
|
||||||
|
{
|
||||||
|
From: kernelPkg,
|
||||||
|
To: kernelModulePkg,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgtest.NewCatalogTester().
|
||||||
|
WithImageResolver(t, "image-kernel-and-modules").
|
||||||
|
IgnoreLocationLayer().
|
||||||
|
Expects(expectedPkgs, expectedRelationships).
|
||||||
|
TestCataloger(t,
|
||||||
|
NewLinuxKernelCataloger(
|
||||||
|
LinuxCatalogerConfig{
|
||||||
|
CatalogModules: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
71
syft/pkg/cataloger/kernel/package.go
Normal file
71
syft/pkg/cataloger/kernel/package.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package kernel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/packageurl-go"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
const linuxKernelPackageName = "linux-kernel"
|
||||||
|
|
||||||
|
func newLinuxKernelPackage(metadata pkg.LinuxKernelMetadata, locations ...source.Location) pkg.Package {
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: linuxKernelPackageName,
|
||||||
|
Version: metadata.Version,
|
||||||
|
Locations: source.NewLocationSet(locations...),
|
||||||
|
PURL: packageURL(linuxKernelPackageName, metadata.Version),
|
||||||
|
Type: pkg.LinuxKernelPkg,
|
||||||
|
MetadataType: pkg.LinuxKernelMetadataType,
|
||||||
|
Metadata: metadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetID()
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLinuxKernelModulePackage(metadata pkg.LinuxKernelModuleMetadata, locations ...source.Location) pkg.Package {
|
||||||
|
var licenses []string
|
||||||
|
if metadata.License != "" {
|
||||||
|
licenses = []string{metadata.License}
|
||||||
|
} else {
|
||||||
|
licenses = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: metadata.Name,
|
||||||
|
Version: metadata.Version,
|
||||||
|
Locations: source.NewLocationSet(locations...),
|
||||||
|
Licenses: licenses,
|
||||||
|
PURL: packageURL(metadata.Name, metadata.Version),
|
||||||
|
Type: pkg.LinuxKernelModulePkg,
|
||||||
|
MetadataType: pkg.LinuxKernelModuleMetadataType,
|
||||||
|
Metadata: metadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
p.SetID()
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// packageURL returns the PURL for the specific Kernel package (see https://github.com/package-url/purl-spec)
|
||||||
|
func packageURL(name, version string) string {
|
||||||
|
var namespace string
|
||||||
|
|
||||||
|
fields := strings.SplitN(name, "/", 2)
|
||||||
|
if len(fields) > 1 {
|
||||||
|
namespace = fields[0]
|
||||||
|
name = fields[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return packageurl.NewPackageURL(
|
||||||
|
packageurl.TypeGeneric,
|
||||||
|
namespace,
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
).ToString()
|
||||||
|
}
|
||||||
92
syft/pkg/cataloger/kernel/parse_linux_kernel_file.go
Normal file
92
syft/pkg/cataloger/kernel/parse_linux_kernel_file.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package kernel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/deitch/magic/pkg/magic"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal/log"
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
const linuxKernelMagicName = "Linux kernel"
|
||||||
|
|
||||||
|
func parseLinuxKernelFile(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
unionReader, err := unionreader.GetUnionReader(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to get union reader for file: %w", err)
|
||||||
|
}
|
||||||
|
magicType, err := magic.GetType(unionReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to get magic type for file: %w", err)
|
||||||
|
}
|
||||||
|
if len(magicType) < 1 || magicType[0] != linuxKernelMagicName {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
metadata := parseLinuxKernelMetadata(magicType)
|
||||||
|
if metadata.Version == "" {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return []pkg.Package{
|
||||||
|
newLinuxKernelPackage(
|
||||||
|
metadata,
|
||||||
|
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
),
|
||||||
|
}, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLinuxKernelMetadata(magicType []string) (p pkg.LinuxKernelMetadata) {
|
||||||
|
// Linux kernel x86 boot executable bzImage,
|
||||||
|
// version 5.10.121-linuxkit (root@buildkitsandbox) #1 SMP Fri Dec 2 10:35:42 UTC 2022,
|
||||||
|
// RO-rootFS,
|
||||||
|
// swap_dev 0XA,
|
||||||
|
// Normal VGA
|
||||||
|
for _, t := range magicType {
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(t, "x86 "):
|
||||||
|
p.Architecture = "x86"
|
||||||
|
case strings.Contains(t, "ARM64 "):
|
||||||
|
p.Architecture = "arm64"
|
||||||
|
case strings.Contains(t, "ARM "):
|
||||||
|
p.Architecture = "arm"
|
||||||
|
case t == "bzImage":
|
||||||
|
p.Format = "bzImage"
|
||||||
|
case t == "zImage":
|
||||||
|
p.Format = "zImage"
|
||||||
|
case strings.HasPrefix(t, "version "):
|
||||||
|
p.ExtendedVersion = strings.TrimPrefix(t, "version ")
|
||||||
|
fields := strings.Fields(p.ExtendedVersion)
|
||||||
|
if len(fields) > 0 {
|
||||||
|
p.Version = fields[0]
|
||||||
|
}
|
||||||
|
case strings.Contains(t, "rootFS") && strings.HasPrefix(t, "RW-"):
|
||||||
|
p.RWRootFS = true
|
||||||
|
case strings.HasPrefix(t, "swap_dev "):
|
||||||
|
swapDevStr := strings.TrimPrefix(t, "swap_dev ")
|
||||||
|
swapDev, err := strconv.ParseInt(swapDevStr, 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("unable to parse swap device: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p.SwapDevice = int(swapDev)
|
||||||
|
case strings.HasPrefix(t, "root_dev "):
|
||||||
|
rootDevStr := strings.TrimPrefix(t, "root_dev ")
|
||||||
|
rootDev, err := strconv.ParseInt(rootDevStr, 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("unable to parse root device: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p.SwapDevice = int(rootDev)
|
||||||
|
case strings.Contains(t, "VGA") || strings.Contains(t, "Video"):
|
||||||
|
p.VideoMode = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
157
syft/pkg/cataloger/kernel/parse_linux_kernel_module_file.go
Normal file
157
syft/pkg/cataloger/kernel/parse_linux_kernel_module_file.go
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
package kernel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"debug/elf"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/artifact"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||||
|
"github.com/anchore/syft/syft/pkg/cataloger/internal/unionreader"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
const modinfoName = ".modinfo"
|
||||||
|
|
||||||
|
func parseLinuxKernelModuleFile(_ source.FileResolver, _ *generic.Environment, reader source.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||||
|
unionReader, err := unionreader.GetUnionReader(reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to get union reader for file: %w", err)
|
||||||
|
}
|
||||||
|
metadata, err := parseLinuxKernelModuleMetadata(unionReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("unable to parse kernel module metadata: %w", err)
|
||||||
|
}
|
||||||
|
if metadata == nil || metadata.KernelVersion == "" {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.Path = reader.Location.RealPath
|
||||||
|
|
||||||
|
return []pkg.Package{
|
||||||
|
newLinuxKernelModulePackage(
|
||||||
|
*metadata,
|
||||||
|
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||||
|
),
|
||||||
|
}, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseLinuxKernelModuleMetadata(r unionreader.UnionReader) (p *pkg.LinuxKernelModuleMetadata, err error) {
|
||||||
|
// filename: /lib/modules/5.15.0-1031-aws/kernel/zfs/zzstd.ko
|
||||||
|
// version: 1.4.5a
|
||||||
|
// license: Dual BSD/GPL
|
||||||
|
// description: ZSTD Compression for ZFS
|
||||||
|
// srcversion: F1F818A6E016499AB7F826E
|
||||||
|
// depends: spl
|
||||||
|
// retpoline: Y
|
||||||
|
// name: zzstd
|
||||||
|
// vermagic: 5.15.0-1031-aws SMP mod_unload modversions
|
||||||
|
// sig_id: PKCS#7
|
||||||
|
// signer: Build time autogenerated kernel key
|
||||||
|
// sig_key: 49:A9:55:87:90:5B:33:41:AF:C0:A7:BE:2A:71:6C:D2:CA:34:E0:AE
|
||||||
|
// sig_hashalgo: sha512
|
||||||
|
//
|
||||||
|
// OR
|
||||||
|
//
|
||||||
|
// filename: /home/ubuntu/eve/rootfs/lib/modules/5.10.121-linuxkit/kernel/drivers/net/wireless/realtek/rtl8821cu/8821cu.ko
|
||||||
|
// version: v5.4.1_28754.20180921_COEX20180712-3232
|
||||||
|
// author: Realtek Semiconductor Corp.
|
||||||
|
// description: Realtek Wireless Lan Driver
|
||||||
|
// license: GPL
|
||||||
|
// srcversion: 960CCC648A0E0369171A2C9
|
||||||
|
// depends: cfg80211
|
||||||
|
// retpoline: Y
|
||||||
|
// name: 8821cu
|
||||||
|
// vermagic: 5.10.121-linuxkit SMP mod_unload
|
||||||
|
p = &pkg.LinuxKernelModuleMetadata{
|
||||||
|
Parameters: make(map[string]pkg.LinuxKernelModuleParameter),
|
||||||
|
}
|
||||||
|
f, err := elf.NewFile(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
modinfo := f.Section(modinfoName)
|
||||||
|
if modinfo == nil {
|
||||||
|
return nil, fmt.Errorf("no section %s", modinfoName)
|
||||||
|
}
|
||||||
|
b, err := modinfo.Data()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading secion %s: %w", modinfoName, err)
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
entry []byte
|
||||||
|
)
|
||||||
|
for _, b2 := range b {
|
||||||
|
if b2 == 0 {
|
||||||
|
if err := addLinuxKernelModuleEntry(p, entry); err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing entry %s: %w", string(entry), err)
|
||||||
|
}
|
||||||
|
entry = []byte{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entry = append(entry, b2)
|
||||||
|
}
|
||||||
|
if err := addLinuxKernelModuleEntry(p, entry); err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing entry %s: %w", string(entry), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addLinuxKernelModuleEntry(k *pkg.LinuxKernelModuleMetadata, entry []byte) error {
|
||||||
|
if len(entry) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var key, value string
|
||||||
|
parts := strings.SplitN(string(entry), "=", 2)
|
||||||
|
if len(parts) > 0 {
|
||||||
|
key = parts[0]
|
||||||
|
}
|
||||||
|
if len(parts) > 1 {
|
||||||
|
value = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch key {
|
||||||
|
case "version":
|
||||||
|
k.Version = value
|
||||||
|
case "license":
|
||||||
|
k.License = value
|
||||||
|
case "author":
|
||||||
|
k.Author = value
|
||||||
|
case "name":
|
||||||
|
k.Name = value
|
||||||
|
case "vermagic":
|
||||||
|
k.VersionMagic = value
|
||||||
|
fields := strings.Fields(value)
|
||||||
|
if len(fields) > 0 {
|
||||||
|
k.KernelVersion = fields[0]
|
||||||
|
}
|
||||||
|
case "srcversion":
|
||||||
|
k.SourceVersion = value
|
||||||
|
case "description":
|
||||||
|
k.Description = value
|
||||||
|
case "parm":
|
||||||
|
parts := strings.SplitN(value, ":", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return fmt.Errorf("invalid parm entry: %s", value)
|
||||||
|
}
|
||||||
|
if m, ok := k.Parameters[parts[0]]; !ok {
|
||||||
|
k.Parameters[parts[0]] = pkg.LinuxKernelModuleParameter{Description: parts[1]}
|
||||||
|
} else {
|
||||||
|
m.Description = parts[1]
|
||||||
|
}
|
||||||
|
case "parmtype":
|
||||||
|
parts := strings.SplitN(value, ":", 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return fmt.Errorf("invalid parmtype entry: %s", value)
|
||||||
|
}
|
||||||
|
if m, ok := k.Parameters[parts[0]]; !ok {
|
||||||
|
k.Parameters[parts[0]] = pkg.LinuxKernelModuleParameter{Type: parts[1]}
|
||||||
|
} else {
|
||||||
|
m.Type = parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
FROM fedora:37@sha256:3f987b7657e944cf87a129cc262982d4f80e38bd98f7db313ccaf90ca7069dd2
|
||||||
|
|
||||||
|
RUN dnf install 'dnf-command(download)' cpio xz -y
|
||||||
|
RUN dnf download kernel-core kernel-modules-core -y
|
||||||
|
|
||||||
|
RUN rpm2cpio kernel-core-*.rpm | cpio -t && \
|
||||||
|
rpm2cpio kernel-core-*.rpm | cpio -idmv ./lib/modules/6.2.9-200.fc37.x86_64/vmlinuz
|
||||||
|
|
||||||
|
RUN rpm2cpio kernel-modules-core-*.rpm | cpio -t && \
|
||||||
|
rpm2cpio kernel-modules-core-*.rpm | cpio -idmv ./lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko.xz
|
||||||
|
|
||||||
|
RUN unxz /lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko.xz
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
|
||||||
|
COPY --from=0 /lib/modules/6.2.9-200.fc37.x86_64/vmlinuz /lib/modules/6.2.9-200.fc37.x86_64/vmlinuz
|
||||||
|
COPY --from=0 /lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko /lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko
|
||||||
34
syft/pkg/linux_kernel_metadata.go
Normal file
34
syft/pkg/linux_kernel_metadata.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package pkg
|
||||||
|
|
||||||
|
// LinuxKernelMetadata represents all captured data for a Linux kernel
|
||||||
|
type LinuxKernelMetadata struct {
|
||||||
|
Name string `mapstructure:"name" json:"name" cyclonedx:"name"`
|
||||||
|
Architecture string `mapstructure:"architecture" json:"architecture" cyclonedx:"architecture"`
|
||||||
|
Version string `mapstructure:"version" json:"version" cyclonedx:"version"`
|
||||||
|
ExtendedVersion string `mapstructure:"extendedVersion" json:"extendedVersion,omitempty" cyclonedx:"extendedVersion"`
|
||||||
|
BuildTime string `mapstructure:"buildTime" json:"buildTime,omitempty" cyclonedx:"buildTime"`
|
||||||
|
Author string `mapstructure:"author" json:"author,omitempty" cyclonedx:"author"`
|
||||||
|
Format string `mapstructure:"format" json:"format,omitempty" cyclonedx:"format"`
|
||||||
|
RWRootFS bool `mapstructure:"rwRootFS" json:"rwRootFS,omitempty" cyclonedx:"rwRootFS"`
|
||||||
|
SwapDevice int `mapstructure:"swapDevice" json:"swapDevice,omitempty" cyclonedx:"swapDevice"`
|
||||||
|
RootDevice int `mapstructure:"rootDevice" json:"rootDevice,omitempty" cyclonedx:"rootDevice"`
|
||||||
|
VideoMode string `mapstructure:"videoMode" json:"videoMode,omitempty" cyclonedx:"videoMode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinuxKernelModuleMetadata struct {
|
||||||
|
Name string `mapstructure:"name" json:"name,omitempty" cyclonedx:"name"`
|
||||||
|
Version string `mapstructure:"version" json:"version,omitempty" cyclonedx:"version"`
|
||||||
|
SourceVersion string `mapstructure:"sourceVersion" json:"sourceVersion,omitempty" cyclonedx:"sourceVersion"`
|
||||||
|
Path string `mapstructure:"path" json:"path,omitempty" cyclonedx:"path"`
|
||||||
|
Description string `mapstructure:"description" json:"description,omitempty" cyclonedx:"description"`
|
||||||
|
Author string `mapstructure:"author" json:"author,omitempty" cyclonedx:"author"`
|
||||||
|
License string `mapstructure:"license" json:"license,omitempty" cyclonedx:"license"`
|
||||||
|
KernelVersion string `mapstructure:"kernelVersion" json:"kernelVersion,omitempty" cyclonedx:"kernelVersion"`
|
||||||
|
VersionMagic string `mapstructure:"versionMagic" json:"versionMagic,omitempty" cyclonedx:"versionMagic"`
|
||||||
|
Parameters map[string]LinuxKernelModuleParameter `mapstructure:"parameters" json:"parameters,omitempty" cyclonedx:"parameters"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LinuxKernelModuleParameter struct {
|
||||||
|
Type string `mapstructure:"type" json:"type,omitempty" cyclonedx:"type"`
|
||||||
|
Description string `mapstructure:"description" json:"description,omitempty" cyclonedx:"description"`
|
||||||
|
}
|
||||||
@ -26,6 +26,8 @@ const (
|
|||||||
HackageMetadataType MetadataType = "HackageMetadataType"
|
HackageMetadataType MetadataType = "HackageMetadataType"
|
||||||
JavaMetadataType MetadataType = "JavaMetadata"
|
JavaMetadataType MetadataType = "JavaMetadata"
|
||||||
KbPackageMetadataType MetadataType = "KbPackageMetadata"
|
KbPackageMetadataType MetadataType = "KbPackageMetadata"
|
||||||
|
LinuxKernelMetadataType MetadataType = "LinuxKernelMetadata"
|
||||||
|
LinuxKernelModuleMetadataType MetadataType = "LinuxKernelModuleMetadata"
|
||||||
MixLockMetadataType MetadataType = "MixLockMetadataType"
|
MixLockMetadataType MetadataType = "MixLockMetadataType"
|
||||||
NixStoreMetadataType MetadataType = "NixStoreMetadata"
|
NixStoreMetadataType MetadataType = "NixStoreMetadata"
|
||||||
NpmPackageJSONMetadataType MetadataType = "NpmPackageJsonMetadata"
|
NpmPackageJSONMetadataType MetadataType = "NpmPackageJsonMetadata"
|
||||||
@ -55,6 +57,8 @@ var AllMetadataTypes = []MetadataType{
|
|||||||
HackageMetadataType,
|
HackageMetadataType,
|
||||||
JavaMetadataType,
|
JavaMetadataType,
|
||||||
KbPackageMetadataType,
|
KbPackageMetadataType,
|
||||||
|
LinuxKernelMetadataType,
|
||||||
|
LinuxKernelModuleMetadataType,
|
||||||
MixLockMetadataType,
|
MixLockMetadataType,
|
||||||
NixStoreMetadataType,
|
NixStoreMetadataType,
|
||||||
NpmPackageJSONMetadataType,
|
NpmPackageJSONMetadataType,
|
||||||
@ -84,6 +88,8 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{
|
|||||||
HackageMetadataType: reflect.TypeOf(HackageMetadata{}),
|
HackageMetadataType: reflect.TypeOf(HackageMetadata{}),
|
||||||
JavaMetadataType: reflect.TypeOf(JavaMetadata{}),
|
JavaMetadataType: reflect.TypeOf(JavaMetadata{}),
|
||||||
KbPackageMetadataType: reflect.TypeOf(KbPackageMetadata{}),
|
KbPackageMetadataType: reflect.TypeOf(KbPackageMetadata{}),
|
||||||
|
LinuxKernelMetadataType: reflect.TypeOf(LinuxKernelMetadata{}),
|
||||||
|
LinuxKernelModuleMetadataType: reflect.TypeOf(LinuxKernelModuleMetadata{}),
|
||||||
MixLockMetadataType: reflect.TypeOf(MixLockMetadata{}),
|
MixLockMetadataType: reflect.TypeOf(MixLockMetadata{}),
|
||||||
NixStoreMetadataType: reflect.TypeOf(NixStoreMetadata{}),
|
NixStoreMetadataType: reflect.TypeOf(NixStoreMetadata{}),
|
||||||
NpmPackageJSONMetadataType: reflect.TypeOf(NpmPackageJSONMetadata{}),
|
NpmPackageJSONMetadataType: reflect.TypeOf(NpmPackageJSONMetadata{}),
|
||||||
|
|||||||
@ -26,6 +26,8 @@ const (
|
|||||||
JavaPkg Type = "java-archive"
|
JavaPkg Type = "java-archive"
|
||||||
JenkinsPluginPkg Type = "jenkins-plugin"
|
JenkinsPluginPkg Type = "jenkins-plugin"
|
||||||
KbPkg Type = "msrc-kb"
|
KbPkg Type = "msrc-kb"
|
||||||
|
LinuxKernelPkg Type = "linux-kernel"
|
||||||
|
LinuxKernelModulePkg Type = "linux-kernel-module"
|
||||||
NixPkg Type = "nix"
|
NixPkg Type = "nix"
|
||||||
NpmPkg Type = "npm"
|
NpmPkg Type = "npm"
|
||||||
PhpComposerPkg Type = "php-composer"
|
PhpComposerPkg Type = "php-composer"
|
||||||
@ -52,6 +54,8 @@ var AllPkgs = []Type{
|
|||||||
JavaPkg,
|
JavaPkg,
|
||||||
JenkinsPluginPkg,
|
JenkinsPluginPkg,
|
||||||
KbPkg,
|
KbPkg,
|
||||||
|
LinuxKernelPkg,
|
||||||
|
LinuxKernelModulePkg,
|
||||||
NixPkg,
|
NixPkg,
|
||||||
NpmPkg,
|
NpmPkg,
|
||||||
PhpComposerPkg,
|
PhpComposerPkg,
|
||||||
@ -88,6 +92,10 @@ func (t Type) PackageURLType() string {
|
|||||||
return packageurl.TypeHackage
|
return packageurl.TypeHackage
|
||||||
case JavaPkg, JenkinsPluginPkg:
|
case JavaPkg, JenkinsPluginPkg:
|
||||||
return packageurl.TypeMaven
|
return packageurl.TypeMaven
|
||||||
|
case LinuxKernelPkg:
|
||||||
|
return "generic/linux-kernel"
|
||||||
|
case LinuxKernelModulePkg:
|
||||||
|
return packageurl.TypeGeneric
|
||||||
case PhpComposerPkg:
|
case PhpComposerPkg:
|
||||||
return packageurl.TypeComposer
|
return packageurl.TypeComposer
|
||||||
case PythonPkg:
|
case PythonPkg:
|
||||||
@ -114,7 +122,11 @@ func TypeFromPURL(p string) Type {
|
|||||||
return UnknownPkg
|
return UnknownPkg
|
||||||
}
|
}
|
||||||
|
|
||||||
return TypeByName(purl.Type)
|
ptype := purl.Type
|
||||||
|
if ptype == "generic" {
|
||||||
|
ptype = purl.Name
|
||||||
|
}
|
||||||
|
return TypeByName(ptype)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TypeByName(name string) Type {
|
func TypeByName(name string) Type {
|
||||||
@ -155,6 +167,10 @@ func TypeByName(name string) Type {
|
|||||||
return PortagePkg
|
return PortagePkg
|
||||||
case packageurl.TypeHex:
|
case packageurl.TypeHex:
|
||||||
return HexPkg
|
return HexPkg
|
||||||
|
case "linux-kernel":
|
||||||
|
return LinuxKernelPkg
|
||||||
|
case "linux-kernel-module":
|
||||||
|
return LinuxKernelModulePkg
|
||||||
case "nix":
|
case "nix":
|
||||||
return NixPkg
|
return NixPkg
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -83,6 +83,10 @@ func TestTypeFromPURL(t *testing.T) {
|
|||||||
purl: "pkg:hex/hpax/hpax@0.1.1",
|
purl: "pkg:hex/hpax/hpax@0.1.1",
|
||||||
expected: HexPkg,
|
expected: HexPkg,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
purl: "pkg:generic/linux-kernel@5.10.15",
|
||||||
|
expected: LinuxKernelPkg,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
purl: "pkg:nix/glibc@2.34?hash=h0cnbmfcn93xm5dg2x27ixhag1cwndga",
|
purl: "pkg:nix/glibc@2.34?hash=h0cnbmfcn93xm5dg2x27ixhag1cwndga",
|
||||||
expected: NixPkg,
|
expected: NixPkg,
|
||||||
@ -101,6 +105,7 @@ func TestTypeFromPURL(t *testing.T) {
|
|||||||
expectedTypes.Remove(string(JenkinsPluginPkg))
|
expectedTypes.Remove(string(JenkinsPluginPkg))
|
||||||
expectedTypes.Remove(string(PortagePkg))
|
expectedTypes.Remove(string(PortagePkg))
|
||||||
expectedTypes.Remove(string(BinaryPkg))
|
expectedTypes.Remove(string(BinaryPkg))
|
||||||
|
expectedTypes.Remove(string(LinuxKernelModulePkg))
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
t.Run(string(test.expected), func(t *testing.T) {
|
t.Run(string(test.expected), func(t *testing.T) {
|
||||||
|
|||||||
@ -55,11 +55,7 @@ func TestAllFormatsConvertable(t *testing.T) {
|
|||||||
for _, traitFn := range assertions {
|
for _, traitFn := range assertions {
|
||||||
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -34,11 +33,7 @@ func TestAllFormatsExpressible(t *testing.T) {
|
|||||||
for _, traitFn := range commonAssertions {
|
for _, traitFn := range commonAssertions {
|
||||||
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,11 +40,7 @@ func TestConvertCmd(t *testing.T) {
|
|||||||
for _, traitFn := range assertions {
|
for _, traitFn := range assertions {
|
||||||
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,11 +52,7 @@ func TestValidCycloneDX(t *testing.T) {
|
|||||||
for _, traitFn := range test.assertions {
|
for _, traitFn := range test.assertions {
|
||||||
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
validateCycloneDXJSON(t, stdout)
|
validateCycloneDXJSON(t, stdout)
|
||||||
})
|
})
|
||||||
@ -95,11 +91,7 @@ func assertValidCycloneDX(tb testing.TB, stdout, stderr string, rc int) {
|
|||||||
tb.Errorf("expected no validation failures for cyclonedx-cli but got rc=%d", rc)
|
tb.Errorf("expected no validation failures for cyclonedx-cli but got rc=%d", rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tb.Failed() {
|
logOutputOnFailure(tb, cmd, stdout, stderr)
|
||||||
tb.Log("STDOUT:\n", stdout)
|
|
||||||
tb.Log("STDERR:\n", stderr)
|
|
||||||
tb.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate --input-format json --input-version v1_4 --input-file bom.json
|
// validate --input-format json --input-version v1_4 --input-file bom.json
|
||||||
@ -134,9 +126,5 @@ func validateCycloneDXJSON(t *testing.T, stdout string) {
|
|||||||
t.Errorf("expected no validation failures for cyclonedx-cli but found invalid BOM")
|
t.Errorf("expected no validation failures for cyclonedx-cli but found invalid BOM")
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -37,10 +36,6 @@ func TestDirectoryScanCompletesWithinTimeout(t *testing.T) {
|
|||||||
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -97,7 +96,7 @@ func TestPackagesCmdFlags(t *testing.T) {
|
|||||||
name: "squashed-scope-flag",
|
name: "squashed-scope-flag",
|
||||||
args: []string{"packages", "-o", "json", "-s", "squashed", coverageImage},
|
args: []string{"packages", "-o", "json", "-s", "squashed", coverageImage},
|
||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertPackageCount(35),
|
assertPackageCount(37),
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -214,7 +213,7 @@ func TestPackagesCmdFlags(t *testing.T) {
|
|||||||
// the application config in the log matches that of what we expect to have been configured.
|
// the application config in the log matches that of what we expect to have been configured.
|
||||||
assertInOutput("parallelism: 2"),
|
assertInOutput("parallelism: 2"),
|
||||||
assertInOutput("parallelism=2"),
|
assertInOutput("parallelism=2"),
|
||||||
assertPackageCount(35),
|
assertPackageCount(37),
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -225,7 +224,7 @@ func TestPackagesCmdFlags(t *testing.T) {
|
|||||||
// the application config in the log matches that of what we expect to have been configured.
|
// the application config in the log matches that of what we expect to have been configured.
|
||||||
assertInOutput("parallelism: 1"),
|
assertInOutput("parallelism: 1"),
|
||||||
assertInOutput("parallelism=1"),
|
assertInOutput("parallelism=1"),
|
||||||
assertPackageCount(35),
|
assertPackageCount(37),
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -239,7 +238,7 @@ func TestPackagesCmdFlags(t *testing.T) {
|
|||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertNotInOutput("secret_password"),
|
assertNotInOutput("secret_password"),
|
||||||
assertNotInOutput("secret_key_path"),
|
assertNotInOutput("secret_key_path"),
|
||||||
assertPackageCount(35),
|
assertPackageCount(37),
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -251,11 +250,7 @@ func TestPackagesCmdFlags(t *testing.T) {
|
|||||||
for _, traitFn := range test.assertions {
|
for _, traitFn := range test.assertions {
|
||||||
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -337,11 +332,7 @@ func TestRegistryAuth(t *testing.T) {
|
|||||||
for _, traitAssertionFn := range test.assertions {
|
for _, traitAssertionFn := range test.assertions {
|
||||||
traitAssertionFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitAssertionFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -96,11 +95,7 @@ func TestPowerUserCmdFlags(t *testing.T) {
|
|||||||
for _, traitFn := range test.assertions {
|
for _, traitFn := range test.assertions {
|
||||||
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/sergi/go-diff/diffmatchpatch"
|
"github.com/sergi/go-diff/diffmatchpatch"
|
||||||
@ -109,11 +108,7 @@ func TestPersistentFlags(t *testing.T) {
|
|||||||
for _, traitFn := range test.assertions {
|
for _, traitFn := range test.assertions {
|
||||||
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,11 +146,7 @@ func TestLogFile(t *testing.T) {
|
|||||||
for _, traitFn := range test.assertions {
|
for _, traitFn := range test.assertions {
|
||||||
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
|
||||||
}
|
}
|
||||||
if t.Failed() {
|
logOutputOnFailure(t, cmd, stdout, stderr)
|
||||||
t.Log("STDOUT:\n", stdout)
|
|
||||||
t.Log("STDERR:\n", stderr)
|
|
||||||
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
@ -21,6 +22,16 @@ import (
|
|||||||
"github.com/anchore/stereoscope/pkg/imagetest"
|
"github.com/anchore/stereoscope/pkg/imagetest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var showOutput = flag.Bool("show-output", false, "show stdout and stderr for failing tests")
|
||||||
|
|
||||||
|
func logOutputOnFailure(t testing.TB, cmd *exec.Cmd, stdout, stderr string) {
|
||||||
|
if t.Failed() && showOutput != nil && *showOutput {
|
||||||
|
t.Log("STDOUT:\n", stdout)
|
||||||
|
t.Log("STDERR:\n", stderr)
|
||||||
|
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func runAndShow(t *testing.T, cmd *exec.Cmd) {
|
func runAndShow(t *testing.T, cmd *exec.Cmd) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,20 @@ type testCase struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var imageOnlyTestCases = []testCase{
|
var imageOnlyTestCases = []testCase{
|
||||||
|
{
|
||||||
|
name: "find kernel packages",
|
||||||
|
pkgType: pkg.LinuxKernelPkg,
|
||||||
|
pkgInfo: map[string]string{
|
||||||
|
"linux-kernel": "6.2.9-200.fc37.x86_64",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "find kernel module packages",
|
||||||
|
pkgType: pkg.LinuxKernelModulePkg,
|
||||||
|
pkgInfo: map[string]string{
|
||||||
|
"fsa4480": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "find gemspec packages",
|
name: "find gemspec packages",
|
||||||
pkgType: pkg.GemPkg,
|
pkgType: pkg.GemPkg,
|
||||||
|
|||||||
@ -221,6 +221,8 @@ func TestPkgCoverageDirectory(t *testing.T) {
|
|||||||
observedPkgs.Remove(string(pkg.UnknownPkg))
|
observedPkgs.Remove(string(pkg.UnknownPkg))
|
||||||
definedPkgs.Remove(string(pkg.BinaryPkg))
|
definedPkgs.Remove(string(pkg.BinaryPkg))
|
||||||
definedPkgs.Remove(string(pkg.UnknownPkg))
|
definedPkgs.Remove(string(pkg.UnknownPkg))
|
||||||
|
definedPkgs.Remove(string(pkg.LinuxKernelPkg))
|
||||||
|
definedPkgs.Remove(string(pkg.LinuxKernelModulePkg))
|
||||||
|
|
||||||
// for directory scans we should not expect to see any of the following package types
|
// for directory scans we should not expect to see any of the following package types
|
||||||
definedPkgs.Remove(string(pkg.KbPkg))
|
definedPkgs.Remove(string(pkg.KbPkg))
|
||||||
|
|||||||
@ -1,5 +1,22 @@
|
|||||||
|
FROM fedora:37@sha256:3f987b7657e944cf87a129cc262982d4f80e38bd98f7db313ccaf90ca7069dd2
|
||||||
|
|
||||||
|
RUN dnf install 'dnf-command(download)' cpio xz -y
|
||||||
|
RUN dnf download kernel-core kernel-modules-core -y
|
||||||
|
|
||||||
|
RUN rpm2cpio kernel-core-*.rpm | cpio -t && \
|
||||||
|
rpm2cpio kernel-core-*.rpm | cpio -idmv ./lib/modules/6.2.9-200.fc37.x86_64/vmlinuz
|
||||||
|
|
||||||
|
RUN rpm2cpio kernel-modules-core-*.rpm | cpio -t && \
|
||||||
|
rpm2cpio kernel-modules-core-*.rpm | cpio -idmv ./lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko.xz
|
||||||
|
|
||||||
|
RUN unxz /lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko.xz
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
|
|
||||||
|
COPY --from=0 /lib/modules/6.2.9-200.fc37.x86_64/vmlinuz /lib/modules/6.2.9-200.fc37.x86_64/vmlinuz
|
||||||
|
COPY --from=0 /lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko /lib/modules/6.2.9-200.fc37.x86_64/kernel/drivers/usb/typec/mux/fsa4480.ko
|
||||||
|
|
||||||
COPY pkgs/ .
|
COPY pkgs/ .
|
||||||
# we duplicate to show a package count difference between all-layers and squashed scopes
|
# we duplicate to show a package count difference between all-layers and squashed scopes
|
||||||
COPY lib lib
|
COPY lib lib
|
||||||
COPY etc/ .
|
COPY etc/ .
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user