github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/formats/gosbomjson/model/package_test.go (about)

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