fix: migrate from *.list to *.md5sums files for dpkg (#9131)

This commit is contained in:
DmitriyLewen
2025-07-04 14:33:46 +06:00
committed by GitHub
parent 28074780a6
commit f224de3e39
5 changed files with 58 additions and 82 deletions

View File

@@ -70,7 +70,7 @@
"PkgName": "libidn2-0",
"PkgIdentifier": {
"PURL": "pkg:deb/debian/libidn2-0@2.0.5-1?arch=amd64\u0026distro=debian-10.1",
"UID": "473f5eb9e3d4a2f2"
"UID": "24f9b08969c58720"
},
"InstalledVersion": "2.0.5-1",
"FixedVersion": "2.0.5-1+deb10u1",

View File

@@ -47,6 +47,8 @@ const (
statusDir = "var/lib/dpkg/status.d/"
infoDir = "var/lib/dpkg/info/"
availableFile = "var/lib/dpkg/available"
md5sumsExtension = ".md5sums"
)
var (
@@ -72,14 +74,14 @@ func (a dpkgAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis
// parse other files
err = fsutils.WalkDir(input.FS, ".", required, func(path string, _ fs.DirEntry, r io.Reader) error {
// parse list files
if a.isListFile(filepath.Split(path)) {
// parse *md5sums files
if a.isMd5SumsFile(filepath.Split(path)) {
scanner := bufio.NewScanner(r)
systemFiles, err := a.parseDpkgInfoList(scanner)
systemFiles, err := a.parseDpkgMd5sums(scanner)
if err != nil {
return err
return xerrors.Errorf("failed to parse %s file: %w", path, err)
}
packageFiles[strings.TrimSuffix(filepath.Base(path), ".list")] = systemFiles
packageFiles[strings.TrimSuffix(filepath.Base(path), md5sumsExtension)] = systemFiles
systemInstalledFiles = append(systemInstalledFiles, systemFiles...)
return nil
}
@@ -113,46 +115,31 @@ func (a dpkgAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis
}
// parseDpkgInfoList parses /var/lib/dpkg/info/*.list
func (a dpkgAnalyzer) parseDpkgInfoList(scanner *bufio.Scanner) ([]string, error) {
var (
allLines []string
installedFiles []string
previous string
)
// parseDpkgMd5sums parses `/var/lib/dpkg/*/*.md5sums` file.
//
// `*.md5sums` files don't contain links (see https://github.com/aquasecurity/trivy/pull/9131#discussion_r2182557288).
// But Trivy doesn't support links, so this will not cause problems.
// TODO use `*.list` files instead of `*.md5sums` files when Trivy will support links.
func (a dpkgAnalyzer) parseDpkgMd5sums(scanner *bufio.Scanner) ([]string, error) {
var installedFiles []string
for scanner.Scan() {
current := scanner.Text()
if current == "/." {
continue
// md5sums file use the following format:
// <digest> <filepath> (2 spaces)
// cf. https://man7.org/linux/man-pages/man5/deb-md5sums.5.html
_, file, ok := strings.Cut(current, " ")
if !ok {
return nil, xerrors.Errorf("invalid md5sums line format: %s", current)
}
allLines = append(allLines, current)
installedFiles = append(installedFiles, "/"+file) // md5sums files don't contain leading slash
}
if err := scanner.Err(); err != nil {
return nil, xerrors.Errorf("scan error: %w", err)
}
// Add the file if it is not directory.
// e.g.
// /usr/sbin
// /usr/sbin/tarcat
//
// In the above case, we should take only /usr/sbin/tarcat since /usr/sbin is a directory
// sort first,see here:https://github.com/aquasecurity/trivy/discussions/6543
sort.Strings(allLines)
for _, current := range allLines {
if !strings.HasPrefix(current, previous+"/") {
installedFiles = append(installedFiles, previous)
}
previous = current
}
// // Add the last file
if previous != "" && !strings.HasSuffix(previous, "/") {
installedFiles = append(installedFiles, previous)
}
sort.Strings(installedFiles)
return installedFiles, nil
}
@@ -290,14 +277,10 @@ func (a dpkgAnalyzer) parseDpkgPkg(header textproto.MIMEHeader) *types.Package {
func (a dpkgAnalyzer) Required(filePath string, _ os.FileInfo) bool {
dir, fileName := filepath.Split(filePath)
if a.isListFile(dir, fileName) || filePath == statusFile || filePath == availableFile {
if a.isMd5SumsFile(dir, fileName) || filePath == statusFile || filePath == availableFile || dir == statusDir {
return true
}
// skip `*.md5sums` files from `status.d` directory
if dir == statusDir && filepath.Ext(fileName) != ".md5sums" {
return true
}
return false
}
@@ -356,12 +339,14 @@ func (a dpkgAnalyzer) consolidateDependencies(pkgs map[string]*types.Package, pk
}
}
func (a dpkgAnalyzer) isListFile(dir, fileName string) bool {
if dir != infoDir {
func (a dpkgAnalyzer) isMd5SumsFile(dir, fileName string) bool {
// - var/lib/dpkg/info/*.md5sums is default path
// - var/lib/dpkg/status.d/*.md5sums path in distroless images (see https://github.com/GoogleContainerTools/distroless/blob/5c119701429fb742ab45682cfc3073f911bad4bf/PACKAGE_METADATA.md#omitted-files)
if dir != infoDir && dir != statusDir {
return false
}
return strings.HasSuffix(fileName, ".list")
return strings.HasSuffix(fileName, md5sumsExtension)
}
func (a dpkgAnalyzer) Type() analyzer.Type {

View File

@@ -18,7 +18,7 @@ func Test_dpkgAnalyzer_Analyze(t *testing.T) {
tests := []struct {
name string
// testFiles contains path in testdata and path in OS
// e.g. tar.list => var/lib/dpkg/info/tar.list
// e.g. tar.md5sums => var/lib/dpkg/info/tar.md5sums
testFiles map[string]string
want *analyzer.AnalysisResult
wantErr bool
@@ -1372,7 +1372,9 @@ func Test_dpkgAnalyzer_Analyze(t *testing.T) {
Packages: []types.Package{
{
ID: "apt@1.6.3ubuntu0.1", Name: "apt", Version: "1.6.3ubuntu0.1",
SrcName: "apt", SrcVersion: "1.6.3ubuntu0.1", Maintainer: "Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>", Arch: "amd64"},
SrcName: "apt", SrcVersion: "1.6.3ubuntu0.1",
Maintainer: "Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>", Arch: "amd64",
},
},
},
},
@@ -1418,12 +1420,11 @@ func Test_dpkgAnalyzer_Analyze(t *testing.T) {
},
},
{
name: "info list",
testFiles: map[string]string{"./testdata/tar.list": "var/lib/dpkg/info/tar.list"},
name: "md5sums",
testFiles: map[string]string{"./testdata/tar.md5sums": "var/lib/dpkg/info/tar.md5sums"},
want: &analyzer.AnalysisResult{
SystemInstalledFiles: []string{
"/bin/tar",
"/etc/rmt",
"/usr/bin/tar",
"/usr/lib/mime/packages/tar",
"/usr/sbin/rmt-tar",
"/usr/sbin/tarcat",
@@ -1488,12 +1489,17 @@ func Test_dpkgAnalyzer_Required(t *testing.T) {
{
name: "*.md5sums file in status dir",
filePath: "var/lib/dpkg/status.d/base-files.md5sums",
want: false,
want: true,
},
{
name: "*.md5sums file in info dir",
filePath: "var/lib/dpkg/info/bash.md5sums",
want: true,
},
{
name: "list file",
filePath: "var/lib/dpkg/info/bash.list",
want: true,
want: false,
},
{
name: "available file",
@@ -1502,7 +1508,7 @@ func Test_dpkgAnalyzer_Required(t *testing.T) {
},
{
name: "sad path",
filePath: "var/lib/dpkg/status/bash.list",
filePath: "var/lib/dpkg/status/bash.md5sums",
want: false,
},
}

View File

@@ -1,28 +0,0 @@
/.
/bin
/bin/tar
/etc
/usr
/usr/lib
/usr/lib/mime
/usr/lib/mime/packages
/usr/lib/mime/packages/tar
/usr/sbin
/usr/sbin/rmt-tar
/usr/sbin/tarcat
/usr/share
/usr/share/doc
/usr/share/doc/tar
/usr/share/doc/tar/AUTHORS
/usr/share/doc/tar/NEWS.gz
/usr/share/doc/tar/README.Debian
/usr/share/doc/tar/THANKS.gz
/usr/share/doc/tar/changelog.Debian.gz
/usr/share/doc/tar/copyright
/usr/share/man
/usr/share/man/man1
/usr/share/man/man1/tar.1.gz
/usr/share/man/man1/tarcat.1.gz
/usr/share/man/man8
/usr/share/man/man8/rmt-tar.8.gz
/etc/rmt

View File

@@ -0,0 +1,13 @@
25de5fcdc3c8ebd9c9f599fb7a899b40 usr/bin/tar
5bf0e62990e0b668830ceb2c8615b497 usr/lib/mime/packages/tar
de1096fbccdc14324196fc6829324ebc usr/sbin/rmt-tar
fd2fab77cf4da2288c11a4de2c0c7fe0 usr/sbin/tarcat
020511595e8fb6a77b29032b3ec4ab10 usr/share/doc/tar/AUTHORS
5386c77b19064999a340c62ec50b9307 usr/share/doc/tar/NEWS.gz
882d20d9ef9c5baf1557a921bb9c6251 usr/share/doc/tar/README.Debian
63b372367a085f8d07c4127828c56999 usr/share/doc/tar/THANKS.gz
e9c4ef9b5dffd7b5b94f019d28bf86d6 usr/share/doc/tar/changelog.Debian.gz
4546fba65a596c8793dca393b32ad9ee usr/share/doc/tar/copyright
0502616f764289571b974ecc5adc1209 usr/share/man/man1/tar.1.gz
9376d82eb54e507863d32114dddd3de6 usr/share/man/man1/tarcat.1.gz
4892b2039586e61ef7b290591e9743e5 usr/share/man/man8/rmt-tar.8.gz