Repository: guacsec/guac
Pull request #2371 (2024-12-16 15:45:21)

[FIX] CDX vulnerability parsing and update ENT VEX index
# Description of the PR

fixes https://github.com/guacsec/guac/issues/2369

Fix CDX vulnerability/VEX ingestion. Removed Status Note and Statement from Ent index as the string can be too long for postgres to index.

# PR Checklist

- [x] All commits have [a Developer Certificate of Origin (DCO)](https://wiki.linuxfoundation.org/dco) -- they are generated using `-s` flag to `git commit`.
- [x] All new changes are covered by tests
- [ ] If GraphQL schema is changed, `make generate` has been run
- [ ] If GraphQL schema is changed, GraphQL client updates/additions have been made
- [ ] If OpenAPI spec is changed, `make generate` has been run
- [x] If ent schema is changed, `make generate` has been run
- [ ] If `collectsub` protobuf has been changed, `make proto` has been run
- [x] All CI checks are passing (tests and formatting)
- [x] All dependent PRs have already been merged



Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 16bd7776..04281b73 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -40,7 +40,7 @@ jobs:
         with:
           persist-credentials: false
       - name: setup-go
-        uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # tag=v3.2.1
+        uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # tag=v3.2.1
         with:
           go-version: '1.21'
       - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
@@ -73,7 +73,7 @@ jobs:
         with:
           persist-credentials: false
       - name: setup-go
-        uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # tag=v3.2.1
+        uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # tag=v3.2.1
         with:
           go-version: '1.21'
       - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
@@ -96,7 +96,7 @@ jobs:
         with:
           persist-credentials: false
       - name: setup-go
-        uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # tag=v3.2.1
+        uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # tag=v3.2.1
         with:
           go-version: '1.21'
       - name: Install atlas
@@ -116,7 +116,7 @@ jobs:
         with:
           persist-credentials: false
       - name: setup-go
-        uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # tag=v5.1.0
+        uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # tag=v5.2.0
         with:
           go-version: '1.21'
       - name: Install atlas
@@ -154,7 +154,7 @@ jobs:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
       with:
         persist-credentials: false
-    - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed
+    - uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a
       with:
         go-version: '~1.21'
     - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b
@@ -242,7 +242,7 @@ jobs:
         with:
           persist-credentials: false
       - name: setup-go
-        uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # tag=v3.2.1
+        uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # tag=v3.2.1
         with:
           go-version: '1.21'
       - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
diff --git a/.github/workflows/postmerge.yaml b/.github/workflows/postmerge.yaml
index 9b62fa28..824ea423 100644
--- a/.github/workflows/postmerge.yaml
+++ b/.github/workflows/postmerge.yaml
@@ -30,7 +30,7 @@ jobs:
         with:
           persist-credentials: false
       - name: setup-go
-        uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # tag=v3.2.1
+        uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # tag=v3.2.1
         with:
           go-version: '1.21'
       - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index e5405bdb..3df378e1 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -50,13 +50,13 @@ jobs:
           username: ${{ github.actor }}
           password: ${{ secrets.GITHUB_TOKEN }}
       - name: Set up Go
-        uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
+        uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
         with:
           go-version: "1.21"
       - name: Install cosign
         uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # main
       - name: Install syft
-        uses: anchore/sbom-action/download-syft@55dc4ee22412511ee8c3142cbea40418e6cec693 # v0.17.8
+        uses: anchore/sbom-action/download-syft@df80a981bc6edbc4e220a492d3cbe9f5547a6e75 # v0.17.9
 
       - name: Run GoReleaser Snapshot
         if: ${{ !startsWith(github.ref, 'refs/tags/') }}
@@ -116,7 +116,7 @@ jobs:
           persist-credentials: false
 
       - name: Set up Docker Buildx
-        uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
+        uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
 
       - name: Log in to GitHub Container Registry
         uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
diff --git a/.github/workflows/reusable-local-build.yaml b/.github/workflows/reusable-local-build.yaml
index 4ddf297d..31c2e862 100644
--- a/.github/workflows/reusable-local-build.yaml
+++ b/.github/workflows/reusable-local-build.yaml
@@ -37,7 +37,7 @@ jobs:
           repository: ${{ inputs.repository }}
           ref: ${{ inputs.ref }}
       - name: Set up Go
-        uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
+        uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
         with:
           go-version: 'stable'
       - name: Install GoReleaser
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
index ffae64d5..572324a8 100644
--- a/.github/workflows/scorecard.yml
+++ b/.github/workflows/scorecard.yml
@@ -68,6 +68,6 @@ jobs:
 
       # Upload the results to GitHub's code scanning dashboard.
       - name: "Upload to code-scanning"
-        uses: github/codeql-action/upload-sarif@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6
+        uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
         with:
           sarif_file: results.sarif
diff --git a/go.mod b/go.mod
index 2f828d7b..ba9a9456 100644
--- a/go.mod
+++ b/go.mod
@@ -9,10 +9,10 @@ require (
 	github.com/fsouza/fake-gcs-server v1.50.2
 	github.com/in-toto/in-toto-golang v0.9.0
 	github.com/neo4j/neo4j-go-driver/v4 v4.4.7
-	github.com/secure-systems-lab/go-securesystemslib v0.8.0
+	github.com/secure-systems-lab/go-securesystemslib v0.9.0
 	github.com/spf13/cobra v1.8.1
 	go.uber.org/zap v1.27.0
-	google.golang.org/api v0.210.0
+	google.golang.org/api v0.212.0
 )
 
 require (
@@ -35,7 +35,7 @@ require (
 	go.opencensus.io v0.24.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	golang.org/x/crypto v0.31.0 // indirect
-	golang.org/x/net v0.31.0 // indirect
+	golang.org/x/net v0.32.0 // indirect
 	golang.org/x/oauth2 v0.24.0
 	golang.org/x/sync v0.10.0 // indirect
 	golang.org/x/sys v0.28.0 // indirect
@@ -49,9 +49,9 @@ require (
 require (
 	ariga.io/atlas v0.25.1-0.20240717145915-af51d3945208 // indirect
 	cel.dev/expr v0.16.1 // indirect
-	cloud.google.com/go/auth v0.11.0 // indirect
+	cloud.google.com/go/auth v0.13.0 // indirect
 	cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
-	cloud.google.com/go/compute/metadata v0.5.2 // indirect
+	cloud.google.com/go/compute/metadata v0.6.0 // indirect
 	cloud.google.com/go/monitoring v1.21.2 // indirect
 	dario.cat/mergo v1.0.0 // indirect
 	deps.dev/util/maven v0.0.0-20241010035105-b3ba03369df1 // indirect
@@ -278,7 +278,7 @@ require (
 	golang.org/x/tools v0.26.0 // indirect
 	golang.org/x/vuln v1.0.4 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 // indirect
 	google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
@@ -293,8 +293,8 @@ require (
 	deps.dev/api/v3 v3.0.0-20241010035105-b3ba03369df1
 	entgo.io/contrib v0.6.0
 	entgo.io/ent v0.14.1
-	github.com/99designs/gqlgen v0.17.59
-	github.com/CycloneDX/cyclonedx-go v0.9.1
+	github.com/99designs/gqlgen v0.17.60
+	github.com/CycloneDX/cyclonedx-go v0.9.2
 	github.com/Khan/genqlient v0.7.0
 	github.com/Masterminds/semver v1.5.0
 	github.com/ProtonMail/gluon v0.17.0
@@ -309,7 +309,7 @@ require (
 	github.com/fsnotify/fsnotify v1.8.0
 	github.com/getkin/kin-openapi v0.128.0
 	github.com/go-chi/chi v4.1.2+incompatible
-	github.com/go-chi/chi/v5 v5.1.0
+	github.com/go-chi/chi/v5 v5.2.0
 	github.com/go-git/go-git/v5 v5.12.0
 	github.com/gobwas/glob v0.2.3
 	github.com/gofrs/uuid v4.4.0+incompatible
diff --git a/go.sum b/go.sum
index 8bf3e8ae..06c92225 100644
--- a/go.sum
+++ b/go.sum
@@ -5,12 +5,12 @@ cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8=
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
 cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
-cloud.google.com/go/auth v0.11.0 h1:Ic5SZz2lsvbYcWT5dfjNWgw6tTlGi2Wc8hyQSC9BstA=
-cloud.google.com/go/auth v0.11.0/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
+cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs=
+cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q=
 cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU=
 cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
-cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
-cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
+cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
+cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
 cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA=
 cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY=
 cloud.google.com/go/kms v1.20.1 h1:og29Wv59uf2FVaZlesaiDAqHFzHaoUyHI3HYp9VUHVg=
@@ -41,8 +41,8 @@ entgo.io/contrib v0.6.0 h1:xfo4TbJE7sJZWx7BV7YrpSz7IPFvS8MzL3fnfzZjKvQ=
 entgo.io/contrib v0.6.0/go.mod h1:3qWIseJ/9Wx2Hu5zVh15FDzv7d/UvKNcYKdViywWCQg=
 entgo.io/ent v0.14.1 h1:fUERL506Pqr92EPHJqr8EYxbPioflJo6PudkrEA8a/s=
 entgo.io/ent v0.14.1/go.mod h1:MH6XLG0KXpkcDQhKiHfANZSzR55TJyPL5IGNpI8wpco=
-github.com/99designs/gqlgen v0.17.59 h1:1hvrBXMlHrnAFZIIHtT049Y2FnlntPESuwRi1SygLqQ=
-github.com/99designs/gqlgen v0.17.59/go.mod h1:vQJzWXyGya2TYL7cig1G4OaCQzyck031MgYBlUwaI9I=
+github.com/99designs/gqlgen v0.17.60 h1:xxl7kQDCNw79itzWQtCUSXgkovCyq9r+ogSXfZpKPYM=
+github.com/99designs/gqlgen v0.17.60/go.mod h1:vQJzWXyGya2TYL7cig1G4OaCQzyck031MgYBlUwaI9I=
 github.com/Azure/azure-amqp-common-go/v3 v3.2.3 h1:uDF62mbd9bypXWi19V1bN5NZEO84JqgmI5G73ibAmrk=
 github.com/Azure/azure-amqp-common-go/v3 v3.2.3/go.mod h1:7rPmbSfszeovxGfc5fSAXE4ehlXQZHpMja2OtxC2Tas=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8=
@@ -75,8 +75,8 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
-github.com/CycloneDX/cyclonedx-go v0.9.1 h1:yffaWOZsv77oTJa/SdVZYdgAgFioCeycBUKkqS2qzQM=
-github.com/CycloneDX/cyclonedx-go v0.9.1/go.mod h1:NE/EWvzELOFlG6+ljX/QeMlVt9VKcTwu8u0ccsACEsw=
+github.com/CycloneDX/cyclonedx-go v0.9.2 h1:688QHn2X/5nRezKe2ueIVCt+NRqf7fl3AVQk+vaFcIo=
+github.com/CycloneDX/cyclonedx-go v0.9.2/go.mod h1:vcK6pKgO1WanCdd61qx4bFnSsDJQ6SbM2ZuMIgq86Jg=
 github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
 github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1 h1:pB2F2JKCj1Znmp2rwxxt1J0Fg0wezTMgWYk5Mpbi1kg=
@@ -324,8 +324,8 @@ github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
 github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
 github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
 github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
-github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
-github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
+github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
+github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
 github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
@@ -735,8 +735,8 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g
 github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
 github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
 github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
-github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbmfHkLguCE9laoZCUzEEpIZXA=
-github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU=
+github.com/secure-systems-lab/go-securesystemslib v0.9.0 h1:rf1HIbL64nUpEIZnjLZ3mcNEL9NBPB0iuVjyxvq3LZc=
+github.com/secure-systems-lab/go-securesystemslib v0.9.0/go.mod h1:DVHKMcZ+V4/woA/peqr+L0joiRXbPpQ042GgJckkFgw=
 github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0=
 github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg=
 github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
@@ -804,8 +804,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
-github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo=
-github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=
+github.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo=
+github.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=
 github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a h1:J/YdBZ46WKpXsxsW93SG+q0F8KI+yFrcIDT4c/RNoc4=
 github.com/tiancaiamao/gp v0.0.0-20221230034425-4025bc8a4d4a/go.mod h1:h4xBhSNtOeEosLJ4P7JyKXX7Cabg7AVkWCK5gV2vOrM=
 github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
@@ -980,8 +980,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
 golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
-golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
-golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
+golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
+golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
 golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
@@ -1092,8 +1092,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk=
 golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
-google.golang.org/api v0.210.0 h1:HMNffZ57OoZCRYSbdWVRoqOa8V8NIHLL0CzdBPLztWk=
-google.golang.org/api v0.210.0/go.mod h1:B9XDZGnx2NtyjzVkOVTGrFSAVZgPcbedzKg/gTLwqBs=
+google.golang.org/api v0.212.0 h1:BcRj3MJfHF3FYD29rk7u9kuu1SyfGqfHcA0hSwKqkHg=
+google.golang.org/api v0.212.0/go.mod h1:gICpLlpp12/E8mycRMzgy3SQ9cFh2XnVJ6vJi/kQbvI=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
@@ -1105,8 +1105,8 @@ google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD
 google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc=
 google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f h1:M65LEviCfuZTfrfzwwEoxVtgvfkFkBUbFnRbxCXuXhU=
 google.golang.org/genproto/googleapis/api v0.0.0-20241113202542-65e8d215514f/go.mod h1:Yo94eF2nj7igQt+TiJ49KxjIH8ndLYPZMIRSiRcEbg0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 h1:IfdSdTcLFy4lqUQrQJLkLt1PB+AsqVz6lwkWPzWEz10=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
 google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
diff --git a/pkg/assembler/backends/ent/backend/certifyVEXStatement.go b/pkg/assembler/backends/ent/backend/certifyVEXStatement.go
index 68dd19ee..a1d538aa 100644
--- a/pkg/assembler/backends/ent/backend/certifyVEXStatement.go
+++ b/pkg/assembler/backends/ent/backend/certifyVEXStatement.go
@@ -44,8 +44,6 @@ func certifyVexConflictColumns() []string {
 	return []string{
 		certifyvex.FieldKnownSince,
 		certifyvex.FieldStatus,
-		certifyvex.FieldStatement,
-		certifyvex.FieldStatusNotes,
 		certifyvex.FieldJustification,
 		certifyvex.FieldOrigin,
 		certifyvex.FieldCollector,
diff --git a/pkg/assembler/backends/ent/backend/search.go b/pkg/assembler/backends/ent/backend/search.go
index e647ea50..77cd76c2 100644
--- a/pkg/assembler/backends/ent/backend/search.go
+++ b/pkg/assembler/backends/ent/backend/search.go
@@ -36,7 +36,6 @@ import (
 	"github.com/guacsec/guac/pkg/assembler/backends/ent/predicate"
 	"github.com/guacsec/guac/pkg/assembler/backends/ent/sourcename"
 	"github.com/guacsec/guac/pkg/assembler/graphql/model"
-	"github.com/guacsec/guac/pkg/assembler/helpers"
 )
 
 const (
@@ -328,10 +327,6 @@ func (b *EntBackend) BatchQueryPkgIDCertifyVuln(ctx context.Context, pkgIDs []st
 		return nil, nil
 	}
 
-	// static ID for noVuln that is generated from type = novuln and vulnid = ""
-	// this is generated via:
-	vulnIDs := helpers.GetKey[*model.VulnerabilityInputSpec, helpers.VulnIds](&model.VulnerabilityInputSpec{Type: NoVuln, VulnerabilityID: ""}, helpers.VulnServerKey)
-	noVulnID := generateUUIDKey([]byte(vulnIDs.VulnerabilityID))
 	var queryList []uuid.UUID
 
 	for _, id := range pkgIDs {
@@ -343,14 +338,16 @@ func (b *EntBackend) BatchQueryPkgIDCertifyVuln(ctx context.Context, pkgIDs []st
 		queryList = append(queryList, convertedID)
 	}
 
-	var cvLatestScan []struct {
+	type cvLatestScan struct {
 		PkgID          uuid.UUID `json:"package_id"`
 		VulnID         uuid.UUID `json:"vulnerability_id"`
 		LastScanTimeDB time.Time `json:"max"`
 	}
 
+	var cvLatestScans []cvLatestScan
+
 	var aggPredicates []predicate.CertifyVuln
-	aggPredicates = append(aggPredicates, certifyvuln.PackageIDIn(queryList...), certifyvuln.VulnerabilityIDNEQ(noVulnID))
+	aggPredicates = append(aggPredicates, certifyvuln.PackageIDIn(queryList...))
 
 	// aggregate to find the latest timescanned for certifyVulns for list of packages
 	err := b.client.CertifyVuln.Query().
@@ -360,14 +357,14 @@ func (b *EntBackend) BatchQueryPkgIDCertifyVuln(ctx context.Context, pkgIDs []st
 			t := sql.Table(certifyvuln.Table)
 			return sql.As(sql.Max(t.C(certifyvuln.FieldTimeScanned)), "max")
 		}).
-		Scan(ctx, &cvLatestScan)
+		Scan(ctx, &cvLatestScans)
 
 	if err != nil {
 		return nil, fmt.Errorf("failed aggregate certifyVuln based on packageIDs with error: %w", err)
 	}
 
 	var predicates []predicate.CertifyVuln
-	for _, record := range cvLatestScan {
+	for _, record := range cvLatestScans {
 		predicates = append(predicates,
 			certifyvuln.And(
 				certifyvuln.VulnerabilityID(record.VulnID),
diff --git a/pkg/assembler/backends/ent/migrate/Dockerfile b/pkg/assembler/backends/ent/migrate/Dockerfile
index 1ca708df..eadcd294 100644
--- a/pkg/assembler/backends/ent/migrate/Dockerfile
+++ b/pkg/assembler/backends/ent/migrate/Dockerfile
@@ -1,4 +1,4 @@
-FROM arigaio/atlas:latest-alpine@sha256:f1719553ebd3318fc4904135178e202dad054403e9a1ba12cddfd4d4b0c98a20
+FROM arigaio/atlas:latest-alpine@sha256:d61e11c6f69383e0c01122993af3978395f3fbfe6cc1611986b7232dc485553b
 
 WORKDIR /app
 
diff --git a/pkg/assembler/backends/ent/migrate/migrations/20241216154012_ent_diff.sql b/pkg/assembler/backends/ent/migrate/migrations/20241216154012_ent_diff.sql
new file mode 100644
index 00000000..3d389f67
--- /dev/null
+++ b/pkg/assembler/backends/ent/migrate/migrations/20241216154012_ent_diff.sql
@@ -0,0 +1,8 @@
+-- Drop index "vex_artifact_id" from table: "certify_vexes"
+DROP INDEX "vex_artifact_id";
+-- Drop index "vex_package_id" from table: "certify_vexes"
+DROP INDEX "vex_package_id";
+-- Create index "vex_artifact_id" to table: "certify_vexes"
+CREATE UNIQUE INDEX "vex_artifact_id" ON "certify_vexes" ("known_since", "justification", "status", "origin", "collector", "document_ref", "vulnerability_id", "package_id") WHERE (artifact_id IS NULL);
+-- Create index "vex_package_id" to table: "certify_vexes"
+CREATE UNIQUE INDEX "vex_package_id" ON "certify_vexes" ("known_since", "justification", "status", "origin", "collector", "document_ref", "vulnerability_id", "artifact_id") WHERE (package_id IS NULL);
diff --git a/pkg/assembler/backends/ent/migrate/migrations/atlas.sum b/pkg/assembler/backends/ent/migrate/migrations/atlas.sum
index cd3d75ab..8c9a8eef 100644
--- a/pkg/assembler/backends/ent/migrate/migrations/atlas.sum
+++ b/pkg/assembler/backends/ent/migrate/migrations/atlas.sum
@@ -1,4 +1,4 @@
-h1:7U2rKCWB5tpN3SOma2KThbIofWfFpnkN72sc+cXrYX8=
+h1:Ugdnk6GoWVQHrBmM441WC8IADVS5bnwL1nuEpmD1GWs=
 20240503123155_baseline.sql h1:oZtbKI8sJj3xQq7ibfvfhFoVl+Oa67CWP7DFrsVLVds=
 20240626153721_ent_diff.sql h1:FvV1xELikdPbtJk7kxIZn9MhvVVoFLF/2/iT/wM5RkA=
 20240702195630_ent_diff.sql h1:y8TgeUg35krYVORmC7cN4O96HqOc3mVO9IQ2lYzIzwg=
@@ -11,3 +11,4 @@ h1:7U2rKCWB5tpN3SOma2KThbIofWfFpnkN72sc+cXrYX8=
 20240919142722_ent_diff.sql h1:hcb42aHj5QUwbd7HXsUFnnAzHIckdXfGRDNYa24rns8=
 20241017140224_ent_diff.sql h1:BrrQdJnjtZJ9FYOXc5PgEafQ6N3ADdydFPevjdyTqnU=
 20241030212025_ent_diff.sql h1:IlCPmPKr+81472GhqF+hris+RX4zaKwBxVC1pCCi8vE=
+20241216154012_ent_diff.sql h1:RzLRAB0SIBcufd46h5eLApX3UCfl+ITHS+K/WLg+edI=
diff --git a/pkg/assembler/backends/ent/migrate/schema.go b/pkg/assembler/backends/ent/migrate/schema.go
index c52f39b4..b01ba4ea 100644
--- a/pkg/assembler/backends/ent/migrate/schema.go
+++ b/pkg/assembler/backends/ent/migrate/schema.go
@@ -347,7 +347,7 @@ var (
 			{
 				Name:    "vex_artifact_id",
 				Unique:  true,
-				Columns: []*schema.Column{CertifyVexesColumns[1], CertifyVexesColumns[5], CertifyVexesColumns[2], CertifyVexesColumns[3], CertifyVexesColumns[4], CertifyVexesColumns[6], CertifyVexesColumns[7], CertifyVexesColumns[8], CertifyVexesColumns[11], CertifyVexesColumns[9]},
+				Columns: []*schema.Column{CertifyVexesColumns[1], CertifyVexesColumns[5], CertifyVexesColumns[2], CertifyVexesColumns[6], CertifyVexesColumns[7], CertifyVexesColumns[8], CertifyVexesColumns[11], CertifyVexesColumns[9]},
 				Annotation: &entsql.IndexAnnotation{
 					Where: "artifact_id IS NULL",
 				},
@@ -355,7 +355,7 @@ var (
 			{
 				Name:    "vex_package_id",
 				Unique:  true,
-				Columns: []*schema.Column{CertifyVexesColumns[1], CertifyVexesColumns[5], CertifyVexesColumns[2], CertifyVexesColumns[3], CertifyVexesColumns[4], CertifyVexesColumns[6], CertifyVexesColumns[7], CertifyVexesColumns[8], CertifyVexesColumns[11], CertifyVexesColumns[10]},
+				Columns: []*schema.Column{CertifyVexesColumns[1], CertifyVexesColumns[5], CertifyVexesColumns[2], CertifyVexesColumns[6], CertifyVexesColumns[7], CertifyVexesColumns[8], CertifyVexesColumns[11], CertifyVexesColumns[10]},
 				Annotation: &entsql.IndexAnnotation{
 					Where: "package_id IS NULL",
 				},
diff --git a/pkg/assembler/backends/ent/schema/certifyvex.go b/pkg/assembler/backends/ent/schema/certifyvex.go
index b095fa2f..fca7be05 100644
--- a/pkg/assembler/backends/ent/schema/certifyvex.go
+++ b/pkg/assembler/backends/ent/schema/certifyvex.go
@@ -62,9 +62,9 @@ func (CertifyVex) Edges() []ent.Edge {
 // Indexes of the VEX.
 func (CertifyVex) Indexes() []ent.Index {
 	return []ent.Index{
-		index.Fields("known_since", "justification", "status", "statement", "status_notes", "origin", "collector", "document_ref").
+		index.Fields("known_since", "justification", "status", "origin", "collector", "document_ref").
 			Edges("vulnerability", "package").Unique().Annotations(entsql.IndexWhere("artifact_id IS NULL")).StorageKey("vex_artifact_id"),
-		index.Fields("known_since", "justification", "status", "statement", "status_notes", "origin", "collector", "document_ref").
-		Edges("vulnerability", "artifact").Unique().Annotations(entsql.IndexWhere("package_id IS NULL")).StorageKey("vex_package_id"),
+		index.Fields("known_since", "justification", "status", "origin", "collector", "document_ref").
+			Edges("vulnerability", "artifact").Unique().Annotations(entsql.IndexWhere("package_id IS NULL")).StorageKey("vex_package_id"),
 	}
 }
diff --git a/pkg/assembler/graphql/generated/root_.generated.go b/pkg/assembler/graphql/generated/root_.generated.go
index bba00349..f9b07268 100644
--- a/pkg/assembler/graphql/generated/root_.generated.go
+++ b/pkg/assembler/graphql/generated/root_.generated.go
@@ -5704,7 +5704,7 @@ extend type Query {
   CertifyVuln(certifyVulnSpec: CertifyVulnSpec!): [CertifyVuln!]!
   "Returns a paginated results via CertifyVulnConnection"
   CertifyVulnList(certifyVulnSpec: CertifyVulnSpec!, after: ID, first: Int): CertifyVulnConnection
-  "Batch queries via pkgVersion IDs to find all CertifyVulns (latest timestamp) that contain vulnerabilities"
+  "Batch queries via pkgVersion IDs to find all CertifyVulns (latest timestamp, including any ` + "`" + `novuln` + "`" + `)"
   BatchQueryPkgIDCertifyVuln(pkgIDs: [ID!]!): [CertifyVuln!]!
 }
 
diff --git a/pkg/assembler/graphql/resolvers/artifact.resolvers.go b/pkg/assembler/graphql/resolvers/artifact.resolvers.go
index 11216822..3db4e4f9 100644
--- a/pkg/assembler/graphql/resolvers/artifact.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/artifact.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/builder.resolvers.go b/pkg/assembler/graphql/resolvers/builder.resolvers.go
index da7f69fa..970961dc 100644
--- a/pkg/assembler/graphql/resolvers/builder.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/builder.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/certifyBad.resolvers.go b/pkg/assembler/graphql/resolvers/certifyBad.resolvers.go
index 25e6287b..a71ed1be 100644
--- a/pkg/assembler/graphql/resolvers/certifyBad.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/certifyBad.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/certifyGood.resolvers.go b/pkg/assembler/graphql/resolvers/certifyGood.resolvers.go
index cee4b74a..e612f42f 100644
--- a/pkg/assembler/graphql/resolvers/certifyGood.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/certifyGood.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/certifyLegal.resolvers.go b/pkg/assembler/graphql/resolvers/certifyLegal.resolvers.go
index ca5ec03d..844bd3ae 100644
--- a/pkg/assembler/graphql/resolvers/certifyLegal.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/certifyLegal.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/certifyScorecard.resolvers.go b/pkg/assembler/graphql/resolvers/certifyScorecard.resolvers.go
index 1c9f0b90..103be99c 100644
--- a/pkg/assembler/graphql/resolvers/certifyScorecard.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/certifyScorecard.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/certifyVEXStatement.resolvers.go b/pkg/assembler/graphql/resolvers/certifyVEXStatement.resolvers.go
index 304db833..e86eb16e 100644
--- a/pkg/assembler/graphql/resolvers/certifyVEXStatement.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/certifyVEXStatement.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/certifyVuln.resolvers.go b/pkg/assembler/graphql/resolvers/certifyVuln.resolvers.go
index df9fbe0b..2593c0cf 100644
--- a/pkg/assembler/graphql/resolvers/certifyVuln.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/certifyVuln.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/contact.resolvers.go b/pkg/assembler/graphql/resolvers/contact.resolvers.go
index 01840fe0..5e870f86 100644
--- a/pkg/assembler/graphql/resolvers/contact.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/contact.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/delete.resolvers.go b/pkg/assembler/graphql/resolvers/delete.resolvers.go
index 273fbd3a..cd70e2fc 100644
--- a/pkg/assembler/graphql/resolvers/delete.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/delete.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/hasSBOM.resolvers.go b/pkg/assembler/graphql/resolvers/hasSBOM.resolvers.go
index 36d79e7e..6142df50 100644
--- a/pkg/assembler/graphql/resolvers/hasSBOM.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/hasSBOM.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/hasSLSA.resolvers.go b/pkg/assembler/graphql/resolvers/hasSLSA.resolvers.go
index 734cd92d..4d2ca4c9 100644
--- a/pkg/assembler/graphql/resolvers/hasSLSA.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/hasSLSA.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/hasSourceAt.resolvers.go b/pkg/assembler/graphql/resolvers/hasSourceAt.resolvers.go
index 227583e6..0a89427c 100644
--- a/pkg/assembler/graphql/resolvers/hasSourceAt.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/hasSourceAt.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/hashEqual.resolvers.go b/pkg/assembler/graphql/resolvers/hashEqual.resolvers.go
index 00337e4a..6675a379 100644
--- a/pkg/assembler/graphql/resolvers/hashEqual.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/hashEqual.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/isDependency.resolvers.go b/pkg/assembler/graphql/resolvers/isDependency.resolvers.go
index 086125c3..8e918e16 100644
--- a/pkg/assembler/graphql/resolvers/isDependency.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/isDependency.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/isOccurrence.resolvers.go b/pkg/assembler/graphql/resolvers/isOccurrence.resolvers.go
index e670cd27..e2f7c5bc 100644
--- a/pkg/assembler/graphql/resolvers/isOccurrence.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/isOccurrence.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/license.resolvers.go b/pkg/assembler/graphql/resolvers/license.resolvers.go
index 193bbe52..541b9f91 100644
--- a/pkg/assembler/graphql/resolvers/license.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/license.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/metadata.resolvers.go b/pkg/assembler/graphql/resolvers/metadata.resolvers.go
index 8dfd639b..19fd24af 100644
--- a/pkg/assembler/graphql/resolvers/metadata.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/metadata.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/package.resolvers.go b/pkg/assembler/graphql/resolvers/package.resolvers.go
index 4ff3b0fb..74543a1c 100644
--- a/pkg/assembler/graphql/resolvers/package.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/package.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/path.resolvers.go b/pkg/assembler/graphql/resolvers/path.resolvers.go
index c2449fdb..6350563e 100644
--- a/pkg/assembler/graphql/resolvers/path.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/path.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/pkgEqual.resolvers.go b/pkg/assembler/graphql/resolvers/pkgEqual.resolvers.go
index dfe7da7a..3a920518 100644
--- a/pkg/assembler/graphql/resolvers/pkgEqual.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/pkgEqual.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/search.resolvers.go b/pkg/assembler/graphql/resolvers/search.resolvers.go
index 24996165..0dfc93ca 100644
--- a/pkg/assembler/graphql/resolvers/search.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/search.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/source.resolvers.go b/pkg/assembler/graphql/resolvers/source.resolvers.go
index 27d24825..d79e29b7 100644
--- a/pkg/assembler/graphql/resolvers/source.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/source.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/vulnEqual.resolvers.go b/pkg/assembler/graphql/resolvers/vulnEqual.resolvers.go
index c167115f..9b3b2d0a 100644
--- a/pkg/assembler/graphql/resolvers/vulnEqual.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/vulnEqual.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/vulnMetadata.resolvers.go b/pkg/assembler/graphql/resolvers/vulnMetadata.resolvers.go
index d240a41e..150934dd 100644
--- a/pkg/assembler/graphql/resolvers/vulnMetadata.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/vulnMetadata.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/resolvers/vulnerability.resolvers.go b/pkg/assembler/graphql/resolvers/vulnerability.resolvers.go
index ff4014c9..3179afc4 100644
--- a/pkg/assembler/graphql/resolvers/vulnerability.resolvers.go
+++ b/pkg/assembler/graphql/resolvers/vulnerability.resolvers.go
@@ -2,7 +2,7 @@ package resolvers
 
 // This file will be automatically regenerated based on the schema, any resolver implementations
 // will be copied through when generating and any unknown code will be moved to the end.
-// Code generated by github.com/99designs/gqlgen version v0.17.59
+// Code generated by github.com/99designs/gqlgen version v0.17.60
 
 import (
 	"context"
diff --git a/pkg/assembler/graphql/schema/certifyVuln.graphql b/pkg/assembler/graphql/schema/certifyVuln.graphql
index e9438f1d..e879aff6 100644
--- a/pkg/assembler/graphql/schema/certifyVuln.graphql
+++ b/pkg/assembler/graphql/schema/certifyVuln.graphql
@@ -129,7 +129,7 @@ extend type Query {
   CertifyVuln(certifyVulnSpec: CertifyVulnSpec!): [CertifyVuln!]!
   "Returns a paginated results via CertifyVulnConnection"
   CertifyVulnList(certifyVulnSpec: CertifyVulnSpec!, after: ID, first: Int): CertifyVulnConnection
-  "Batch queries via pkgVersion IDs to find all CertifyVulns (latest timestamp) that contain vulnerabilities"
+  "Batch queries via pkgVersion IDs to find all CertifyVulns (latest timestamp, including any `novuln`)"
   BatchQueryPkgIDCertifyVuln(pkgIDs: [ID!]!): [CertifyVuln!]!
 }
 
diff --git a/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go b/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go
index 9790f210..cdd61dd4 100644
--- a/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go
+++ b/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go
@@ -37,7 +37,7 @@ import (
 
 var json = jsoniter.ConfigCompatibleWithStandardLibrary
 
-var zeroTime = time.Unix(0, 0)
+var zeroTime = time.Unix(0, 0).UTC()
 
 var vexStatusMap = map[cdx.ImpactAnalysisState]model.VexStatus{
 	cdx.IASResolved:    model.VexStatusFixed,
@@ -171,8 +171,10 @@ func (c *cyclonedxParser) getTopLevelPackage() error {
 		}
 
 		// get top level licenses
-		if err := c.getLicenseInformation(*c.cdxBom.Metadata.Component); err != nil {
-			return fmt.Errorf("failed to get license information for top level package with error: %w", err)
+		if c.cdxBom.Metadata.Component != nil {
+			if err := c.getLicenseInformation(*c.cdxBom.Metadata.Component); err != nil {
+				return fmt.Errorf("failed to get license information for top level package with error: %w", err)
+			}
 		}
 		return nil
 	} else {
@@ -552,7 +554,7 @@ func (c *cyclonedxParser) getVulnerabilities(ctx context.Context) error {
 			return fmt.Errorf("failed to create vuln input spec %v", err)
 		}
 		var vd model.VexStatementInputSpec
-		publishedTime := time.Unix(0, 0)
+		publishedTime := zeroTime
 		if vulnerability.Analysis != nil {
 			if vexStatus, ok := vexStatusMap[vulnerability.Analysis.State]; ok {
 				vd.Status = vexStatus
@@ -597,40 +599,57 @@ func (c *cyclonedxParser) getVulnerabilities(ctx context.Context) error {
 			}
 		}
 
-		for _, affect := range *vulnerability.Affects {
-			vi, err := c.getAffectedPackages(ctx, vuln, vd, affect)
-			if vi == nil || err != nil {
-				return fmt.Errorf("failed to get affected packages for vulnerability %s - %v", vulnerability.ID, err)
+		var foundVexIngest []assembler.VexIngest
+		if vulnerability.Affects != nil {
+			for _, affect := range *vulnerability.Affects {
+				vi, err := c.getAffectedPackages(ctx, vuln, vd, affect)
+				if vi == nil || err != nil {
+					return fmt.Errorf("failed to get affected packages for vulnerability %s - %v", vulnerability.ID, err)
+				}
+				foundVexIngest = append(foundVexIngest, vi...)
 			}
-			c.vulnData.vex = append(c.vulnData.vex, *vi...)
-
-			for _, v := range *vi {
-				if v.VexData.Status == model.VexStatusAffected || v.VexData.Status == model.VexStatusUnderInvestigation {
-					cv := assembler.CertifyVulnIngest{
-						Vulnerability: vuln,
-						VulnData: &model.ScanMetadataInput{
-							TimeScanned: v.VexData.KnownSince,
-						},
-						Pkg: v.Pkg,
-					}
-					c.vulnData.certifyVuln = append(c.vulnData.certifyVuln, cv)
+		} else {
+			if strings.Contains(vulnerability.BOMRef, "pkg:") {
+				for _, foundPkgElement := range c.packagePackages[vulnerability.BOMRef] {
+					foundVexIngest = append(foundVexIngest, assembler.VexIngest{VexData: &vd, Vulnerability: vuln, Pkg: foundPkgElement})
 				}
 			}
 		}
 
-		for _, vulnRating := range *vulnerability.Ratings {
-			if vulnRating.Method != "" {
-				vm := assembler.VulnMetadataIngest{
+		c.vulnData.vex = append(c.vulnData.vex, foundVexIngest...)
+
+		for _, v := range foundVexIngest {
+			if v.VexData.Status == model.VexStatusAffected || v.VexData.Status == model.VexStatusUnderInvestigation {
+				cv := assembler.CertifyVulnIngest{
 					Vulnerability: vuln,
-					VulnMetadata: &model.VulnerabilityMetadataInputSpec{
-						ScoreType:  model.VulnerabilityScoreType(vulnRating.Method),
-						ScoreValue: *vulnRating.Score,
-						Timestamp:  publishedTime,
+					VulnData: &model.ScanMetadataInput{
+						TimeScanned: v.VexData.KnownSince,
 					},
+					Pkg: v.Pkg,
+				}
+				c.vulnData.certifyVuln = append(c.vulnData.certifyVuln, cv)
+			}
+		}
+
+		if vulnerability.Ratings != nil {
+			for _, vulnRating := range *vulnerability.Ratings {
+				if vulnRating.Method != "" {
+					var score float64 = 0
+					if vulnRating.Score != nil {
+						score = *vulnRating.Score
+					}
+					vm := assembler.VulnMetadataIngest{
+						Vulnerability: vuln,
+						VulnMetadata: &model.VulnerabilityMetadataInputSpec{
+							ScoreType:  model.VulnerabilityScoreType(vulnRating.Method),
+							ScoreValue: score,
+							Timestamp:  publishedTime,
+						},
+					}
+					c.vulnData.vulnMetadata = append(c.vulnData.vulnMetadata, vm)
+				} else {
+					logger.Debugf("vulnerability method not specified in cdx sbom: %s, skipping", c.doc.SourceInformation.DocumentRef)
 				}
-				c.vulnData.vulnMetadata = append(c.vulnData.vulnMetadata, vm)
-			} else {
-				logger.Debugf("vulnerability method not specified in cdx sbom: %s, skipping", c.doc.SourceInformation.DocumentRef)
 			}
 		}
 	}
@@ -638,7 +657,7 @@ func (c *cyclonedxParser) getVulnerabilities(ctx context.Context) error {
 }
 
 // Get package name and range versions to create package input spec for the affected packages.
-func (c *cyclonedxParser) getAffectedPackages(ctx context.Context, vulnInput *model.VulnerabilityInputSpec, vexData model.VexStatementInputSpec, affectsObj cdx.Affects) (*[]assembler.VexIngest, error) {
+func (c *cyclonedxParser) getAffectedPackages(ctx context.Context, vulnInput *model.VulnerabilityInputSpec, vexData model.VexStatementInputSpec, affectsObj cdx.Affects) ([]assembler.VexIngest, error) {
 	logger := logging.FromContext(ctx)
 	pkgRef := affectsObj.Ref
 
@@ -649,7 +668,7 @@ func (c *cyclonedxParser) getAffectedPackages(ctx context.Context, vulnInput *mo
 	}
 
 	if len(foundVexIngest) > 0 {
-		return &foundVexIngest, nil
+		return foundVexIngest, nil
 	}
 
 	// split ref using # as delimiter.
@@ -666,7 +685,7 @@ func (c *cyclonedxParser) getAffectedPackages(ctx context.Context, vulnInput *mo
 			return nil, fmt.Errorf("unable to create package input spec: %v", err)
 		}
 		c.identifierStrings.PurlStrings = append(c.identifierStrings.PurlStrings, pkdIdentifier)
-		return &[]assembler.VexIngest{{VexData: &vexData, Vulnerability: vulnInput, Pkg: pkg}}, nil
+		return []assembler.VexIngest{{VexData: &vexData, Vulnerability: vulnInput, Pkg: pkg}}, nil
 	}
 
 	if affectsObj.Range == nil {
@@ -674,32 +693,34 @@ func (c *cyclonedxParser) getAffectedPackages(ctx context.Context, vulnInput *mo
 	}
 
 	var viList []assembler.VexIngest
-	for _, affect := range *affectsObj.Range {
-		// TODO: Handle package range versions (see - https://github.com/CycloneDX/bom-examples/blob/master/VEX/CISA-Use-Cases/Case-8/vex.json#L42)
-		if affect.Range != "" {
-			logger.Debugf("[cdx vex] package range versions not supported yet: %q", affect.Range)
-			continue
-		}
-		if affect.Version == "" {
-			return nil, fmt.Errorf("no version found for package ref %q", pkgRef)
-		}
-		vi := &assembler.VexIngest{
-			VexData:       &vexData,
-			Vulnerability: vulnInput,
-		}
+	if affectsObj.Range != nil {
+		for _, affect := range *affectsObj.Range {
+			// TODO: Handle package range versions (see - https://github.com/CycloneDX/bom-examples/blob/master/VEX/CISA-Use-Cases/Case-8/vex.json#L42)
+			if affect.Range != "" {
+				logger.Debugf("[cdx vex] package range versions not supported yet: %q", affect.Range)
+				continue
+			}
+			if affect.Version == "" {
+				return nil, fmt.Errorf("no version found for package ref %q", pkgRef)
+			}
+			vi := &assembler.VexIngest{
+				VexData:       &vexData,
+				Vulnerability: vulnInput,
+			}
 
-		// create guac specific identifier string using affected package name and version.
-		pkgID := guacCDXPkgPurl(pkdIdentifier, affect.Version, "", false)
-		pkg, err := asmhelpers.PurlToPkg(pkgID)
-		if err != nil {
-			return nil, fmt.Errorf("unable to create package input spec from guac pkg purl: %v", err)
+			// create guac specific identifier string using affected package name and version.
+			pkgID := guacCDXPkgPurl(pkdIdentifier, affect.Version, "", false)
+			pkg, err := asmhelpers.PurlToPkg(pkgID)
+			if err != nil {
+				return nil, fmt.Errorf("unable to create package input spec from guac pkg purl: %v", err)
+			}
+			vi.Pkg = pkg
+			viList = append(viList, *vi)
+			c.identifierStrings.PurlStrings = append(c.identifierStrings.PurlStrings, pkgID)
 		}
-		vi.Pkg = pkg
-		viList = append(viList, *vi)
-		c.identifierStrings.PurlStrings = append(c.identifierStrings.PurlStrings, pkgID)
 	}
 
-	return &viList, nil
+	return viList, nil
 }
 
 func guacCDXFilePurl(fileName string, version string, topLevel bool) string {


Test patch:
diff --git a/internal/testing/backend/certifyVEXStatement_test.go b/internal/testing/backend/certifyVEXStatement_test.go
index 82c0df37..7df8e9d1 100644
--- a/internal/testing/backend/certifyVEXStatement_test.go
+++ b/internal/testing/backend/certifyVEXStatement_test.go
@@ -579,9 +579,9 @@ func TestVEX(t *testing.T) {
 					},
 					Vuln: testdata.C1,
 					In: &model.VexStatementInputSpec{
-						VexJustification: "test justification",
+						VexJustification: "test justification with status note one",
 						KnownSince:       time.Unix(1e9, 0),
-						StatusNotes:      "status one",
+						StatusNotes:      "There are no applicability scanners for this specific CVE\n##### Deployment mitigations\n\nClient-side mitigation: In case a repository is cloned/pulled with no intention of pushing anything, the `git sparse-checkout` feature can be enabled to avoid pulling the `.gitattributes` file. It can be performed as follows:\r\n```\r\ngit clone \u003cREPOSITORY URL\u003e --no-checkout\r\ncd \u003cREPOSITORY NAME\u003e\r\ngit sparse-checkout init\r\ngit sparse-checkout set --no-cone '/*' '!.gitattributes'\r\ngit checkout\r\n```\n\n##### Deployment mitigations\n\nAlthough the issue resides on the Git client's side, Git servers can also avoid infection by malicious actors from their side as well. Here is a git hook that will run after each push to check the size of the `.gitattributes` file can prevent from this vulnerability. The hook should be in the `/path/to/repository.git/hooks/` folder under the name of `pre-receive`:\r\n```\r\n#!/bin/sh\r\n# pre-receive hook to prevent oversized .gitattributes files from being pushed\r\n\r\n# 1GB of maximum allowed size for .gitattributes file (in bytes)\r\nmax_size=1048576\r\n\r\n# check each pushed file\r\nwhile read oldrev newrev refname; do\r\n # check for .gitattributes file\r\n if [ \"$(git rev-parse --verify $newrev:.gitattributes 2\u003e /dev/null)\" != \"\" ]; then\r\n # check file size\r\n size=$(git cat-file -s $newrev:.gitattributes)\r\n if [ $size -gt $max_size ]; then\r\n echo \"Error: .gitattributes file exceeds maximum allowed size of $max_size bytes.\"\r\n exit 1\r\n fi\r\n fi\r\ndone\r\n\r\nexit 0\r\n```",
 					},
 				},
 				{
@@ -590,14 +590,14 @@ func TestVEX(t *testing.T) {
 					},
 					Vuln: testdata.O1,
 					In: &model.VexStatementInputSpec{
-						VexJustification: "test justification",
+						VexJustification: "test justification with status note two",
 						KnownSince:       time.Unix(1e9, 0),
 						StatusNotes:      "status two",
 					},
 				},
 			},
 			Query: &model.CertifyVEXStatementSpec{
-				StatusNotes: ptrfrom.String("status one"),
+				StatusNotes: ptrfrom.String("There are no applicability scanners for this specific CVE\n##### Deployment mitigations\n\nClient-side mitigation: In case a repository is cloned/pulled with no intention of pushing anything, the `git sparse-checkout` feature can be enabled to avoid pulling the `.gitattributes` file. It can be performed as follows:\r\n```\r\ngit clone \u003cREPOSITORY URL\u003e --no-checkout\r\ncd \u003cREPOSITORY NAME\u003e\r\ngit sparse-checkout init\r\ngit sparse-checkout set --no-cone '/*' '!.gitattributes'\r\ngit checkout\r\n```\n\n##### Deployment mitigations\n\nAlthough the issue resides on the Git client's side, Git servers can also avoid infection by malicious actors from their side as well. Here is a git hook that will run after each push to check the size of the `.gitattributes` file can prevent from this vulnerability. The hook should be in the `/path/to/repository.git/hooks/` folder under the name of `pre-receive`:\r\n```\r\n#!/bin/sh\r\n# pre-receive hook to prevent oversized .gitattributes files from being pushed\r\n\r\n# 1GB of maximum allowed size for .gitattributes file (in bytes)\r\nmax_size=1048576\r\n\r\n# check each pushed file\r\nwhile read oldrev newrev refname; do\r\n # check for .gitattributes file\r\n if [ \"$(git rev-parse --verify $newrev:.gitattributes 2\u003e /dev/null)\" != \"\" ]; then\r\n # check file size\r\n size=$(git cat-file -s $newrev:.gitattributes)\r\n if [ $size -gt $max_size ]; then\r\n echo \"Error: .gitattributes file exceeds maximum allowed size of $max_size bytes.\"\r\n exit 1\r\n fi\r\n fi\r\ndone\r\n\r\nexit 0\r\n```"),
 			},
 			ExpVEX: []*model.CertifyVEXStatement{
 				{
@@ -606,9 +606,9 @@ func TestVEX(t *testing.T) {
 						Type:             "cve",
 						VulnerabilityIDs: []*model.VulnerabilityID{testdata.C1out},
 					},
-					VexJustification: "test justification",
+					VexJustification: "test justification with status note one",
 					KnownSince:       time.Unix(1e9, 0),
-					StatusNotes:      "status one",
+					StatusNotes:      "There are no applicability scanners for this specific CVE\n##### Deployment mitigations\n\nClient-side mitigation: In case a repository is cloned/pulled with no intention of pushing anything, the `git sparse-checkout` feature can be enabled to avoid pulling the `.gitattributes` file. It can be performed as follows:\r\n```\r\ngit clone \u003cREPOSITORY URL\u003e --no-checkout\r\ncd \u003cREPOSITORY NAME\u003e\r\ngit sparse-checkout init\r\ngit sparse-checkout set --no-cone '/*' '!.gitattributes'\r\ngit checkout\r\n```\n\n##### Deployment mitigations\n\nAlthough the issue resides on the Git client's side, Git servers can also avoid infection by malicious actors from their side as well. Here is a git hook that will run after each push to check the size of the `.gitattributes` file can prevent from this vulnerability. The hook should be in the `/path/to/repository.git/hooks/` folder under the name of `pre-receive`:\r\n```\r\n#!/bin/sh\r\n# pre-receive hook to prevent oversized .gitattributes files from being pushed\r\n\r\n# 1GB of maximum allowed size for .gitattributes file (in bytes)\r\nmax_size=1048576\r\n\r\n# check each pushed file\r\nwhile read oldrev newrev refname; do\r\n # check for .gitattributes file\r\n if [ \"$(git rev-parse --verify $newrev:.gitattributes 2\u003e /dev/null)\" != \"\" ]; then\r\n # check file size\r\n size=$(git cat-file -s $newrev:.gitattributes)\r\n if [ $size -gt $max_size ]; then\r\n echo \"Error: .gitattributes file exceeds maximum allowed size of $max_size bytes.\"\r\n exit 1\r\n fi\r\n fi\r\ndone\r\n\r\nexit 0\r\n```",
 				},
 			},
 		},
@@ -623,7 +623,7 @@ func TestVEX(t *testing.T) {
 					},
 					Vuln: testdata.O1,
 					In: &model.VexStatementInputSpec{
-						VexJustification: "test justification",
+						VexJustification: "test justification with statement one",
 						KnownSince:       time.Unix(1e9, 0),
 						Statement:        "statement one",
 					},
@@ -634,14 +634,14 @@ func TestVEX(t *testing.T) {
 					},
 					Vuln: testdata.O1,
 					In: &model.VexStatementInputSpec{
-						VexJustification: "test justification",
+						VexJustification: "test justification with statement two",
 						KnownSince:       time.Unix(1e9, 0),
-						Statement:        "statement two",
+						Statement:        "There are no applicability scanners for this specific CVE\n##### Deployment mitigations\n\nClient-side mitigation: In case a repository is cloned/pulled with no intention of pushing anything, the `git sparse-checkout` feature can be enabled to avoid pulling the `.gitattributes` file. It can be performed as follows:\r\n```\r\ngit clone \u003cREPOSITORY URL\u003e --no-checkout\r\ncd \u003cREPOSITORY NAME\u003e\r\ngit sparse-checkout init\r\ngit sparse-checkout set --no-cone '/*' '!.gitattributes'\r\ngit checkout\r\n```\n\n##### Deployment mitigations\n\nAlthough the issue resides on the Git client's side, Git servers can also avoid infection by malicious actors from their side as well. Here is a git hook that will run after each push to check the size of the `.gitattributes` file can prevent from this vulnerability. The hook should be in the `/path/to/repository.git/hooks/` folder under the name of `pre-receive`:\r\n```\r\n#!/bin/sh\r\n# pre-receive hook to prevent oversized .gitattributes files from being pushed\r\n\r\n# 1GB of maximum allowed size for .gitattributes file (in bytes)\r\nmax_size=1048576\r\n\r\n# check each pushed file\r\nwhile read oldrev newrev refname; do\r\n # check for .gitattributes file\r\n if [ \"$(git rev-parse --verify $newrev:.gitattributes 2\u003e /dev/null)\" != \"\" ]; then\r\n # check file size\r\n size=$(git cat-file -s $newrev:.gitattributes)\r\n if [ $size -gt $max_size ]; then\r\n echo \"Error: .gitattributes file exceeds maximum allowed size of $max_size bytes.\"\r\n exit 1\r\n fi\r\n fi\r\ndone\r\n\r\nexit 0\r\n```",
 					},
 				},
 			},
 			Query: &model.CertifyVEXStatementSpec{
-				Statement: ptrfrom.String("statement two"),
+				Statement: ptrfrom.String("There are no applicability scanners for this specific CVE\n##### Deployment mitigations\n\nClient-side mitigation: In case a repository is cloned/pulled with no intention of pushing anything, the `git sparse-checkout` feature can be enabled to avoid pulling the `.gitattributes` file. It can be performed as follows:\r\n```\r\ngit clone \u003cREPOSITORY URL\u003e --no-checkout\r\ncd \u003cREPOSITORY NAME\u003e\r\ngit sparse-checkout init\r\ngit sparse-checkout set --no-cone '/*' '!.gitattributes'\r\ngit checkout\r\n```\n\n##### Deployment mitigations\n\nAlthough the issue resides on the Git client's side, Git servers can also avoid infection by malicious actors from their side as well. Here is a git hook that will run after each push to check the size of the `.gitattributes` file can prevent from this vulnerability. The hook should be in the `/path/to/repository.git/hooks/` folder under the name of `pre-receive`:\r\n```\r\n#!/bin/sh\r\n# pre-receive hook to prevent oversized .gitattributes files from being pushed\r\n\r\n# 1GB of maximum allowed size for .gitattributes file (in bytes)\r\nmax_size=1048576\r\n\r\n# check each pushed file\r\nwhile read oldrev newrev refname; do\r\n # check for .gitattributes file\r\n if [ \"$(git rev-parse --verify $newrev:.gitattributes 2\u003e /dev/null)\" != \"\" ]; then\r\n # check file size\r\n size=$(git cat-file -s $newrev:.gitattributes)\r\n if [ $size -gt $max_size ]; then\r\n echo \"Error: .gitattributes file exceeds maximum allowed size of $max_size bytes.\"\r\n exit 1\r\n fi\r\n fi\r\ndone\r\n\r\nexit 0\r\n```"),
 			},
 			ExpVEX: []*model.CertifyVEXStatement{
 				{
@@ -650,9 +650,9 @@ func TestVEX(t *testing.T) {
 						Type:             "osv",
 						VulnerabilityIDs: []*model.VulnerabilityID{testdata.O1out},
 					},
-					VexJustification: "test justification",
+					VexJustification: "test justification with statement two",
 					KnownSince:       time.Unix(1e9, 0),
-					Statement:        "statement two",
+					Statement:        "There are no applicability scanners for this specific CVE\n##### Deployment mitigations\n\nClient-side mitigation: In case a repository is cloned/pulled with no intention of pushing anything, the `git sparse-checkout` feature can be enabled to avoid pulling the `.gitattributes` file. It can be performed as follows:\r\n```\r\ngit clone \u003cREPOSITORY URL\u003e --no-checkout\r\ncd \u003cREPOSITORY NAME\u003e\r\ngit sparse-checkout init\r\ngit sparse-checkout set --no-cone '/*' '!.gitattributes'\r\ngit checkout\r\n```\n\n##### Deployment mitigations\n\nAlthough the issue resides on the Git client's side, Git servers can also avoid infection by malicious actors from their side as well. Here is a git hook that will run after each push to check the size of the `.gitattributes` file can prevent from this vulnerability. The hook should be in the `/path/to/repository.git/hooks/` folder under the name of `pre-receive`:\r\n```\r\n#!/bin/sh\r\n# pre-receive hook to prevent oversized .gitattributes files from being pushed\r\n\r\n# 1GB of maximum allowed size for .gitattributes file (in bytes)\r\nmax_size=1048576\r\n\r\n# check each pushed file\r\nwhile read oldrev newrev refname; do\r\n # check for .gitattributes file\r\n if [ \"$(git rev-parse --verify $newrev:.gitattributes 2\u003e /dev/null)\" != \"\" ]; then\r\n # check file size\r\n size=$(git cat-file -s $newrev:.gitattributes)\r\n if [ $size -gt $max_size ]; then\r\n echo \"Error: .gitattributes file exceeds maximum allowed size of $max_size bytes.\"\r\n exit 1\r\n fi\r\n fi\r\ndone\r\n\r\nexit 0\r\n```",
 				},
 			},
 		},
diff --git a/internal/testing/testdata/exampledata/xray-cdx-vulns.json b/internal/testing/testdata/exampledata/xray-cdx-vulns.json
new file mode 100644
index 00000000..3668db7a
--- /dev/null
+++ b/internal/testing/testdata/exampledata/xray-cdx-vulns.json
@@ -0,0 +1,58 @@
+{
+    "bomFormat": "CycloneDX",
+    "specVersion": "1.4",
+    "serialNumber": "urn:uuid:e8300d83-d8d8-4e91-63e7-3d95b8900f45",
+    "version": 1,
+    "metadata": {
+      "timestamp": "2024-12-11T10:06:41Z",
+      "tools": [
+        {
+          "vendor": "JFrog Inc.",
+          "name": "Xray",
+          "version": "3.103.6"
+        }
+      ],
+      "component": {
+        "type": "container",
+        "name": "library/maven",
+        "version": "sha256__09c4bf58d7e7e31bdc1ab73ef10349b3a47c9a814e715e409034fb3293253ce2"
+      }
+    },
+    "components": [
+      {
+        "bom-ref": "pkg:deb/debian:buster:apt@1.8.2.2",
+        "type": "application",
+        "name": "debian:buster:apt",
+        "version": "1.8.2.2",
+        "hashes": [
+          {
+            "alg": "SHA-256",
+            "content": "db5c8bd205d41e520f615251ae97c9610a0fb312841428a7a25072831f6bee83"
+          }
+        ],
+        "licenses": [
+          {
+            "license": {
+              "id": "GPL-2.0-only",
+              "url": "http://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html"
+            }
+          }
+        ],
+        "purl": "pkg:deb/debian:buster:apt@1.8.2.2"
+      }
+    ],
+    "dependencies": [],
+    "vulnerabilities": [
+      {
+        "bom-ref": "pkg:deb/debian:buster:apt@1.8.2.2",
+        "id": "CVE-2011-3374",
+        "analysis": {
+          "state": "in_triage",
+          "response": [
+            "workaround_available"
+          ],
+          "detail": "There are no applicability scanners for this specific CVE\n##### Deployment mitigations\n\nClient-side mitigation: In case a repository is cloned/pulled with no intention of pushing anything, the `git sparse-checkout` feature can be enabled to avoid pulling the `.gitattributes` file. It can be performed as follows:\r\n```\r\ngit clone \u003cREPOSITORY URL\u003e --no-checkout\r\ncd \u003cREPOSITORY NAME\u003e\r\ngit sparse-checkout init\r\ngit sparse-checkout set --no-cone '/*' '!.gitattributes'\r\ngit checkout\r\n```\n\n##### Deployment mitigations\n\nAlthough the issue resides on the Git client's side, Git servers can also avoid infection by malicious actors from their side as well. Here is a git hook that will run after each push to check the size of the `.gitattributes` file can prevent from this vulnerability. The hook should be in the `/path/to/repository.git/hooks/` folder under the name of `pre-receive`:\r\n```\r\n#!/bin/sh\r\n# pre-receive hook to prevent oversized .gitattributes files from being pushed\r\n\r\n# 1GB of maximum allowed size for .gitattributes file (in bytes)\r\nmax_size=1048576\r\n\r\n# check each pushed file\r\nwhile read oldrev newrev refname; do\r\n    # check for .gitattributes file\r\n    if [ \"$(git rev-parse --verify $newrev:.gitattributes 2\u003e /dev/null)\" != \"\" ]; then\r\n        # check file size\r\n        size=$(git cat-file -s $newrev:.gitattributes)\r\n        if [ $size -gt $max_size ]; then\r\n            echo \"Error: .gitattributes file exceeds maximum allowed size of $max_size bytes.\"\r\n            exit 1\r\n        fi\r\n    fi\r\ndone\r\n\r\nexit 0\r\n```"
+        }
+      }
+    ]
+}
diff --git a/internal/testing/testdata/testdata.go b/internal/testing/testdata/testdata.go
index 3d151ba8..cb6a44f1 100644
--- a/internal/testing/testdata/testdata.go
+++ b/internal/testing/testdata/testdata.go
@@ -123,6 +123,9 @@ var (
 	//go:embed exampledata/cyclonedx-vex.xml
 	CyloneDXVEXExampleXML []byte
 
+	//go:embed exampledata/xray-cdx-vulns.json
+	CyloneDXXRAYExampleVulns []byte
+
 	//go:embed exampledata/crev-review.json
 	ITE6CREVExample []byte
 
@@ -272,14 +275,14 @@ var (
 		VexJustification: generated.VexJustificationNotProvided,
 		Statement:        "",
 		StatusNotes:      "Versions of Product ABC are affected by the vulnerability. Customers are advised to upgrade to the latest release.",
-		KnownSince:       time.Unix(0, 0),
+		KnownSince:       time.Unix(0, 0).UTC(),
 	}
 	VexDataNoAnalysis = &generated.VexStatementInputSpec{
 		Status:           generated.VexStatusAffected,
 		VexJustification: generated.VexJustificationNotProvided,
 		Statement:        "com.fasterxml.jackson.core:jackson-databind is a library which contains the general-purpose data-binding functionality and tree-model for Jackson Data Processor.\n\nAffected versions of this package are vulnerable to XML External Entity (XXE) Injection. A flaw was found in FasterXML Jackson Databind, where it does not have entity expansion secured properly in the DOMDeserializer class. The highest threat from this vulnerability is data integrity.",
 		StatusNotes:      "",
-		KnownSince:       time.Unix(0, 0),
+		KnownSince:       time.Unix(0, 0).UTC(),
 	}
 	CycloneDXAffectedVulnMetadata = []assembler.VulnMetadataIngest{
 		{
@@ -287,7 +290,7 @@ var (
 			VulnMetadata: &generated.VulnerabilityMetadataInputSpec{
 				ScoreType:  generated.VulnerabilityScoreTypeCvssv31,
 				ScoreValue: 10,
-				Timestamp:  time.Unix(0, 0),
+				Timestamp:  time.Unix(0, 0).UTC(),
 			},
 		},
 	}
@@ -297,7 +300,7 @@ var (
 			VulnMetadata: &generated.VulnerabilityMetadataInputSpec{
 				ScoreType:  generated.VulnerabilityScoreTypeCvssv31,
 				ScoreValue: 10,
-				Timestamp:  time.Unix(0, 0),
+				Timestamp:  time.Unix(0, 0).UTC(),
 			},
 		},
 	}
@@ -1795,6 +1798,127 @@ var (
 		HasSBOM: flatComponentsHasSBOM,
 	}
 
+	XRayComponentsTime, _ = time.Parse(time.RFC3339, "2024-12-11T10:06:41+00:00")
+
+	XraySBOMVulnsPredicates = assembler.IngestPredicates{
+		IsDependency: []assembler.IsDependencyIngest{
+			{
+				Pkg: &model.PkgInputSpec{
+					Type:      "guac",
+					Namespace: ptrfrom.String("cdx/library"),
+					Name:      "maven",
+					Version:   ptrfrom.String("sha256__09c4bf58d7e7e31bdc1ab73ef10349b3a47c9a814e715e409034fb3293253ce2"),
+					Subpath:   ptrfrom.String(""),
+				},
+				DepPkg: &model.PkgInputSpec{
+					Type:      "deb",
+					Namespace: ptrfrom.String(""),
+					Name:      "debian:buster:apt",
+					Version:   ptrfrom.String("1.8.2.2"),
+					Subpath:   ptrfrom.String(""),
+				},
+				IsDependency: &model.IsDependencyInputSpec{
+					DependencyType: model.DependencyTypeUnknown,
+					Justification:  isDepJustifyTopPkgJustification,
+				},
+			},
+		},
+		IsOccurrence: []assembler.IsOccurrenceIngest{
+			{
+				Pkg: &model.PkgInputSpec{
+					Type:      "deb",
+					Namespace: ptrfrom.String(""),
+					Name:      "debian:buster:apt",
+					Version:   ptrfrom.String("1.8.2.2"),
+					Subpath:   ptrfrom.String(""),
+				},
+				Artifact: &model.ArtifactInputSpec{
+					Algorithm: "sha-256",
+					Digest:    "db5c8bd205d41e520f615251ae97c9610a0fb312841428a7a25072831f6bee83",
+				},
+				IsOccurrence: isOccurrenceJustifyTopPkg,
+			},
+		},
+		HasSBOM: []assembler.HasSBOMIngest{
+			{
+				Pkg: &model.PkgInputSpec{
+					Type:      "guac",
+					Namespace: ptrfrom.String("cdx/library"),
+					Name:      "maven",
+					Version:   ptrfrom.String("sha256__09c4bf58d7e7e31bdc1ab73ef10349b3a47c9a814e715e409034fb3293253ce2"),
+					Subpath:   ptrfrom.String(""),
+				},
+				HasSBOM: &model.HasSBOMInputSpec{
+					Uri:        "urn:uuid:e8300d83-d8d8-4e91-63e7-3d95b8900f45",
+					Algorithm:  "sha256",
+					Digest:     "5b43f9ae2939c3ce859a1beda091d699d05853f76ed2843e021c24e266dbbc4d",
+					KnownSince: XRayComponentsTime,
+				},
+			},
+		},
+		CertifyVuln: []assembler.CertifyVulnIngest{
+			{
+				Pkg: &model.PkgInputSpec{
+					Type:      "deb",
+					Namespace: ptrfrom.String(""),
+					Name:      "debian:buster:apt",
+					Version:   ptrfrom.String("1.8.2.2"),
+					Subpath:   ptrfrom.String(""),
+				},
+				Vulnerability: &model.VulnerabilityInputSpec{
+					Type:            "cve",
+					VulnerabilityID: "cve-2011-3374",
+				},
+				VulnData: &model.ScanMetadataInput{
+					TimeScanned: time.Unix(0, 0).UTC(),
+				},
+			},
+		},
+		Vex: []assembler.VexIngest{
+			{
+				Pkg: &model.PkgInputSpec{
+					Type:      "deb",
+					Namespace: ptrfrom.String(""),
+					Name:      "debian:buster:apt",
+					Version:   ptrfrom.String("1.8.2.2"),
+					Subpath:   ptrfrom.String(""),
+				},
+				Vulnerability: &model.VulnerabilityInputSpec{
+					Type:            "cve",
+					VulnerabilityID: "cve-2011-3374",
+				},
+				VexData: &model.VexStatementInputSpec{
+					Status:           model.VexStatusUnderInvestigation,
+					VexJustification: model.VexJustificationNotProvided,
+					StatusNotes:      "There are no applicability scanners for this specific CVE\n##### Deployment mitigations\n\nClient-side mitigation: In case a repository is cloned/pulled with no intention of pushing anything, the `git sparse-checkout` feature can be enabled to avoid pulling the `.gitattributes` file. It can be performed as follows:\r\n```\r\ngit clone \u003cREPOSITORY URL\u003e --no-checkout\r\ncd \u003cREPOSITORY NAME\u003e\r\ngit sparse-checkout init\r\ngit sparse-checkout set --no-cone '/*' '!.gitattributes'\r\ngit checkout\r\n```\n\n##### Deployment mitigations\n\nAlthough the issue resides on the Git client's side, Git servers can also avoid infection by malicious actors from their side as well. Here is a git hook that will run after each push to check the size of the `.gitattributes` file can prevent from this vulnerability. The hook should be in the `/path/to/repository.git/hooks/` folder under the name of `pre-receive`:\r\n```\r\n#!/bin/sh\r\n# pre-receive hook to prevent oversized .gitattributes files from being pushed\r\n\r\n# 1GB of maximum allowed size for .gitattributes file (in bytes)\r\nmax_size=1048576\r\n\r\n# check each pushed file\r\nwhile read oldrev newrev refname; do\r\n    # check for .gitattributes file\r\n    if [ \"$(git rev-parse --verify $newrev:.gitattributes 2\u003e /dev/null)\" != \"\" ]; then\r\n        # check file size\r\n        size=$(git cat-file -s $newrev:.gitattributes)\r\n        if [ $size -gt $max_size ]; then\r\n            echo \"Error: .gitattributes file exceeds maximum allowed size of $max_size bytes.\"\r\n            exit 1\r\n        fi\r\n    fi\r\ndone\r\n\r\nexit 0\r\n```",
+					KnownSince:       time.Unix(0, 0).UTC(),
+				},
+			},
+		},
+		CertifyLegal: []assembler.CertifyLegalIngest{
+			{
+				Pkg: &model.PkgInputSpec{
+					Type:      "deb",
+					Namespace: ptrfrom.String(""),
+					Name:      "debian:buster:apt",
+					Version:   ptrfrom.String("1.8.2.2"),
+					Subpath:   ptrfrom.String(""),
+				},
+				Declared: []model.LicenseInputSpec{
+					{
+						Name:        "GPL-2.0-only",
+						ListVersion: ptrfrom.String("UNKNOWN"),
+					},
+				},
+				CertifyLegal: &model.CertifyLegalInputSpec{
+					DeclaredLicense: "GPL-2.0-only",
+					Justification:   "Found in CycloneDX document",
+					TimeScanned:     XRayComponentsTime,
+				},
+			},
+		},
+	}
+
 	ociComponentsIsDependencyIngests = []assembler.IsDependencyIngest{
 		{
 			Pkg:    ociMandrel,
diff --git a/pkg/assembler/graphql/resolvers/certifyBad.resolvers_test.go b/pkg/assembler/graphql/resolvers/certifyBad.resolvers_test.go
index 8c6f05d3..bb98fee4 100644
--- a/pkg/assembler/graphql/resolvers/certifyBad.resolvers_test.go
+++ b/pkg/assembler/graphql/resolvers/certifyBad.resolvers_test.go
@@ -28,7 +28,7 @@ import (
 	"go.uber.org/mock/gomock"
 )
 
-var ZeroTime = time.Unix(0, 0)
+var ZeroTime = time.Unix(0, 0).UTC()
 
 func TestIngestCertifyBad(t *testing.T) {
 	type call struct {
diff --git a/pkg/ingestor/parser/cyclonedx/parser_cyclonedx_test.go b/pkg/ingestor/parser/cyclonedx/parser_cyclonedx_test.go
index dfa59d3b..48e64b59 100644
--- a/pkg/ingestor/parser/cyclonedx/parser_cyclonedx_test.go
+++ b/pkg/ingestor/parser/cyclonedx/parser_cyclonedx_test.go
@@ -19,7 +19,6 @@ import (
 	"context"
 	"errors"
 	"testing"
-	"time"
 
 	cdx "github.com/CycloneDX/cyclonedx-go"
 	"github.com/google/go-cmp/cmp"
@@ -188,6 +187,15 @@ func Test_cyclonedxParser(t *testing.T) {
 		},
 		wantPredicates: &testdata.FlatComponentsPredicates,
 		wantErr:        false,
+	}, {
+		name: "CycloneDX Xray SBOM with Vulns",
+		doc: &processor.Document{
+			Blob:   testdata.CyloneDXXRAYExampleVulns,
+			Format: processor.FormatJSON,
+			Type:   processor.DocumentCycloneDX,
+		},
+		wantPredicates: &testdata.XraySBOMVulnsPredicates,
+		wantErr:        false,
 	}}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -608,14 +616,14 @@ func affectedVexPredicates() *assembler.IngestPredicates {
 				Pkg:           guacPkgHelper("product-ABC", "2.4"),
 				Vulnerability: testdata.VulnSpecAffected,
 				VulnData: &model.ScanMetadataInput{
-					TimeScanned: time.Unix(0, 0),
+					TimeScanned: zeroTime,
 				},
 			},
 			{
 				Pkg:           guacPkgHelper("product-ABC", "2.6"),
 				Vulnerability: testdata.VulnSpecAffected,
 				VulnData: &model.ScanMetadataInput{
-					TimeScanned: time.Unix(0, 0),
+					TimeScanned: zeroTime,
 				},
 			},
 		},
@@ -643,14 +651,14 @@ func noAnalysisVexPredicates() *assembler.IngestPredicates {
 				Pkg:           guacPkgHelper("product-ABC", "2.4"),
 				Vulnerability: testdata.VulnSpecAffected,
 				VulnData: &model.ScanMetadataInput{
-					TimeScanned: time.Unix(0, 0),
+					TimeScanned: zeroTime,
 				},
 			},
 			{
 				Pkg:           guacPkgHelper("product-ABC", "2.6"),
 				Vulnerability: testdata.VulnSpecAffected,
 				VulnData: &model.ScanMetadataInput{
-					TimeScanned: time.Unix(0, 0),
+					TimeScanned: zeroTime,
 				},
 			},
 		},