github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/pkg/cataloger/common/cpe/apk_test.go (about)

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