github.com/kastenhq/syft@v0.0.0-20230821225854-0710af25cdbe/syft/pkg/cataloger/common/cpe/java_test.go (about)

     1  package cpe
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  
     9  	"github.com/kastenhq/syft/syft/pkg"
    10  )
    11  
    12  func Test_productsFromArtifactAndGroupIDs(t *testing.T) {
    13  	tests := []struct {
    14  		groupIDs   []string
    15  		artifactID string
    16  		expected   []string
    17  	}{
    18  		{
    19  			groupIDs:   []string{"org.sonatype.nexus"},
    20  			artifactID: "nexus-extender",
    21  			expected:   []string{"nexus", "nexus-extender"},
    22  		},
    23  		{
    24  			groupIDs: []string{"org.sonatype.nexus"},
    25  			expected: []string{"nexus"},
    26  		},
    27  		{
    28  			groupIDs:   []string{"org.jenkins-ci.plugins"},
    29  			artifactID: "ant",
    30  			expected:   []string{"ant"},
    31  		},
    32  		{
    33  			groupIDs:   []string{"org.jenkins-ci.plugins"},
    34  			artifactID: "antisamy-markup-formatter",
    35  			expected:   []string{"antisamy-markup-formatter"},
    36  		},
    37  		{
    38  			groupIDs:   []string{"io.jenkins.plugins"},
    39  			artifactID: "aws-global-configuration",
    40  			expected:   []string{"aws-global-configuration"},
    41  		},
    42  		{
    43  			groupIDs:   []string{"com.cloudbees.jenkins.plugins"},
    44  			artifactID: "cloudbees-servicenow-jenkins-plugin",
    45  			expected:   []string{"cloudbees-servicenow-jenkins-plugin"},
    46  		},
    47  		{
    48  			groupIDs:   []string{"com.atlassian.confluence.plugins"},
    49  			artifactID: "confluence-mobile-plugin",
    50  			expected:   []string{"confluence-mobile-plugin"},
    51  		},
    52  		{
    53  			groupIDs:   []string{"com.atlassian.confluence.plugins"},
    54  			artifactID: "confluence-view-file-macro",
    55  			expected:   []string{"confluence-view-file-macro"},
    56  		},
    57  		{
    58  			groupIDs:   []string{"com.google.guava"},
    59  			artifactID: "failureaccess",
    60  			expected:   []string{"failureaccess"},
    61  		},
    62  	}
    63  	for _, test := range tests {
    64  		t.Run(strings.Join(test.groupIDs, ",")+":"+test.artifactID, func(t *testing.T) {
    65  			actual := productsFromArtifactAndGroupIDs(test.artifactID, test.groupIDs)
    66  			assert.ElementsMatch(t, test.expected, actual, "different products")
    67  		})
    68  	}
    69  }
    70  
    71  func Test_candidateProductsForJava(t *testing.T) {
    72  	tests := []struct {
    73  		name     string
    74  		pkg      pkg.Package
    75  		expected []string
    76  	}{
    77  		{
    78  			name: "duplicate groupID in artifactID field",
    79  			pkg: pkg.Package{
    80  				Metadata: pkg.JavaMetadata{
    81  					PomProperties: &pkg.PomProperties{
    82  						GroupID:    "org.sonatype.nexus",
    83  						ArtifactID: "org.sonatype.nexus",
    84  					},
    85  				},
    86  			},
    87  			expected: []string{"nexus"},
    88  		},
    89  		{
    90  			name: "detect groupID-like value in artifactID field",
    91  			pkg: pkg.Package{
    92  				Metadata: pkg.JavaMetadata{
    93  					PomProperties: &pkg.PomProperties{
    94  						ArtifactID: "org.sonatype.nexus",
    95  					},
    96  				},
    97  			},
    98  			expected: []string{"nexus"},
    99  		},
   100  	}
   101  	for _, test := range tests {
   102  		t.Run(test.name, func(t *testing.T) {
   103  			actual := candidateProductsForJava(test.pkg)
   104  			assert.ElementsMatch(t, test.expected, actual, "different products")
   105  		})
   106  	}
   107  }
   108  
   109  func Test_vendorsFromGroupIDs(t *testing.T) {
   110  	tests := []struct {
   111  		groupID  string
   112  		expected []string
   113  	}{
   114  		{
   115  			groupID:  "org.sonatype.nexus",
   116  			expected: []string{"sonatype", "nexus"},
   117  		},
   118  		{
   119  			groupID:  "org.jenkins-ci.plugins",
   120  			expected: []string{"jenkins-ci"},
   121  		},
   122  		{
   123  			groupID:  "io.jenkins.plugins",
   124  			expected: []string{"jenkins"},
   125  		},
   126  		{
   127  			groupID:  "com.cloudbees.jenkins.plugins",
   128  			expected: []string{"cloudbees", "jenkins"},
   129  		},
   130  		{
   131  			groupID:  "com.atlassian.confluence.plugins",
   132  			expected: []string{"atlassian", "confluence"},
   133  		},
   134  		{
   135  			groupID:  "com.google.guava",
   136  			expected: []string{"google", "guava"},
   137  		},
   138  	}
   139  	for _, test := range tests {
   140  		t.Run(test.groupID, func(t *testing.T) {
   141  			assert.ElementsMatch(t, test.expected, vendorsFromGroupIDs([]string{test.groupID}).values(), "different vendors")
   142  		})
   143  	}
   144  }
   145  
   146  func Test_groupIDsFromJavaPackage(t *testing.T) {
   147  	tests := []struct {
   148  		name    string
   149  		pkg     pkg.Package
   150  		expects []string
   151  	}{
   152  		{
   153  			name: "go case",
   154  			pkg: pkg.Package{
   155  				Metadata: pkg.JavaMetadata{
   156  					PomProperties: &pkg.PomProperties{
   157  						GroupID: "io.jenkins-ci.plugin.thing;version='[2,3)'",
   158  					},
   159  				},
   160  			},
   161  			expects: []string{"io.jenkins-ci.plugin.thing"},
   162  		},
   163  		{
   164  			name: "from artifactID",
   165  			pkg: pkg.Package{
   166  				Metadata: pkg.JavaMetadata{
   167  					PomProperties: &pkg.PomProperties{
   168  						ArtifactID: "io.jenkins-ci.plugin.thing; version='[2,3)' ; org.something.else",
   169  					},
   170  				},
   171  			},
   172  			expects: []string{"io.jenkins-ci.plugin.thing"},
   173  		},
   174  		{
   175  			name: "from main Extension-Name field",
   176  			pkg: pkg.Package{
   177  				Metadata: pkg.JavaMetadata{
   178  					Manifest: &pkg.JavaManifest{
   179  						Main: map[string]string{
   180  							"Extension-Name": "io.jenkins-ci.plugin.thing",
   181  						},
   182  					},
   183  				},
   184  			},
   185  			expects: []string{"io.jenkins-ci.plugin.thing"},
   186  		},
   187  		{
   188  			name: "from named section Extension-Name field",
   189  			pkg: pkg.Package{
   190  				Metadata: pkg.JavaMetadata{
   191  					Manifest: &pkg.JavaManifest{
   192  						NamedSections: map[string]map[string]string{
   193  							"section": {
   194  								"Extension-Name": "io.jenkins-ci.plugin.thing",
   195  							},
   196  						},
   197  					},
   198  				},
   199  			},
   200  			expects: []string{"io.jenkins-ci.plugin.thing"},
   201  		},
   202  		{
   203  			name: "from main field - tier 1",
   204  			pkg: pkg.Package{
   205  				Metadata: pkg.JavaMetadata{
   206  					Manifest: &pkg.JavaManifest{
   207  						Main: map[string]string{
   208  							// positive cases
   209  							// tier 1
   210  							"Extension-Name":           "io.jenkins-ci.plugin.1",
   211  							"Specification-Vendor":     "io.jenkins-ci.plugin.2",
   212  							"Implementation-Vendor":    "io.jenkins-ci.plugin.3",
   213  							"Bundle-SymbolicName":      "io.jenkins-ci.plugin.4",
   214  							"Implementation-Vendor-Id": "io.jenkins-ci.plugin.5",
   215  							"Implementation-Title":     "io.jenkins-ci.plugin.6",
   216  							"Bundle-Activator":         "io.jenkins-ci.plugin.7",
   217  							// tier 2
   218  							"Automatic-Module-Name": "io.jenkins-ci.plugin.8",
   219  							"Main-Class":            "io.jenkins-ci.plugin.9",
   220  							"Package":               "io.jenkins-ci.plugin.10",
   221  						},
   222  					},
   223  				},
   224  			},
   225  			expects: []string{
   226  				"io.jenkins-ci.plugin.1",
   227  				"io.jenkins-ci.plugin.2",
   228  				"io.jenkins-ci.plugin.3",
   229  				"io.jenkins-ci.plugin.4",
   230  				"io.jenkins-ci.plugin.5",
   231  				"io.jenkins-ci.plugin.6",
   232  				"io.jenkins-ci.plugin.7",
   233  			},
   234  		},
   235  		{
   236  			name: "from main field - tier 2",
   237  			pkg: pkg.Package{
   238  				Metadata: pkg.JavaMetadata{
   239  					Manifest: &pkg.JavaManifest{
   240  						Main: map[string]string{
   241  							// positive cases
   242  							"Automatic-Module-Name": "io.jenkins-ci.plugin.8",
   243  							"Main-Class":            "io.jenkins-ci.plugin.9",
   244  							"Package":               "io.jenkins-ci.plugin.10",
   245  						},
   246  					},
   247  				},
   248  			},
   249  			expects: []string{
   250  				"io.jenkins-ci.plugin.8",
   251  				"io.jenkins-ci.plugin.9",
   252  				"io.jenkins-ci.plugin.10",
   253  			},
   254  		},
   255  		{
   256  			name: "from main field - negative cases",
   257  			pkg: pkg.Package{
   258  				Metadata: pkg.JavaMetadata{
   259  					Manifest: &pkg.JavaManifest{
   260  						Main: map[string]string{
   261  							// negative cases
   262  							"Extension-Name": "not.a-group.id",
   263  							"bogus":          "io.jenkins-ci.plugin.please-dont-find-me",
   264  						},
   265  					},
   266  				},
   267  			},
   268  			expects: nil,
   269  		},
   270  		{
   271  			name: "from named section field - tier 1",
   272  			pkg: pkg.Package{
   273  				Metadata: pkg.JavaMetadata{
   274  					Manifest: &pkg.JavaManifest{
   275  						NamedSections: map[string]map[string]string{
   276  							"section": {
   277  								// positive cases
   278  								// tier 1
   279  								"Extension-Name":           "io.jenkins-ci.plugin.1",
   280  								"Specification-Vendor":     "io.jenkins-ci.plugin.2",
   281  								"Implementation-Vendor":    "io.jenkins-ci.plugin.3",
   282  								"Bundle-SymbolicName":      "io.jenkins-ci.plugin.4",
   283  								"Implementation-Vendor-Id": "io.jenkins-ci.plugin.5",
   284  								"Implementation-Title":     "io.jenkins-ci.plugin.6",
   285  								"Bundle-Activator":         "io.jenkins-ci.plugin.7",
   286  								// tier 2
   287  								"Automatic-Module-Name": "io.jenkins-ci.plugin.8",
   288  								"Main-Class":            "io.jenkins-ci.plugin.9",
   289  								"Package":               "io.jenkins-ci.plugin.10",
   290  							},
   291  						},
   292  					},
   293  				},
   294  			},
   295  			expects: []string{
   296  				"io.jenkins-ci.plugin.1",
   297  				"io.jenkins-ci.plugin.2",
   298  				"io.jenkins-ci.plugin.3",
   299  				"io.jenkins-ci.plugin.4",
   300  				"io.jenkins-ci.plugin.5",
   301  				"io.jenkins-ci.plugin.6",
   302  				"io.jenkins-ci.plugin.7",
   303  			},
   304  		},
   305  		{
   306  			name: "from named section field - negative cases",
   307  			pkg: pkg.Package{
   308  				Metadata: pkg.JavaMetadata{
   309  					Manifest: &pkg.JavaManifest{
   310  						NamedSections: map[string]map[string]string{
   311  							"section": {
   312  								// negative cases
   313  								"Extension-Name": "not.a-group.id",
   314  								"bogus":          "io.jenkins-ci.plugin.please-dont-find-me",
   315  							},
   316  						},
   317  					},
   318  				},
   319  			},
   320  			expects: nil,
   321  		},
   322  		{
   323  			name: "no manifest or pom info",
   324  			pkg: pkg.Package{
   325  				Metadata: pkg.JavaMetadata{},
   326  			},
   327  			expects: nil,
   328  		},
   329  		{
   330  			name:    "no java info",
   331  			pkg:     pkg.Package{},
   332  			expects: nil,
   333  		},
   334  	}
   335  	for _, test := range tests {
   336  		t.Run(test.name, func(t *testing.T) {
   337  			assert.ElementsMatch(t, test.expects, GroupIDsFromJavaPackage(test.pkg))
   338  		})
   339  	}
   340  }
   341  
   342  func Test_artifactIDFromJavaPackage(t *testing.T) {
   343  	tests := []struct {
   344  		name    string
   345  		pkg     pkg.Package
   346  		expects string
   347  	}{
   348  		{
   349  			name: "go case",
   350  			pkg: pkg.Package{
   351  				Metadata: pkg.JavaMetadata{
   352  					PomProperties: &pkg.PomProperties{
   353  						ArtifactID: "cloudbees-installation-manager",
   354  					},
   355  				},
   356  			},
   357  			expects: "cloudbees-installation-manager",
   358  		},
   359  		{
   360  			name: "ignore groupID-like things",
   361  			pkg: pkg.Package{
   362  				Metadata: pkg.JavaMetadata{
   363  					PomProperties: &pkg.PomProperties{
   364  						ArtifactID: "io.jenkins-ci.plugin.thing",
   365  					},
   366  				},
   367  			},
   368  			expects: "",
   369  		},
   370  		{
   371  			name:    "no java info",
   372  			pkg:     pkg.Package{},
   373  			expects: "",
   374  		},
   375  	}
   376  	for _, test := range tests {
   377  		t.Run(test.name, func(t *testing.T) {
   378  			assert.Equal(t, test.expects, artifactIDFromJavaPackage(test.pkg))
   379  		})
   380  	}
   381  }
   382  
   383  func Test_vendorsFromJavaManifestNames(t *testing.T) {
   384  	tests := []struct {
   385  		name    string
   386  		pkg     pkg.Package
   387  		expects []string
   388  	}{
   389  		{
   390  			name: "from manifest named section fields",
   391  			pkg: pkg.Package{
   392  				Metadata: pkg.JavaMetadata{
   393  					Manifest: &pkg.JavaManifest{
   394  						NamedSections: map[string]map[string]string{
   395  							"section": {
   396  								// positive cases
   397  								"Specification-Vendor":  "Alex Goodman",
   398  								"Implementation-Vendor": "William Goodman",
   399  							},
   400  						},
   401  					},
   402  				},
   403  			},
   404  			expects: []string{"alex_goodman", "william_goodman"},
   405  		},
   406  		{
   407  			name: "from manifest named section fields - negative cases",
   408  			pkg: pkg.Package{
   409  				Metadata: pkg.JavaMetadata{
   410  					Manifest: &pkg.JavaManifest{
   411  						NamedSections: map[string]map[string]string{
   412  							"section": {
   413  								// negative cases
   414  								"Specification-Vendor":     "io.jenkins-ci.plugin.thing",
   415  								"Implementation-Vendor-ID": "William Goodman",
   416  							},
   417  						},
   418  					},
   419  				},
   420  			},
   421  			expects: nil,
   422  		},
   423  	}
   424  	for _, test := range tests {
   425  		t.Run(test.name, func(t *testing.T) {
   426  			assert.ElementsMatch(t, test.expects, vendorsFromJavaManifestNames(test.pkg).values())
   427  		})
   428  	}
   429  }