github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/rpm/parse_rpm_db_test.go (about)

     1  package rpm
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  
    10  	"github.com/anchore/syft/syft/file"
    11  	"github.com/anchore/syft/syft/pkg"
    12  	"github.com/anchore/syft/syft/pkg/cataloger/internal/pkgtest"
    13  )
    14  
    15  var _ file.Resolver = (*rpmdbTestFileResolverMock)(nil)
    16  
    17  type rpmdbTestFileResolverMock struct {
    18  	ignorePaths bool
    19  }
    20  
    21  func (r rpmdbTestFileResolverMock) FilesByExtension(extensions ...string) ([]file.Location, error) {
    22  	panic("not implemented")
    23  }
    24  
    25  func (r rpmdbTestFileResolverMock) FilesByBasename(filenames ...string) ([]file.Location, error) {
    26  	panic("not implemented")
    27  }
    28  
    29  func (r rpmdbTestFileResolverMock) FilesByBasenameGlob(globs ...string) ([]file.Location, error) {
    30  	panic("not implemented")
    31  }
    32  
    33  func (r rpmdbTestFileResolverMock) FileContentsByLocation(location file.Location) (io.ReadCloser, error) {
    34  	panic("not implemented")
    35  }
    36  
    37  func (r rpmdbTestFileResolverMock) AllLocations() <-chan file.Location {
    38  	panic("not implemented")
    39  }
    40  
    41  func (r rpmdbTestFileResolverMock) FileMetadataByLocation(location file.Location) (file.Metadata, error) {
    42  	panic("not implemented")
    43  }
    44  
    45  func newTestFileResolver(ignorePaths bool) *rpmdbTestFileResolverMock {
    46  	return &rpmdbTestFileResolverMock{
    47  		ignorePaths: ignorePaths,
    48  	}
    49  }
    50  
    51  func (r rpmdbTestFileResolverMock) HasPath(path string) bool {
    52  	return !r.ignorePaths
    53  }
    54  
    55  func (r *rpmdbTestFileResolverMock) FilesByPath(paths ...string) ([]file.Location, error) {
    56  	if r.ignorePaths {
    57  		// act as if no paths exist
    58  		return nil, nil
    59  	}
    60  	// act as if all files exist
    61  	var locations = make([]file.Location, len(paths))
    62  	for i, p := range paths {
    63  		locations[i] = file.NewLocation(p)
    64  	}
    65  	return locations, nil
    66  }
    67  
    68  func (r *rpmdbTestFileResolverMock) FilesByGlob(...string) ([]file.Location, error) {
    69  	return nil, fmt.Errorf("not implemented")
    70  }
    71  
    72  func (r *rpmdbTestFileResolverMock) RelativeFileByPath(file.Location, string) *file.Location {
    73  	panic(fmt.Errorf("not implemented"))
    74  	return nil
    75  }
    76  
    77  func (r *rpmdbTestFileResolverMock) FilesByMIMEType(...string) ([]file.Location, error) {
    78  	return nil, fmt.Errorf("not implemented")
    79  }
    80  
    81  func TestParseRpmDB(t *testing.T) {
    82  	packagesLocation := file.NewLocation("test-fixtures/Packages")
    83  	tests := []struct {
    84  		fixture     string
    85  		expected    []pkg.Package
    86  		ignorePaths bool
    87  	}{
    88  		{
    89  			fixture: "test-fixtures/Packages",
    90  			// we only surface package paths for files that exist (here we DO NOT expect a path)
    91  			ignorePaths: true,
    92  			expected: []pkg.Package{
    93  				{
    94  					Name:         "dive",
    95  					Version:      "0.9.2-1",
    96  					PURL:         "pkg:rpm/dive@0.9.2-1?arch=x86_64&upstream=dive-0.9.2-1.src.rpm",
    97  					Locations:    file.NewLocationSet(file.NewLocation("test-fixtures/Packages")),
    98  					Type:         pkg.RpmPkg,
    99  					MetadataType: pkg.RpmMetadataType,
   100  					Licenses: pkg.NewLicenseSet(
   101  						pkg.NewLicenseFromLocations("MIT", packagesLocation),
   102  					),
   103  					Metadata: pkg.RpmMetadata{
   104  						Name:      "dive",
   105  						Epoch:     nil,
   106  						Arch:      "x86_64",
   107  						Release:   "1",
   108  						Version:   "0.9.2",
   109  						SourceRpm: "dive-0.9.2-1.src.rpm",
   110  						Size:      12406784,
   111  						Vendor:    "",
   112  						Files:     []pkg.RpmdbFileRecord{},
   113  					},
   114  				},
   115  			},
   116  		},
   117  		{
   118  			fixture: "test-fixtures/Packages",
   119  			// we only surface package paths for files that exist (here we expect a path)
   120  			ignorePaths: false,
   121  			expected: []pkg.Package{
   122  				{
   123  					Name:         "dive",
   124  					Version:      "0.9.2-1",
   125  					PURL:         "pkg:rpm/dive@0.9.2-1?arch=x86_64&upstream=dive-0.9.2-1.src.rpm",
   126  					Locations:    file.NewLocationSet(packagesLocation),
   127  					Type:         pkg.RpmPkg,
   128  					MetadataType: pkg.RpmMetadataType,
   129  					Licenses: pkg.NewLicenseSet(
   130  						pkg.NewLicenseFromLocations("MIT", packagesLocation),
   131  					),
   132  					Metadata: pkg.RpmMetadata{
   133  						Name:      "dive",
   134  						Epoch:     nil,
   135  						Arch:      "x86_64",
   136  						Release:   "1",
   137  						Version:   "0.9.2",
   138  						SourceRpm: "dive-0.9.2-1.src.rpm",
   139  						Size:      12406784,
   140  						Vendor:    "",
   141  						Files: []pkg.RpmdbFileRecord{
   142  							{
   143  								Path: "/usr/local/bin/dive",
   144  								Mode: 33261,
   145  								Size: 12406784,
   146  								Digest: file.Digest{
   147  									Algorithm: "sha256",
   148  									Value:     "81d29f327ba23096b3c52ff6fe1c425641e618bc87b5c05ee377edc650afaa55",
   149  								},
   150  								// note: there is no username, groupname, or flags for this RPM
   151  							},
   152  						},
   153  					},
   154  				},
   155  			},
   156  		},
   157  	}
   158  
   159  	for _, test := range tests {
   160  		t.Run(test.fixture, func(t *testing.T) {
   161  			pkgtest.NewCatalogTester().
   162  				WithResolver(newTestFileResolver(test.ignorePaths)).
   163  				FromFile(t, test.fixture).
   164  				Expects(test.expected, nil).
   165  				TestParser(t, parseRpmDB)
   166  		})
   167  	}
   168  }
   169  
   170  func TestToElVersion(t *testing.T) {
   171  	tests := []struct {
   172  		name     string
   173  		entry    pkg.RpmMetadata
   174  		expected string
   175  	}{
   176  		{
   177  			name: "no epoch",
   178  			entry: pkg.RpmMetadata{
   179  				Version: "1.2.3-4",
   180  				Release: "el7",
   181  				Arch:    "x86-64",
   182  			},
   183  			expected: "1.2.3-4-el7",
   184  		},
   185  		{
   186  			name: "with 0 epoch",
   187  			entry: pkg.RpmMetadata{
   188  				Version: "1.2.3-4",
   189  				Release: "el7",
   190  				Arch:    "x86-64",
   191  				Epoch:   intRef(0),
   192  			},
   193  			expected: "0:1.2.3-4-el7",
   194  		},
   195  		{
   196  			name: "with non-zero epoch",
   197  			entry: pkg.RpmMetadata{
   198  				Version: "1.2.3-4",
   199  				Release: "el7",
   200  				Arch:    "x86-64",
   201  				Epoch:   intRef(12),
   202  			},
   203  			expected: "12:1.2.3-4-el7",
   204  		},
   205  	}
   206  
   207  	for _, test := range tests {
   208  		t.Run(test.name, func(t *testing.T) {
   209  			assert.Equal(t, test.expected, toELVersion(test.entry))
   210  		})
   211  	}
   212  }
   213  
   214  func intRef(i int) *int {
   215  	return &i
   216  }