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  }