github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/alpine/cataloger_test.go (about)

     1  package alpine
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/google/go-cmp/cmp/cmpopts"
     9  
    10  	"github.com/anchore/syft/syft/artifact"
    11  	"github.com/anchore/syft/syft/file"
    12  	"github.com/anchore/syft/syft/pkg"
    13  	"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
    14  )
    15  
    16  func TestApkDBCataloger(t *testing.T) {
    17  	dbLocation := file.NewLocation("lib/apk/db/installed")
    18  	ctx := context.TODO()
    19  	bashPkg := pkg.Package{
    20  		Name:    "bash",
    21  		Version: "5.2.21-r0",
    22  		Type:    pkg.ApkPkg,
    23  		FoundBy: "apk-db-cataloger",
    24  		Licenses: pkg.NewLicenseSet(
    25  			pkg.NewLicenseFromLocationsWithContext(ctx, "GPL-3.0-or-later", dbLocation),
    26  		),
    27  		Locations: file.NewLocationSet(dbLocation),
    28  		Metadata: pkg.ApkDBEntry{
    29  			Package:       "bash",
    30  			OriginPackage: "bash",
    31  			Maintainer:    "Natanael Copa <ncopa@alpinelinux.org>",
    32  			Version:       "5.2.21-r0",
    33  			Architecture:  "x86_64",
    34  			URL:           "https://www.gnu.org/software/bash/bash.html",
    35  			Description:   "The GNU Bourne Again shell",
    36  			Size:          448728,
    37  			InstalledSize: 1396736,
    38  			Dependencies: []string{
    39  				"/bin/sh", "so:libc.musl-x86_64.so.1", "so:libreadline.so.8",
    40  			},
    41  			Provides: []string{
    42  				"cmd:bash=5.2.21-r0",
    43  			},
    44  			// note: files not provided and not under test
    45  		},
    46  	}
    47  
    48  	busyboxBinshPkg := pkg.Package{
    49  		Name:    "busybox-binsh",
    50  		Version: "1.36.1-r15",
    51  		Type:    pkg.ApkPkg,
    52  		FoundBy: "apk-db-cataloger",
    53  		Licenses: pkg.NewLicenseSet(
    54  			pkg.NewLicenseFromLocationsWithContext(ctx, "GPL-2.0-only", dbLocation),
    55  		),
    56  		Locations: file.NewLocationSet(dbLocation),
    57  		Metadata: pkg.ApkDBEntry{
    58  			Package:       "busybox-binsh",
    59  			OriginPackage: "busybox",
    60  			Maintainer:    "Sören Tempel <soeren+alpine@soeren-tempel.net>",
    61  			Version:       "1.36.1-r15",
    62  			Architecture:  "x86_64",
    63  			URL:           "https://busybox.net/",
    64  			Description:   "busybox ash /bin/sh",
    65  			Size:          1543,
    66  			InstalledSize: 8192,
    67  			Dependencies: []string{
    68  				"busybox=1.36.1-r15",
    69  			},
    70  			Provides: []string{
    71  				"/bin/sh", "cmd:sh=1.36.1-r15",
    72  			},
    73  			// note: files not provided and not under test
    74  		},
    75  	}
    76  
    77  	muslPkg := pkg.Package{
    78  		Name:    "musl",
    79  		Version: "1.2.4_git20230717-r4",
    80  		Type:    pkg.ApkPkg,
    81  		FoundBy: "apk-db-cataloger",
    82  		Licenses: pkg.NewLicenseSet(
    83  			pkg.NewLicenseFromLocationsWithContext(ctx, "MIT", dbLocation),
    84  		),
    85  		Locations: file.NewLocationSet(dbLocation),
    86  		Metadata: pkg.ApkDBEntry{
    87  			Package:       "musl",
    88  			OriginPackage: "musl",
    89  			Maintainer:    "Timo Teräs <timo.teras@iki.fi>",
    90  			Version:       "1.2.4_git20230717-r4",
    91  			Architecture:  "x86_64",
    92  			URL:           "https://musl.libc.org/",
    93  			Description:   "the musl c library (libc) implementation",
    94  			Size:          407278,
    95  			InstalledSize: 667648,
    96  			Dependencies:  []string{},
    97  			Provides: []string{
    98  				"so:libc.musl-x86_64.so.1=1",
    99  			},
   100  			// note: files not provided and not under test
   101  		},
   102  	}
   103  
   104  	readlinePkg := pkg.Package{
   105  		Name:    "readline",
   106  		Version: "8.2.1-r2",
   107  		Type:    pkg.ApkPkg,
   108  		FoundBy: "apk-db-cataloger",
   109  		Licenses: pkg.NewLicenseSet(
   110  			pkg.NewLicenseFromLocationsWithContext(ctx, "GPL-2.0-or-later", dbLocation),
   111  		),
   112  		Locations: file.NewLocationSet(dbLocation),
   113  		Metadata: pkg.ApkDBEntry{
   114  			Package:       "readline",
   115  			OriginPackage: "readline",
   116  			Maintainer:    "Natanael Copa <ncopa@alpinelinux.org>",
   117  			Version:       "8.2.1-r2",
   118  			Architecture:  "x86_64",
   119  			URL:           "https://tiswww.cwru.edu/php/chet/readline/rltop.html",
   120  			Description:   "GNU readline library",
   121  			Size:          119878,
   122  			InstalledSize: 303104,
   123  			Dependencies: []string{
   124  				"so:libc.musl-x86_64.so.1", "so:libncursesw.so.6",
   125  			},
   126  			Provides: []string{
   127  				"so:libreadline.so.8=8.2",
   128  			},
   129  			// note: files not provided and not under test
   130  		},
   131  	}
   132  
   133  	expectedPkgs := []pkg.Package{
   134  		bashPkg,
   135  		busyboxBinshPkg,
   136  		muslPkg,
   137  		readlinePkg,
   138  	}
   139  
   140  	// # apk info --depends bash
   141  	//   bash-5.2.21-r0 depends on:
   142  	//   /bin/sh
   143  	//   so:libc.musl-x86_64.so.1
   144  	//   so:libreadline.so.8
   145  	//
   146  	// # apk info --who-owns /bin/sh
   147  	//   /bin/sh is owned by busybox-binsh-1.36.1-r15
   148  	//
   149  	// # find / | grep musl
   150  	//   /lib/ld-musl-x86_64.so.1
   151  	//   /lib/libc.musl-x86_64.so.1
   152  	//
   153  	// # apk info --who-owns '/lib/libc.musl-x86_64.so.1'
   154  	//   /lib/libc.musl-x86_64.so.1 is owned by musl-1.2.4_git20230717-r4
   155  	//
   156  	// # find / | grep libreadline
   157  	//   /usr/lib/libreadline.so.8.2
   158  	//   /usr/lib/libreadline.so.8
   159  	//
   160  	// # apk info --who-owns '/usr/lib/libreadline.so.8'
   161  	//   /usr/lib/libreadline.so.8 is owned by readline-8.2.1-r2
   162  
   163  	expectedRelationships := []artifact.Relationship{
   164  		{
   165  			From: busyboxBinshPkg,
   166  			To:   bashPkg,
   167  			Type: artifact.DependencyOfRelationship,
   168  		},
   169  		{
   170  			From: readlinePkg,
   171  			To:   bashPkg,
   172  			Type: artifact.DependencyOfRelationship,
   173  		},
   174  		{
   175  			From: muslPkg,
   176  			To:   readlinePkg,
   177  			Type: artifact.DependencyOfRelationship,
   178  		},
   179  		{
   180  			From: muslPkg,
   181  			To:   bashPkg,
   182  			Type: artifact.DependencyOfRelationship,
   183  		},
   184  	}
   185  
   186  	pkgtest.NewCatalogTester().
   187  		FromDirectory(t, "test-fixtures/multiple-1").
   188  		WithCompareOptions(cmpopts.IgnoreFields(pkg.ApkDBEntry{}, "Files", "GitCommit", "Checksum")).
   189  		Expects(expectedPkgs, expectedRelationships).
   190  		TestCataloger(t, NewDBCataloger())
   191  
   192  }
   193  
   194  func Test_corruptDb(t *testing.T) {
   195  	pkgtest.NewCatalogTester().
   196  		FromDirectory(t, "test-fixtures/corrupt").
   197  		WithCompareOptions(cmpopts.IgnoreFields(pkg.ApkDBEntry{}, "Files", "GitCommit", "Checksum")).
   198  		WithError().
   199  		TestCataloger(t, NewDBCataloger())
   200  }
   201  
   202  func TestCatalogerDependencyTree(t *testing.T) {
   203  	assertion := func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
   204  		expected := map[string][]string{
   205  			"alpine-baselayout": {"busybox", "alpine-baselayout-data", "musl"},
   206  			"apk-tools":         {"ca-certificates-bundle", "musl", "libcrypto1.1", "libssl1.1", "zlib"},
   207  			"busybox":           {"musl"},
   208  			"libc-utils":        {"musl-utils"},
   209  			"libcrypto1.1":      {"musl"},
   210  			"libssl1.1":         {"musl", "libcrypto1.1"},
   211  			"musl-utils":        {"scanelf", "musl"},
   212  			"scanelf":           {"musl"},
   213  			"ssl_client":        {"musl", "libcrypto1.1", "libssl1.1"},
   214  			"zlib":              {"musl"},
   215  		}
   216  		pkgsByID := make(map[artifact.ID]pkg.Package)
   217  		for _, p := range pkgs {
   218  			p.SetID()
   219  			pkgsByID[p.ID()] = p
   220  		}
   221  
   222  		actualDependencies := make(map[string][]string)
   223  
   224  		for _, r := range relationships {
   225  			switch r.Type {
   226  			case artifact.DependencyOfRelationship:
   227  				to := pkgsByID[r.To.ID()]
   228  				from := pkgsByID[r.From.ID()]
   229  				actualDependencies[to.Name] = append(actualDependencies[to.Name], from.Name)
   230  			default:
   231  				t.Fatalf("unexpected relationship type: %+v", r.Type)
   232  			}
   233  		}
   234  
   235  		if d := cmp.Diff(expected, actualDependencies); d != "" {
   236  			t.Fail()
   237  			t.Log(d)
   238  		}
   239  	}
   240  
   241  	pkgtest.NewCatalogTester().
   242  		FromDirectory(t, "test-fixtures/multiple-2").
   243  		ExpectsAssertion(assertion).
   244  		TestCataloger(t, NewDBCataloger())
   245  
   246  }
   247  
   248  func TestCataloger_Globs(t *testing.T) {
   249  	tests := []struct {
   250  		name     string
   251  		fixture  string
   252  		expected []string
   253  	}{
   254  		{
   255  			name:     "obtain DB files",
   256  			fixture:  "test-fixtures/glob-paths",
   257  			expected: []string{"lib/apk/db/installed"},
   258  		},
   259  	}
   260  
   261  	for _, test := range tests {
   262  		t.Run(test.name, func(t *testing.T) {
   263  			pkgtest.NewCatalogTester().
   264  				FromDirectory(t, test.fixture).
   265  				ExpectsResolverContentQueries(test.expected).
   266  				IgnoreUnfulfilledPathResponses("etc/apk/repositories").
   267  				TestCataloger(t, NewDBCataloger())
   268  		})
   269  	}
   270  }