github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/formats/syftjson/model/package_test.go (about) 1 package model 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/anchore/syft/syft/license" 12 "github.com/anchore/syft/syft/pkg" 13 ) 14 15 func TestUnmarshalPackageGolang(t *testing.T) { 16 tests := []struct { 17 name string 18 packageData []byte 19 assert func(*Package) 20 }{ 21 { 22 name: "unmarshal package metadata", 23 packageData: []byte(`{ 24 "id": "8b594519bc23da50", 25 "name": "gopkg.in/square/go-jose.v2", 26 "version": "v2.6.0", 27 "type": "go-module", 28 "foundBy": "go-module-binary-cataloger", 29 "locations": [ 30 { 31 "path": "/Users/hal/go/bin/syft" 32 } 33 ], 34 "licenses": [ 35 { 36 "value": "MIT", 37 "spdxExpression": "MIT", 38 "type": "declared", 39 "url": [] 40 } 41 ], 42 "language": "go", 43 "cpes": [], 44 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0", 45 "metadataType": "GolangBinMetadata", 46 "metadata": { 47 "goCompiledVersion": "go1.18", 48 "architecture": "amd64", 49 "h1Digest": "h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=" 50 } 51 }`), 52 assert: func(p *Package) { 53 assert.NotNil(t, p.Metadata) 54 golangMetadata := p.Metadata.(pkg.GolangBinMetadata) 55 assert.NotEmpty(t, golangMetadata) 56 assert.Equal(t, "go1.18", golangMetadata.GoCompiledVersion) 57 }, 58 }, 59 { 60 name: "can handle package without metadata", 61 packageData: []byte(`{ 62 "id": "8b594519bc23da50", 63 "name": "gopkg.in/square/go-jose.v2", 64 "version": "v2.6.0", 65 "type": "go-module", 66 "foundBy": "go-mod-cataloger", 67 "locations": [ 68 { 69 "path": "/Users/hal/go/bin/syft" 70 } 71 ], 72 "licenses": [ 73 { 74 "value": "MIT", 75 "spdxExpression": "MIT", 76 "type": "declared", 77 "url": ["https://www.github.com"] 78 }, 79 { 80 "value": "MIT", 81 "spdxExpression": "MIT", 82 "type": "declared", 83 "locations": [{"path": "/Users/hal/go/bin/syft"}] 84 } 85 ], 86 "language": "go", 87 "cpes": [], 88 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0" 89 }`), 90 assert: func(p *Package) { 91 assert.Empty(t, p.MetadataType) 92 assert.Empty(t, p.Metadata) 93 }, 94 }, 95 { 96 name: "can handle package with []string licenses", 97 packageData: []byte(`{ 98 "id": "8b594519bc23da50", 99 "name": "gopkg.in/square/go-jose.v2", 100 "version": "v2.6.0", 101 "type": "go-module", 102 "foundBy": "go-mod-cataloger", 103 "locations": [ 104 { 105 "path": "/Users/hal/go/bin/syft" 106 } 107 ], 108 "licenses": ["MIT", "Apache-2.0"], 109 "language": "go", 110 "cpes": [], 111 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0" 112 }`), 113 assert: func(p *Package) { 114 assert.Equal(t, licenses{ 115 { 116 Value: "MIT", 117 SPDXExpression: "MIT", 118 Type: license.Declared, 119 }, 120 { 121 Value: "Apache-2.0", 122 SPDXExpression: "Apache-2.0", 123 Type: license.Declared, 124 }, 125 }, p.Licenses) 126 }, 127 }, 128 { 129 name: "can handle package with []pkg.License licenses", 130 packageData: []byte(`{ 131 "id": "8b594519bc23da50", 132 "name": "gopkg.in/square/go-jose.v2", 133 "version": "v2.6.0", 134 "type": "go-module", 135 "foundBy": "go-mod-cataloger", 136 "locations": [ 137 { 138 "path": "/Users/hal/go/bin/syft" 139 } 140 ], 141 "licenses": [ 142 { 143 "value": "MIT", 144 "spdxExpression": "MIT", 145 "type": "declared" 146 }, 147 { 148 "value": "Apache-2.0", 149 "spdxExpression": "Apache-2.0", 150 "type": "declared" 151 } 152 ], 153 "language": "go", 154 "cpes": [], 155 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0" 156 }`), 157 assert: func(p *Package) { 158 assert.Equal(t, licenses{ 159 { 160 Value: "MIT", 161 SPDXExpression: "MIT", 162 Type: license.Declared, 163 }, 164 { 165 Value: "Apache-2.0", 166 SPDXExpression: "Apache-2.0", 167 Type: license.Declared, 168 }, 169 }, p.Licenses) 170 }, 171 }, 172 } 173 174 for _, test := range tests { 175 t.Run(test.name, func(t *testing.T) { 176 p := &Package{} 177 err := p.UnmarshalJSON(test.packageData) 178 require.NoError(t, err) 179 test.assert(p) 180 }) 181 } 182 } 183 184 func Test_unpackMetadata(t *testing.T) { 185 tests := []struct { 186 name string 187 packageData []byte 188 metadataType pkg.MetadataType 189 wantMetadata interface{} 190 wantErr require.ErrorAssertionFunc 191 }{ 192 { 193 name: "unmarshal package metadata", 194 metadataType: pkg.GolangBinMetadataType, 195 packageData: []byte(`{ 196 "id": "8b594519bc23da50", 197 "name": "gopkg.in/square/go-jose.v2", 198 "version": "v2.6.0", 199 "type": "go-module", 200 "foundBy": "go-module-binary-cataloger", 201 "locations": [ 202 { 203 "path": "/Users/hal/go/bin/syft" 204 } 205 ], 206 "licenses": [], 207 "language": "go", 208 "cpes": [], 209 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0", 210 "metadataType": "GolangBinMetadata", 211 "metadata": { 212 "goCompiledVersion": "go1.18", 213 "architecture": "amd64", 214 "h1Digest": "h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=" 215 } 216 }`), 217 }, 218 { 219 name: "can handle package without metadata", 220 metadataType: "", 221 packageData: []byte(`{ 222 "id": "8b594519bc23da50", 223 "name": "gopkg.in/square/go-jose.v2", 224 "version": "v2.6.0", 225 "type": "go-module", 226 "foundBy": "go-mod-cataloger", 227 "locations": [ 228 { 229 "path": "/Users/hal/go/bin/syft" 230 } 231 ], 232 "licenses": [], 233 "language": "go", 234 "cpes": [], 235 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0" 236 }`), 237 }, 238 { 239 name: "can handle RpmdbMetadata", 240 metadataType: pkg.RpmMetadataType, 241 packageData: []byte(`{ 242 "id": "4ac699c3b8fe1835", 243 "name": "acl", 244 "version": "2.2.53-1.el8", 245 "type": "rpm", 246 "foundBy": "rpm-db-cataloger", 247 "locations": [ 248 { 249 "path": "/var/lib/rpm/Packages", 250 "layerID": "sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59" 251 } 252 ], 253 "language": "", 254 "cpes": [ 255 "cpe:2.3:a:centos:acl:2.2.53-1.el8:*:*:*:*:*:*:*", 256 "cpe:2.3:a:acl:acl:2.2.53-1.el8:*:*:*:*:*:*:*" 257 ], 258 "purl": "pkg:rpm/centos/acl@2.2.53-1.el8?arch=x86_64&upstream=acl-2.2.53-1.el8.src.rpm&distro=centos-8", 259 "metadataType": "RpmdbMetadata", 260 "metadata": { 261 "name": "acl", 262 "version": "2.2.53", 263 "epoch": null, 264 "architecture": "x86_64", 265 "release": "1.el8", 266 "sourceRpm": "acl-2.2.53-1.el8.src.rpm", 267 "size": 205740, 268 "license": "GPLv2+", 269 "vendor": "CentOS", 270 "modularityLabel": "" 271 } 272 }`), 273 }, 274 { 275 name: "bad metadata type is an error", 276 metadataType: "BOGOSITY", 277 wantErr: require.Error, 278 packageData: []byte(`{ 279 "id": "8b594519bc23da50", 280 "name": "gopkg.in/square/go-jose.v2", 281 "version": "v2.6.0", 282 "type": "go-module", 283 "foundBy": "go-mod-cataloger", 284 "locations": [ 285 { 286 "path": "/Users/hal/go/bin/syft" 287 } 288 ], 289 "licenses": [], 290 "language": "go", 291 "cpes": [], 292 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0", 293 "metadataType": "BOGOSITY" 294 }`), 295 }, 296 { 297 name: "unknown metadata type", 298 packageData: []byte(`{ 299 "metadataType": "NewMetadataType", 300 "metadata": { 301 "thing": "thing-1" 302 } 303 }`), 304 wantErr: require.Error, 305 metadataType: "NewMetadataType", 306 wantMetadata: map[string]interface{}{ 307 "thing": "thing-1", 308 }, 309 }, 310 { 311 name: "can handle package with metadata type but missing metadata", 312 packageData: []byte(`{ 313 "metadataType": "GolangBinMetadata" 314 }`), 315 metadataType: pkg.GolangBinMetadataType, 316 wantMetadata: pkg.GolangBinMetadata{}, 317 }, 318 { 319 name: "can handle package with golang bin metadata type", 320 packageData: []byte(`{ 321 "metadataType": "GolangBinMetadata" 322 }`), 323 metadataType: pkg.GolangBinMetadataType, 324 wantMetadata: pkg.GolangBinMetadata{}, 325 }, 326 { 327 name: "can handle package with unknonwn metadata type and missing metadata", 328 packageData: []byte(`{ 329 "metadataType": "BadMetadata" 330 }`), 331 wantErr: require.Error, 332 metadataType: "BadMetadata", 333 wantMetadata: nil, 334 }, 335 { 336 name: "can handle package with unknonwn metadata type and metadata", 337 packageData: []byte(`{ 338 "metadataType": "BadMetadata", 339 "metadata": { 340 "random": "thing" 341 } 342 }`), 343 wantErr: require.Error, 344 metadataType: "BadMetadata", 345 wantMetadata: map[string]interface{}{ 346 "random": "thing", 347 }, 348 }, 349 } 350 351 for _, test := range tests { 352 t.Run(test.name, func(t *testing.T) { 353 if test.wantErr == nil { 354 test.wantErr = require.NoError 355 } 356 p := &Package{} 357 358 var basic PackageBasicData 359 require.NoError(t, json.Unmarshal(test.packageData, &basic)) 360 p.PackageBasicData = basic 361 362 var unpacker packageMetadataUnpacker 363 require.NoError(t, json.Unmarshal(test.packageData, &unpacker)) 364 365 err := unpackPkgMetadata(p, unpacker) 366 assert.Equal(t, test.metadataType, p.MetadataType) 367 test.wantErr(t, err) 368 369 if test.wantMetadata != nil { 370 assert.True(t, reflect.DeepEqual(test.wantMetadata, p.Metadata)) 371 } 372 }) 373 } 374 }