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 }