github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/common/cpe/generate_test.go (about) 1 package cpe 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 "testing" 8 9 "github.com/scylladb/go-set" 10 "github.com/scylladb/go-set/strset" 11 "github.com/stretchr/testify/assert" 12 13 "github.com/anchore/syft/syft/cpe" 14 "github.com/anchore/syft/syft/pkg" 15 ) 16 17 func TestGeneratePackageCPEs(t *testing.T) { 18 tests := []struct { 19 name string 20 p pkg.Package 21 expected []string 22 }{ 23 { 24 name: "hyphen replacement", 25 p: pkg.Package{ 26 Name: "name-part", 27 Version: "3.2", 28 FoundBy: "some-analyzer", 29 Language: pkg.Python, 30 Type: pkg.DebPkg, 31 }, 32 expected: []string{ 33 "cpe:2.3:a:name-part:name-part:3.2:*:*:*:*:*:*:*", 34 "cpe:2.3:a:name-part:name_part:3.2:*:*:*:*:*:*:*", 35 "cpe:2.3:a:name-part:python-name-part:3.2:*:*:*:*:*:*:*", 36 "cpe:2.3:a:name-part:python_name_part:3.2:*:*:*:*:*:*:*", 37 "cpe:2.3:a:name:name-part:3.2:*:*:*:*:*:*:*", 38 "cpe:2.3:a:name:name_part:3.2:*:*:*:*:*:*:*", 39 "cpe:2.3:a:name:python-name-part:3.2:*:*:*:*:*:*:*", 40 "cpe:2.3:a:name:python_name_part:3.2:*:*:*:*:*:*:*", 41 "cpe:2.3:a:name_part:name-part:3.2:*:*:*:*:*:*:*", 42 "cpe:2.3:a:name_part:name_part:3.2:*:*:*:*:*:*:*", 43 "cpe:2.3:a:name_part:python-name-part:3.2:*:*:*:*:*:*:*", 44 "cpe:2.3:a:name_part:python_name_part:3.2:*:*:*:*:*:*:*", 45 "cpe:2.3:a:python-name-part:name-part:3.2:*:*:*:*:*:*:*", 46 "cpe:2.3:a:python-name-part:name_part:3.2:*:*:*:*:*:*:*", 47 "cpe:2.3:a:python-name-part:python-name-part:3.2:*:*:*:*:*:*:*", 48 "cpe:2.3:a:python-name-part:python_name_part:3.2:*:*:*:*:*:*:*", 49 "cpe:2.3:a:python-name:name-part:3.2:*:*:*:*:*:*:*", 50 "cpe:2.3:a:python-name:name_part:3.2:*:*:*:*:*:*:*", 51 "cpe:2.3:a:python-name:python-name-part:3.2:*:*:*:*:*:*:*", 52 "cpe:2.3:a:python-name:python_name_part:3.2:*:*:*:*:*:*:*", 53 "cpe:2.3:a:python:name-part:3.2:*:*:*:*:*:*:*", 54 "cpe:2.3:a:python:name_part:3.2:*:*:*:*:*:*:*", 55 "cpe:2.3:a:python:python-name-part:3.2:*:*:*:*:*:*:*", 56 "cpe:2.3:a:python:python_name_part:3.2:*:*:*:*:*:*:*", 57 "cpe:2.3:a:python_name:name-part:3.2:*:*:*:*:*:*:*", 58 "cpe:2.3:a:python_name:name_part:3.2:*:*:*:*:*:*:*", 59 "cpe:2.3:a:python_name:python-name-part:3.2:*:*:*:*:*:*:*", 60 "cpe:2.3:a:python_name:python_name_part:3.2:*:*:*:*:*:*:*", 61 "cpe:2.3:a:python_name_part:name-part:3.2:*:*:*:*:*:*:*", 62 "cpe:2.3:a:python_name_part:name_part:3.2:*:*:*:*:*:*:*", 63 "cpe:2.3:a:python_name_part:python-name-part:3.2:*:*:*:*:*:*:*", 64 "cpe:2.3:a:python_name_part:python_name_part:3.2:*:*:*:*:*:*:*", 65 }, 66 }, 67 { 68 name: "python language", 69 p: pkg.Package{ 70 Name: "name", 71 Version: "3.2", 72 FoundBy: "some-analyzer", 73 Language: pkg.Python, 74 Type: pkg.DebPkg, 75 MetadataType: pkg.PythonPackageMetadataType, 76 Metadata: pkg.PythonPackageMetadata{ 77 Author: "alex goodman", 78 AuthorEmail: "william.goodman@anchore.com", 79 }, 80 }, 81 expected: []string{ 82 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 83 "cpe:2.3:a:name:python-name:3.2:*:*:*:*:*:*:*", 84 "cpe:2.3:a:name:python_name:3.2:*:*:*:*:*:*:*", 85 "cpe:2.3:a:python-name:name:3.2:*:*:*:*:*:*:*", 86 "cpe:2.3:a:python-name:python-name:3.2:*:*:*:*:*:*:*", 87 "cpe:2.3:a:python-name:python_name:3.2:*:*:*:*:*:*:*", 88 "cpe:2.3:a:python:name:3.2:*:*:*:*:*:*:*", 89 "cpe:2.3:a:python:python-name:3.2:*:*:*:*:*:*:*", 90 "cpe:2.3:a:python:python_name:3.2:*:*:*:*:*:*:*", 91 "cpe:2.3:a:python_name:name:3.2:*:*:*:*:*:*:*", 92 "cpe:2.3:a:python_name:python-name:3.2:*:*:*:*:*:*:*", 93 "cpe:2.3:a:python_name:python_name:3.2:*:*:*:*:*:*:*", 94 "cpe:2.3:a:alex_goodman:name:3.2:*:*:*:*:*:*:*", 95 "cpe:2.3:a:alex_goodman:python-name:3.2:*:*:*:*:*:*:*", 96 "cpe:2.3:a:alex_goodman:python_name:3.2:*:*:*:*:*:*:*", 97 "cpe:2.3:a:william-goodman:name:3.2:*:*:*:*:*:*:*", 98 "cpe:2.3:a:william-goodman:python-name:3.2:*:*:*:*:*:*:*", 99 "cpe:2.3:a:william-goodman:python_name:3.2:*:*:*:*:*:*:*", 100 "cpe:2.3:a:william_goodman:name:3.2:*:*:*:*:*:*:*", 101 "cpe:2.3:a:william_goodman:python-name:3.2:*:*:*:*:*:*:*", 102 "cpe:2.3:a:william_goodman:python_name:3.2:*:*:*:*:*:*:*", 103 "cpe:2.3:a:alex_goodman_project:python_name:3.2:*:*:*:*:*:*:*", 104 "cpe:2.3:a:alex_goodman_project:name:3.2:*:*:*:*:*:*:*", 105 "cpe:2.3:a:alex_goodman_project:python-name:3.2:*:*:*:*:*:*:*", 106 "cpe:2.3:a:alex_goodmanproject:name:3.2:*:*:*:*:*:*:*", 107 "cpe:2.3:a:alex_goodmanproject:python-name:3.2:*:*:*:*:*:*:*", 108 "cpe:2.3:a:alex_goodmanproject:python_name:3.2:*:*:*:*:*:*:*", 109 "cpe:2.3:a:william_goodman_project:name:3.2:*:*:*:*:*:*:*", 110 "cpe:2.3:a:william_goodman_project:python-name:3.2:*:*:*:*:*:*:*", 111 "cpe:2.3:a:william_goodman_project:python_name:3.2:*:*:*:*:*:*:*", 112 "cpe:2.3:a:william_goodmanproject:name:3.2:*:*:*:*:*:*:*", 113 "cpe:2.3:a:william_goodmanproject:python-name:3.2:*:*:*:*:*:*:*", 114 "cpe:2.3:a:william_goodmanproject:python_name:3.2:*:*:*:*:*:*:*", 115 }, 116 }, 117 { 118 name: "javascript language", 119 p: pkg.Package{ 120 Name: "name", 121 Version: "3.2", 122 FoundBy: "some-analyzer", 123 Language: pkg.JavaScript, 124 MetadataType: pkg.NpmPackageJSONMetadataType, 125 Metadata: pkg.NpmPackageJSONMetadata{ 126 Author: "jon", 127 URL: "https://github.com/bob/npm-name", 128 }, 129 }, 130 expected: []string{ 131 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 132 "cpe:2.3:a:bob:name:3.2:*:*:*:*:*:*:*", 133 }, 134 }, 135 { 136 name: "ruby language", 137 p: pkg.Package{ 138 Name: "name", 139 Version: "3.2", 140 FoundBy: "some-analyzer", 141 Language: pkg.Ruby, 142 Type: pkg.DebPkg, 143 MetadataType: pkg.GemMetadataType, 144 Metadata: pkg.GemMetadata{ 145 Authors: []string{ 146 "someones name", 147 "someones.elses.name@gmail.com", 148 }, 149 Homepage: "https://github.com/tom/ruby-name", 150 }, 151 }, 152 expected: []string{ 153 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 154 "cpe:2.3:a:ruby-lang:name:3.2:*:*:*:*:*:*:*", 155 "cpe:2.3:a:ruby:name:3.2:*:*:*:*:*:*:*", 156 "cpe:2.3:a:ruby_lang:name:3.2:*:*:*:*:*:*:*", 157 "cpe:2.3:a:someones-elses-name:name:3.2:*:*:*:*:*:*:*", 158 "cpe:2.3:a:someones-name:name:3.2:*:*:*:*:*:*:*", 159 "cpe:2.3:a:someones_elses_name:name:3.2:*:*:*:*:*:*:*", 160 "cpe:2.3:a:someones_name:name:3.2:*:*:*:*:*:*:*", 161 "cpe:2.3:a:tom:name:3.2:*:*:*:*:*:*:*", 162 }, 163 }, 164 { 165 name: "java language", 166 p: pkg.Package{ 167 Name: "name", 168 Version: "3.2", 169 FoundBy: "some-analyzer", 170 Language: pkg.Java, 171 Type: pkg.JavaPkg, 172 }, 173 expected: []string{ 174 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 175 }, 176 }, 177 { 178 name: "java language with groupID", 179 p: pkg.Package{ 180 Name: "name", 181 Version: "3.2", 182 FoundBy: "some-analyzer", 183 Language: pkg.Java, 184 Type: pkg.JavaPkg, 185 MetadataType: pkg.JavaMetadataType, 186 Metadata: pkg.JavaMetadata{ 187 PomProperties: &pkg.PomProperties{ 188 GroupID: "org.sonatype.nexus", 189 }, 190 }, 191 }, 192 expected: []string{ 193 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 194 "cpe:2.3:a:name:nexus:3.2:*:*:*:*:*:*:*", 195 "cpe:2.3:a:nexus:name:3.2:*:*:*:*:*:*:*", 196 "cpe:2.3:a:nexus:nexus:3.2:*:*:*:*:*:*:*", 197 "cpe:2.3:a:sonatype:name:3.2:*:*:*:*:*:*:*", 198 "cpe:2.3:a:sonatype:nexus:3.2:*:*:*:*:*:*:*", 199 }, 200 }, 201 { 202 name: "java with URL in metadata", // regression: https://github.com/anchore/grype/issues/417 203 p: pkg.Package{ 204 Name: "wstx-asl", 205 Version: "3.2.7", 206 Type: pkg.JavaPkg, 207 MetadataType: pkg.JavaMetadataType, 208 Metadata: pkg.JavaMetadata{ 209 Manifest: &pkg.JavaManifest{ 210 Main: map[string]string{ 211 "Ant-Version": "Apache Ant 1.6.5", 212 "Built-By": "tatu", 213 "Created-By": "1.4.2_03-b02 (Sun Microsystems Inc.)", 214 "Implementation-Title": "WoodSToX XML-processor", 215 "Implementation-Vendor": "woodstox.codehaus.org", 216 "Implementation-Version": "3.2.7", 217 "Manifest-Version": "1.0", 218 "Specification-Title": "StAX 1.0 API", 219 "Specification-Vendor": "http://jcp.org/en/jsr/detail?id=173", 220 "Specification-Version": "1.0", 221 }, 222 }, 223 }, 224 }, 225 expected: []string{ 226 "cpe:2.3:a:woodstox_codehaus_org:wstx-asl:3.2.7:*:*:*:*:*:*:*", 227 "cpe:2.3:a:woodstox_codehaus_org:wstx_asl:3.2.7:*:*:*:*:*:*:*", 228 "cpe:2.3:a:woodstox-codehaus-org:wstx_asl:3.2.7:*:*:*:*:*:*:*", 229 "cpe:2.3:a:woodstox-codehaus-org:wstx-asl:3.2.7:*:*:*:*:*:*:*", 230 "cpe:2.3:a:wstx_asl:wstx-asl:3.2.7:*:*:*:*:*:*:*", 231 "cpe:2.3:a:wstx-asl:wstx-asl:3.2.7:*:*:*:*:*:*:*", 232 "cpe:2.3:a:wstx-asl:wstx_asl:3.2.7:*:*:*:*:*:*:*", 233 "cpe:2.3:a:wstx_asl:wstx_asl:3.2.7:*:*:*:*:*:*:*", 234 "cpe:2.3:a:wstx:wstx_asl:3.2.7:*:*:*:*:*:*:*", 235 "cpe:2.3:a:wstx:wstx-asl:3.2.7:*:*:*:*:*:*:*", 236 }, 237 }, 238 { 239 name: "jenkins package identified via pkg type", 240 p: pkg.Package{ 241 Name: "name", 242 Version: "3.2", 243 FoundBy: "some-analyzer", 244 Language: pkg.Java, 245 Type: pkg.JenkinsPluginPkg, 246 }, 247 expected: []string{ 248 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 249 }, 250 }, 251 { 252 name: "java language - multi tier manifest fields", 253 p: pkg.Package{ 254 Name: "cxf-rt-bindings-xml", 255 Version: "3.3.10", 256 FoundBy: "java-cataloger", 257 Language: pkg.Java, 258 Type: pkg.JavaPkg, 259 MetadataType: pkg.JavaMetadataType, 260 Metadata: pkg.JavaMetadata{ 261 VirtualPath: "/opt/jboss/keycloak/modules/system/layers/base/org/apache/cxf/impl/main/cxf-rt-bindings-xml-3.3.10.jar", 262 Manifest: &pkg.JavaManifest{ 263 Main: map[string]string{ 264 "Automatic-Module-Name": "org.apache.cxf.binding.xml", 265 "Bnd-LastModified": "1615836524860", 266 "Build-Jdk": "1.8.0_261", 267 "Built-By": "dkulp", 268 "Bundle-ActivationPolicy": "lazy", 269 "Bundle-Description": "Apache CXF Runtime XML Binding", 270 "Bundle-DocURL": "http://cxf.apache.org", 271 "Bundle-License": "https://www.apache.org/licenses/LICENSE-2.0.txt", 272 "Bundle-ManifestVersion": "2", 273 "Bundle-Name": "Apache CXF Runtime XML Binding", 274 "Bundle-SymbolicName": "org.apache.cxf.cxf-rt-bindings-xml", 275 "Bundle-Vendor": "The Apache Software Foundation", 276 "Bundle-Version": "3.3.10", 277 "Created-By": "Apache Maven Bundle Plugin", 278 "Export-Package": "org.apache.cxf.binding.xml;version=\"3.3.10\",org.apache.cxf.binding.xml.wsdl11;version=\"3.3.10\",org.apache.cxf.binding.xml.interceptor;version=\"3.3.10\",org.apache.cxf.bindings.xformat;version=\"3.3.10\"", 279 "Implementation-Vendor": "The Apache Software Foundation", 280 "Implementation-Vendor-Id": "org.apache", 281 "Implementation-Version": "3.3.10", 282 "Import-Package": "javax.xml.bind;version=\"[0,3)\",javax.xml.bind.annotation;version=\"[0,3)\",javax.wsdl;resolution:=optional,javax.wsdl.extensions;resolution:=optional,javax.wsdl.extensions.http;resolution:=optional,javax.xml.namespace,javax.xml.stream,org.apache.cxf;version=\"[3.3,4)\",org.apache.cxf.binding;version=\"[3.3,4)\",org.apache.cxf.binding.xml,org.apache.cxf.binding.xml.interceptor,org.apache.cxf.bindings.xformat,org.apache.cxf.common.i18n;version=\"[3.3,4)\",org.apache.cxf.common.injection;version=\"[3.3,4)\",org.apache.cxf.common.logging;version=\"[3.3,4)\",org.apache.cxf.common.util;version=\"[3.3,4)\",org.apache.cxf.endpoint;version=\"[3.3,4)\",org.apache.cxf.helpers;version=\"[3.3,4)\",org.apache.cxf.interceptor;version=\"[3.3,4)\",org.apache.cxf.message;version=\"[3.3,4)\",org.apache.cxf.service.model;version=\"[3.3,4)\",org.apache.cxf.staxutils;version=\"[3.3,4)\",org.apache.cxf.tools.common;version=\"[3.3,4)\";resolution:=optional,org.apache.cxf.tools.validator;version=\"[3.3,4)\";resolution:=optional,org.apache.cxf.transport;version=\"[3.3,4)\",org.apache.cxf.wsdl;version=\"[3.3,4)\";resolution:=optional,org.apache.cxf.wsdl.http;version=\"[3.3,4)\",org.apache.cxf.wsdl.interceptors;version=\"[3.3,4)\";resolution:=optional,org.w3c.dom", 283 "Manifest-Version": "1.0", 284 "Require-Capability": "osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=1.8))\"", 285 "Specification-Vendor": "The Apache Software Foundation", 286 "Specification-Version": "3.3.10", 287 "Tool": "Bnd-4.2.0.201903051501", 288 }, 289 }, 290 PomProperties: &pkg.PomProperties{ 291 Path: "META-INF/maven/org.apache.cxf/cxf-rt-bindings-xml/pom.properties", 292 GroupID: "org.apache.cxf", 293 ArtifactID: "cxf-rt-bindings-xml", 294 Version: "3.3.10", 295 }, 296 }, 297 }, 298 expected: []string{ 299 "cpe:2.3:a:apache:cxf-rt-bindings-xml:3.3.10:*:*:*:*:*:*:*", 300 "cpe:2.3:a:apache:cxf:3.3.10:*:*:*:*:*:*:*", 301 "cpe:2.3:a:apache:cxf_rt_bindings_xml:3.3.10:*:*:*:*:*:*:*", 302 }, 303 }, 304 { 305 name: "rpm vendor selection", 306 p: pkg.Package{ 307 Name: "name", 308 Version: "3.2", 309 FoundBy: "some-analyzer", 310 Type: pkg.RpmPkg, 311 MetadataType: pkg.RpmMetadataType, 312 Metadata: pkg.RpmMetadata{ 313 Vendor: "some-vendor", 314 }, 315 }, 316 expected: []string{ 317 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 318 "cpe:2.3:a:some-vendor:name:3.2:*:*:*:*:*:*:*", 319 "cpe:2.3:a:some_vendor:name:3.2:*:*:*:*:*:*:*", 320 }, 321 }, 322 { 323 name: "rpm with epoch", 324 p: pkg.Package{ 325 Name: "name", 326 Version: "1:3.2", 327 FoundBy: "some-analyzer", 328 Type: pkg.RpmPkg, 329 MetadataType: pkg.RpmMetadataType, 330 Metadata: pkg.RpmMetadata{ 331 Vendor: "some-vendor", 332 }, 333 }, 334 expected: []string{ 335 "cpe:2.3:a:name:name:1\\:3.2:*:*:*:*:*:*:*", 336 "cpe:2.3:a:some-vendor:name:1\\:3.2:*:*:*:*:*:*:*", 337 "cpe:2.3:a:some_vendor:name:1\\:3.2:*:*:*:*:*:*:*", 338 }, 339 }, 340 { 341 name: "deb with epoch", 342 p: pkg.Package{ 343 Name: "name", 344 Version: "1:3.2", 345 FoundBy: "some-analyzer", 346 Type: pkg.DebPkg, 347 MetadataType: pkg.DpkgMetadataType, 348 Metadata: pkg.DpkgMetadata{}, 349 }, 350 expected: []string{ 351 "cpe:2.3:a:name:name:1\\:3.2:*:*:*:*:*:*:*", 352 }, 353 }, 354 { 355 name: "cloudbees jenkins package identified via groupId", 356 p: pkg.Package{ 357 Name: "name", 358 Version: "3.2", 359 FoundBy: "some-analyzer", 360 Language: pkg.Java, 361 Type: pkg.JenkinsPluginPkg, 362 MetadataType: pkg.JavaMetadataType, 363 Metadata: pkg.JavaMetadata{ 364 PomProperties: &pkg.PomProperties{ 365 GroupID: "com.cloudbees.jenkins.plugins", 366 }, 367 }, 368 }, 369 expected: []string{ 370 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 371 "cpe:2.3:a:jenkins:name:3.2:*:*:*:*:*:*:*", 372 "cpe:2.3:a:cloudbees:name:3.2:*:*:*:*:*:*:*", 373 }, 374 }, 375 { 376 name: "jenkins.io package identified via groupId prefix", 377 p: pkg.Package{ 378 Name: "name", 379 Version: "3.2", 380 FoundBy: "some-analyzer", 381 Language: pkg.Java, 382 Type: pkg.JenkinsPluginPkg, 383 MetadataType: pkg.JavaMetadataType, 384 Metadata: pkg.JavaMetadata{ 385 PomProperties: &pkg.PomProperties{ 386 GroupID: "io.jenkins.plugins.name.something", 387 }, 388 }, 389 }, 390 expected: []string{ 391 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 392 "cpe:2.3:a:name:something:3.2:*:*:*:*:*:*:*", 393 "cpe:2.3:a:something:name:3.2:*:*:*:*:*:*:*", 394 "cpe:2.3:a:something:something:3.2:*:*:*:*:*:*:*", 395 "cpe:2.3:a:jenkins:name:3.2:*:*:*:*:*:*:*", 396 "cpe:2.3:a:jenkins:something:3.2:*:*:*:*:*:*:*", 397 }, 398 }, 399 { 400 name: "jenkins.io package identified via groupId", 401 p: pkg.Package{ 402 Name: "name", 403 Version: "3.2", 404 FoundBy: "some-analyzer", 405 Language: pkg.Java, 406 Type: pkg.JenkinsPluginPkg, 407 MetadataType: pkg.JavaMetadataType, 408 Metadata: pkg.JavaMetadata{ 409 PomProperties: &pkg.PomProperties{ 410 GroupID: "io.jenkins.plugins", 411 }, 412 }, 413 }, 414 expected: []string{ 415 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 416 "cpe:2.3:a:jenkins:name:3.2:*:*:*:*:*:*:*", 417 }, 418 }, 419 { 420 name: "jenkins-ci.io package identified via groupId", 421 p: pkg.Package{ 422 Name: "name", 423 Version: "3.2", 424 FoundBy: "some-analyzer", 425 Language: pkg.Java, 426 Type: pkg.JenkinsPluginPkg, 427 MetadataType: pkg.JavaMetadataType, 428 Metadata: pkg.JavaMetadata{ 429 PomProperties: &pkg.PomProperties{ 430 GroupID: "io.jenkins-ci.plugins", 431 }, 432 }, 433 }, 434 expected: []string{ 435 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 436 "cpe:2.3:a:jenkins-ci:name:3.2:*:*:*:*:*:*:*", 437 "cpe:2.3:a:jenkins:name:3.2:*:*:*:*:*:*:*", 438 "cpe:2.3:a:jenkins_ci:name:3.2:*:*:*:*:*:*:*", 439 }, 440 }, 441 { 442 name: "jenkins-ci.org package identified via groupId", 443 p: pkg.Package{ 444 Name: "name", 445 Version: "3.2", 446 FoundBy: "some-analyzer", 447 Language: pkg.Java, 448 Type: pkg.JenkinsPluginPkg, 449 MetadataType: pkg.JavaMetadataType, 450 Metadata: pkg.JavaMetadata{ 451 PomProperties: &pkg.PomProperties{ 452 GroupID: "org.jenkins-ci.plugins", 453 }, 454 }, 455 }, 456 expected: []string{ 457 "cpe:2.3:a:name:name:3.2:*:*:*:*:*:*:*", 458 "cpe:2.3:a:jenkins-ci:name:3.2:*:*:*:*:*:*:*", 459 "cpe:2.3:a:jenkins:name:3.2:*:*:*:*:*:*:*", 460 "cpe:2.3:a:jenkins_ci:name:3.2:*:*:*:*:*:*:*", 461 }, 462 }, 463 { 464 name: "jira-atlassian filtering", 465 p: pkg.Package{ 466 Name: "jira_client_core", 467 Version: "3.2", 468 FoundBy: "some-analyzer", 469 Language: pkg.Java, 470 Type: pkg.JavaPkg, 471 MetadataType: pkg.JavaMetadataType, 472 Metadata: pkg.JavaMetadata{ 473 PomProperties: &pkg.PomProperties{ 474 GroupID: "org.atlassian.jira", 475 ArtifactID: "jira_client_core", 476 }, 477 }, 478 }, 479 expected: []string{ 480 "cpe:2.3:a:atlassian:jira-client-core:3.2:*:*:*:*:*:*:*", 481 "cpe:2.3:a:atlassian:jira_client_core:3.2:*:*:*:*:*:*:*", 482 "cpe:2.3:a:jira-client-core:jira-client-core:3.2:*:*:*:*:*:*:*", 483 "cpe:2.3:a:jira-client-core:jira:3.2:*:*:*:*:*:*:*", 484 "cpe:2.3:a:jira-client-core:jira_client_core:3.2:*:*:*:*:*:*:*", 485 "cpe:2.3:a:jira-client:jira-client-core:3.2:*:*:*:*:*:*:*", 486 "cpe:2.3:a:jira-client:jira:3.2:*:*:*:*:*:*:*", 487 "cpe:2.3:a:jira-client:jira_client_core:3.2:*:*:*:*:*:*:*", 488 "cpe:2.3:a:jira:jira-client-core:3.2:*:*:*:*:*:*:*", 489 "cpe:2.3:a:jira:jira_client_core:3.2:*:*:*:*:*:*:*", 490 "cpe:2.3:a:jira_client:jira-client-core:3.2:*:*:*:*:*:*:*", 491 "cpe:2.3:a:jira_client:jira:3.2:*:*:*:*:*:*:*", 492 "cpe:2.3:a:jira_client:jira_client_core:3.2:*:*:*:*:*:*:*", 493 "cpe:2.3:a:jira_client_core:jira-client-core:3.2:*:*:*:*:*:*:*", 494 "cpe:2.3:a:jira_client_core:jira:3.2:*:*:*:*:*:*:*", 495 "cpe:2.3:a:jira_client_core:jira_client_core:3.2:*:*:*:*:*:*:*", 496 }, 497 }, 498 { 499 name: "jenkins filtering", 500 p: pkg.Package{ 501 Name: "cloudbees-installation-manager", 502 Version: "2.89.0.33", 503 FoundBy: "some-analyzer", 504 Language: pkg.Java, 505 Type: pkg.JavaPkg, 506 MetadataType: pkg.JavaMetadataType, 507 Metadata: pkg.JavaMetadata{ 508 PomProperties: &pkg.PomProperties{ 509 GroupID: "com.cloudbees.jenkins.modules", 510 ArtifactID: "cloudbees-installation-manager", 511 }, 512 }, 513 }, 514 expected: []string{ 515 "cpe:2.3:a:cloudbees-installation-manager:cloudbees-installation-manager:2.89.0.33:*:*:*:*:*:*:*", 516 "cpe:2.3:a:cloudbees-installation-manager:cloudbees_installation_manager:2.89.0.33:*:*:*:*:*:*:*", 517 "cpe:2.3:a:cloudbees-installation:cloudbees-installation-manager:2.89.0.33:*:*:*:*:*:*:*", 518 "cpe:2.3:a:cloudbees-installation:cloudbees_installation_manager:2.89.0.33:*:*:*:*:*:*:*", 519 "cpe:2.3:a:cloudbees:cloudbees-installation-manager:2.89.0.33:*:*:*:*:*:*:*", 520 "cpe:2.3:a:cloudbees:cloudbees_installation_manager:2.89.0.33:*:*:*:*:*:*:*", 521 "cpe:2.3:a:cloudbees_installation:cloudbees-installation-manager:2.89.0.33:*:*:*:*:*:*:*", 522 "cpe:2.3:a:cloudbees_installation:cloudbees_installation_manager:2.89.0.33:*:*:*:*:*:*:*", 523 "cpe:2.3:a:cloudbees_installation_manager:cloudbees-installation-manager:2.89.0.33:*:*:*:*:*:*:*", 524 "cpe:2.3:a:cloudbees_installation_manager:cloudbees_installation_manager:2.89.0.33:*:*:*:*:*:*:*", 525 "cpe:2.3:a:jenkins:cloudbees-installation-manager:2.89.0.33:*:*:*:*:*:*:*", 526 "cpe:2.3:a:jenkins:cloudbees_installation_manager:2.89.0.33:*:*:*:*:*:*:*", 527 "cpe:2.3:a:modules:cloudbees-installation-manager:2.89.0.33:*:*:*:*:*:*:*", 528 "cpe:2.3:a:modules:cloudbees_installation_manager:2.89.0.33:*:*:*:*:*:*:*", 529 }, 530 }, 531 { 532 name: "go product and vendor candidates are wired up", 533 p: pkg.Package{ 534 Name: "github.com/someone/something", 535 Version: "3.2", 536 FoundBy: "go-cataloger", 537 Language: pkg.Go, 538 Type: pkg.GoModulePkg, 539 }, 540 expected: []string{ 541 "cpe:2.3:a:someone:something:3.2:*:*:*:*:*:*:*", 542 }, 543 }, 544 { 545 name: "go product with vendor candidates and an extra sub-item", 546 p: pkg.Package{ 547 Name: "github.com/someone/something/more", 548 Version: "3.2", 549 FoundBy: "go-cataloger", 550 Language: pkg.Go, 551 Type: pkg.GoModulePkg, 552 }, 553 expected: []string{ 554 "cpe:2.3:a:someone:something\\/more:3.2:*:*:*:*:*:*:*", 555 }, 556 }, 557 { 558 name: "generate no CPEs for indeterminate golang package name", 559 p: pkg.Package{ 560 Name: "github.com/what", 561 Version: "3.2", 562 FoundBy: "go-cataloger", 563 Language: pkg.Go, 564 Type: pkg.GoModulePkg, 565 }, 566 expected: []string{}, 567 }, 568 { 569 name: "regression: handlebars within java archive", 570 p: pkg.Package{ 571 Name: "handlebars", 572 Version: "3.0.8", 573 Type: pkg.JavaPkg, 574 Language: pkg.Java, 575 FoundBy: "java-cataloger", 576 MetadataType: pkg.JavaMetadataType, 577 Metadata: pkg.JavaMetadata{ 578 Manifest: &pkg.JavaManifest{ 579 Main: map[string]string{ 580 "Extension-Name": "handlebars", 581 "Group-Id": "org.jenkins-ci.ui", 582 "Hudson-Version": "2.204", 583 "Implementation-Title": "handlebars", 584 "Implementation-Version": "3.0.8", 585 "Plugin-Version": "3.0.8", 586 "Short-Name": "handlebars", 587 }, 588 }, 589 PomProperties: &pkg.PomProperties{ 590 GroupID: "org.jenkins-ci.ui", 591 ArtifactID: "handlebars", 592 Version: "3.0.8", 593 }, 594 }, 595 }, 596 expected: []string{ 597 "cpe:2.3:a:handlebars:handlebars:3.0.8:*:*:*:*:*:*:*", 598 "cpe:2.3:a:handlebarsjs:handlebars:3.0.8:*:*:*:*:*:*:*", // important! 599 "cpe:2.3:a:jenkins-ci:handlebars:3.0.8:*:*:*:*:*:*:*", 600 "cpe:2.3:a:jenkins:handlebars:3.0.8:*:*:*:*:*:*:*", 601 "cpe:2.3:a:jenkins_ci:handlebars:3.0.8:*:*:*:*:*:*:*", 602 "cpe:2.3:a:ui:handlebars:3.0.8:*:*:*:*:*:*:*", 603 }, 604 }, 605 { 606 name: "regression: jenkins plugin active-directory", 607 p: pkg.Package{ 608 Name: "active-directory", 609 Version: "2.25.1", 610 Type: pkg.JenkinsPluginPkg, 611 FoundBy: "java-cataloger", 612 Language: pkg.Java, 613 MetadataType: pkg.JavaMetadataType, 614 Metadata: pkg.JavaMetadata{ 615 Manifest: &pkg.JavaManifest{ 616 Main: map[string]string{ 617 "Extension-Name": "active-directory", 618 "Group-Id": "org.jenkins-ci.plugins", 619 }, 620 }, 621 PomProperties: &pkg.PomProperties{ 622 GroupID: "org.jenkins-ci.plugins", 623 ArtifactID: "org.jenkins-ci.plugins", 624 Version: "2.25.1", 625 }, 626 }, 627 }, 628 expected: []string{ 629 "cpe:2.3:a:active-directory:active-directory:2.25.1:*:*:*:*:*:*:*", 630 "cpe:2.3:a:active-directory:active_directory:2.25.1:*:*:*:*:*:*:*", 631 "cpe:2.3:a:active:active-directory:2.25.1:*:*:*:*:*:*:*", 632 "cpe:2.3:a:active:active_directory:2.25.1:*:*:*:*:*:*:*", 633 "cpe:2.3:a:active_directory:active-directory:2.25.1:*:*:*:*:*:*:*", 634 "cpe:2.3:a:active_directory:active_directory:2.25.1:*:*:*:*:*:*:*", 635 "cpe:2.3:a:jenkins-ci:active-directory:2.25.1:*:*:*:*:*:*:*", 636 "cpe:2.3:a:jenkins-ci:active_directory:2.25.1:*:*:*:*:*:*:*", 637 "cpe:2.3:a:jenkins:active-directory:2.25.1:*:*:*:*:*:*:*", // important! 638 "cpe:2.3:a:jenkins:active_directory:2.25.1:*:*:*:*:*:*:*", // important! 639 "cpe:2.3:a:jenkins_ci:active-directory:2.25.1:*:*:*:*:*:*:*", 640 "cpe:2.3:a:jenkins_ci:active_directory:2.25.1:*:*:*:*:*:*:*", 641 }, 642 }, 643 { 644 name: "regression: special characters in CPE should result in no generation", 645 p: pkg.Package{ 646 Name: "bundler", 647 Version: "2.1.4", 648 Type: pkg.GemPkg, 649 FoundBy: "gem-cataloger", 650 Language: pkg.Ruby, 651 MetadataType: pkg.GemMetadataType, 652 Metadata: pkg.GemMetadata{ 653 Name: "bundler", 654 Version: "2.1.4", 655 Authors: []string{ 656 "jessica lynn suttles", 657 "stephanie morillo", 658 "david rodrÃguez", 659 "andré medeiros", 660 }, 661 }, 662 }, 663 expected: []string{ 664 "cpe:2.3:a:bundler:bundler:2.1.4:*:*:*:*:*:*:*", 665 "cpe:2.3:a:ruby-lang:bundler:2.1.4:*:*:*:*:*:*:*", 666 "cpe:2.3:a:ruby:bundler:2.1.4:*:*:*:*:*:*:*", 667 "cpe:2.3:a:ruby_lang:bundler:2.1.4:*:*:*:*:*:*:*", 668 "cpe:2.3:a:jessica-lynn-suttles:bundler:2.1.4:*:*:*:*:*:*:*", 669 "cpe:2.3:a:jessica_lynn_suttles:bundler:2.1.4:*:*:*:*:*:*:*", 670 "cpe:2.3:a:stephanie-morillo:bundler:2.1.4:*:*:*:*:*:*:*", 671 "cpe:2.3:a:stephanie_morillo:bundler:2.1.4:*:*:*:*:*:*:*", 672 }, 673 }, 674 { 675 name: "regression: python redis shadows normal redis", 676 p: pkg.Package{ 677 Name: "redis", 678 Version: "2.1.4", 679 Type: pkg.PythonPkg, 680 FoundBy: "some-analyzer", 681 Language: pkg.Python, 682 }, 683 expected: []string{ 684 "cpe:2.3:a:python-redis:python-redis:2.1.4:*:*:*:*:*:*:*", 685 "cpe:2.3:a:python-redis:python_redis:2.1.4:*:*:*:*:*:*:*", 686 "cpe:2.3:a:python-redis:redis:2.1.4:*:*:*:*:*:*:*", 687 "cpe:2.3:a:python:python-redis:2.1.4:*:*:*:*:*:*:*", 688 "cpe:2.3:a:python:python_redis:2.1.4:*:*:*:*:*:*:*", 689 "cpe:2.3:a:python:redis:2.1.4:*:*:*:*:*:*:*", 690 "cpe:2.3:a:python_redis:python-redis:2.1.4:*:*:*:*:*:*:*", 691 "cpe:2.3:a:python_redis:python_redis:2.1.4:*:*:*:*:*:*:*", 692 "cpe:2.3:a:python_redis:redis:2.1.4:*:*:*:*:*:*:*", 693 }, 694 }, 695 { 696 name: "regression: ruby-rake apk missing expected ruby-lang:rake CPE", 697 p: pkg.Package{ 698 Name: "ruby-rake", 699 Version: "2.7.6-r0", 700 Type: pkg.ApkPkg, 701 FoundBy: "apk-db-analyzer", 702 Language: pkg.UnknownLanguage, 703 MetadataType: pkg.ApkMetadataType, 704 Metadata: pkg.ApkMetadata{ 705 Package: "ruby-rake", 706 URL: "https://www.ruby-lang.org/", 707 OriginPackage: "ruby", 708 }, 709 }, 710 expected: []string{ 711 "cpe:2.3:a:ruby-lang:rake:2.7.6-r0:*:*:*:*:*:*:*", 712 "cpe:2.3:a:rake:rake:2.7.6-r0:*:*:*:*:*:*:*", 713 "cpe:2.3:a:rake:ruby-rake:2.7.6-r0:*:*:*:*:*:*:*", 714 "cpe:2.3:a:rake:ruby_rake:2.7.6-r0:*:*:*:*:*:*:*", 715 "cpe:2.3:a:ruby-lang:ruby-rake:2.7.6-r0:*:*:*:*:*:*:*", 716 "cpe:2.3:a:ruby-lang:ruby_rake:2.7.6-r0:*:*:*:*:*:*:*", 717 "cpe:2.3:a:ruby-rake:rake:2.7.6-r0:*:*:*:*:*:*:*", 718 "cpe:2.3:a:ruby-rake:ruby-rake:2.7.6-r0:*:*:*:*:*:*:*", 719 "cpe:2.3:a:ruby-rake:ruby_rake:2.7.6-r0:*:*:*:*:*:*:*", 720 "cpe:2.3:a:ruby:rake:2.7.6-r0:*:*:*:*:*:*:*", 721 "cpe:2.3:a:ruby:ruby-rake:2.7.6-r0:*:*:*:*:*:*:*", 722 "cpe:2.3:a:ruby:ruby_rake:2.7.6-r0:*:*:*:*:*:*:*", 723 "cpe:2.3:a:ruby_lang:rake:2.7.6-r0:*:*:*:*:*:*:*", 724 "cpe:2.3:a:ruby_lang:ruby-rake:2.7.6-r0:*:*:*:*:*:*:*", 725 "cpe:2.3:a:ruby_lang:ruby_rake:2.7.6-r0:*:*:*:*:*:*:*", 726 "cpe:2.3:a:ruby_rake:rake:2.7.6-r0:*:*:*:*:*:*:*", 727 "cpe:2.3:a:ruby_rake:ruby-rake:2.7.6-r0:*:*:*:*:*:*:*", 728 "cpe:2.3:a:ruby_rake:ruby_rake:2.7.6-r0:*:*:*:*:*:*:*", 729 }, 730 }, 731 } 732 733 for _, test := range tests { 734 t.Run(test.name, func(t *testing.T) { 735 actual := Generate(test.p) 736 737 expectedCpeSet := set.NewStringSet(test.expected...) 738 actualCpeSet := set.NewStringSet() 739 for _, a := range actual { 740 actualCpeSet.Add(cpe.String(a)) 741 } 742 743 extra := strset.Difference(actualCpeSet, expectedCpeSet).List() 744 sort.Strings(extra) 745 if len(extra) > 0 { 746 t.Errorf("found extra CPEs:") 747 } 748 for _, d := range extra { 749 fmt.Printf(" %q,\n", d) 750 } 751 752 missing := strset.Difference(expectedCpeSet, actualCpeSet).List() 753 sort.Strings(missing) 754 if len(missing) > 0 { 755 t.Errorf("missing CPEs:") 756 } 757 for _, d := range missing { 758 fmt.Printf(" %q,\n", d) 759 } 760 }) 761 } 762 } 763 764 func TestCandidateProducts(t *testing.T) { 765 tests := []struct { 766 name string 767 p pkg.Package 768 expected []string 769 }{ 770 { 771 name: "apache-cassandra", 772 p: pkg.Package{ 773 Name: "apache-cassandra", 774 Type: pkg.JavaPkg, 775 }, 776 expected: []string{"cassandra" /* <-- known good names | default guess --> */, "apache-cassandra", "apache_cassandra"}, 777 }, 778 { 779 name: "springframework", 780 p: pkg.Package{ 781 Name: "springframework", 782 Type: pkg.JavaPkg, 783 }, 784 expected: []string{"spring_framework", "springsource_spring_framework" /* <-- known good names | default guess --> */, "springframework"}, 785 }, 786 { 787 name: "spring-security-core", 788 p: pkg.Package{ 789 Name: "spring-security-core", 790 Type: pkg.JavaPkg, 791 }, 792 expected: []string{"spring-security-core", "spring_security", "spring_security_core"}, 793 }, 794 { 795 name: "java", 796 p: pkg.Package{ 797 Name: "some-java-package-with-group-id", 798 Type: pkg.JavaPkg, 799 Language: pkg.Java, 800 Metadata: pkg.JavaMetadata{ 801 PomProperties: &pkg.PomProperties{ 802 GroupID: "com.apple.itunes", 803 }, 804 }, 805 }, 806 expected: []string{"itunes", "some-java-package-with-group-id", "some_java_package_with_group_id"}, 807 }, 808 { 809 name: "java-with-asterisk", 810 p: pkg.Package{ 811 Name: "some-java-package-with-group-id", 812 Type: pkg.JavaPkg, 813 Language: pkg.Java, 814 Metadata: pkg.JavaMetadata{ 815 PomProperties: &pkg.PomProperties{ 816 GroupID: "com.apple.itunes.*", 817 }, 818 }, 819 }, 820 expected: []string{"itunes", "some-java-package-with-group-id", "some_java_package_with_group_id"}, 821 }, 822 { 823 name: "jenkins-plugin", 824 p: pkg.Package{ 825 Name: "some-jenkins-plugin", 826 Type: pkg.JenkinsPluginPkg, 827 Language: pkg.Java, 828 Metadata: pkg.JavaMetadata{ 829 PomProperties: &pkg.PomProperties{ 830 GroupID: "com.cloudbees.jenkins.plugins", 831 }, 832 }, 833 }, 834 expected: []string{"some-jenkins-plugin", "some_jenkins_plugin", "jenkins"}, 835 }, 836 { 837 name: "javascript", 838 p: pkg.Package{ 839 Name: "handlebars.js", 840 Type: pkg.NpmPkg, 841 }, 842 expected: []string{"handlebars" /* <-- known good names | default guess --> */, "handlebars.js"}, 843 }, 844 { 845 name: "gem", 846 p: pkg.Package{ 847 Name: "RedCloth", 848 Type: pkg.GemPkg, 849 }, 850 expected: []string{"redcloth_library" /* <-- known good names | default guess --> */, "RedCloth"}, 851 }, 852 { 853 name: "python", 854 p: pkg.Package{ 855 Name: "python-rrdtool", 856 Type: pkg.PythonPkg, 857 }, 858 expected: []string{"rrdtool" /* <-- known good names | default guess --> */, "python-rrdtool", "python_rrdtool"}, 859 }, 860 } 861 862 for _, test := range tests { 863 t.Run(test.name, func(t *testing.T) { 864 assert.ElementsMatch(t, test.expected, candidateProducts(test.p)) 865 }) 866 } 867 } 868 869 func TestCandidateVendor(t *testing.T) { 870 tests := []struct { 871 name string 872 p pkg.Package 873 expected []string 874 }{ 875 { 876 name: "elasticsearch", 877 p: pkg.Package{ 878 Name: "elasticsearch", 879 Type: pkg.JavaPkg, 880 }, 881 expected: []string{"elastic" /* <-- known good names | default guess --> */, "elasticsearch"}, 882 }, 883 { 884 name: "spring-security", 885 p: pkg.Package{ 886 Name: "spring-security-core", 887 Type: pkg.JavaPkg, 888 }, 889 expected: []string{"vmware" /* <-- known good names | default guess --> */, "spring", "spring-security", "spring-security-core", "spring_security_core", "spring_security"}, 890 }, 891 { 892 name: "log4j", 893 p: pkg.Package{ 894 Name: "log4j", 895 Type: pkg.JavaPkg, 896 }, 897 expected: []string{"apache"}, 898 }, 899 { 900 name: "Django", 901 p: pkg.Package{ 902 Name: "Django", 903 Type: pkg.PythonPkg, 904 }, 905 expected: []string{"djangoproject" /* <-- known good names | default guess --> */, "Django"}, 906 }, 907 } 908 909 for _, test := range tests { 910 t.Run(fmt.Sprintf("%+v %+v", test.p, test.expected), func(t *testing.T) { 911 assert.ElementsMatch(t, test.expected, candidateVendors(test.p)) 912 }) 913 } 914 } 915 916 func Test_generateSubSelections(t *testing.T) { 917 tests := []struct { 918 field string 919 expected []string 920 }{ 921 { 922 field: "jenkins", 923 expected: []string{"jenkins"}, 924 }, 925 { 926 field: "jenkins-ci", 927 expected: []string{"jenkins", "jenkins-ci"}, 928 }, 929 { 930 field: "jenkins--ci", 931 expected: []string{"jenkins", "jenkins-ci"}, 932 }, 933 { 934 field: "jenkins_ci_tools", 935 expected: []string{"jenkins", "jenkins_ci", "jenkins_ci_tools"}, 936 }, 937 { 938 field: "-jenkins", 939 expected: []string{"jenkins"}, 940 }, 941 { 942 field: "jenkins_", 943 expected: []string{"jenkins"}, 944 }, 945 { 946 field: "", 947 expected: nil, 948 }, 949 { 950 field: "-", 951 expected: nil, 952 }, 953 { 954 field: "_", 955 expected: nil, 956 }, 957 } 958 for _, test := range tests { 959 t.Run(test.field, func(t *testing.T) { 960 assert.ElementsMatch(t, test.expected, generateSubSelections(test.field)) 961 }) 962 } 963 } 964 965 func Test_addSeparatorVariations(t *testing.T) { 966 tests := []struct { 967 input []string 968 expected []string 969 }{ 970 { 971 input: []string{"jenkins-ci"}, 972 expected: []string{"jenkins-ci", "jenkins_ci"}, //, "jenkinsci"}, 973 }, 974 { 975 input: []string{"jenkins_ci"}, 976 expected: []string{"jenkins_ci", "jenkins-ci"}, //, "jenkinsci"}, 977 }, 978 { 979 input: []string{"jenkins"}, 980 expected: []string{"jenkins"}, 981 }, 982 { 983 input: []string{"jenkins-ci", "circle-ci"}, 984 expected: []string{"jenkins-ci", "jenkins_ci", "circle-ci", "circle_ci"}, //, "jenkinsci", "circleci"}, 985 }, 986 } 987 for _, test := range tests { 988 t.Run(strings.Join(test.input, ","), func(t *testing.T) { 989 val := newFieldCandidateSet(test.input...) 990 addDelimiterVariations(val) 991 assert.ElementsMatch(t, test.expected, val.values()) 992 }) 993 } 994 } 995 996 func TestDictionaryFindIsWired(t *testing.T) { 997 998 tests := []struct { 999 name string 1000 pkg pkg.Package 1001 want string 1002 wantExists bool 1003 }{ 1004 { 1005 name: "sanity check that cpe data is wired up", 1006 pkg: pkg.Package{ 1007 Name: "openssl", 1008 Version: "1.0.2k", 1009 Type: pkg.GemPkg, 1010 }, 1011 want: "cpe:2.3:a:ruby-lang:openssl:1.0.2k:*:*:*:*:*:*:*", 1012 // without the cpe data wired up, this would be empty (generation also creates cpe:2.3:a:openssl:openssl:1.0.2k:*:*:*:*:*:*:*) 1013 wantExists: true, 1014 }, 1015 } 1016 for _, tt := range tests { 1017 t.Run(tt.name, func(t *testing.T) { 1018 got, gotExists := DictionaryFind(tt.pkg) 1019 1020 assert.Equal(t, tt.want, got.BindToFmtString()) 1021 assert.Equal(t, tt.wantExists, gotExists) 1022 }) 1023 } 1024 }