github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/common/cpe/apk_test.go (about)

     1  package cpe
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/assert"
     7  
     8  	"github.com/anchore/syft/syft/pkg"
     9  )
    10  
    11  func Test_candidateVendorsForAPK(t *testing.T) {
    12  	tests := []struct {
    13  		name     string
    14  		pkg      pkg.Package
    15  		expected []string
    16  	}{
    17  		{
    18  			name: "py3-cryptography Package",
    19  			pkg: pkg.Package{
    20  				Metadata: pkg.ApkMetadata{
    21  					Package: "py3-cryptography",
    22  				},
    23  			},
    24  			expected: []string{"python-cryptography_project", "cryptography", "cryptographyproject", "cryptography_project"},
    25  		},
    26  		{
    27  			name: "py2-pypdf with explicit different origin",
    28  			pkg: pkg.Package{
    29  				Metadata: pkg.ApkMetadata{
    30  					Package:       "py2-pypdf",
    31  					OriginPackage: "abcdefg",
    32  				},
    33  			},
    34  			expected: []string{"pypdf", "pypdfproject", "pypdf_project"},
    35  		},
    36  		{
    37  			name: "ruby-armadillo Package",
    38  			pkg: pkg.Package{
    39  				Metadata: pkg.ApkMetadata{
    40  					Package: "ruby-armadillo",
    41  				},
    42  			},
    43  			expected: []string{"armadillo"},
    44  		},
    45  		{
    46  			name: "python-3.6",
    47  			pkg: pkg.Package{
    48  				Metadata: pkg.ApkMetadata{
    49  					Package: "python-3.6",
    50  				},
    51  			},
    52  			expected: []string{"python", "python_software_foundation"},
    53  		},
    54  		{
    55  			name: "ruby-3.6",
    56  			pkg: pkg.Package{
    57  				Metadata: pkg.ApkMetadata{
    58  					Package: "ruby-3.6",
    59  					URL:     "https://www.ruby-lang.org/",
    60  				},
    61  			},
    62  			expected: []string{"ruby", "ruby-lang"},
    63  		},
    64  		{
    65  			name: "make",
    66  			pkg: pkg.Package{
    67  				Metadata: pkg.ApkMetadata{
    68  					Package: "make",
    69  					URL:     "https://www.gnu.org/software/make",
    70  				},
    71  			},
    72  			expected: []string{"gnu", "make"},
    73  		},
    74  		{
    75  			name: "ruby-rake with matching origin",
    76  			pkg: pkg.Package{
    77  				Name:         "ruby-rake",
    78  				Type:         pkg.ApkPkg,
    79  				MetadataType: pkg.ApkMetadataType,
    80  				Metadata: pkg.ApkMetadata{
    81  					Package:       "ruby-rake",
    82  					URL:           "https://github.com/ruby/rake",
    83  					OriginPackage: "ruby-rake",
    84  				},
    85  			},
    86  			expected: []string{"rake", "ruby-lang", "ruby"},
    87  		},
    88  		{
    89  			name: "ruby-rake with non-matching origin",
    90  			pkg: pkg.Package{
    91  				Name:         "ruby-rake",
    92  				Type:         pkg.ApkPkg,
    93  				MetadataType: pkg.ApkMetadataType,
    94  				Metadata: pkg.ApkMetadata{
    95  					Package:       "ruby-rake",
    96  					URL:           "https://www.ruby-lang.org/",
    97  					OriginPackage: "ruby",
    98  				},
    99  			},
   100  			expected: []string{"rake", "ruby-lang"},
   101  		},
   102  	}
   103  	for _, test := range tests {
   104  		t.Run(test.name, func(t *testing.T) {
   105  			assert.ElementsMatch(t, test.expected, candidateVendorsForAPK(test.pkg).uniqueValues(), "different vendors")
   106  		})
   107  	}
   108  }
   109  
   110  func Test_candidateProductsForAPK(t *testing.T) {
   111  	tests := []struct {
   112  		name     string
   113  		pkg      pkg.Package
   114  		expected []string
   115  	}{
   116  		{
   117  			name: "py3-cryptography Package",
   118  			pkg: pkg.Package{
   119  				Metadata: pkg.ApkMetadata{
   120  					Package: "py3-cryptography",
   121  				},
   122  			},
   123  			expected: []string{"cryptography", "python-cryptography"},
   124  		},
   125  		{
   126  			name: "py2-pypdf with explicit different origin",
   127  			pkg: pkg.Package{
   128  				Metadata: pkg.ApkMetadata{
   129  					Package:       "py2-pypdf",
   130  					OriginPackage: "abcdefg",
   131  				},
   132  			},
   133  			expected: []string{"pypdf"},
   134  		},
   135  		{
   136  			name: "ruby-armadillo Package",
   137  			pkg: pkg.Package{
   138  				Metadata: pkg.ApkMetadata{
   139  					Package: "ruby-armadillo",
   140  				},
   141  			},
   142  			expected: []string{"armadillo"},
   143  		},
   144  		{
   145  			name: "python-3.6",
   146  			pkg: pkg.Package{
   147  				Metadata: pkg.ApkMetadata{
   148  					Package: "python-3.6",
   149  				},
   150  			},
   151  			expected: []string{"python"},
   152  		},
   153  		{
   154  			name: "ruby-3.6",
   155  			pkg: pkg.Package{
   156  				Metadata: pkg.ApkMetadata{
   157  					Package: "ruby-3.6",
   158  					URL:     "https://www.ruby-lang.org/",
   159  				},
   160  			},
   161  			expected: []string{"ruby"},
   162  		},
   163  		{
   164  			name: "make",
   165  			pkg: pkg.Package{
   166  				Metadata: pkg.ApkMetadata{
   167  					Package: "make",
   168  					URL:     "https://www.gnu.org/software/make",
   169  				},
   170  			},
   171  			expected: []string{"make"},
   172  		},
   173  		{
   174  			name: "ruby-rake with matching origin",
   175  			pkg: pkg.Package{
   176  				Metadata: pkg.ApkMetadata{
   177  					Package:       "ruby-rake",
   178  					URL:           "https://github.com/ruby/rake",
   179  					OriginPackage: "ruby-rake",
   180  				},
   181  			},
   182  			expected: []string{"rake"},
   183  		},
   184  		{
   185  			name: "ruby-rake with non-matching origin",
   186  			pkg: pkg.Package{
   187  				Name:         "ruby-rake",
   188  				Type:         pkg.ApkPkg,
   189  				MetadataType: pkg.ApkMetadataType,
   190  				Metadata: pkg.ApkMetadata{
   191  					Package:       "ruby-rake",
   192  					URL:           "https://www.ruby-lang.org/",
   193  					OriginPackage: "ruby",
   194  				},
   195  			},
   196  			expected: []string{"rake"},
   197  		},
   198  	}
   199  	for _, test := range tests {
   200  		t.Run(test.name, func(t *testing.T) {
   201  			assert.ElementsMatch(t, test.expected, candidateProductsForAPK(test.pkg).uniqueValues(), "different products")
   202  		})
   203  	}
   204  }
   205  
   206  func Test_upstreamCandidates(t *testing.T) {
   207  	tests := []struct {
   208  		name     string
   209  		metadata pkg.ApkMetadata
   210  		expected []upstreamCandidate
   211  	}{
   212  		{
   213  			name: "gocase",
   214  			metadata: pkg.ApkMetadata{
   215  				Package: "p",
   216  			},
   217  			expected: []upstreamCandidate{
   218  				{Name: "p", Type: pkg.UnknownPkg},
   219  			},
   220  		},
   221  		{
   222  			name: "same package and origin simple case",
   223  			metadata: pkg.ApkMetadata{
   224  				Package:       "p",
   225  				OriginPackage: "p",
   226  			},
   227  			expected: []upstreamCandidate{
   228  				{Name: "p", Type: pkg.UnknownPkg},
   229  			},
   230  		},
   231  		{
   232  			name: "different package and origin",
   233  			metadata: pkg.ApkMetadata{
   234  				Package:       "p",
   235  				OriginPackage: "origin",
   236  			},
   237  			expected: []upstreamCandidate{
   238  				{Name: "p", Type: pkg.UnknownPkg},
   239  			},
   240  		},
   241  		{
   242  			name: "upstream python package information as qualifier py- prefix",
   243  			metadata: pkg.ApkMetadata{
   244  				Package:       "py-potatoes",
   245  				OriginPackage: "py-potatoes",
   246  			},
   247  			expected: []upstreamCandidate{
   248  				{Name: "potatoes", Type: pkg.PythonPkg},
   249  			},
   250  		},
   251  		{
   252  			name: "upstream python package information as qualifier py3- prefix",
   253  			metadata: pkg.ApkMetadata{
   254  				Package:       "py3-potatoes",
   255  				OriginPackage: "py3-potatoes",
   256  			},
   257  			expected: []upstreamCandidate{
   258  				{Name: "potatoes", Type: pkg.PythonPkg},
   259  			},
   260  		},
   261  		{
   262  			name: "python package with distinct origin package",
   263  			metadata: pkg.ApkMetadata{
   264  				Package:       "py3-non-existant",
   265  				OriginPackage: "abcdefg",
   266  			},
   267  			expected: []upstreamCandidate{
   268  				{Name: "non-existant", Type: pkg.PythonPkg},
   269  			},
   270  		},
   271  		{
   272  			name: "upstream ruby package information as qualifier",
   273  			metadata: pkg.ApkMetadata{
   274  				Package:       "ruby-something",
   275  				OriginPackage: "ruby-something",
   276  			},
   277  			expected: []upstreamCandidate{
   278  				{Name: "something", Type: pkg.GemPkg},
   279  			},
   280  		},
   281  		{
   282  			name: "ruby package with distinct origin package",
   283  			metadata: pkg.ApkMetadata{
   284  				Package:       "ruby-something",
   285  				OriginPackage: "1234567",
   286  			},
   287  			expected: []upstreamCandidate{
   288  				{Name: "something", Type: pkg.GemPkg},
   289  			},
   290  		},
   291  		{
   292  			name: "postgesql-15 upstream postgresql",
   293  			metadata: pkg.ApkMetadata{
   294  				Package: "postgresql-15",
   295  			},
   296  			expected: []upstreamCandidate{
   297  				{Name: "postgresql", Type: pkg.UnknownPkg},
   298  			},
   299  		},
   300  		{
   301  			name: "postgesql15 upstream postgresql",
   302  			metadata: pkg.ApkMetadata{
   303  				Package: "postgresql15",
   304  			},
   305  			expected: []upstreamCandidate{
   306  				{Name: "postgresql", Type: pkg.UnknownPkg},
   307  			},
   308  		},
   309  		{
   310  			name: "go-1.19 upstream go",
   311  			metadata: pkg.ApkMetadata{
   312  				Package: "go-1.19",
   313  			},
   314  			expected: []upstreamCandidate{
   315  				{Name: "go", Type: pkg.UnknownPkg},
   316  			},
   317  		},
   318  		{
   319  			name: "go1.143 upstream go",
   320  			metadata: pkg.ApkMetadata{
   321  				Package: "go1.143",
   322  			},
   323  			expected: []upstreamCandidate{
   324  				{Name: "go", Type: pkg.UnknownPkg},
   325  			},
   326  		},
   327  		{
   328  			name: "abc-101.191.23456 upstream abc",
   329  			metadata: pkg.ApkMetadata{
   330  				Package: "abc-101.191.23456",
   331  			},
   332  			expected: []upstreamCandidate{
   333  				{Name: "abc", Type: pkg.UnknownPkg},
   334  			},
   335  		},
   336  		{
   337  			name: "abc101.191.23456 upstream abc",
   338  			metadata: pkg.ApkMetadata{
   339  				Package: "abc101.191.23456",
   340  			},
   341  			expected: []upstreamCandidate{
   342  				{Name: "abc", Type: pkg.UnknownPkg},
   343  			},
   344  		},
   345  		{
   346  			name: "abc101-12345-1045 upstream abc101-12345",
   347  			metadata: pkg.ApkMetadata{
   348  				Package: "abc101-12345-1045",
   349  			},
   350  			expected: []upstreamCandidate{
   351  				{Name: "abc101-12345", Type: pkg.UnknownPkg},
   352  			},
   353  		},
   354  		{
   355  			name: "abc101-a12345-1045 upstream abc101-a12345",
   356  			metadata: pkg.ApkMetadata{
   357  				Package: "abc101-a12345-1045",
   358  			},
   359  			expected: []upstreamCandidate{
   360  				{Name: "abc-a12345-1045", Type: pkg.UnknownPkg},
   361  			},
   362  		},
   363  		{
   364  			name: "package starting with single digit",
   365  			metadata: pkg.ApkMetadata{
   366  				Package: "3proxy",
   367  			},
   368  			expected: []upstreamCandidate{
   369  				{Name: "3proxy", Type: pkg.UnknownPkg},
   370  			},
   371  		},
   372  		{
   373  			name: "package starting with multiple digits",
   374  			metadata: pkg.ApkMetadata{
   375  				Package: "356proxy",
   376  			},
   377  			expected: []upstreamCandidate{
   378  				{Name: "356proxy", Type: pkg.UnknownPkg},
   379  			},
   380  		},
   381  		{
   382  			name: "package composed of only digits",
   383  			metadata: pkg.ApkMetadata{
   384  				Package: "123456",
   385  			},
   386  			expected: []upstreamCandidate{
   387  				{Name: "123456", Type: pkg.UnknownPkg},
   388  			},
   389  		},
   390  		{
   391  			name: "ruby-3.6 upstream ruby",
   392  			metadata: pkg.ApkMetadata{
   393  				Package: "ruby-3.6",
   394  			},
   395  			expected: []upstreamCandidate{
   396  				{Name: "ruby", Type: pkg.UnknownPkg},
   397  			},
   398  		},
   399  		{
   400  			name: "ruby3.6 upstream ruby",
   401  			metadata: pkg.ApkMetadata{
   402  				Package: "ruby3.6",
   403  			},
   404  			expected: []upstreamCandidate{
   405  				{Name: "ruby", Type: pkg.UnknownPkg},
   406  			},
   407  		},
   408  		{
   409  			name: "ruby3.6-tacos upstream tacos",
   410  			metadata: pkg.ApkMetadata{
   411  				Package: "ruby3.6-tacos",
   412  			},
   413  			expected: []upstreamCandidate{
   414  				{Name: "tacos", Type: pkg.GemPkg},
   415  			},
   416  		},
   417  		{
   418  			name: "ruby-3.6-tacos upstream tacos",
   419  			metadata: pkg.ApkMetadata{
   420  				Package: "ruby-3.6-tacos",
   421  			},
   422  			expected: []upstreamCandidate{
   423  				{Name: "tacos", Type: pkg.GemPkg},
   424  			},
   425  		},
   426  		{
   427  			name: "abc1234jksajflksa",
   428  			metadata: pkg.ApkMetadata{
   429  				Package: "abc1234jksajflksa",
   430  			},
   431  			expected: []upstreamCandidate{
   432  				{Name: "abc1234jksajflksa", Type: pkg.UnknownPkg},
   433  			},
   434  		},
   435  	}
   436  
   437  	for _, test := range tests {
   438  		t.Run(test.name, func(t *testing.T) {
   439  			actual := upstreamCandidates(test.metadata)
   440  			assert.Equal(t, test.expected, actual)
   441  		})
   442  	}
   443  }