Compare commits

...
Author SHA1 Message Date
Keith Zantow 51159ce204 chore: update tests
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-10-23 15:00:05 -04:00
Keith Zantow 7c644ea3d1 chore: update tests & naming conventions
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2025-10-23 14:14:23 -04:00
Christopher Phillips 319bb12627 chore: do not redesign private
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2025-09-26 15:07:48 -04:00
Christopher Phillips 7a131ff462 chore: update config injection
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2025-09-26 14:51:29 -04:00
Christopher Phillips 6fa1831484 chore: update feature to include config to restore previous behavior
Signed-off-by: Christopher Phillips <32073428+spiffcs@users.noreply.github.com>
2025-09-26 14:16:49 -04:00
Ross Kirk 9b60b3e33d Ignore dpkg entries that have "deinstall" status indicating package has been removed but not purged
Signed-off-by: Ross Kirk <ross.kirk@upwind.io>
2025-09-22 13:14:37 +01:00
12 changed files with 241 additions and 25 deletions
+5
View File
@@ -19,6 +19,7 @@ import (
"github.com/anchore/syft/syft/file/cataloger/executable"
"github.com/anchore/syft/syft/file/cataloger/filecontent"
"github.com/anchore/syft/syft/pkg/cataloger/binary"
"github.com/anchore/syft/syft/pkg/cataloger/debian"
"github.com/anchore/syft/syft/pkg/cataloger/dotnet"
"github.com/anchore/syft/syft/pkg/cataloger/golang"
"github.com/anchore/syft/syft/pkg/cataloger/java"
@@ -44,6 +45,7 @@ type Catalog struct {
Enrich []string `yaml:"enrich" json:"enrich" mapstructure:"enrich"`
// ecosystem-specific cataloger configuration
Debian debianConfig `yaml:"debian" json:"debian" mapstructure:"debian"`
Dotnet dotnetConfig `yaml:"dotnet" json:"dotnet" mapstructure:"dotnet"`
Golang golangConfig `yaml:"golang" json:"golang" mapstructure:"golang"`
Java javaConfig `yaml:"java" json:"java" mapstructure:"java"`
@@ -76,6 +78,7 @@ func DefaultCatalog() Catalog {
Scope: source.SquashedScope.String(),
Package: defaultPackageConfig(),
License: defaultLicenseConfig(),
Debian: defaultDebianConfig(),
LinuxKernel: defaultLinuxKernelConfig(),
Nix: defaultNixConfig(),
Dotnet: defaultDotnetConfig(),
@@ -170,6 +173,8 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config {
}
return pkgcataloging.Config{
Binary: binary.DefaultClassifierCatalogerConfig(),
Debian: debian.DefaultCatalogerConfig().
WithIncludeDeInstalled(cfg.Debian.IncludeDeInstalled),
Dotnet: dotnet.DefaultCatalogerConfig().
WithDepPackagesMustHaveDLL(cfg.Dotnet.DepPackagesMustHaveDLL).
WithDepPackagesMustClaimDLL(cfg.Dotnet.DepPackagesMustClaimDLL).
+26
View File
@@ -0,0 +1,26 @@
package options
import (
"github.com/anchore/clio"
"github.com/anchore/syft/syft/pkg/cataloger/debian"
)
type debianConfig struct {
IncludeDeInstalled bool `yaml:"include-deinstalled" json:"include-deinstalled" mapstructure:"include-deinstalled"`
}
var _ interface {
clio.FieldDescriber
} = (*debianConfig)(nil)
func (o *debianConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
descriptions.Add(&o.IncludeDeInstalled, `include debian packages that have been removed but not purged (deinstall status)
by default these packages are excluded from the SBOM`)
}
func defaultDebianConfig() debianConfig {
def := debian.DefaultCatalogerConfig()
return debianConfig{
IncludeDeInstalled: def.IncludeDeInstalled,
}
}
+12 -2
View File
@@ -59,13 +59,23 @@ func DefaultPackageTaskFactories() Factories {
// OS package installed catalogers ///////////////////////////////////////////////////////////////////////////
newSimplePackageTaskFactory(arch.NewDBCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.OSTag, "linux", "alpm", "archlinux"),
newSimplePackageTaskFactory(alpine.NewDBCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.OSTag, "linux", "apk", "alpine"),
newSimplePackageTaskFactory(debian.NewDBCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.OSTag, "linux", "dpkg", "debian"),
newPackageTaskFactory(
func(cfg CatalogingFactoryConfig) pkg.Cataloger {
return debian.NewDpkgDBCataloger(cfg.PackagesConfig.Debian)
},
pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.OSTag, "linux", "dpkg", "debian",
),
newSimplePackageTaskFactory(gentoo.NewPortageCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.OSTag, "linux", "portage", "gentoo"),
newSimplePackageTaskFactory(redhat.NewDBCataloger, pkgcataloging.DirectoryTag, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.OSTag, "linux", "rpm", "redhat"),
// OS package declared catalogers ///////////////////////////////////////////////////////////////////////////
newSimplePackageTaskFactory(redhat.NewArchiveCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.OSTag, "linux", "rpm", "redhat"),
newSimplePackageTaskFactory(debian.NewArchiveCataloger, pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.OSTag, "linux", "deb", "debian"),
newPackageTaskFactory(
func(cfg CatalogingFactoryConfig) pkg.Cataloger {
return debian.NewDpkgArchiveCataloger(cfg.PackagesConfig.Debian)
},
pkgcataloging.DeclaredTag, pkgcataloging.DirectoryTag, pkgcataloging.OSTag, "linux", "deb", "debian",
),
// language-specific package installed catalogers ///////////////////////////////////////////////////////////////////////////
newSimplePackageTaskFactory(cpp.NewConanInfoCataloger, pkgcataloging.InstalledTag, pkgcataloging.ImageTag, pkgcataloging.LanguageTag, "cpp", "conan"),
+8
View File
@@ -2,6 +2,7 @@ package pkgcataloging
import (
"github.com/anchore/syft/syft/pkg/cataloger/binary"
"github.com/anchore/syft/syft/pkg/cataloger/debian"
"github.com/anchore/syft/syft/pkg/cataloger/dotnet"
"github.com/anchore/syft/syft/pkg/cataloger/golang"
"github.com/anchore/syft/syft/pkg/cataloger/java"
@@ -13,6 +14,7 @@ import (
type Config struct {
Binary binary.ClassifierCatalogerConfig `yaml:"binary" json:"binary" mapstructure:"binary"`
Debian debian.CatalogerConfig `yaml:"debian" json:"debian" mapstructure:"debian"`
Dotnet dotnet.CatalogerConfig `yaml:"dotnet" json:"dotnet" mapstructure:"dotnet"`
Golang golang.CatalogerConfig `yaml:"golang" json:"golang" mapstructure:"golang"`
JavaArchive java.ArchiveCatalogerConfig `yaml:"java-archive" json:"java-archive" mapstructure:"java-archive"`
@@ -25,6 +27,7 @@ type Config struct {
func DefaultConfig() Config {
return Config{
Binary: binary.DefaultClassifierCatalogerConfig(),
Debian: debian.DefaultCatalogerConfig(),
Dotnet: dotnet.DefaultCatalogerConfig(),
Golang: golang.DefaultCatalogerConfig(),
JavaArchive: java.DefaultArchiveCatalogerConfig(),
@@ -73,3 +76,8 @@ func (c Config) WithJavaArchiveConfig(cfg java.ArchiveCatalogerConfig) Config {
c.JavaArchive = cfg
return c
}
func (c Config) WithDebianConfig(cfg debian.CatalogerConfig) Config {
c.Debian = cfg
return c
}
+14 -2
View File
@@ -10,16 +10,28 @@ import (
)
// NewDBCataloger returns a new Deb package cataloger capable of parsing DPKG status DB flat-file stores.
// Deprecated: use NewDpkgDBCataloger with a configuration
func NewDBCataloger() pkg.Cataloger {
return NewDpkgDBCataloger(DefaultCatalogerConfig())
}
// NewDpkgDBCataloger returns a new Deb package cataloger capable of parsing DPKG status DB flat-file stores with syft configuration.
func NewDpkgDBCataloger(cfg CatalogerConfig) pkg.Cataloger {
return generic.NewCataloger("dpkg-db-cataloger").
// note: these globs have been intentionally split up in order to improve search performance,
// please do NOT combine into: "**/var/lib/dpkg/{status,status.d/*}"
WithParserByGlobs(parseDpkgDB, "**/lib/dpkg/status", "**/lib/dpkg/status.d/*", "**/lib/opkg/info/*.control", "**/lib/opkg/status").
WithParserByGlobs(parseDpkgDB(cfg), "**/lib/dpkg/status", "**/lib/dpkg/status.d/*", "**/lib/opkg/info/*.control", "**/lib/opkg/status").
WithProcessors(dependency.Processor(dbEntryDependencySpecifier))
}
// NewArchiveCataloger returns a new Debian package cataloger object capable of parsing .deb archive files
// Deprecated: use NewDpkgArchiveCataloger with a configuration
func NewArchiveCataloger() pkg.Cataloger {
return NewDpkgDBCataloger(DefaultCatalogerConfig())
}
// NewDpkgArchiveCataloger returns a new Debian package cataloger object capable of parsing .deb archive files with syft configuration.
func NewDpkgArchiveCataloger(cfg CatalogerConfig) pkg.Cataloger {
return generic.NewCataloger("deb-archive-cataloger").
WithParserByGlobs(parseDebArchive, "**/*.deb")
WithParserByGlobs(parseDebArchive(cfg), "**/*.deb")
}
+1 -1
View File
@@ -281,7 +281,7 @@ func TestDpkgArchiveCataloger(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := NewArchiveCataloger()
c := NewDpkgArchiveCataloger(CatalogerConfig{IncludeDeInstalled: true})
pkgtest.NewCatalogTester().
WithImageResolver(t, tt.name).
IgnoreLocationLayer(). // this fixture can be rebuilt, thus the layer ID will change
+16
View File
@@ -0,0 +1,16 @@
package debian
type CatalogerConfig struct {
IncludeDeInstalled bool `yaml:"include-deinstalled" json:"include-deinstalled" mapstructure:"include-deinstalled"`
}
func DefaultCatalogerConfig() CatalogerConfig {
return CatalogerConfig{
IncludeDeInstalled: false,
}
}
func (c CatalogerConfig) WithIncludeDeInstalled(include bool) CatalogerConfig {
c.IncludeDeInstalled = include
return c
}
+14 -8
View File
@@ -28,7 +28,13 @@ import (
// - data.tar.gz/xz/zst: Contains the actual files to be installed (not processed by this cataloger)
//
// This function extracts and processes the control information to create package metadata.
func parseDebArchive(ctx context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
func parseDebArchive(cfg CatalogerConfig) generic.Parser {
return func(ctx context.Context, resolver file.Resolver, env *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
return parseDebArchiveWithConfig(ctx, resolver, env, reader, cfg)
}
}
func parseDebArchiveWithConfig(ctx context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser, cfg CatalogerConfig) ([]pkg.Package, []artifact.Relationship, error) {
arReader := ar.NewReader(reader)
var metadata *pkg.DpkgArchiveEntry
@@ -50,7 +56,7 @@ func parseDebArchive(ctx context.Context, _ file.Resolver, _ *generic.Environmen
if err != nil {
return nil, nil, unknown.New(reader.Location, fmt.Errorf("failed to decompress control.tar.* file: %w", err))
}
metadata, err = processControlTar(dcReader)
metadata, err = processControlTar(dcReader, cfg)
if err != nil {
return nil, nil, unknown.New(reader.Location, fmt.Errorf("failed to process control.tar.* file: %w", err))
}
@@ -104,7 +110,7 @@ func processDataTar(dcReader io.ReadCloser) ([]string, error) {
return licenses, nil
}
func processControlTar(dcReader io.ReadCloser) (*pkg.DpkgArchiveEntry, error) {
func processControlTar(dcReader io.ReadCloser, cfg CatalogerConfig) (*pkg.DpkgArchiveEntry, error) {
defer internal.CloseAndLogError(dcReader, "")
// Extract control, md5sums, and conffiles files from control.tar
@@ -118,7 +124,7 @@ func processControlTar(dcReader io.ReadCloser) (*pkg.DpkgArchiveEntry, error) {
return nil, fmt.Errorf("control file not found in archive")
}
metadata, err := newDpkgArchiveMetadata(controlFileContent, md5Content, confContent)
metadata, err := newDpkgArchiveMetadata(controlFileContent, md5Content, confContent, cfg)
if err != nil {
return nil, fmt.Errorf("failed to create package metadata: %w", err)
}
@@ -126,9 +132,9 @@ func processControlTar(dcReader io.ReadCloser) (*pkg.DpkgArchiveEntry, error) {
return &metadata, nil
}
func newDpkgArchiveMetadata(controlFile, md5sums, confFiles []byte) (pkg.DpkgArchiveEntry, error) {
func newDpkgArchiveMetadata(controlFile, md5sums, confFiles []byte, cfg CatalogerConfig) (pkg.DpkgArchiveEntry, error) {
// parse the control file to get package metadata
metadata, err := parseControlFile(string(controlFile))
metadata, err := parseControlFile(string(controlFile), cfg)
if err != nil {
return pkg.DpkgArchiveEntry{}, fmt.Errorf("failed to parse control file: %w", err)
}
@@ -201,11 +207,11 @@ func readControlFiles(tarReader *tar.Reader) (controlFile, md5sums, conffiles []
}
// parseControlFile parses the content of a debian control file into package metadata
func parseControlFile(controlFileContent string) (pkg.DpkgArchiveEntry, error) {
func parseControlFile(controlFileContent string, cfg CatalogerConfig) (pkg.DpkgArchiveEntry, error) {
// Reuse the existing dpkg status file parsing logic
reader := strings.NewReader(controlFileContent)
entries, err := parseDpkgStatus(reader)
entries, err := parseDpkgStatus(reader, cfg)
if err != nil {
return pkg.DpkgArchiveEntry{}, fmt.Errorf("failed to parse control file: %w", err)
}
@@ -127,7 +127,7 @@ Description: This is a test package
And even more details
`
metadata, err := parseControlFile(controlContent)
metadata, err := parseControlFile(controlContent, CatalogerConfig{})
require.NoError(t, err)
assert.Equal(t, "test-package", metadata.Package)
+21 -8
View File
@@ -24,14 +24,23 @@ import (
"github.com/anchore/syft/syft/pkg/cataloger/generic"
)
const (
deinstallStatus string = "deinstall"
)
var (
errEndOfPackages = fmt.Errorf("no more packages to read")
sourceRegexp = regexp.MustCompile(`(?P<name>\S+)( \((?P<version>.*)\))?`)
)
// parseDpkgDB reads a dpkg database "status" file (and surrounding data files) and returns the packages and relationships found.
func parseDpkgDB(ctx context.Context, resolver file.Resolver, env *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
metadata, err := parseDpkgStatus(reader)
func parseDpkgDB(cfg CatalogerConfig) generic.Parser {
return func(ctx context.Context, resolver file.Resolver, env *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
return parseDpkgDBWithConfig(ctx, resolver, env, reader, cfg)
}
}
func parseDpkgDBWithConfig(ctx context.Context, resolver file.Resolver, env *generic.Environment, reader file.LocationReadCloser, cfg CatalogerConfig) ([]pkg.Package, []artifact.Relationship, error) {
metadata, err := parseDpkgStatus(reader, cfg)
if err != nil {
return nil, nil, fmt.Errorf("unable to catalog dpkg DB=%q: %w", reader.RealPath, err)
}
@@ -73,14 +82,13 @@ func findDpkgInfoFiles(name string, resolver file.Resolver, dbLocation file.Loca
return locations
}
// parseDpkgStatus is a parser function for Debian DB status contents, returning all Debian packages listed.
func parseDpkgStatus(reader io.Reader) ([]pkg.DpkgDBEntry, error) {
func parseDpkgStatus(reader io.Reader, cfg CatalogerConfig) ([]pkg.DpkgDBEntry, error) {
buffedReader := bufio.NewReader(reader)
var metadata []pkg.DpkgDBEntry
continueProcessing := true
for continueProcessing {
entry, err := parseDpkgStatusEntry(buffedReader)
entry, err := parseDpkgStatusEntry(buffedReader, cfg)
if err != nil {
if errors.Is(err, errEndOfPackages) {
continueProcessing = false
@@ -112,10 +120,10 @@ type dpkgExtractedMetadata struct {
Provides string `mapstructure:"Provides"`
Depends string `mapstructure:"Depends"`
PreDepends string `mapstructure:"PreDepends"` // note: original doc is Pre-Depends
Status string `mapstructure:"Status"`
}
// parseDpkgStatusEntry returns an individual Dpkg entry, or returns errEndOfPackages if there are no more packages to parse from the reader.
func parseDpkgStatusEntry(reader *bufio.Reader) (*pkg.DpkgDBEntry, error) {
func parseDpkgStatusEntry(reader *bufio.Reader, cfg CatalogerConfig) (*pkg.DpkgDBEntry, error) {
var retErr error
dpkgFields, err := extractAllFields(reader)
if err != nil {
@@ -134,6 +142,11 @@ func parseDpkgStatusEntry(reader *bufio.Reader) (*pkg.DpkgDBEntry, error) {
return nil, err
}
// Skip entries which have been removed but not purged, e.g. "rc" status in dpkg -l
if !cfg.IncludeDeInstalled && strings.Contains(raw.Status, deinstallStatus) {
return nil, nil
}
sourceName, sourceVersion := extractSourceVersion(raw.Source)
if sourceVersion != "" {
raw.SourceVersion = sourceVersion
@@ -237,6 +237,37 @@ func Test_parseDpkgStatus(t *testing.T) {
},
},
},
{
name: "deinstall status packages are ignored",
fixturePath: "test-fixtures/var/lib/dpkg/status.d/deinstall",
expected: []pkg.DpkgDBEntry{
{
Package: "linux-image-6.14.0-1012-aws",
Source: "linux-signed-aws-6.14",
Version: "6.14.0-1012.12~24.04.1",
Architecture: "amd64",
InstalledSize: 15221,
Maintainer: "Canonical Kernel Team <kernel-team@lists.ubuntu.com>",
Description: `Signed kernel image aws
A kernel image for aws. This version of it is signed with
Canonical's signing key.`,
Provides: []string{"fuse-module",
"linux-image",
"spl-dkms",
"spl-modules",
"v4l2loopback-dkms",
"v4l2loopback-modules",
"zfs-dkms",
"zfs-modules"},
Depends: []string{
"kmod",
"linux-base (>= 4.5ubuntu1~16.04.1)",
"linux-modules-6.14.0-1012-aws",
},
Files: []pkg.DpkgFileRecord{},
},
},
},
}
for _, test := range tests {
@@ -247,7 +278,7 @@ func Test_parseDpkgStatus(t *testing.T) {
reader := bufio.NewReader(f)
entries, err := parseDpkgStatus(reader)
entries, err := parseDpkgStatus(reader, CatalogerConfig{})
require.NoError(t, err)
if diff := cmp.Diff(test.expected, entries); diff != "" {
@@ -264,7 +295,7 @@ func Test_corruptEntry(t *testing.T) {
reader := bufio.NewReader(f)
_, err = parseDpkgStatus(reader)
_, err = parseDpkgStatus(reader, CatalogerConfig{})
require.Error(t, err)
}
@@ -372,7 +403,7 @@ Installed-Size: 10kib
WithErrorAssertion(tt.wantErr).
WithLinuxRelease(linux.Release{ID: "debian", VersionID: "10"}).
Expects(tt.want, nil).
TestParser(t, parseDpkgDB)
TestParser(t, parseDpkgDB(DefaultCatalogerConfig()))
})
}
}
@@ -463,3 +494,54 @@ func abstractRelationships(t testing.TB, relationships []artifact.Relationship)
return abstracted
}
func Test_parseDpkgStatus_deinstall(t *testing.T) {
tests := []struct {
name string
includeDeinstall bool
expectedCount int
}{
{
name: "exclude deinstalled packages (default)",
includeDeinstall: false,
expectedCount: 1,
},
{
name: "include deinstalled packages",
includeDeinstall: true,
expectedCount: 2,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fixture, err := os.Open("test-fixtures/var/lib/dpkg/status.d/deinstall")
require.NoError(t, err)
defer fixture.Close()
cfg := CatalogerConfig{
IncludeDeInstalled: tt.includeDeinstall,
}
entries, err := parseDpkgStatus(fixture, cfg)
require.NoError(t, err)
assert.Len(t, entries, tt.expectedCount, "expected %d entries", tt.expectedCount)
if tt.includeDeinstall {
var foundDeinstalled bool
for _, entry := range entries {
if entry.Package == "linux-image-6.8.0-1029-aws" {
foundDeinstalled = true
break
}
}
assert.True(t, foundDeinstalled, "should find deinstalled package when includeDeinstall=true")
} else {
for _, entry := range entries {
assert.NotEqual(t, "linux-image-6.8.0-1029-aws", entry.Package, "should not find deinstalled package when includeDeinstall=false")
}
}
})
}
}
@@ -0,0 +1,38 @@
Package: linux-image-6.14.0-1012-aws
Status: install ok installed
Priority: optional
Section: kernel
Installed-Size: 15221
Maintainer: Canonical Kernel Team <kernel-team@lists.ubuntu.com>
Architecture: amd64
Source: linux-signed-aws-6.14
Version: 6.14.0-1012.12~24.04.1
Provides: fuse-module, linux-image, spl-dkms, spl-modules, v4l2loopback-dkms, v4l2loopback-modules, zfs-dkms, zfs-modules
Depends: kmod, linux-base (>= 4.5ubuntu1~16.04.1), linux-modules-6.14.0-1012-aws
Recommends: grub-pc | grub-efi-amd64 | grub-efi-ia32 | grub | lilo, initramfs-tools | linux-initramfs-tool
Suggests: bpftool, linux-perf, linux-aws-6.14-doc-6.14.0 | linux-aws-6.14-source-6.14.0, linux-aws-6.14-tools, linux-headers-6.14.0-1012-aws
Conflicts: linux-image-unsigned-6.14.0-1012-aws
Description: Signed kernel image aws
A kernel image for aws. This version of it is signed with
Canonical's signing key.
Built-Using: linux-aws-6.14 (= 6.14.0-1012.12~24.04.1)
Package: linux-image-6.8.0-1029-aws
Status: deinstall ok config-files
Priority: optional
Section: kernel
Installed-Size: 14591
Maintainer: Canonical Kernel Team <kernel-team@lists.ubuntu.com>
Architecture: amd64
Source: linux-signed-aws
Version: 6.8.0-1029.31
Config-Version: 6.8.0-1029.31
Provides: fuse-module, linux-image, spl-dkms, spl-modules, v4l2loopback-dkms, v4l2loopback-modules, zfs-dkms, zfs-modules
Depends: kmod, linux-base (>= 4.5ubuntu1~16.04.1), linux-modules-6.8.0-1029-aws
Recommends: grub-pc | grub-efi-amd64 | grub-efi-ia32 | grub | lilo, initramfs-tools | linux-initramfs-tool
Suggests: fdutils, linux-aws-doc-6.8.0 | linux-aws-source-6.8.0, linux-aws-tools, linux-headers-6.8.0-1029-aws
Conflicts: linux-image-unsigned-6.8.0-1029-aws
Description: Signed kernel image aws
A kernel image for aws. This version of it is signed with
Canonical's signing key.
Built-Using: linux-aws (= 6.8.0-1029.31)