github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/format/common/spdxhelpers/to_syft_model_test.go (about)

     1  package spdxhelpers
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/google/go-cmp/cmp/cmpopts"
     9  	"github.com/spdx/tools-golang/spdx"
    10  	"github.com/spdx/tools-golang/spdx/v2/common"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/anchore/packageurl-go"
    15  	"github.com/anchore/syft/syft/artifact"
    16  	"github.com/anchore/syft/syft/file"
    17  	"github.com/anchore/syft/syft/pkg"
    18  	"github.com/anchore/syft/syft/sbom"
    19  	"github.com/anchore/syft/syft/source"
    20  )
    21  
    22  func TestToSyftModel(t *testing.T) {
    23  	sbom, err := ToSyftModel(&spdx.Document{
    24  		SPDXVersion:                "1",
    25  		DataLicense:                "GPL",
    26  		SPDXIdentifier:             "id-doc-1",
    27  		DocumentName:               "docName",
    28  		DocumentNamespace:          "docNamespace",
    29  		ExternalDocumentReferences: nil,
    30  		DocumentComment:            "",
    31  		CreationInfo: &spdx.CreationInfo{
    32  			LicenseListVersion: "",
    33  			Created:            "",
    34  			CreatorComment:     "",
    35  		},
    36  		Packages: []*spdx.Package{
    37  			{
    38  				PackageName:            "pkg-1",
    39  				PackageSPDXIdentifier:  "id-pkg-1",
    40  				PackageVersion:         "5.4.3",
    41  				PackageLicenseDeclared: "",
    42  				PackageDescription:     "",
    43  				PackageExternalReferences: []*spdx.PackageExternalReference{
    44  					{
    45  						Category: "SECURITY",
    46  						Locator:  "cpe:2.3:a:pkg-1:pkg-1:5.4.3:*:*:*:*:*:*:*",
    47  						RefType:  "cpe23Type",
    48  					},
    49  					{
    50  						Category: "SECURITY",
    51  						Locator:  "cpe:2.3:a:pkg_1:pkg_1:5.4.3:*:*:*:*:*:*:*",
    52  						RefType:  "cpe23Type",
    53  					},
    54  					{
    55  						Category: "PACKAGE-MANAGER",
    56  						Locator:  "pkg:apk/alpine/pkg-1@5.4.3?arch=x86_64&upstream=p1-origin&distro=alpine-3.10.9",
    57  						RefType:  "purl",
    58  					},
    59  				},
    60  				Files: nil,
    61  			},
    62  			{
    63  				PackageName:            "pkg-2",
    64  				PackageSPDXIdentifier:  "id-pkg-2",
    65  				PackageVersion:         "7.3.1",
    66  				PackageLicenseDeclared: "",
    67  				PackageDescription:     "",
    68  				PackageExternalReferences: []*spdx.PackageExternalReference{
    69  					{
    70  						Category: "SECURITY",
    71  						Locator:  "cpe:2.3:a:pkg-2:pkg-2:7.3.1:*:*:*:*:*:*:*",
    72  						RefType:  "cpe23Type",
    73  					},
    74  					{
    75  						Category: "SECURITY",
    76  						Locator:  "cpe:2.3:a:pkg_2:pkg_2:7.3.1:*:*:*:*:*:*:*",
    77  						RefType:  "cpe23Type",
    78  					},
    79  					{
    80  						Category: "SECURITY",
    81  						Locator:  "cpe:2.3:a:pkg-2:pkg_2:7.3.1:*:*:*:*:*:*:*",
    82  						RefType:  "cpe23Type",
    83  					},
    84  					{
    85  						Category: "PACKAGE-MANAGER",
    86  						Locator:  "pkg:deb/pkg-2@7.3.1?arch=x86_64&upstream=p2-origin@9.1.3&distro=debian-3.10.9",
    87  						RefType:  "purl",
    88  					},
    89  				},
    90  				Files: nil,
    91  			},
    92  		},
    93  		Relationships: []*spdx.Relationship{},
    94  	})
    95  
    96  	assert.NoError(t, err)
    97  
    98  	assert.NotNil(t, sbom)
    99  
   100  	pkgs := sbom.Artifacts.Packages.Sorted()
   101  
   102  	assert.Len(t, pkgs, 2)
   103  
   104  	p1 := pkgs[0]
   105  	assert.Equal(t, p1.Name, "pkg-1")
   106  	p1meta := p1.Metadata.(pkg.ApkDBEntry)
   107  	assert.Equal(t, p1meta.OriginPackage, "p1-origin")
   108  	assert.Len(t, p1.CPEs, 2)
   109  
   110  	p2 := pkgs[1]
   111  	assert.Equal(t, p2.Name, "pkg-2")
   112  	p2meta := p2.Metadata.(pkg.DpkgDBEntry)
   113  	assert.Equal(t, p2meta.Source, "p2-origin")
   114  	assert.Equal(t, p2meta.SourceVersion, "9.1.3")
   115  	assert.Len(t, p2.CPEs, 3)
   116  }
   117  
   118  func Test_extractMetadata(t *testing.T) {
   119  	oneTwoThreeFour := 1234
   120  	tests := []struct {
   121  		pkg  spdx.Package
   122  		meta interface{}
   123  	}{
   124  		{
   125  			pkg: spdx.Package{
   126  				PackageName:    "SomeDebPkg",
   127  				PackageVersion: "43.1.235",
   128  				PackageExternalReferences: []*spdx.PackageExternalReference{
   129  					{
   130  						Category: "PACKAGE-MANAGER",
   131  						Locator:  "pkg:deb/pkg-2@7.3.1?arch=x86_64&upstream=somedebpkg-origin@9.1.3&distro=debian-3.10.9",
   132  						RefType:  "purl",
   133  					},
   134  				},
   135  			},
   136  			meta: pkg.DpkgDBEntry{
   137  				Package:       "SomeDebPkg",
   138  				Source:        "somedebpkg-origin",
   139  				Version:       "43.1.235",
   140  				SourceVersion: "9.1.3",
   141  				Architecture:  "x86_64",
   142  			},
   143  		},
   144  		{
   145  			pkg: spdx.Package{
   146  				PackageName:    "SomeApkPkg",
   147  				PackageVersion: "3.2.9",
   148  				PackageExternalReferences: []*spdx.PackageExternalReference{
   149  					{
   150  						Category: "PACKAGE-MANAGER",
   151  						Locator:  "pkg:apk/alpine/pkg-2@7.3.1?arch=x86_64&upstream=apk-origin@9.1.3&distro=alpine-3.10.9",
   152  						RefType:  "purl",
   153  					},
   154  				},
   155  			},
   156  			meta: pkg.ApkDBEntry{
   157  				Package:       "SomeApkPkg",
   158  				OriginPackage: "apk-origin",
   159  				Version:       "3.2.9",
   160  				Architecture:  "x86_64",
   161  			},
   162  		},
   163  		{
   164  			pkg: spdx.Package{
   165  				PackageName:    "SomeRpmPkg",
   166  				PackageVersion: "13.2.79",
   167  				PackageExternalReferences: []*spdx.PackageExternalReference{
   168  					{
   169  						Category: "PACKAGE-MANAGER",
   170  						Locator:  "pkg:rpm/pkg-2@7.3.1?arch=x86_64&epoch=1234&upstream=some-rpm-origin-1.16.3&distro=alpine-3.10.9",
   171  						RefType:  "purl",
   172  					},
   173  				},
   174  			},
   175  			meta: pkg.RpmDBEntry{
   176  				Name:      "SomeRpmPkg",
   177  				Version:   "13.2.79",
   178  				Epoch:     &oneTwoThreeFour,
   179  				Arch:      "x86_64",
   180  				Release:   "",
   181  				SourceRpm: "some-rpm-origin-1.16.3",
   182  			},
   183  		},
   184  	}
   185  
   186  	for _, test := range tests {
   187  		t.Run(test.pkg.PackageName, func(t *testing.T) {
   188  			info := extractPkgInfo(&test.pkg)
   189  			meta := extractMetadata(&test.pkg, info)
   190  			assert.EqualValues(t, test.meta, meta)
   191  		})
   192  	}
   193  }
   194  
   195  func TestExtractSourceFromNamespaces(t *testing.T) {
   196  	tests := []struct {
   197  		namespace string
   198  		expected  any
   199  	}{
   200  		{
   201  			namespace: "https://anchore.com/syft/file/d42b01d0-7325-409b-b03f-74082935c4d3",
   202  			expected:  source.FileMetadata{},
   203  		},
   204  		{
   205  			namespace: "https://anchore.com/syft/image/d42b01d0-7325-409b-b03f-74082935c4d3",
   206  			expected:  source.ImageMetadata{},
   207  		},
   208  		{
   209  			namespace: "https://anchore.com/syft/dir/d42b01d0-7325-409b-b03f-74082935c4d3",
   210  			expected:  source.DirectoryMetadata{},
   211  		},
   212  		{
   213  			namespace: "https://another-host/blob/123",
   214  			expected:  nil,
   215  		},
   216  		{
   217  			namespace: "bla bla",
   218  			expected:  nil,
   219  		},
   220  		{
   221  			namespace: "",
   222  			expected:  nil,
   223  		},
   224  	}
   225  
   226  	for _, tt := range tests {
   227  		desc := extractSourceFromNamespace(tt.namespace)
   228  		if tt.expected == nil && desc.Metadata == nil {
   229  			return
   230  		}
   231  		if tt.expected != nil && desc.Metadata == nil {
   232  			t.Fatal("expected metadata but got nil")
   233  		}
   234  		if tt.expected == nil && desc.Metadata != nil {
   235  			t.Fatal("expected nil metadata but got something")
   236  		}
   237  		require.Equal(t, reflect.TypeOf(tt.expected), reflect.TypeOf(desc.Metadata))
   238  	}
   239  }
   240  
   241  func TestH1Digest(t *testing.T) {
   242  	tests := []struct {
   243  		name           string
   244  		pkg            spdx.Package
   245  		expectedDigest string
   246  	}{
   247  		{
   248  			name: "valid h1digest",
   249  			pkg: spdx.Package{
   250  				PackageName:    "github.com/googleapis/gnostic",
   251  				PackageVersion: "v0.5.5",
   252  				PackageExternalReferences: []*spdx.PackageExternalReference{
   253  					{
   254  						Category: "PACKAGE-MANAGER",
   255  						Locator:  "pkg:golang/github.com/googleapis/gnostic@v0.5.5",
   256  						RefType:  "purl",
   257  					},
   258  				},
   259  				PackageChecksums: []spdx.Checksum{
   260  					{
   261  						Algorithm: spdx.SHA256,
   262  						Value:     "f5f1c0b4ad2e0dfa6f79eaaaa3586411925c16f61702208ddd4bad2fc17dc47c",
   263  					},
   264  				},
   265  			},
   266  			expectedDigest: "h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=",
   267  		},
   268  		{
   269  			name: "invalid h1digest algorithm",
   270  			pkg: spdx.Package{
   271  				PackageName:    "github.com/googleapis/gnostic",
   272  				PackageVersion: "v0.5.5",
   273  				PackageExternalReferences: []*spdx.PackageExternalReference{
   274  					{
   275  						Category: "PACKAGE-MANAGER",
   276  						Locator:  "pkg:golang/github.com/googleapis/gnostic@v0.5.5",
   277  						RefType:  "purl",
   278  					},
   279  				},
   280  				PackageChecksums: []spdx.Checksum{
   281  					{
   282  						Algorithm: spdx.SHA1,
   283  						Value:     "f5f1c0b4ad2e0dfa6f79eaaaa3586411925c16f61702208ddd4bad2fc17dc47c",
   284  					},
   285  				},
   286  			},
   287  			expectedDigest: "",
   288  		},
   289  		{
   290  			name: "invalid h1digest digest",
   291  			pkg: spdx.Package{
   292  				PackageName:    "github.com/googleapis/gnostic",
   293  				PackageVersion: "v0.5.5",
   294  				PackageExternalReferences: []*spdx.PackageExternalReference{
   295  					{
   296  						Category: "PACKAGE-MANAGER",
   297  						Locator:  "pkg:golang/github.com/googleapis/gnostic@v0.5.5",
   298  						RefType:  "purl",
   299  					},
   300  				},
   301  				PackageChecksums: []spdx.Checksum{
   302  					{
   303  						Algorithm: spdx.SHA256,
   304  						Value:     "",
   305  					},
   306  				},
   307  			},
   308  			expectedDigest: "",
   309  		},
   310  	}
   311  
   312  	for _, test := range tests {
   313  		t.Run(test.name, func(t *testing.T) {
   314  			p := toSyftPackage(&test.pkg)
   315  			meta := p.Metadata.(pkg.GolangBinaryBuildinfoEntry)
   316  			require.Equal(t, test.expectedDigest, meta.H1Digest)
   317  		})
   318  	}
   319  }
   320  
   321  func Test_toSyftRelationships(t *testing.T) {
   322  	type args struct {
   323  		spdxIDMap map[string]any
   324  		doc       *spdx.Document
   325  	}
   326  
   327  	pkg1 := pkg.Package{
   328  		Name:    "github.com/googleapis/gnostic",
   329  		Version: "v0.5.5",
   330  	}
   331  	pkg1.SetID()
   332  
   333  	pkg2 := pkg.Package{
   334  		Name:    "rfc3339",
   335  		Version: "1.2",
   336  		Type:    pkg.RpmPkg,
   337  	}
   338  	pkg2.SetID()
   339  
   340  	pkg3 := pkg.Package{
   341  		Name:    "rfc3339",
   342  		Version: "1.2",
   343  		Type:    pkg.PythonPkg,
   344  	}
   345  	pkg3.SetID()
   346  
   347  	loc1 := file.NewLocationFromCoordinates(file.Coordinates{
   348  		RealPath:     "/somewhere/real",
   349  		FileSystemID: "abc",
   350  	})
   351  
   352  	tests := []struct {
   353  		name string
   354  		args args
   355  		want []artifact.Relationship
   356  	}{
   357  		{
   358  			name: "evident-by relationship",
   359  			args: args{
   360  				spdxIDMap: map[string]any{
   361  					string(toSPDXID(pkg1)): pkg1,
   362  					string(toSPDXID(loc1)): loc1,
   363  				},
   364  				doc: &spdx.Document{
   365  					Relationships: []*spdx.Relationship{
   366  						{
   367  							RefA: common.DocElementID{
   368  								ElementRefID: toSPDXID(pkg1),
   369  							},
   370  							RefB: common.DocElementID{
   371  								ElementRefID: toSPDXID(loc1),
   372  							},
   373  							Relationship:        spdx.RelationshipOther,
   374  							RelationshipComment: "evident-by: indicates the package's existence is evident by the given file",
   375  						},
   376  					},
   377  				},
   378  			},
   379  			want: []artifact.Relationship{
   380  				{
   381  					From: pkg1,
   382  					To:   loc1,
   383  					Type: artifact.EvidentByRelationship,
   384  				},
   385  			},
   386  		},
   387  		{
   388  			name: "ownership-by-file-overlap relationship",
   389  			args: args{
   390  				spdxIDMap: map[string]any{
   391  					string(toSPDXID(pkg2)): pkg2,
   392  					string(toSPDXID(pkg3)): pkg3,
   393  				},
   394  				doc: &spdx.Document{
   395  					Relationships: []*spdx.Relationship{
   396  						{
   397  							RefA: common.DocElementID{
   398  								ElementRefID: toSPDXID(pkg2),
   399  							},
   400  							RefB: common.DocElementID{
   401  								ElementRefID: toSPDXID(pkg3),
   402  							},
   403  							Relationship:        spdx.RelationshipOther,
   404  							RelationshipComment: "ownership-by-file-overlap: indicates that the parent package claims ownership of a child package since the parent metadata indicates overlap with a location that a cataloger found the child package by",
   405  						},
   406  					},
   407  				},
   408  			},
   409  			want: []artifact.Relationship{
   410  				{
   411  					From: pkg2,
   412  					To:   pkg3,
   413  					Type: artifact.OwnershipByFileOverlapRelationship,
   414  				},
   415  			},
   416  		},
   417  		{
   418  			name: "dependency-of relationship",
   419  			args: args{
   420  				spdxIDMap: map[string]any{
   421  					string(toSPDXID(pkg2)): pkg2,
   422  					string(toSPDXID(pkg3)): pkg3,
   423  				},
   424  				doc: &spdx.Document{
   425  					Relationships: []*spdx.Relationship{
   426  						{
   427  							RefA: common.DocElementID{
   428  								ElementRefID: toSPDXID(pkg2),
   429  							},
   430  							RefB: common.DocElementID{
   431  								ElementRefID: toSPDXID(pkg3),
   432  							},
   433  							Relationship:        spdx.RelationshipDependencyOf,
   434  							RelationshipComment: "dependency-of: indicates that the package in RefA is a dependency of the package in RefB",
   435  						},
   436  					},
   437  				},
   438  			},
   439  			want: []artifact.Relationship{
   440  				{
   441  					From: pkg2,
   442  					To:   pkg3,
   443  					Type: artifact.DependencyOfRelationship,
   444  				},
   445  			},
   446  		},
   447  		{
   448  			name: "dependends-on relationship",
   449  			args: args{
   450  				spdxIDMap: map[string]any{
   451  					string(toSPDXID(pkg2)): pkg2,
   452  					string(toSPDXID(pkg3)): pkg3,
   453  				},
   454  				doc: &spdx.Document{
   455  					Relationships: []*spdx.Relationship{
   456  						{
   457  							RefA: common.DocElementID{
   458  								ElementRefID: toSPDXID(pkg3),
   459  							},
   460  							RefB: common.DocElementID{
   461  								ElementRefID: toSPDXID(pkg2),
   462  							},
   463  							Relationship:        spdx.RelationshipDependsOn,
   464  							RelationshipComment: "dependends-on: indicates that the package in RefA depends on the package in RefB",
   465  						},
   466  					},
   467  				},
   468  			},
   469  			want: []artifact.Relationship{
   470  				{
   471  					From: pkg2,
   472  					To:   pkg3,
   473  					Type: artifact.DependencyOfRelationship,
   474  				},
   475  			},
   476  		},
   477  	}
   478  	for _, tt := range tests {
   479  		t.Run(tt.name, func(t *testing.T) {
   480  			actual := toSyftRelationships(tt.args.spdxIDMap, tt.args.doc)
   481  			require.Len(t, actual, len(tt.want))
   482  			for i := range actual {
   483  				require.Equal(t, tt.want[i].From.ID(), actual[i].From.ID())
   484  				require.Equal(t, tt.want[i].To.ID(), actual[i].To.ID())
   485  				require.Equal(t, tt.want[i].Type, actual[i].Type)
   486  			}
   487  		})
   488  	}
   489  }
   490  
   491  func Test_convertToAndFromFormat(t *testing.T) {
   492  	packages := []pkg.Package{
   493  		{
   494  			Name: "pkg1",
   495  		},
   496  		{
   497  			Name: "pkg2",
   498  		},
   499  	}
   500  
   501  	for i := range packages {
   502  		(&packages[i]).SetID()
   503  	}
   504  
   505  	relationships := []artifact.Relationship{
   506  		{
   507  			From: packages[0],
   508  			To:   packages[1],
   509  			Type: artifact.ContainsRelationship,
   510  		},
   511  	}
   512  
   513  	tests := []struct {
   514  		name          string
   515  		source        source.Description
   516  		packages      []pkg.Package
   517  		relationships []artifact.Relationship
   518  	}{
   519  		{
   520  			name: "image source",
   521  			source: source.Description{
   522  				ID: "DocumentRoot-Image-some-image",
   523  				Metadata: source.ImageMetadata{
   524  					ID:             "DocumentRoot-Image-some-image",
   525  					UserInput:      "some-image:some-tag",
   526  					ManifestDigest: "sha256:ab8b83234bc28f28d8e",
   527  				},
   528  				Name:    "some-image",
   529  				Version: "some-tag",
   530  			},
   531  			packages:      packages,
   532  			relationships: relationships,
   533  		},
   534  		{
   535  			name: ". directory source",
   536  			source: source.Description{
   537  				ID:   "DocumentRoot-Directory-.",
   538  				Name: ".",
   539  				Metadata: source.DirectoryMetadata{
   540  					Path: ".",
   541  				},
   542  			},
   543  			packages:      packages,
   544  			relationships: relationships,
   545  		},
   546  		{
   547  			name: "directory source",
   548  			source: source.Description{
   549  				ID:   "DocumentRoot-Directory-my-app",
   550  				Name: "my-app",
   551  				Metadata: source.DirectoryMetadata{
   552  					Path: "my-app",
   553  				},
   554  			},
   555  			packages:      packages,
   556  			relationships: relationships,
   557  		},
   558  		{
   559  			name: "file source",
   560  			source: source.Description{
   561  				ID: "DocumentRoot-File-my-app.exe",
   562  				Metadata: source.FileMetadata{
   563  					Path: "my-app.exe",
   564  					Digests: []file.Digest{
   565  						{
   566  							Algorithm: "sha256",
   567  							Value:     "3723cae0b8b83234bc28f28d8e",
   568  						},
   569  					},
   570  				},
   571  				Name: "my-app.exe",
   572  			},
   573  			packages:      packages,
   574  			relationships: relationships,
   575  		},
   576  	}
   577  
   578  	for _, test := range tests {
   579  		t.Run(test.name, func(t *testing.T) {
   580  			src := &test.source
   581  			s := sbom.SBOM{
   582  				Source: *src,
   583  				Artifacts: sbom.Artifacts{
   584  					Packages: pkg.NewCollection(test.packages...),
   585  				},
   586  				Relationships: test.relationships,
   587  			}
   588  			doc := ToFormatModel(s)
   589  			got, err := ToSyftModel(doc)
   590  			require.NoError(t, err)
   591  
   592  			if diff := cmp.Diff(&s, got,
   593  				cmpopts.IgnoreUnexported(artifact.Relationship{}),
   594  				cmpopts.IgnoreUnexported(file.LocationSet{}),
   595  				cmpopts.IgnoreUnexported(pkg.Collection{}),
   596  				cmpopts.IgnoreUnexported(pkg.Package{}),
   597  				cmpopts.IgnoreUnexported(pkg.LicenseSet{}),
   598  				cmpopts.IgnoreFields(sbom.Artifacts{}, "FileMetadata", "FileDigests"),
   599  			); diff != "" {
   600  				t.Fatalf("packages do not match:\n%s", diff)
   601  			}
   602  		})
   603  	}
   604  }
   605  
   606  func Test_purlValue(t *testing.T) {
   607  	tests := []struct {
   608  		purl     packageurl.PackageURL
   609  		expected string
   610  	}{
   611  		{
   612  			purl:     packageurl.PackageURL{},
   613  			expected: "",
   614  		},
   615  		{
   616  			purl: packageurl.PackageURL{
   617  				Name:    "name",
   618  				Version: "version",
   619  			},
   620  			expected: "",
   621  		},
   622  		{
   623  			purl: packageurl.PackageURL{
   624  				Type:    "typ",
   625  				Version: "version",
   626  			},
   627  			expected: "",
   628  		},
   629  		{
   630  			purl: packageurl.PackageURL{
   631  				Type:    "typ",
   632  				Name:    "name",
   633  				Version: "version",
   634  			},
   635  			expected: "pkg:typ/name@version",
   636  		},
   637  		{
   638  			purl: packageurl.PackageURL{
   639  				Type:    "typ",
   640  				Name:    "name",
   641  				Version: "version",
   642  				Qualifiers: packageurl.Qualifiers{
   643  					{
   644  						Key:   "q",
   645  						Value: "v",
   646  					},
   647  				},
   648  			},
   649  			expected: "pkg:typ/name@version?q=v",
   650  		},
   651  	}
   652  
   653  	for _, test := range tests {
   654  		t.Run(test.purl.String(), func(t *testing.T) {
   655  			got := purlValue(test.purl)
   656  			require.Equal(t, test.expected, got)
   657  		})
   658  	}
   659  }
   660  
   661  func Test_directPackageFiles(t *testing.T) {
   662  	doc := &spdx.Document{
   663  		SPDXVersion: "SPDX-2.3",
   664  		Packages: []*spdx.Package{
   665  			{
   666  				PackageName:           "some-package",
   667  				PackageSPDXIdentifier: "1",
   668  				PackageVersion:        "1.0.5",
   669  				Files: []*spdx.File{
   670  					{
   671  						FileName:           "some-file",
   672  						FileSPDXIdentifier: "2",
   673  						Checksums: []spdx.Checksum{
   674  							{
   675  								Algorithm: "SHA1",
   676  								Value:     "a8d733c64f9123",
   677  							},
   678  						},
   679  					},
   680  				},
   681  			},
   682  		},
   683  	}
   684  
   685  	got, err := ToSyftModel(doc)
   686  	require.NoError(t, err)
   687  
   688  	p := pkg.Package{
   689  		Name:    "some-package",
   690  		Version: "1.0.5",
   691  	}
   692  	p.SetID()
   693  	f := file.Location{
   694  		LocationData: file.LocationData{
   695  			Coordinates: file.Coordinates{
   696  				RealPath:     "some-file",
   697  				FileSystemID: "",
   698  			},
   699  			AccessPath: "some-file",
   700  		},
   701  		LocationMetadata: file.LocationMetadata{
   702  			Annotations: map[string]string{},
   703  		},
   704  	}
   705  	s := &sbom.SBOM{
   706  		Artifacts: sbom.Artifacts{
   707  			Packages: pkg.NewCollection(p),
   708  			FileMetadata: map[file.Coordinates]file.Metadata{
   709  				f.Coordinates: {},
   710  			},
   711  			FileDigests: map[file.Coordinates][]file.Digest{
   712  				f.Coordinates: {
   713  					{
   714  						Algorithm: "sha1",
   715  						Value:     "a8d733c64f9123",
   716  					},
   717  				},
   718  			},
   719  		},
   720  		Relationships: []artifact.Relationship{
   721  			{
   722  				From: p,
   723  				To:   f,
   724  				Type: artifact.ContainsRelationship,
   725  			},
   726  		},
   727  		Source:     source.Description{},
   728  		Descriptor: sbom.Descriptor{},
   729  	}
   730  
   731  	require.Equal(t, s, got)
   732  }