diff --git a/cmd/guacone/cmd/files.go b/cmd/guacone/cmd/files.go
index 320ede6ed3..9b561cde09 100644
--- a/cmd/guacone/cmd/files.go
+++ b/cmd/guacone/cmd/files.go
@@ -83,7 +83,7 @@ var exampleCmd = &cobra.Command{
 			logger.Errorf("error: %v", err)
 			os.Exit(1)
 		}
-		ingestorFunc, err := getIngestor()
+		ingestorFunc, err := getIngestor(ctx)
 		if err != nil {
 			logger.Errorf("error: %v", err)
 			os.Exit(1)
@@ -151,9 +151,9 @@ func getProcessor(ctx context.Context) (func(*processor.Document) (processor.Doc
 		return process.Process(ctx, d)
 	}, nil
 }
-func getIngestor() (func(processor.DocumentTree) ([]assembler.Graph, error), error) {
+func getIngestor(ctx context.Context) (func(processor.DocumentTree) ([]assembler.Graph, error), error) {
 	return func(doc processor.DocumentTree) ([]assembler.Graph, error) {
-		inputs, err := parser.ParseDocumentTree(doc)
+		inputs, err := parser.ParseDocumentTree(ctx, doc)
 		if err != nil {
 			return nil, err
 		}
diff --git a/cmd/ingest/cmd/example.go b/cmd/ingest/cmd/example.go
index bf75570b39..c190f7d7ac 100644
--- a/cmd/ingest/cmd/example.go
+++ b/cmd/ingest/cmd/example.go
@@ -79,7 +79,7 @@ var exampleCmd = &cobra.Command{
 			Edges: []assembler.GuacEdge{},
 		}
 		for _, doc := range docs {
-			inputs, err := parser.ParseDocumentTree(doc)
+			inputs, err := parser.ParseDocumentTree(ctx, doc)
 			if err != nil {
 				logger.Errorf("unable to parse document: %v", err)
 				os.Exit(1)
diff --git a/go.mod b/go.mod
index 55ffd58793..978c8307f0 100644
--- a/go.mod
+++ b/go.mod
@@ -66,5 +66,5 @@ require (
 
 require (
 	github.com/sigstore/sigstore v1.4.2
-	github.com/spdx/tools-golang v0.3.1-0.20220818163346-5eb9315c0c55
+	github.com/spdx/tools-golang v0.3.1-0.20221003161519-fb7fe8874d01
 )
diff --git a/go.sum b/go.sum
index 92ecbea4a9..6a82221b32 100644
--- a/go.sum
+++ b/go.sum
@@ -285,8 +285,8 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0
 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
-github.com/spdx/tools-golang v0.3.1-0.20220818163346-5eb9315c0c55 h1:vVdz7zz4iQvAyUYbjGvd35FMyQEoFjV3BvpnzzBKXZc=
-github.com/spdx/tools-golang v0.3.1-0.20220818163346-5eb9315c0c55/go.mod h1:VHzvNsKAfAGqs4ZvwRL+7a0dNsL20s7lGui4K9C0xQM=
+github.com/spdx/tools-golang v0.3.1-0.20221003161519-fb7fe8874d01 h1:HSwhIjCVoxeYkVPkUNH1l0ej8WBLgl7pNYz17vFOp/g=
+github.com/spdx/tools-golang v0.3.1-0.20221003161519-fb7fe8874d01/go.mod h1:VHzvNsKAfAGqs4ZvwRL+7a0dNsL20s7lGui4K9C0xQM=
 github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
 github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
diff --git a/internal/testing/ingestor/testdata/testdata.go b/internal/testing/ingestor/testdata/testdata.go
index d74d0f9662..1d36686372 100644
--- a/internal/testing/ingestor/testdata/testdata.go
+++ b/internal/testing/ingestor/testdata/testdata.go
@@ -18,6 +18,7 @@ package testdata
 import (
 	"encoding/base64"
 	"encoding/json"
+	"reflect"
 
 	"github.com/guacsec/guac/internal/testing/ingestor/keyutil"
 	"github.com/guacsec/guac/pkg/assembler"
@@ -28,6 +29,8 @@ import (
 )
 
 var (
+	// DSSE/SLSA Testdata
+
 	// Taken from: https://slsa.dev/provenance/v0.1#example
 	ite6SLSA = `
 	{
@@ -151,6 +154,96 @@ var (
 			ArtifactDependency: mat2,
 		},
 	}
+
+	// SDPX Testdata
+
+	topLevelPack = assembler.PackageNode{
+		Name:   "gcr.io/google-containers/alpine-latest",
+		Digest: nil,
+		Purl:   "pkg:oci/alpine-latest?repository_url=gcr.io/google-containers",
+		CPEs:   nil,
+	}
+
+	baselayoutPack = assembler.PackageNode{
+		Name:   "alpine-baselayout",
+		Digest: nil,
+		Purl:   "pkg:alpine/alpine-baselayout@3.2.0-r22?arch=x86_64&upstream=alpine-baselayout&distro=alpine-3.16.2",
+		CPEs: []string{
+			"cpe:2.3:a:alpine-baselayout:alpine-baselayout:3.2.0-r22:*:*:*:*:*:*:*",
+			"cpe:2.3:a:alpine-baselayout:alpine_baselayout:3.2.0-r22:*:*:*:*:*:*:*",
+		},
+	}
+
+	keysPack = assembler.PackageNode{
+		Name:   "alpine-keys",
+		Digest: nil,
+		Purl:   "pkg:alpine/alpine-keys@2.4-r1?arch=x86_64&upstream=alpine-keys&distro=alpine-3.16.2",
+		CPEs: []string{
+			"cpe:2.3:a:alpine-keys:alpine-keys:2.4-r1:*:*:*:*:*:*:*",
+			"cpe:2.3:a:alpine-keys:alpine_keys:2.4-r1:*:*:*:*:*:*:*",
+			"cpe:2.3:a:alpine:alpine-keys:2.4-r1:*:*:*:*:*:*:*",
+			"cpe:2.3:a:alpine:alpine_keys:2.4-r1:*:*:*:*:*:*:*",
+		},
+	}
+
+	baselayoutdataPack = assembler.PackageNode{
+		Name:   "alpine-baselayout-data",
+		Digest: nil,
+		Purl:   "pkg:alpine/alpine-baselayout-data@3.2.0-r22?arch=x86_64&upstream=alpine-baselayout&distro=alpine-3.16.2",
+		CPEs: []string{
+			"cpe:2.3:a:alpine-baselayout-data:alpine-baselayout-data:3.2.0-r22:*:*:*:*:*:*:*",
+			"cpe:2.3:a:alpine-baselayout-data:alpine_baselayout_data:3.2.0-r22:*:*:*:*:*:*:*",
+		},
+	}
+
+	worldFile = assembler.ArtifactNode{
+		Name:   "/etc/apk/world",
+		Digest: "SHA256:713e3907167dce202d7c16034831af3d670191382a3e9026e0ac0a4023013201",
+	}
+	rootFile = assembler.ArtifactNode{
+		Name:   "/etc/crontabs/root",
+		Digest: "SHA256:575d810a9fae5f2f0671c9b2c0ce973e46c7207fbe5cb8d1b0d1836a6a0470e3",
+	}
+	triggersFile = assembler.ArtifactNode{
+		Name:   "/lib/apk/db/triggers",
+		Digest: "SHA256:5415cfe5f88c0af38df3b7141a3f9bc6b8178e9cf72d700658091b8f5539c7b4",
+	}
+	rsaPubFile = assembler.ArtifactNode{
+		Name:   "/usr/share/apk/keys/alpine-devel@lists.alpinelinux.org-58cbb476.rsa.pub",
+		Digest: "SHA256:9a4cd858d9710963848e6d5f555325dc199d1c952b01cf6e64da2c15deedbd97",
+	}
+
+	SpdxNodes = []assembler.GuacNode{topLevelPack, baselayoutPack, baselayoutdataPack, rsaPubFile, keysPack, worldFile, rootFile, triggersFile}
+	SpdxEdges = []assembler.GuacEdge{
+		assembler.DependsOnEdge{
+			PackageNode:       topLevelPack,
+			PackageDependency: baselayoutPack,
+		},
+		assembler.DependsOnEdge{
+			PackageNode:       topLevelPack,
+			PackageDependency: baselayoutdataPack,
+		},
+		assembler.DependsOnEdge{
+			PackageNode:       topLevelPack,
+			PackageDependency: keysPack,
+		},
+		assembler.DependsOnEdge{
+			PackageNode:       baselayoutPack,
+			PackageDependency: keysPack,
+		},
+		assembler.DependsOnEdge{
+			ArtifactNode:       rootFile,
+			ArtifactDependency: rsaPubFile,
+		},
+		assembler.ContainsEdge{
+			PackageNode:       baselayoutPack,
+			ContainedArtifact: rootFile,
+		},
+		assembler.ContainsEdge{
+			PackageNode:       keysPack,
+			ContainedArtifact: rsaPubFile,
+		},
+	}
 )
 
 type mockSigstoreVerifier struct{}
@@ -179,3 +272,100 @@ func (m *mockSigstoreVerifier) Verify(payloadBytes []byte) ([]verifier.Identity,
 func (m *mockSigstoreVerifier) Type() verifier.VerifierType {
 	return "sigstore"
 }
+
+func GuacNodeSliceEqual(slice1, slice2 []assembler.GuacNode) bool {
+	if len(slice1) != len(slice2) {
+		return false
+	}
+
+	result := true
+
+	for _, node1 := range slice1 {
+		e := false
+		for _, node2 := range slice2 {
+			if node1.Type() == "Package" && node2.Type() == "Package" {
+				if node1.(assembler.PackageNode).Name == node2.(assembler.PackageNode).Name {
+					if reflect.DeepEqual(node1, node2) {
+						e = true
+						break
+					}
+				}
+			} else if node1.Type() == "Artifact" && node2.Type() == "Artifact" {
+				if node1.(assembler.ArtifactNode).Name == node2.(assembler.ArtifactNode).Name {
+					if reflect.DeepEqual(node1, node2) {
+						e = true
+						break
+					}
+				}
+			} else if node1.Type() == "Attestation" && node2.Type() == "Attestation" {
+				if node1.(assembler.AttestationNode).FilePath == node2.(assembler.AttestationNode).FilePath {
+					if reflect.DeepEqual(node1, node2) {
+						e = true
+						break
+					}
+				}
+			} else if node1.Type() == "Builder" && node2.Type() == "Builder" {
+				if node1.(assembler.BuilderNode).BuilderId == node2.(assembler.BuilderNode).BuilderId {
+					if reflect.DeepEqual(node1, node2) {
+						e = true
+						break
+					}
+				}
+			} else if node1.Type() == "Identity" && node2.Type() == "Identity" {
+				if node1.(assembler.IdentityNode).ID == node2.(assembler.IdentityNode).ID {
+					if reflect.DeepEqual(node1, node2) {
+						e = true
+						break
+					}
+				}
+			}
+		}
+		if !e {
+			result = false
+		}
+	}
+	return result
+}
+
+func GuacEdgeSliceEqual(slice1, slice2 []assembler.GuacEdge) bool {
+	if len(slice1) != len(slice2) {
+		return false
+	}
+
+	result := true
+	for _, edge1 := range slice1 {
+		e := false
+		for _, edge2 := range slice2 {
+			if edge1.Type() == "DependsOn" && edge2.Type() == "DependsOn" {
+				if reflect.DeepEqual(edge1, edge2) {
+					e = true
+					break
+				}
+			} else if edge1.Type() == "Contains" && edge2.Type() == "Contains" {
+				if reflect.DeepEqual(edge1, edge2) {
+					e = true
+					break
+				}
+			} else if edge1.Type() == "Attestation" && edge2.Type() == "Attestation" {
+				if reflect.DeepEqual(edge1, edge2) {
+					e = true
+					break
+				}
+			} else if edge1.Type() == "Identity" && edge2.Type() == "Identity" {
+				if reflect.DeepEqual(edge1, edge2) {
+					e = true
+					break
+				}
+			} else if edge1.Type() == "BuiltBy" && edge2.Type() == "BuiltBy" {
+				if reflect.DeepEqual(edge1, edge2) {
+					e = true
+					break
+				}
+			}
+		}
+		if !e {
+			result = false
+		}
+	}
+	return result
+}
diff --git a/internal/testing/processor/testdata.go b/internal/testing/processor/testdata.go
index f722313769..b27fcda9ea 100644
--- a/internal/testing/processor/testdata.go
+++ b/internal/testing/processor/testdata.go
@@ -25,6 +25,9 @@ var (
 	//go:embed testdata/alpine-spdx.json
 	SpdxExampleBig []byte
 
+	//go:embed testdata/alpine-small-spdx.json
+	SpdxExampleAlpine []byte
+
 	// Invalid types for field spdxVersion
 	//go:embed testdata/invalid-spdx.json
 	SpdxInvalidExample []byte
diff --git a/internal/testing/processor/testdata/alpine-small-spdx.json b/internal/testing/processor/testdata/alpine-small-spdx.json
new file mode 100644
index 0000000000..0b1dbe8f20
--- /dev/null
+++ b/internal/testing/processor/testdata/alpine-small-spdx.json
@@ -0,0 +1,633 @@
+{
+ "SPDXID": "SPDXRef-DOCUMENT",
+ "name": "gcr.io/google-containers/alpine-latest",
+ "spdxVersion": "SPDX-2.2",
+ "creationInfo": {
+  "created": "2022-09-24T17:27:55.556104Z",
+  "creators": [
+   "Organization: Anchore, Inc",
+   "Tool: syft-0.57.0"
+  ],
+  "licenseListVersion": "3.18"
+ },
+ "dataLicense": "CC0-1.0",
+ "documentNamespace": "https://anchore.com/syft/image/alpine-latest-e78eca08-d9f4-49c7-97e0-6d4b9bfa99c2",
+ "packages": [
+  {
+   "SPDXID": "SPDXRef-35085779bdf473bb",
+   "name": "alpine-baselayout",
+   "licenseConcluded": "GPL-2.0-only",
+   "description": "Alpine base dir structure and init scripts",
+   "downloadLocation": "https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout",
+   "externalRefs": [
+    {
+     "referenceCategory": "SECURITY",
+     "referenceLocator": "cpe:2.3:a:alpine-baselayout:alpine-baselayout:3.2.0-r22:*:*:*:*:*:*:*",
+     "referenceType": "cpe23Type"
+    },
+    {
+     "referenceCategory": "SECURITY",
+     "referenceLocator": "cpe:2.3:a:alpine-baselayout:alpine_baselayout:3.2.0-r22:*:*:*:*:*:*:*",
+     "referenceType": "cpe23Type"
+    },
+    {
+     "referenceCategory": "PACKAGE_MANAGER",
+     "referenceLocator": "pkg:alpine/alpine-baselayout@3.2.0-r22?arch=x86_64&upstream=alpine-baselayout&distro=alpine-3.16.2",
+     "referenceType": "purl"
+    }
+   ],
+   "filesAnalyzed": false,
+   "hasFiles": [
+    "SPDXRef-1ee0f450becc786f",
+    "SPDXRef-336bc8ce40e7fc42",
+    "SPDXRef-3cf575889d9cc66c",
+    "SPDXRef-5be401ad758d7c8",
+    "SPDXRef-757351ee498badd7",
+    "SPDXRef-786c4e711c1a558b",
+    "SPDXRef-88b0f6fae4de13a0",
+    "SPDXRef-a6c4c4e977ddf6d8",
+    "SPDXRef-cb0990ff1c4365e4",
+    "SPDXRef-da399cec16efc781",
+    "SPDXRef-de2a9cb8a967fb5b"
+   ],
+   "licenseDeclared": "GPL-2.0-only",
+   "originator": "Person: Natanael Copa <ncopa@alpinelinux.org>",
+   "sourceInfo": "acquired package info from APK DB: /lib/apk/db/installed",
+   "versionInfo": "3.2.0-r22"
+  },
+  {
+   "SPDXID": "SPDXRef-33b5ab4a81e975bd",
+   "name": "alpine-baselayout-data",
+   "licenseConcluded": "GPL-2.0-only",
+   "description": "Alpine base dir structure and init scripts",
+   "downloadLocation": "https://git.alpinelinux.org/cgit/aports/tree/main/alpine-baselayout",
+   "externalRefs": [
+    {
+     "referenceCategory": "SECURITY",
+     "referenceLocator": "cpe:2.3:a:alpine-baselayout-data:alpine-baselayout-data:3.2.0-r22:*:*:*:*:*:*:*",
+     "referenceType": "cpe23Type"
+    },
+    {
+     "referenceCategory": "SECURITY",
+     "referenceLocator": "cpe:2.3:a:alpine-baselayout-data:alpine_baselayout_data:3.2.0-r22:*:*:*:*:*:*:*",
+     "referenceType": "cpe23Type"
+    },
+    {
+     "referenceCategory": "PACKAGE_MANAGER",
+     "referenceLocator": "pkg:alpine/alpine-baselayout-data@3.2.0-r22?arch=x86_64&upstream=alpine-baselayout&distro=alpine-3.16.2",
+     "referenceType": "purl"
+    }
+   ],
+   "filesAnalyzed": false,
+   "hasFiles": [
+    "SPDXRef-14c57fa7ac8df92",
+    "SPDXRef-2ac427870f248704",
+    "SPDXRef-2be29626dd7a31e2",
+    "SPDXRef-2e3b308d2192da55",
+    "SPDXRef-4cb78c1b83f3f6fa",
+    "SPDXRef-58256f3c5c4e6aa2",
+    "SPDXRef-5b4c64f05d9b355a",
+    "SPDXRef-5c71002e828599e6",
+    "SPDXRef-5ec7e40e4299d952",
+    "SPDXRef-75b6ed72d694a357",
+    "SPDXRef-795c342188acc719",
+    "SPDXRef-9622c4a77c0af92d",
+    "SPDXRef-bd8e6d084d722e0a"
+   ],
+   "licenseDeclared": "GPL-2.0-only",
+   "originator": "Person: Natanael Copa <ncopa@alpinelinux.org>",
+   "sourceInfo": "acquired package info from APK DB: /lib/apk/db/installed",
+   "versionInfo": "3.2.0-r22"
+  },
+  {
+   "SPDXID": "SPDXRef-3f53edc3b14056c3",
+   "name": "alpine-keys",
+   "licenseConcluded": "MIT",
+   "description": "Public keys for Alpine Linux packages",
+   "downloadLocation": "https://alpinelinux.org",
+   "externalRefs": [
+    {
+     "referenceCategory": "SECURITY",
+     "referenceLocator": "cpe:2.3:a:alpine-keys:alpine-keys:2.4-r1:*:*:*:*:*:*:*",
+     "referenceType": "cpe23Type"
+    },
+    {
+     "referenceCategory": "SECURITY",
+     "referenceLocator": "cpe:2.3:a:alpine-keys:alpine_keys:2.4-r1:*:*:*:*:*:*:*",
+     "referenceType": "cpe23Type"
+    },
+    {
+     "referenceCategory": "SECURITY",
+     "referenceLocator": "cpe:2.3:a:alpine:alpine-keys:2.4-r1:*:*:*:*:*:*:*",
+     "referenceType": "cpe23Type"
+    },
+    {
+     "referenceCategory": "SECURITY",
+     "referenceLocator": "cpe:2.3:a:alpine:alpine_keys:2.4-r1:*:*:*:*:*:*:*",
+     "referenceType": "cpe23Type"
+    },
+    {
+     "referenceCategory": "PACKAGE_MANAGER",
+     "referenceLocator": "pkg:alpine/alpine-keys@2.4-r1?arch=x86_64&upstream=alpine-keys&distro=alpine-3.16.2",
+     "referenceType": "purl"
+    }
+   ],
+   "filesAnalyzed": false,
+   "hasFiles": [
+    "SPDXRef-14473a45c2af16d7",
+    "SPDXRef-156d627c97a2de34",
+    "SPDXRef-1ee1cd40588ab89c",
+    "SPDXRef-221af60be84b09c0",
+    "SPDXRef-274572174bc1cc7a",
+    "SPDXRef-300f983a142f9504",
+    "SPDXRef-44193297ee82bac1",
+    "SPDXRef-45232e260abd77f7",
+    "SPDXRef-492cf038d1d9fd9b",
+    "SPDXRef-4cbd1b18ddd59c42",
+    "SPDXRef-4d1c352ad50e20b2",
+    "SPDXRef-6d7742dc4838b698",
+    "SPDXRef-716461c423874936",
+    "SPDXRef-879bdb5c61068a44",
+    "SPDXRef-9b559b61986fccb0",
+    "SPDXRef-af1d9aa588b56c47",
+    "SPDXRef-c549a0b76f823487",
+    "SPDXRef-eb93193a7276c76a",
+    "SPDXRef-f542a07f45615070",
+    "SPDXRef-f91e100c74bf27e",
+    "SPDXRef-f96f56f789a464ad",
+    "SPDXRef-fb57f5df1fd169db"
+   ],
+   "licenseDeclared": "MIT",
+   "originator": "Person: Natanael Copa <ncopa@alpinelinux.org>",
+   "sourceInfo": "acquired package info from APK DB: /lib/apk/db/installed",
+   "versionInfo": "2.4-r1"
+  }
+  ],
+ "files": [
+  {
+   "SPDXID": "SPDXRef-a3cc05285a46b7f7",
+   "comment": "layerID: sha256:994393dc58e7931862558d06e46aa2bb17487044f670f310dffe1d24e4d1eec7",
+   "licenseConcluded": "NOASSERTION",
+   "fileName": "/bin",
+   "fileTypes": [
+    "OTHER"
+   ]
+  },
+  {
+   "SPDXID": "SPDXRef-9936d4f0772f184e",
+   "comment": "layerID: sha256:994393dc58e7931862558d06e46aa2bb17487044f670f310dffe1d24e4d1eec7",
+   "licenseConcluded": "NOASSERTION",
+   "checksums": [
+    {
+     "algorithm": "SHA256",
+     "checksumValue": "713e3907167dce202d7c16034831af3d670191382a3e9026e0ac0a4023013201"
+    }
+   ],
+   "fileName": "/etc/apk/world",
+   "fileTypes": [
+    "TEXT"
+   ]
+  },
+  {
+   "SPDXID": "SPDXRef-5be401ad758d7c8",
+   "comment": "layerID: sha256:994393dc58e7931862558d06e46aa2bb17487044f670f310dffe1d24e4d1eec7",
+   "licenseConcluded": "NOASSERTION",
+   "checksums": [
+    {
+     "algorithm": "SHA256",
+     "checksumValue": "575d810a9fae5f2f0671c9b2c0ce973e46c7207fbe5cb8d1b0d1836a6a0470e3"
+    }
+   ],
+   "fileName": "/etc/crontabs/root",
+   "fileTypes": [
+    "TEXT"
+   ]
+  },
+  {
+   "SPDXID": "SPDXRef-6cf3a5a9353a152d",
+   "comment": "layerID: sha256:994393dc58e7931862558d06e46aa2bb17487044f670f310dffe1d24e4d1eec7",
+   "licenseConcluded": "NOASSERTION",
+   "checksums": [
+    {
+     "algorithm": "SHA256",
+     "checksumValue": "5415cfe5f88c0af38df3b7141a3f9bc6b8178e9cf72d700658091b8f5539c7b4"
+    }
+   ],
+   "fileName": "/lib/apk/db/triggers",
+   "fileTypes": [
+    "TEXT"
+   ]
+  },
+  {
+   "SPDXID": "SPDXRef-9b559b61986fccb0",
+   "comment": "layerID: sha256:994393dc58e7931862558d06e46aa2bb17487044f670f310dffe1d24e4d1eec7",
+   "licenseConcluded": "NOASSERTION",
+   "checksums": [
+    {
+     "algorithm": "SHA256",
+     "checksumValue": "9a4cd858d9710963848e6d5f555325dc199d1c952b01cf6e64da2c15deedbd97"
+    }
+   ],
+   "fileName": "/usr/share/apk/keys/alpine-devel@lists.alpinelinux.org-58cbb476.rsa.pub",
+   "fileTypes": [
+    "TEXT"
+   ]
+  },
+  {
+   "SPDXID": "SPDXRef-659b325adddd783e",
+   "comment": "layerID: sha256:994393dc58e7931862558d06e46aa2bb17487044f670f310dffe1d24e4d1eec7",
+   "licenseConcluded": "NOASSERTION",
+   "fileName": "/var/tmp",
+   "fileTypes": [
+    "OTHER"
+   ]
+  }
+ ],
+ "relationships": [
+  {
+   "spdxElementId": "SPDXRef-2bc2db5bac1d0fe4",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-1ba0b361ecdca2c4"
+  },
+  {
+    "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+    "relationshipType": "CONTAINS",
+    "relatedSpdxElement": "SPDXRef-2ac427870f248704"
+   },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "DEPENDS_ON",
+   "relatedSpdxElement": "SPDXRef-3f53edc3b14056c3"
+  },
+  {
+   "spdxElementId": "SPDXRef-2bc2db5bac1d0fe4",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-7dc15fca12e2f017"
+  },
+  {
+    "spdxElementId": "SPDXRef-5be401ad758d7c8",
+    "relationshipType": "DEPENDS_ON",
+    "relatedSpdxElement": "SPDXRef-9b559b61986fccb0"
+   },
+  {
+   "spdxElementId": "SPDXRef-2bc2db5bac1d0fe4",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-8197f64c214a5a16"
+  },
+  {
+   "spdxElementId": "SPDXRef-2bc2db5bac1d0fe4",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-9ce55bcb43ee284f"
+  },
+  {
+   "spdxElementId": "SPDXRef-2bc2db5bac1d0fe4",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-f475459004544a56"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-14c57fa7ac8df92"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-2ac427870f248704"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-2be29626dd7a31e2"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-2e3b308d2192da55"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-4cb78c1b83f3f6fa"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-58256f3c5c4e6aa2"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-5b4c64f05d9b355a"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-5c71002e828599e6"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-5ec7e40e4299d952"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-75b6ed72d694a357"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-795c342188acc719"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-9622c4a77c0af92d"
+  },
+  {
+   "spdxElementId": "SPDXRef-33b5ab4a81e975bd",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-bd8e6d084d722e0a"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-1ee0f450becc786f"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-336bc8ce40e7fc42"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-3cf575889d9cc66c"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-5be401ad758d7c8"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-757351ee498badd7"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-786c4e711c1a558b"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-88b0f6fae4de13a0"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-a6c4c4e977ddf6d8"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-cb0990ff1c4365e4"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-da399cec16efc781"
+  },
+  {
+   "spdxElementId": "SPDXRef-35085779bdf473bb",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-de2a9cb8a967fb5b"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-14473a45c2af16d7"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-156d627c97a2de34"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-1ee1cd40588ab89c"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-221af60be84b09c0"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-274572174bc1cc7a"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-300f983a142f9504"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-44193297ee82bac1"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-45232e260abd77f7"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-492cf038d1d9fd9b"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-4cbd1b18ddd59c42"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-4d1c352ad50e20b2"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-6d7742dc4838b698"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-716461c423874936"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-879bdb5c61068a44"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-9b559b61986fccb0"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-af1d9aa588b56c47"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-c549a0b76f823487"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-eb93193a7276c76a"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-f542a07f45615070"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-f91e100c74bf27e"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-f96f56f789a464ad"
+  },
+  {
+   "spdxElementId": "SPDXRef-3f53edc3b14056c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-fb57f5df1fd169db"
+  },
+  {
+   "spdxElementId": "SPDXRef-3ff09d7a5e0dc2ed",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-754289e667437895"
+  },
+  {
+   "spdxElementId": "SPDXRef-7514a98b23f9928c",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-19e9882925c797f5"
+  },
+  {
+   "spdxElementId": "SPDXRef-7aec2be3ffd82c3c",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-a74d39439f2d84b8"
+  },
+  {
+   "spdxElementId": "SPDXRef-94e7e84b87c1f8c3",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-6d1b682f6d48f488"
+  },
+  {
+   "spdxElementId": "SPDXRef-9bb9cb82a4ce72b1",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-4fb0c07667dac902"
+  },
+  {
+   "spdxElementId": "SPDXRef-9bb9cb82a4ce72b1",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-d8bdade972f61759"
+  },
+  {
+   "spdxElementId": "SPDXRef-b703a8e4e90dd6dc",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-1b08cd6c03818e29"
+  },
+  {
+   "spdxElementId": "SPDXRef-b703a8e4e90dd6dc",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-2cd2aeb015390775"
+  },
+  {
+   "spdxElementId": "SPDXRef-b703a8e4e90dd6dc",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-4a324ad304be8e9a"
+  },
+  {
+   "spdxElementId": "SPDXRef-b703a8e4e90dd6dc",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-98233f67f18b2755"
+  },
+  {
+   "spdxElementId": "SPDXRef-b703a8e4e90dd6dc",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-c1d35477db673e2d"
+  },
+  {
+   "spdxElementId": "SPDXRef-bebc881007d932d",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-535cfe0185d18797"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-1087f474228124bb"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-1b1e12f00cbb2df9"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-28854548e0d878c2"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-61a86d4a797602e5"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-c35e7c8840928dba"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-c3c38e46778cd717"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-dd0104ad41122fa2"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-e5e1738bbb13275f"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-eb47016cd05f7d35"
+  },
+  {
+   "spdxElementId": "SPDXRef-cce075f4f19baaee",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-fa7856d6d0b238f1"
+  },
+  {
+   "spdxElementId": "SPDXRef-ec1d619a28263eb0",
+   "relationshipType": "CONTAINS",
+   "relatedSpdxElement": "SPDXRef-e2c90ae8ae67431f"
+  }
+ ]
+}
diff --git a/pkg/ingestor/parser/common/graph_builder.go b/pkg/ingestor/parser/common/graph_builder.go
index 01aebae7bf..dda280a8eb 100644
--- a/pkg/ingestor/parser/common/graph_builder.go
+++ b/pkg/ingestor/parser/common/graph_builder.go
@@ -16,6 +16,8 @@
 package common
 
 import (
+	"context"
+
 	"github.com/guacsec/guac/pkg/assembler"
 )
 
@@ -34,10 +36,10 @@ func NewGenericGraphBuilder(docParser DocumentParser, foundIdentities []assemble
 }
 
 // CreateAssemblerInput creates the GuacNodes and GuacEdges that are needed by the assembler
-func (b *GraphBuilder) CreateAssemblerInput(foundIdentities []assembler.IdentityNode) assembler.AssemblerInput {
+func (b *GraphBuilder) CreateAssemblerInput(ctx context.Context, foundIdentities []assembler.IdentityNode) assembler.AssemblerInput {
 	assemblerinput := assembler.AssemblerInput{
 		Nodes: b.docParser.CreateNodes(),
-		Edges: b.docParser.CreateEdges(foundIdentities),
+		Edges: b.docParser.CreateEdges(ctx, foundIdentities),
 	}
 	return assemblerinput
 }
diff --git a/pkg/ingestor/parser/common/types.go b/pkg/ingestor/parser/common/types.go
index 6bfb8534a8..00b9034f5b 100644
--- a/pkg/ingestor/parser/common/types.go
+++ b/pkg/ingestor/parser/common/types.go
@@ -16,6 +16,8 @@
 package common
 
 import (
+	"context"
+
 	"github.com/guacsec/guac/pkg/assembler"
 	"github.com/guacsec/guac/pkg/handler/processor"
 )
@@ -28,5 +30,5 @@ type DocumentParser interface {
 	// CreateNodes creates the GuacNode for the graph inputs
 	CreateNodes() []assembler.GuacNode
 	// CreateEdges creates the GuacEdges that form the relationship for the graph inputs
-	CreateEdges(foundIdentities []assembler.IdentityNode) []assembler.GuacEdge
+	CreateEdges(ctx context.Context, foundIdentities []assembler.IdentityNode) []assembler.GuacEdge
 }
diff --git a/pkg/ingestor/parser/dsse/parser_dsse.go b/pkg/ingestor/parser/dsse/parser_dsse.go
index 4eec63e5ef..9a0deccedc 100644
--- a/pkg/ingestor/parser/dsse/parser_dsse.go
+++ b/pkg/ingestor/parser/dsse/parser_dsse.go
@@ -16,6 +16,7 @@
 package dsse
 
 import (
+	"context"
 	"encoding/base64"
 	"fmt"
 
@@ -76,6 +77,6 @@ func (d *dsseParser) CreateNodes() []assembler.GuacNode {
 }
 
 // CreateEdges creates the GuacEdges that form the relationship for the graph inputs
-func (d *dsseParser) CreateEdges(foundIdentities []assembler.IdentityNode) []assembler.GuacEdge {
+func (d *dsseParser) CreateEdges(ctx context.Context, foundIdentities []assembler.IdentityNode) []assembler.GuacEdge {
 	return []assembler.GuacEdge{}
 }
diff --git a/pkg/ingestor/parser/dsse/parser_dsse_test.go b/pkg/ingestor/parser/dsse/parser_dsse_test.go
index a056625ad1..def262482e 100644
--- a/pkg/ingestor/parser/dsse/parser_dsse_test.go
+++ b/pkg/ingestor/parser/dsse/parser_dsse_test.go
@@ -16,6 +16,7 @@
 package dsse
 
 import (
+	"context"
 	"reflect"
 	"testing"
 
@@ -23,21 +24,29 @@ import (
 	"github.com/guacsec/guac/pkg/assembler"
 	"github.com/guacsec/guac/pkg/handler/processor"
 	"github.com/guacsec/guac/pkg/ingestor/verifier"
+	"github.com/guacsec/guac/pkg/logging"
 )
 
 func Test_DsseParser(t *testing.T) {
+	ctx := logging.WithLogger(context.Background())
 	err := verifier.RegisterVerifier(testdata.NewMockSigstoreVerifier(), "sigstore")
 	if err != nil {
 		t.Errorf("verifier.RegisterVerifier() failed with error: %v", err)
 	}
 	tests := []struct {
-		name    string
-		doc     *processor.Document
-		wantErr bool
+		name         string
+		doc          *processor.Document
+		wantNodes    []assembler.GuacNode
+		wantEdges    []assembler.GuacEdge
+		wantIdentity assembler.IdentityNode
+		wantErr      bool
 	}{{
-		name:    "testing",
-		doc:     &testdata.Ite6DSSEDoc,
-		wantErr: false,
+		name:         "testing",
+		doc:          &testdata.Ite6DSSEDoc,
+		wantNodes:    testdata.DsseNodes,
+		wantEdges:    testdata.DsseEdges,
+		wantIdentity: testdata.Ident,
+		wantErr:      false,
 	}}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -45,14 +54,14 @@ func Test_DsseParser(t *testing.T) {
 			if err := d.Parse(tt.doc); (err != nil) != tt.wantErr {
 				t.Errorf("slsa.Parse() error = %v, wantErr %v", err, tt.wantErr)
 			}
-			if nodes := d.CreateNodes(); !reflect.DeepEqual(nodes, testdata.DsseNodes) {
-				t.Errorf("slsa.CreateNodes() = %v, want %v", nodes, testdata.DsseNodes)
+			if nodes := d.CreateNodes(); !reflect.DeepEqual(nodes, tt.wantNodes) {
+				t.Errorf("slsa.CreateNodes() = %v, want %v", nodes, tt.wantNodes)
 			}
-			if edges := d.CreateEdges([]assembler.IdentityNode{testdata.Ident}); !reflect.DeepEqual(edges, testdata.DsseEdges) {
-				t.Errorf("slsa.CreateEdges() = %v, want %v", edges, testdata.DsseEdges)
+			if edges := d.CreateEdges(ctx, []assembler.IdentityNode{tt.wantIdentity}); !reflect.DeepEqual(edges, tt.wantEdges) {
+				t.Errorf("slsa.CreateEdges() = %v, want %v", edges, tt.wantEdges)
 			}
-			if identity := d.GetIdentities(); !reflect.DeepEqual(identity, []assembler.IdentityNode{testdata.Ident}) {
-				t.Errorf("slsa.GetDocType() = %v, want %v", identity, []assembler.IdentityNode{testdata.Ident})
+			if identity := d.GetIdentities(); !reflect.DeepEqual(identity, []assembler.IdentityNode{tt.wantIdentity}) {
+				t.Errorf("slsa.GetDocType() = %v, want %v", identity, []assembler.IdentityNode{tt.wantIdentity})
 			}
 		})
 	}
diff --git a/pkg/ingestor/parser/parser.go b/pkg/ingestor/parser/parser.go
index a1f54996a1..c4e6cb555c 100644
--- a/pkg/ingestor/parser/parser.go
+++ b/pkg/ingestor/parser/parser.go
@@ -16,6 +16,7 @@
 package parser
 
 import (
+	"context"
 	"fmt"
 
 	"github.com/guacsec/guac/pkg/assembler"
@@ -23,6 +24,7 @@ import (
 	"github.com/guacsec/guac/pkg/ingestor/parser/common"
 	"github.com/guacsec/guac/pkg/ingestor/parser/dsse"
 	"github.com/guacsec/guac/pkg/ingestor/parser/slsa"
+	"github.com/guacsec/guac/pkg/ingestor/parser/spdx"
 )
 
 type docTreeBuilder struct {
@@ -38,7 +40,7 @@ func newDocTreeBuilder() *docTreeBuilder {
 }
 
 // ParseDocumentTree takes the DocumentTree and create graph inputs (nodes and edges) per document node
-func ParseDocumentTree(docTree processor.DocumentTree) ([]assembler.AssemblerInput, error) {
+func ParseDocumentTree(ctx context.Context, docTree processor.DocumentTree) ([]assembler.AssemblerInput, error) {
 	assemblerinputs := []assembler.AssemblerInput{}
 	docTreeBuilder := newDocTreeBuilder()
 	err := docTreeBuilder.parse(docTree)
@@ -46,7 +48,7 @@ func ParseDocumentTree(docTree processor.DocumentTree) ([]assembler.AssemblerInp
 		return nil, err
 	}
 	for _, builder := range docTreeBuilder.graphBuilders {
-		assemblerinput := builder.CreateAssemblerInput(docTreeBuilder.identities)
+		assemblerinput := builder.CreateAssemblerInput(ctx, docTreeBuilder.identities)
 		assemblerinputs = append(assemblerinputs, assemblerinput)
 	}
 
@@ -93,6 +95,14 @@ func parseHelper(doc *processor.Document) (*common.GraphBuilder, error) {
 		}
 		slsaGraphBuilder := common.NewGenericGraphBuilder(slsaParser, nil)
 		return slsaGraphBuilder, nil
+	case processor.DocumentSPDX:
+		spdxParser := spdx.NewSpdxParser()
+		err := spdxParser.Parse(doc)
+		if err != nil {
+			return nil, err
+		}
+		spdxGraphBuilder := common.NewGenericGraphBuilder(spdxParser, nil)
+		return spdxGraphBuilder, nil
 	}
 	return nil, fmt.Errorf("no parser found for document type: %v", doc.Type)
 }
diff --git a/pkg/ingestor/parser/parser_test.go b/pkg/ingestor/parser/parser_test.go
index af92859340..63da2e8c94 100644
--- a/pkg/ingestor/parser/parser_test.go
+++ b/pkg/ingestor/parser/parser_test.go
@@ -16,17 +16,19 @@
 package parser
 
 import (
-	"reflect"
+	"context"
 	"testing"
 
 	"github.com/guacsec/guac/internal/testing/ingestor/testdata"
+	processor_data "github.com/guacsec/guac/internal/testing/processor"
 	"github.com/guacsec/guac/pkg/assembler"
 	"github.com/guacsec/guac/pkg/handler/processor"
 	"github.com/guacsec/guac/pkg/ingestor/verifier"
+	"github.com/guacsec/guac/pkg/logging"
 )
 
 var (
-	docTree = processor.DocumentNode{
+	dsseDocTree = processor.DocumentNode{
 		Document: &testdata.Ite6DSSEDoc,
 		Children: []*processor.DocumentNode{
 			{
@@ -36,6 +38,16 @@ var (
 		},
 	}
 
+	spdxDocTree = processor.DocumentNode{
+		Document: &processor.Document{
+			Blob:              processor_data.SpdxExampleAlpine,
+			Format:            processor.FormatJSON,
+			Type:              processor.DocumentSPDX,
+			SourceInformation: processor.SourceInformation{},
+		},
+		Children: []*processor.DocumentNode{},
+	}
+
 	graphInput = []assembler.AssemblerInput{{
 		Nodes: testdata.DsseNodes,
 		Edges: testdata.DsseEdges,
@@ -43,9 +55,15 @@ var (
 		Nodes: testdata.SlsaNodes,
 		Edges: testdata.SlsaEdges,
 	}}
+
+	spdxGraphInput = []assembler.AssemblerInput{{
+		Nodes: testdata.SpdxNodes,
+		Edges: testdata.SpdxEdges,
+	}}
 )
 
 func TestParseDocumentTree(t *testing.T) {
+	ctx := logging.WithLogger(context.Background())
 	err := verifier.RegisterVerifier(testdata.NewMockSigstoreVerifier(), "sigstore")
 	if err != nil {
 		t.Errorf("verifier.RegisterVerifier() failed with error: %v", err)
@@ -57,20 +75,39 @@ func TestParseDocumentTree(t *testing.T) {
 		wantErr bool
 	}{{
 		name:    "testing",
-		tree:    processor.DocumentTree(&docTree),
+		tree:    processor.DocumentTree(&dsseDocTree),
 		want:    graphInput,
 		wantErr: false,
+	}, {
+		name:    "valid big SPDX document",
+		tree:    processor.DocumentTree(&spdxDocTree),
+		want:    spdxGraphInput,
+		wantErr: false,
 	}}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got, err := ParseDocumentTree(tt.tree)
+			got, err := ParseDocumentTree(ctx, tt.tree)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("ParseDocumentTree() error = %v, wantErr %v", err, tt.wantErr)
 				return
 			}
-			if !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("ParseDocumentTree() = %v, want %v", got, tt.want)
+			if err == nil {
+				if len(got) != len(tt.want) {
+					t.Errorf("ParseDocumentTree() = %v, want %v", got, tt.want)
+				}
+				for i := range got {
+					compare(t, got[i].Edges, tt.want[i].Edges, got[i].Nodes, tt.want[i].Nodes)
+				}
 			}
 		})
 	}
 }
+
+func compare(t *testing.T, gotEdges, wantEdges []assembler.GuacEdge, gotNodes, wantNodes []assembler.GuacNode) {
+	if !testdata.GuacEdgeSliceEqual(gotEdges, wantEdges) {
+		t.Errorf("ParseDocumentTree() = %v, want %v", gotEdges, wantEdges)
+	}
+	if !testdata.GuacNodeSliceEqual(gotNodes, wantNodes) {
+		t.Errorf("ParseDocumentTree() = %v, want %v", gotNodes, wantNodes)
+	}
+}
diff --git a/pkg/ingestor/parser/slsa/parser_slsa.go b/pkg/ingestor/parser/slsa/parser_slsa.go
index 85c4600245..05f8d39dcc 100644
--- a/pkg/ingestor/parser/slsa/parser_slsa.go
+++ b/pkg/ingestor/parser/slsa/parser_slsa.go
@@ -16,6 +16,7 @@
 package slsa
 
 import (
+	"context"
 	"crypto/sha256"
 	"encoding/hex"
 	"encoding/json"
@@ -119,7 +120,7 @@ func (s *slsaParser) CreateNodes() []assembler.GuacNode {
 }
 
 // CreateEdges creates the GuacEdges that form the relationship for the graph inputs
-func (s *slsaParser) CreateEdges(foundIdentities []assembler.IdentityNode) []assembler.GuacEdge {
+func (s *slsaParser) CreateEdges(ctx context.Context, foundIdentities []assembler.IdentityNode) []assembler.GuacEdge {
 	edges := []assembler.GuacEdge{}
 	for _, i := range foundIdentities {
 		for _, a := range s.attestations {
diff --git a/pkg/ingestor/parser/slsa/parser_slsa_test.go b/pkg/ingestor/parser/slsa/parser_slsa_test.go
index 778eaf0cf7..81a65d9acb 100644
--- a/pkg/ingestor/parser/slsa/parser_slsa_test.go
+++ b/pkg/ingestor/parser/slsa/parser_slsa_test.go
@@ -16,23 +16,30 @@
 package slsa
 
 import (
+	"context"
 	"reflect"
 	"testing"
 
 	"github.com/guacsec/guac/internal/testing/ingestor/testdata"
 	"github.com/guacsec/guac/pkg/assembler"
 	"github.com/guacsec/guac/pkg/handler/processor"
+	"github.com/guacsec/guac/pkg/logging"
 )
 
 func Test_slsaParser(t *testing.T) {
+	ctx := logging.WithLogger(context.Background())
 	tests := []struct {
-		name    string
-		doc     *processor.Document
-		wantErr bool
+		name      string
+		doc       *processor.Document
+		wantNodes []assembler.GuacNode
+		wantEdges []assembler.GuacEdge
+		wantErr   bool
 	}{{
-		name:    "testing",
-		doc:     &testdata.Ite6SLSADoc,
-		wantErr: false,
+		name:      "testing",
+		doc:       &testdata.Ite6SLSADoc,
+		wantNodes: testdata.SlsaNodes,
+		wantEdges: testdata.SlsaEdges,
+		wantErr:   false,
 	}}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -40,11 +47,11 @@ func Test_slsaParser(t *testing.T) {
 			if err := s.Parse(tt.doc); (err != nil) != tt.wantErr {
 				t.Errorf("slsa.Parse() error = %v, wantErr %v", err, tt.wantErr)
 			}
-			if nodes := s.CreateNodes(); !reflect.DeepEqual(nodes, testdata.SlsaNodes) {
-				t.Errorf("slsa.CreateNodes() = %v, want %v", nodes, testdata.SlsaNodes)
+			if nodes := s.CreateNodes(); !reflect.DeepEqual(nodes, tt.wantNodes) {
+				t.Errorf("slsa.CreateNodes() = %v, want %v", nodes, tt.wantNodes)
 			}
-			if edges := s.CreateEdges([]assembler.IdentityNode{testdata.Ident}); !reflect.DeepEqual(edges, testdata.SlsaEdges) {
-				t.Errorf("slsa.CreateEdges() = %v, want %v", edges, testdata.SlsaEdges)
+			if edges := s.CreateEdges(ctx, []assembler.IdentityNode{testdata.Ident}); !reflect.DeepEqual(edges, tt.wantEdges) {
+				t.Errorf("slsa.CreateEdges() = %v, want %v", edges, tt.wantEdges)
 			}
 		})
 	}
diff --git a/pkg/ingestor/parser/spdx/parse_spdx.go b/pkg/ingestor/parser/spdx/parse_spdx.go
new file mode 100644
index 0000000000..39249d8a8c
--- /dev/null
+++ b/pkg/ingestor/parser/spdx/parse_spdx.go
@@ -0,0 +1,254 @@
+//
+// Copyright 2022 The GUAC Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package spdx
+
+import (
+	"bytes"
+	"context"
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/guacsec/guac/pkg/assembler"
+	"github.com/guacsec/guac/pkg/handler/processor"
+	"github.com/guacsec/guac/pkg/logging"
+	spdx_json "github.com/spdx/tools-golang/json"
+	spdx_common "github.com/spdx/tools-golang/spdx/common"
+	"github.com/spdx/tools-golang/spdx/v2_2"
+)
+
+type spdxParser struct {
+	packages map[string][]assembler.PackageNode
+	files    map[string][]assembler.ArtifactNode
+	spdxDoc  *v2_2.Document
+}
+
+func NewSpdxParser() *spdxParser {
+	return &spdxParser{
+		packages: map[string][]assembler.PackageNode{},
+		files:    map[string][]assembler.ArtifactNode{},
+	}
+}
+
+func (s *spdxParser) Parse(doc *processor.Document) error {
+	spdxDoc, err := parseSpdxBlob(doc.Blob)
+	if err != nil {
+		return fmt.Errorf("failed to parse SPDX document: %w", err)
+	}
+	s.spdxDoc = spdxDoc
+	s.getPackages()
+	s.getFiles()
+	return nil
+}
+
+// creating top level package manually until https://github.com/anchore/syft/issues/1241 is resolved
+func (s *spdxParser) getTopLevelPackage() {
+	// oci purl: pkg:oci/debian@sha256%3A244fd47e07d10?repository_url=ghcr.io/debian&tag=bullseye
+	splitImage := strings.Split(s.spdxDoc.DocumentName, "/")
+	if len(splitImage) == 3 {
+		topPackage := assembler.PackageNode{}
+		topPackage.Purl = "pkg:oci/" + splitImage[2] + "?repository_url=" + splitImage[0] + "/" + splitImage[1]
+		topPackage.Name = s.spdxDoc.DocumentName
+		s.packages[string(s.spdxDoc.SPDXIdentifier)] = append(s.packages[string(s.spdxDoc.SPDXIdentifier)], topPackage)
+	}
+}
+
+func (s *spdxParser) getPackages() {
+	s.getTopLevelPackage()
+	for _, pac := range s.spdxDoc.Packages {
+		currentPackage := assembler.PackageNode{}
+		currentPackage.Name = pac.PackageName
+		if len(pac.PackageExternalReferences) > 0 {
+			for _, ext := range pac.PackageExternalReferences {
+				if strings.HasPrefix(ext.RefType, "cpe") {
+					currentPackage.CPEs = append(currentPackage.CPEs, ext.Locator)
+				} else if ext.RefType == spdx_common.TypePackageManagerPURL {
+					currentPackage.Purl = ext.Locator
+				}
+			}
+		}
+		if len(pac.PackageChecksums) > 0 {
+			for _, checksum := range pac.PackageChecksums {
+				currentPackage.Digest = append(currentPackage.Digest, string(checksum.Algorithm)+":"+checksum.Value)
+			}
+		}
+		s.packages[string(pac.PackageSPDXIdentifier)] = append(s.packages[string(pac.PackageSPDXIdentifier)], currentPackage)
+	}
+}
+
+func (s *spdxParser) getFiles() {
+	for _, file := range s.spdxDoc.Files {
+		currentFile := assembler.ArtifactNode{}
+		for _, checksum := range file.Checksums {
+			currentFile.Name = file.FileName
+			currentFile.Digest = string(checksum.Algorithm) + ":" + checksum.Value
+			s.files[string(file.FileSPDXIdentifier)] = append(s.files[string(file.FileSPDXIdentifier)], currentFile)
+		}
+	}
+}
+
+func parseSpdxBlob(p []byte) (*v2_2.Document, error) {
+	reader := bytes.NewReader(p)
+	spdx, err := spdx_json.Load2_2(reader)
+	if err != nil {
+		return nil, err
+	}
+	return spdx, nil
+}
+
+func (s *spdxParser) CreateNodes() []assembler.GuacNode {
+	nodes := []assembler.GuacNode{}
+	for _, packNodes := range s.packages {
+		for _, packNode := range packNodes {
+			nodes = append(nodes, packNode)
+		}
+	}
+	for _, fileNodes := range s.files {
+		for _, fileNode := range fileNodes {
+			nodes = append(nodes, fileNode)
+		}
+	}
+	return nodes
+}
+
+func (s *spdxParser) getPackageElement(elementID string) []assembler.PackageNode {
+	if packNode, ok := s.packages[string(elementID)]; ok {
+		return packNode
+	}
+	return nil
+}
+
+func (s *spdxParser) getFileElement(elementID string) []assembler.ArtifactNode {
+	if fileNode, ok := s.files[string(elementID)]; ok {
+		return fileNode
+	}
+	return nil
+}
+
+func (s *spdxParser) CreateEdges(ctx context.Context, foundIdentities []assembler.IdentityNode) []assembler.GuacEdge {
+	logger := logging.FromContext(ctx)
+	edges := []assembler.GuacEdge{}
+	toplevel := s.getPackageElement("SPDXRef-DOCUMENT")
+	// adding top level package edge manually for all depends on package
+	if toplevel != nil {
+		edges = append(edges, createTopLevelEdges(toplevel[0], s.packages)...)
+	}
+	for _, rel := range s.spdxDoc.Relationships {
+		foundPackNodes := s.getPackageElement("SPDXRef-" + string(rel.RefA.ElementRefID))
+		foundFileNodes := s.getFileElement("SPDXRef-" + string(rel.RefA.ElementRefID))
+		relatedPackNodes := s.getPackageElement("SPDXRef-" + string(rel.RefB.ElementRefID))
+		relatedFileNodes := s.getFileElement("SPDXRef-" + string(rel.RefB.ElementRefID))
+		for _, packNode := range foundPackNodes {
+			createdEdge, err := getEdge(packNode, rel.Relationship, relatedPackNodes, relatedFileNodes)
+			if err != nil {
+				logger.Errorf("error generating spdx edge %v", err)
+				continue
+			}
+			if createdEdge != nil {
+				edges = append(edges, createdEdge)
+			}
+		}
+		for _, fileNode := range foundFileNodes {
+			createdEdge, err := getEdge(fileNode, rel.Relationship, relatedPackNodes, relatedFileNodes)
+			if err != nil {
+				logger.Errorf("error generating spdx edge %v", err)
+				continue
+			}
+			if createdEdge != nil {
+				edges = append(edges, createdEdge)
+			}
+		}
+	}
+	return edges
+}
+
+func createTopLevelEdges(toplevel assembler.PackageNode, packages map[string][]assembler.PackageNode) []assembler.GuacEdge {
+	edges := []assembler.GuacEdge{}
+	for _, packNodes := range packages {
+		for _, packNode := range packNodes {
+			if packNode.Purl != toplevel.Purl {
+				e := assembler.DependsOnEdge{
+					PackageNode:       toplevel,
+					PackageDependency: packNode,
+				}
+				edges = append(edges, e)
+			}
+		}
+	}
+	return edges
+}
+
+func getEdge(foundNode assembler.GuacNode, relationship string, relatedPackNodes []assembler.PackageNode, relatedFileNodes []assembler.ArtifactNode) (assembler.GuacEdge, error) {
+	if len(relatedFileNodes) > 0 {
+		for _, rfileNode := range relatedFileNodes {
+			return getEdgeByType(relationship, foundNode, rfileNode)
+		}
+	} else if len(relatedPackNodes) > 0 {
+		for _, rpackNode := range relatedPackNodes {
+			return getEdgeByType(relationship, foundNode, rpackNode)
+		}
+	}
+	return nil, nil
+}
+
+func getEdgeByType(relationship string, foundNode assembler.GuacNode, relatedNode assembler.GuacNode) (assembler.GuacEdge, error) {
+	switch relationship {
+	case spdx_common.TypeRelationshipContains:
+		return getContainsEdge(foundNode, relatedNode)
+	case spdx_common.TypeRelationshipDependsOn:
+		return getDependsOnEdge(foundNode, relatedNode), nil
+	}
+	return nil, nil
+}
+
+func getContainsEdge(foundNode assembler.GuacNode, relatedNode assembler.GuacNode) (assembler.GuacEdge, error) {
+	e := assembler.ContainsEdge{}
+	if foundNode.Type() == "Package" {
+		e.PackageNode = foundNode.(assembler.PackageNode)
+	} else {
+		return nil, errors.New("node type mismatch during contains edge creation")
+	}
+	if relatedNode.Type() == "Artifact" {
+		e.ContainedArtifact = relatedNode.(assembler.ArtifactNode)
+	} else {
+		return nil, errors.New("node type mismatch during contains edge creation")
+	}
+	return e, nil
+}
+
+func getDependsOnEdge(foundNode assembler.GuacNode, relatedNode assembler.GuacNode) assembler.GuacEdge {
+	e := assembler.DependsOnEdge{}
+	if foundNode.Type() == "Package" {
+		e.PackageNode = foundNode.(assembler.PackageNode)
+	} else {
+		e.ArtifactNode = foundNode.(assembler.ArtifactNode)
+	}
+
+	if relatedNode.Type() == "Package" {
+		e.PackageDependency = relatedNode.(assembler.PackageNode)
+	} else {
+		e.ArtifactDependency = relatedNode.(assembler.ArtifactNode)
+	}
+	return e
+}
+
+func (s *spdxParser) GetIdentities() []assembler.IdentityNode {
+	return nil
+}
+
+func (s *spdxParser) GetDocType() processor.DocumentType {
+	return processor.DocumentSPDX
+}
diff --git a/pkg/ingestor/parser/spdx/parse_spdx_test.go b/pkg/ingestor/parser/spdx/parse_spdx_test.go
new file mode 100644
index 0000000000..de389756a0
--- /dev/null
+++ b/pkg/ingestor/parser/spdx/parse_spdx_test.go
@@ -0,0 +1,70 @@
+//
+// Copyright 2022 The GUAC Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package spdx
+
+import (
+	"context"
+	"reflect"
+	"testing"
+
+	"github.com/guacsec/guac/internal/testing/ingestor/testdata"
+	processor_data "github.com/guacsec/guac/internal/testing/processor"
+	"github.com/guacsec/guac/pkg/assembler"
+	"github.com/guacsec/guac/pkg/handler/processor"
+	"github.com/guacsec/guac/pkg/logging"
+)
+
+func Test_spdxParser(t *testing.T) {
+	ctx := logging.WithLogger(context.Background())
+	tests := []struct {
+		name      string
+		doc       *processor.Document
+		wantNodes []assembler.GuacNode
+		wantEdges []assembler.GuacEdge
+		wantErr   bool
+	}{{
+		name: "valid big SPDX document",
+		doc: &processor.Document{
+			Blob:              processor_data.SpdxExampleAlpine,
+			Format:            processor.FormatJSON,
+			Type:              processor.DocumentSPDX,
+			SourceInformation: processor.SourceInformation{},
+		},
+		wantNodes: testdata.SpdxNodes,
+		wantEdges: testdata.SpdxEdges,
+		wantErr:   false,
+	}}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			s := NewSpdxParser()
+			err := s.Parse(tt.doc)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("spdxParser.Parse() error = %v, wantErr %v", err, tt.wantErr)
+			}
+			if err == nil {
+				if nodes := s.CreateNodes(); !testdata.GuacNodeSliceEqual(nodes, tt.wantNodes) {
+					t.Errorf("spdxParser.CreateNodes() = %v, want %v", nodes, tt.wantNodes)
+				}
+				if edges := s.CreateEdges(ctx, nil); !testdata.GuacEdgeSliceEqual(edges, tt.wantEdges) {
+					t.Errorf("spdxParser.CreateEdges() = %v, want %v", edges, tt.wantEdges)
+				}
+				if docType := s.GetDocType(); !reflect.DeepEqual(docType, processor.DocumentSPDX) {
+					t.Errorf("spdxParser.GetDocType() = %v, want %v", docType, processor.DocumentSPDX)
+				}
+			}
+		})
+	}
+}