Repository: google/osv-scanner

Issue:
[Github action] exit code 0 returned on incorrect cli usage
When using the `osv-scanner` GitHub action incorrectly by providing non existing args providing args after the scan path, the action succeeds. The reason: `127` exit code is redirected to `0` [here](https://github.com/google/osv-scanner/blob/main/exit_code_redirect.sh#L45-L47).

Real example:
`--config` arg is provided after the scan path [here](https://github.com/envoyproxy/gateway/blob/71519afe106178f97066e777fcbfc6879edbf439/.github/workflows/osv-scanner.yml#L30C8-L30C17) but action succeeds although there are errors in the log:
```log
Unable to parse git ignores: stat --config: no such file or directory
Failed to walk --config: lstat --config: no such file or directory
lstat --config: no such file or directory
Exit code: 127
``` 

Discussion:
@github-actions: This issue has not had any activity for 60 days and will be automatically closed in two weeks

See https://github.com/google/osv-scanner/blob/main/CONTRIBUTING.md for how to contribute a PR if you're interested in helping out.@shahar-h: Another example: I tried to use the new `vulnerability.ignore` feature that was added in `v1.9.1`, but got an error since I used osv-scanner v1.9.0:
```log
Failed to read config file: unknown keys in config file: PackageOverrides.vulnerability.ignore
unknown keys in config file: PackageOverrides.vulnerability.ignore
```
The error code here is also 127 so the github action succeeds also in this case.@github-actions: This issue has not had any activity for 60 days and will be automatically closed in two weeks

See https://github.com/google/osv-scanner/blob/main/CONTRIBUTING.md for how to contribute a PR if you're interested in helping out.@another-rex: I think two changes are needed here:
1. 127 should not redirect to 0,
2. Return special error code for user config error, (invalid config, incorrect CLI usage...etc)@G-Rath: > Return special error code for user config error, (invalid config, incorrect CLI usage...etc)

I don't actually think we can easily do this because it doesn't look like a specific error is returned by the CLI library, and at least in the scope of this issue I don't actually know why we'd want to single that case out - even if it was to show some GH annotation, I think that'd be something we could do for all errors 🤷 @another-rex: This is now released in v2.0.3

Solution patch:
diff --git a/.github/workflows/lint-action/action.yml b/.github/workflows/lint-action/action.yml
index b77b3227..c99e2ec9 100644
--- a/.github/workflows/lint-action/action.yml
+++ b/.github/workflows/lint-action/action.yml
@@ -19,8 +19,8 @@ runs:
   using: composite
   steps:
     - name: Run golangci-lint
-      uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 # v6.5.2
+      uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0
       with:
         # Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
-        version: v1.64.4
+        version: v2.1
         args: --timeout=5m
diff --git a/.golangci.yaml b/.golangci.yaml
index 7fe5bcf0..05a8ffa6 100644
--- a/.golangci.yaml
+++ b/.golangci.yaml
@@ -1,136 +1,157 @@
-output:
-  sort-results: true
+version: "2"
+
 linters:
-  enable-all: true
+  default: all
   # prettier-ignore
   disable:
-    - cyclop
+    - cyclop           #
     - err113           # will re-add later (another-rex)
     - exhaustruct      # overkill (g-rath)
     - forcetypeassert  # too hard (g-rath)
-    - funlen
-    - gci
+    - funlen           #
+    - funcorder        #
     - gochecknoglobals # disagree with, for non changing variables (another-rex)
-    - gocognit
+    - gocognit         #
     - goconst          # not everything should be a constant
-    - gocyclo
+    - gocyclo          #
     - godot            # comments are fine without full stops (g-rath)
     - godox            # to-do comments are fine (g-rath)
-    - gofumpt
     - ireturn          # disagree with, sort of (g-rath)
     - lll              # line length is hard (g-rath)
-    - maintidx
+    - maintidx         #
     - mnd              # not every number is magic (g-rath)
-    - nestif
+    - nestif           #
     - nonamedreturns   # disagree with, for now (another-rex)
     - tagliatelle      # we're parsing data from external sources (g-rath)
-    - tenv             # deprecated
     - testpackage      # will re-add later (another-rex)
     - varnamelen       # maybe later (g-rath)
     - wrapcheck        # too difficult, will re-add later (another-rex)
     - wsl              # disagree with, for now (g-rath)
-
-linters-settings:
-  exhaustive:
-    default-signifies-exhaustive: true
-  forbidigo:
-    forbid:
-      - p: ^testing.T.Skip
-        pkg: ^testing$
-        msg: "go-snaps needs to know the test has been skipped, so use `testutility.Skip` instead"
-    analyze-types: true
-  govet:
-    settings:
-      printf:
-        funcs:
-          - (github.com/google/osv-scanner/v2/pkg/reporter.Reporter).Errorf
-          - (github.com/google/osv-scanner/v2/pkg/reporter.Reporter).Warnf
-          - (github.com/google/osv-scanner/v2/pkg/reporter.Reporter).Infof
-  depguard:
+    - nilnesserr       # todo: should get enabled
+  settings:
+    depguard:
+      rules:
+        regexp:
+          files:
+            - "!**/internal/cachedregexp/**"
+            - "!**/internal/testutility/normalize.go"
+          deny:
+            - pkg: regexp
+              desc: Use github.com/google/osv-scanner/v2/internal/cachedregexp instead
+    exhaustive:
+      default-signifies-exhaustive: true
+    forbidigo:
+      forbid:
+        - pattern: ^testing.T.Skip
+          pkg: ^testing$
+          msg: go-snaps needs to know the test has been skipped, so use `testutility.Skip` instead
+      analyze-types: true
+    gocritic:
+      disabled-checks:
+        - ifElseChain
+    govet:
+      settings:
+        printf:
+          funcs:
+            - (github.com/google/osv-scanner/v2/pkg/reporter.Reporter).Errorf
+            - (github.com/google/osv-scanner/v2/pkg/reporter.Reporter).Warnf
+            - (github.com/google/osv-scanner/v2/pkg/reporter.Reporter).Infof
+    nlreturn:
+      block-size: 2
+    revive:
+      rules:
+        - name: increment-decrement
+          disabled: true
+        - name: blank-imports
+          disabled: false
+        - name: context-as-argument
+          disabled: false
+        - name: context-keys-type
+          disabled: false
+        - name: dot-imports
+          disabled: false
+        - name: empty-block
+          disabled: false
+        - name: error-naming
+          disabled: false
+        - name: error-return
+          disabled: false
+        - name: error-strings
+          disabled: false
+        - name: errorf
+          disabled: false
+        - name: exported
+          disabled: false
+        - name: indent-error-flow
+          disabled: false
+        - name: package-comments
+          disabled: false
+        - name: range
+          disabled: false
+        - name: receiver-naming
+          disabled: false
+        - name: redefines-builtin-id
+          disabled: false
+        # todo: enable once we've upgraded to v2, as the validation schema
+        #    used by the github v1 action does not have this rule yet
+        # - name: redundant-test-main-exit
+        #   disabled: false
+        - name: superfluous-else
+          disabled: false
+        - name: time-naming
+          disabled: false
+        - name: unexported-return
+          disabled: false
+        - name: unreachable-code
+          disabled: false
+        - name: unused-parameter
+          disabled: false
+        - name: use-any
+          disabled: false
+        - name: var-declaration
+          disabled: false
+        - name: var-naming
+          disabled: false
+    staticcheck:
+      checks:
+        - all
+        - -QF1001 # apply De Morgan's law
+        - -QF1002 # use tagged switch on base
+        - -QF1003 # use tagged switch on prefix
+        - -QF1006 # lift into loop condition
+        - -QF1008 # remove embedded field from selector
+  exclusions:
+    generated: lax
+    presets:
+      - comments
+      - common-false-positives
+      - legacy
+      - std-error-handling
     rules:
-      regexp:
-        files:
-          - "!**/internal/cachedregexp/**"
-          - "!**/internal/testutility/normalize.go"
-        deny:
-          - pkg: "regexp"
-            desc: "Use github.com/google/osv-scanner/v2/internal/cachedregexp instead"
-  gocritic:
-    disabled-checks:
-      - ifElseChain
-  revive:
-    # enable-all-rules: true
-    rules:
-      # Overrides ----
-      # This is just here for documentation purposes, as all rules are disabled by default
-      - name: increment-decrement
-        disabled: true
-      # Defaults ----
-      - name: blank-imports
-        disabled: false
-      - name: context-as-argument
-        disabled: false
-      - name: context-keys-type
-        disabled: false
-      - name: dot-imports
-        disabled: false
-      - name: empty-block
-        disabled: false
-      - name: error-naming
-        disabled: false
-      - name: error-return
-        disabled: false
-      - name: error-strings
-        disabled: false
-      - name: errorf
-        disabled: false
-      - name: exported
-        disabled: false
-      - name: indent-error-flow
-        disabled: false
-      - name: package-comments
-        disabled: false
-      - name: range
-        disabled: false
-      - name: receiver-naming
-        disabled: false
-      - name: redefines-builtin-id
-        disabled: false
-      # todo: enable once we've upgraded to v2, as the validation schema
-      #    used by the github v1 action does not have this rule yet
-      # - name: redundant-test-main-exit
-      #   disabled: false
-      - name: superfluous-else
-        disabled: false
-      - name: time-naming
-        disabled: false
-      - name: unexported-return
-        disabled: false
-      - name: unreachable-code
-        disabled: false
-      - name: unused-parameter
-        disabled: false
-      - name: use-any
-        disabled: false
-      - name: var-declaration
-        disabled: false
-      - name: var-naming
-        disabled: false
-  nlreturn:
-    # Size of the block (including return statement that is still "OK")
-    # so no return split required.
-    # Default: 1
-    block-size: 2
+      - linters:
+          - dupl
+        path: pkg/reporter
+      - linters:
+          - dupl
+        path: _test\.go
+    paths:
+      - internal/thirdparty/
+      - third_party$
+      - builtin$
+      - examples$
+
+formatters:
+  enable:
+    - gofmt
+    - goimports
+  exclusions:
+    generated: lax
+    paths:
+      - internal/thirdparty/
+      - third_party$
+      - builtin$
+      - examples$
 
 issues:
   max-issues-per-linter: 0
   max-same-issues: 0
-  exclude-rules:
-    - path: pkg/reporter
-      linters:
-        - dupl
-    - path: _test\.go
-      linters:
-        - dupl
-  exclude-dirs:
-    - internal/thirdparty/
diff --git a/cmd/osv-scanner/scan/image/__snapshots__/command_test.snap b/cmd/osv-scanner/scan/image/__snapshots__/command_test.snap
index f7cd4851..e87a0287 100755
--- a/cmd/osv-scanner/scan/image/__snapshots__/command_test.snap
+++ b/cmd/osv-scanner/scan/image/__snapshots__/command_test.snap
@@ -215,12 +215,26 @@ You can also view the full vulnerability list in your terminal with: `osv-scanne
 Scanning local image tarball "../../../../internal/image/fixtures/test-python-empty.tar"
 
 Container Scanning Result (Debian GNU/Linux 10 (buster)):
-Total 12 packages affected by 18 known vulnerabilities (0 Critical, 3 High, 1 Medium, 0 Low, 14 Unknown) from 2 ecosystems.
-18 vulnerabilities can be fixed.
+Total 14 packages affected by 22 known vulnerabilities (0 Critical, 6 High, 2 Medium, 0 Low, 14 Unknown) from 2 ecosystems.
+22 vulnerabilities can be fixed.
 
 
 PyPI
 +---------------------------------------------------------------------------------------------+
+| Source:artifact:usr/local/lib/python3.9/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl      |
++---------+-------------------+---------------+------------+------------------+---------------+
+| PACKAGE | INSTALLED VERSION | FIX AVAILABLE | VULN COUNT | INTRODUCED LAYER | IN BASE IMAGE |
++---------+-------------------+---------------+------------+------------------+---------------+
+| pip     | 23.0.1            | Fix Available |          1 | # 7 Layer        | python        |
++---------+-------------------+---------------+------------+------------------+---------------+
++------------------------------------------------------------------------------------------------+
+| Source:artifact:usr/local/lib/python3.9/ensurepip/_bundled/setuptools-58.1.0-py3-none-any.whl  |
++------------+-------------------+---------------+------------+------------------+---------------+
+| PACKAGE    | INSTALLED VERSION | FIX AVAILABLE | VULN COUNT | INTRODUCED LAYER | IN BASE IMAGE |
++------------+-------------------+---------------+------------+------------------+---------------+
+| setuptools | 58.1.0            | Fix Available |          3 | # 7 Layer        | python        |
++------------+-------------------+---------------+------------+------------------+---------------+
++---------------------------------------------------------------------------------------------+
 | Source:artifact:usr/local/lib/python3.9/site-packages/pip-23.0.1.dist-info/METADATA         |
 +---------+-------------------+---------------+------------+------------------+---------------+
 | PACKAGE | INSTALLED VERSION | FIX AVAILABLE | VULN COUNT | INTRODUCED LAYER | IN BASE IMAGE |
@@ -265,12 +279,26 @@ You can also view the full vulnerability list in your terminal with: `osv-scanne
 Scanning local image tarball "../../../../internal/image/fixtures/test-python-full.tar"
 
 Container Scanning Result (Debian GNU/Linux 10 (buster)):
-Total 17 packages affected by 32 known vulnerabilities (0 Critical, 9 High, 8 Medium, 0 Low, 15 Unknown) from 2 ecosystems.
-32 vulnerabilities can be fixed.
+Total 19 packages affected by 36 known vulnerabilities (0 Critical, 12 High, 9 Medium, 0 Low, 15 Unknown) from 2 ecosystems.
+36 vulnerabilities can be fixed.
 
 
 PyPI
 +---------------------------------------------------------------------------------------------+
+| Source:artifact:usr/local/lib/python3.9/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl      |
++---------+-------------------+---------------+------------+------------------+---------------+
+| PACKAGE | INSTALLED VERSION | FIX AVAILABLE | VULN COUNT | INTRODUCED LAYER | IN BASE IMAGE |
++---------+-------------------+---------------+------------+------------------+---------------+
+| pip     | 23.0.1            | Fix Available |          1 | # 7 Layer        | python        |
++---------+-------------------+---------------+------------+------------------+---------------+
++------------------------------------------------------------------------------------------------+
+| Source:artifact:usr/local/lib/python3.9/ensurepip/_bundled/setuptools-58.1.0-py3-none-any.whl  |
++------------+-------------------+---------------+------------+------------------+---------------+
+| PACKAGE    | INSTALLED VERSION | FIX AVAILABLE | VULN COUNT | INTRODUCED LAYER | IN BASE IMAGE |
++------------+-------------------+---------------+------------+------------------+---------------+
+| setuptools | 58.1.0            | Fix Available |          3 | # 7 Layer        | python        |
++------------+-------------------+---------------+------------+------------------+---------------+
++---------------------------------------------------------------------------------------------+
 | Source:artifact:usr/local/lib/python3.9/site-packages/Django-1.11.29.dist-info/METADATA     |
 +---------+-------------------+---------------+------------+------------------+---------------+
 | PACKAGE | INSTALLED VERSION | FIX AVAILABLE | VULN COUNT | INTRODUCED LAYER | IN BASE IMAGE |
@@ -590,6 +618,54 @@ You can also view the full vulnerability list in your terminal with: `osv-scanne
 [TestCommand_OCIImageAllPackagesJSON/Scanning_python_image_with_some_packages - 1]
 {
   "results": [
+    {
+      "source": {
+        "path": "usr/local/lib/python3.9/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl",
+        "type": "artifact"
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "pip",
+            "version": "23.0.1",
+            "ecosystem": "PyPI",
+            "image_origin_details": {
+              "index": 7
+            }
+          },
+          "vulnerabilities": [
+            "GHSA-mq26-g339-26xf",
+            "PYSEC-2023-228"
+          ],
+          "groups": 1
+        }
+      ]
+    },
+    {
+      "source": {
+        "path": "usr/local/lib/python3.9/ensurepip/_bundled/setuptools-58.1.0-py3-none-any.whl",
+        "type": "artifact"
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "setuptools",
+            "version": "58.1.0",
+            "ecosystem": "PyPI",
+            "image_origin_details": {
+              "index": 7
+            }
+          },
+          "vulnerabilities": [
+            "GHSA-5rjg-fvgr-3xxf",
+            "GHSA-cx63-2mw6-8hw5",
+            "GHSA-r9hx-vwmv-q579",
+            "PYSEC-2022-43012"
+          ],
+          "groups": 3
+        }
+      ]
+    },
     {
       "source": {
         "path": "usr/local/lib/python3.9/site-packages/Django-1.11.29.dist-info/METADATA",
diff --git a/cmd/osv-scanner/scan/source/__snapshots__/command_test.snap b/cmd/osv-scanner/scan/source/__snapshots__/command_test.snap
index 00c54eec..7f7ad120 100755
--- a/cmd/osv-scanner/scan/source/__snapshots__/command_test.snap
+++ b/cmd/osv-scanner/scan/source/__snapshots__/command_test.snap
@@ -725,6 +725,7 @@ Filtered 9 local/unscannable package/s from the scan.
 | https://osv.dev/CVE-2024-4741       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/CVE-2024-5535       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/CVE-2024-9143       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
+| https://osv.dev/CVE-2025-4575       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/DLA-3008-1          |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/DLA-3325-1          |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/DLA-3449-1          |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
@@ -2219,6 +2220,7 @@ Loaded OSS-Fuzz local db from <tempdir>/osv-scanner/OSS-Fuzz/all.zip
 | https://osv.dev/CVE-2024-4741       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/CVE-2024-5535       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/CVE-2024-9143       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
+| https://osv.dev/CVE-2025-4575       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/DLA-3008-1          |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/DLA-3325-1          |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/DLA-3449-1          |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
@@ -2442,6 +2444,7 @@ Loaded OSS-Fuzz local db from <tempdir>/osv-scanner/OSS-Fuzz/all.zip
 | https://osv.dev/CVE-2024-4741       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/CVE-2024-5535       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/CVE-2024-9143       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
+| https://osv.dev/CVE-2025-4575       |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/DLA-3008-1          |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/DLA-3325-1          |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
 | https://osv.dev/DLA-3449-1          |      | Debian    | openssl                        | 1.1.0l-1~deb9u5                    | fixtures/sbom-insecure/postgres-stretch.cdx.xml |
diff --git a/exit_code_redirect.sh b/exit_code_redirect.sh
index ea4391ea..46dcafe8 100755
--- a/exit_code_redirect.sh
+++ b/exit_code_redirect.sh
@@ -39,10 +39,8 @@ osv-scanner $args "${split_args[@]}"
 exit_code=$?
 
 echo "Exit code: ${exit_code}"
-# Check if the exit code is 127 or 128 and modify it to 0
-# - 127: General error, not something the user can fix most of the time
-# - 128: No lockfiles found
-if [[ $exit_code -eq 127 || $exit_code -eq 128 ]]; then
+# don't error if there are no lockfiles found
+if [[ $exit_code -eq 128 ]]; then
   exit_code=0
 fi
 
diff --git a/go.mod b/go.mod
index 1761a80f..b1ead613 100644
--- a/go.mod
+++ b/go.mod
@@ -17,7 +17,7 @@ require (
 	github.com/go-git/go-billy/v5 v5.6.2
 	github.com/go-git/go-git/v5 v5.16.0
 	github.com/google/go-cmp v0.7.0
-	github.com/google/osv-scalibr v0.2.0
+	github.com/google/osv-scalibr v0.2.1
 	github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b
 	github.com/jedib0t/go-pretty/v6 v6.6.7
 	github.com/muesli/reflow v0.3.0
@@ -79,8 +79,11 @@ require (
 	github.com/dlclark/regexp2 v1.11.0 // indirect
 	github.com/docker/cli v27.1.1+incompatible // indirect
 	github.com/docker/distribution v2.8.3+incompatible // indirect
+	github.com/docker/docker v28.0.4+incompatible // indirect
 	github.com/docker/docker-credential-helpers v0.8.1 // indirect
+	github.com/docker/go-connections v0.4.0 // indirect
 	github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
+	github.com/docker/go-units v0.5.0 // indirect
 	github.com/edsrzf/mmap-go v1.1.0 // indirect
 	github.com/emirpasic/gods v1.18.1 // indirect
 	github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
@@ -112,6 +115,7 @@ require (
 	github.com/mattn/go-sqlite3 v1.14.28 // indirect
 	github.com/microcosm-cc/bluemonday v1.0.27 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
+	github.com/moby/docker-image-spec v1.3.1 // indirect
 	github.com/moby/locker v1.0.1 // indirect
 	github.com/moby/sys/mountinfo v0.6.2 // indirect
 	github.com/moby/sys/sequential v0.5.0 // indirect
diff --git a/go.sum b/go.sum
index 91e06c16..7177bfc1 100644
--- a/go.sum
+++ b/go.sum
@@ -15,6 +15,8 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9
 github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
 github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA=
 github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
 github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
@@ -51,6 +53,8 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP
 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
 github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
 github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
+github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
 github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
@@ -116,10 +120,16 @@ github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2
 github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
 github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v28.0.4+incompatible h1:JNNkBctYKurkw6FrHfKqY0nKIDf5nrbxjVBtS+cdcok=
+github.com/docker/docker v28.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
 github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
 github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
 github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
@@ -167,6 +177,8 @@ github.com/goccy/go-yaml v1.15.13 h1:Xd87Yddmr2rC1SLLTm2MNDcTjeO/GYo0JGiww6gSTDg
 github.com/goccy/go-yaml v1.15.13/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/gohugoio/hashstructure v0.5.0 h1:G2fjSBU36RdwEJBWJ+919ERvOVqAg9tfcYp47K9swqg=
+github.com/gohugoio/hashstructure v0.5.0/go.mod h1:Ser0TniXuu/eauYmrwM4o64EBvySxNzITEOLlm4igec=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
@@ -199,8 +211,10 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
 github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
 github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo=
 github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8=
-github.com/google/osv-scalibr v0.2.0 h1:nzekkAmZXIeNnLN+saBX6jJ5nzTCP/jVgU/zqyYIWEc=
-github.com/google/osv-scalibr v0.2.0/go.mod h1:dipibNd3fpUxqJTeh76c4yS5feBa+CGLxytd77K6Ja0=
+github.com/google/go-cpy v0.0.0-20211218193943-a9c933c06932 h1:5/4TSDzpDnHQ8rKEEQBjRlYx77mHOvXu08oGchxej7o=
+github.com/google/go-cpy v0.0.0-20211218193943-a9c933c06932/go.mod h1:cC6EdPbj/17GFCPDK39NRarlMI+kt+O60S12cNB5J9Y=
+github.com/google/osv-scalibr v0.2.1 h1:d1SpwzXfNiRafUMNpei3tQg8dDLSWe7JAPNEHxhzxDk=
+github.com/google/osv-scalibr v0.2.1/go.mod h1:gTmbCPgh9ooYnU55N32qPxHgFubkxgiDxsoCAMQc2Nc=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -208,6 +222,8 @@ github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
 github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
 github.com/groob/plist v0.1.1 h1:JUsmXVPGJ0HqG4Ta1z3HYbO0XwOHsgc0PqahpvgU5Q0=
 github.com/groob/plist v0.1.1/go.mod h1:itkABA+w2cw7x5nYUS/pLRef6ludkZKOigbROmCTaFw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
 github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
 github.com/ianlancetaylor/demangle v0.0.0-20250417193237-f615e6bd150b h1:ogbOPx86mIhFy764gGkqnkFC8m5PJA7sPzlk9ppLVQA=
@@ -248,6 +264,8 @@ github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwX
 github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
 github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
 github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
 github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
@@ -260,6 +278,12 @@ github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
 github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
 github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
 github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
+github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
+github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
 github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
@@ -393,6 +417,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZ
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q=
 go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
 go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
 go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
 go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
 go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
@@ -401,6 +429,8 @@ go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce
 go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
 go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
 go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
+go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
+go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -479,6 +509,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
 golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
+golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
diff --git a/internal/imodels/imodels.go b/internal/imodels/imodels.go
index 6ebd7d2a..bfa643de 100644
--- a/internal/imodels/imodels.go
+++ b/internal/imodels/imodels.go
@@ -8,9 +8,11 @@ import (
 	"github.com/google/osv-scalibr/extractor"
 	"github.com/google/osv-scalibr/extractor/filesystem/language/golang/gobinary"
 	"github.com/google/osv-scalibr/extractor/filesystem/language/java/archive"
+	archivemetadata "github.com/google/osv-scalibr/extractor/filesystem/language/java/archive/metadata"
 	"github.com/google/osv-scalibr/extractor/filesystem/language/python/wheelegg"
 	"github.com/google/osv-scalibr/extractor/filesystem/os/apk"
 	"github.com/google/osv-scalibr/extractor/filesystem/os/dpkg"
+	dpkgmetadata "github.com/google/osv-scalibr/extractor/filesystem/os/dpkg/metadata"
 	"github.com/google/osv-scalibr/extractor/filesystem/os/rpm"
 	"github.com/google/osv-scalibr/extractor/filesystem/sbom/cdx"
 	"github.com/google/osv-scalibr/extractor/filesystem/sbom/spdx"
@@ -78,7 +80,7 @@ func (pkg *PackageInfo) Name() string {
 	}
 
 	// Patch Maven archive extractor package names
-	if metadata, ok := pkg.Package.Metadata.(*archive.Metadata); ok {
+	if metadata, ok := pkg.Package.Metadata.(*archivemetadata.Metadata); ok {
 		// Debian uses source name on osv.dev
 		// (fallback to using the normal name if source name is empty)
 		if metadata.ArtifactID != "" && metadata.GroupID != "" {
@@ -87,7 +89,7 @@ func (pkg *PackageInfo) Name() string {
 	}
 
 	// --- OS metadata ---
-	if metadata, ok := pkg.Package.Metadata.(*dpkg.Metadata); ok {
+	if metadata, ok := pkg.Package.Metadata.(*dpkgmetadata.Metadata); ok {
 		// Debian uses source name on osv.dev
 		// (fallback to using the normal name if source name is empty)
 		if metadata.SourceName != "" {
@@ -199,7 +201,7 @@ func (pkg *PackageInfo) OSPackageName() string {
 	if metadata, ok := pkg.Package.Metadata.(*apk.Metadata); ok {
 		return metadata.PackageName
 	}
-	if metadata, ok := pkg.Package.Metadata.(*dpkg.Metadata); ok {
+	if metadata, ok := pkg.Package.Metadata.(*dpkgmetadata.Metadata); ok {
 		return metadata.PackageName
 	}
 	if metadata, ok := pkg.Package.Metadata.(*rpm.Metadata); ok {
diff --git a/internal/output/__snapshots__/cyclonedx_test.snap b/internal/output/__snapshots__/cyclonedx_test.snap
index 7af1e616..10612008 100755
--- a/internal/output/__snapshots__/cyclonedx_test.snap
+++ b/internal/output/__snapshots__/cyclonedx_test.snap
@@ -546,6 +546,59 @@
 
 ---
 
+[TestPrintCycloneDX14Results_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1@1.2.3",
+      "type": "library",
+      "name": "mine1",
+      "version": "1.2.3",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine1@1.2.3"
+    }
+  ],
+  "vulnerabilities": []
+}
+
+---
+
+[TestPrintCycloneDX14Results_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1",
+      "type": "library",
+      "name": "mine1",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine1"
+    }
+  ],
+  "vulnerabilities": []
+}
+
+---
+
 [TestPrintCycloneDX14Results_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 {
   "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
@@ -787,6 +840,105 @@
 
 ---
 
+[TestPrintCycloneDX14Results_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1@1.2.3",
+      "type": "library",
+      "name": "mine1",
+      "version": "1.2.3",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine1@1.2.3"
+    },
+    {
+      "bom-ref": "pkg:npm/mine1@1.3.5",
+      "type": "library",
+      "name": "mine1",
+      "version": "1.3.5",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine1@1.3.5"
+    },
+    {
+      "bom-ref": "pkg:npm/mine2",
+      "type": "library",
+      "name": "mine2",
+      "licenses": [
+        {
+          "license": {
+            "id": "ISC"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine2"
+    },
+    {
+      "bom-ref": "pkg:npm/mine3@0.4.1",
+      "type": "library",
+      "name": "mine3",
+      "version": "0.4.1",
+      "licenses": [
+        {
+          "license": {
+            "id": "ISC"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine3@0.4.1"
+    }
+  ],
+  "vulnerabilities": [
+    {
+      "id": "OSV-1",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    },
+    {
+      "id": "OSV-2",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something less scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    }
+  ]
+}
+
+---
+
 [TestPrintCycloneDX14Results_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
 {
   "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
@@ -1518,6 +1670,111 @@
 
 ---
 
+[TestPrintCycloneDX14Results_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:composer/author1/mine1@1.2.3",
+      "type": "library",
+      "name": "author1/mine1",
+      "version": "1.2.3",
+      "licenses": [],
+      "purl": "pkg:composer/author1/mine1@1.2.3"
+    },
+    {
+      "bom-ref": "pkg:composer/author3/mine3@0.4.1",
+      "type": "library",
+      "name": "author3/mine3",
+      "version": "0.4.1",
+      "licenses": [],
+      "purl": "pkg:composer/author3/mine3@0.4.1"
+    },
+    {
+      "bom-ref": "pkg:npm/mine1",
+      "type": "library",
+      "name": "mine1",
+      "licenses": [],
+      "purl": "pkg:npm/mine1"
+    },
+    {
+      "bom-ref": "pkg:nuget/mine2@3.2.5",
+      "type": "library",
+      "name": "mine2",
+      "version": "3.2.5",
+      "licenses": [],
+      "purl": "pkg:nuget/mine2@3.2.5"
+    }
+  ],
+  "vulnerabilities": [
+    {
+      "id": "OSV-1",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    },
+    {
+      "id": "OSV-2",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something less scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    },
+    {
+      "id": "OSV-3",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something mildly scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    },
+    {
+      "id": "OSV-5",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scarier!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    }
+  ]
+}
+
+---
+
 [TestPrintCycloneDX14Results_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 {
   "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
@@ -1889,7 +2146,7 @@
 
 ---
 
-[TestPrintCycloneDX14Results_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
+[TestPrintCycloneDX14Results_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
 {
   "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
   "bomFormat": "CycloneDX",
@@ -1903,14 +2160,87 @@
       "version": "1.2.3",
       "licenses": [],
       "purl": "pkg:npm/mine1@1.2.3"
-    },
-    {
-      "bom-ref": "pkg:npm/mine3@0.10.2-rc",
-      "type": "library",
-      "name": "mine3",
-      "version": "0.10.2-rc",
-      "licenses": [],
-      "purl": "pkg:npm/mine3@0.10.2-rc"
+    }
+  ],
+  "vulnerabilities": [
+    {
+      "id": "OSV-1",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    }
+  ]
+}
+
+---
+
+[TestPrintCycloneDX14Results_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1",
+      "type": "library",
+      "name": "mine1",
+      "licenses": [],
+      "purl": "pkg:npm/mine1"
+    }
+  ],
+  "vulnerabilities": [
+    {
+      "id": "OSV-1",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    }
+  ]
+}
+
+---
+
+[TestPrintCycloneDX14Results_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.4",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1@1.2.3",
+      "type": "library",
+      "name": "mine1",
+      "version": "1.2.3",
+      "licenses": [],
+      "purl": "pkg:npm/mine1@1.2.3"
+    },
+    {
+      "bom-ref": "pkg:npm/mine3@0.10.2-rc",
+      "type": "library",
+      "name": "mine3",
+      "version": "0.10.2-rc",
+      "licenses": [],
+      "purl": "pkg:npm/mine3@0.10.2-rc"
     }
   ],
   "vulnerabilities": [
@@ -2569,6 +2899,59 @@
 
 ---
 
+[TestPrintCycloneDX15Results_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.5",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1@1.2.3",
+      "type": "library",
+      "name": "mine1",
+      "version": "1.2.3",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine1@1.2.3"
+    }
+  ],
+  "vulnerabilities": []
+}
+
+---
+
+[TestPrintCycloneDX15Results_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.5",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1",
+      "type": "library",
+      "name": "mine1",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine1"
+    }
+  ],
+  "vulnerabilities": []
+}
+
+---
+
 [TestPrintCycloneDX15Results_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 {
   "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
@@ -2810,6 +3193,105 @@
 
 ---
 
+[TestPrintCycloneDX15Results_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.5",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1@1.2.3",
+      "type": "library",
+      "name": "mine1",
+      "version": "1.2.3",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine1@1.2.3"
+    },
+    {
+      "bom-ref": "pkg:npm/mine1@1.3.5",
+      "type": "library",
+      "name": "mine1",
+      "version": "1.3.5",
+      "licenses": [
+        {
+          "license": {
+            "id": "MIT"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine1@1.3.5"
+    },
+    {
+      "bom-ref": "pkg:npm/mine2",
+      "type": "library",
+      "name": "mine2",
+      "licenses": [
+        {
+          "license": {
+            "id": "ISC"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine2"
+    },
+    {
+      "bom-ref": "pkg:npm/mine3@0.4.1",
+      "type": "library",
+      "name": "mine3",
+      "version": "0.4.1",
+      "licenses": [
+        {
+          "license": {
+            "id": "ISC"
+          }
+        }
+      ],
+      "purl": "pkg:npm/mine3@0.4.1"
+    }
+  ],
+  "vulnerabilities": [
+    {
+      "id": "OSV-1",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    },
+    {
+      "id": "OSV-2",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something less scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    }
+  ]
+}
+
+---
+
 [TestPrintCycloneDX15Results_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
 {
   "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
@@ -3541,6 +4023,111 @@
 
 ---
 
+[TestPrintCycloneDX15Results_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.5",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:composer/author1/mine1@1.2.3",
+      "type": "library",
+      "name": "author1/mine1",
+      "version": "1.2.3",
+      "licenses": [],
+      "purl": "pkg:composer/author1/mine1@1.2.3"
+    },
+    {
+      "bom-ref": "pkg:composer/author3/mine3@0.4.1",
+      "type": "library",
+      "name": "author3/mine3",
+      "version": "0.4.1",
+      "licenses": [],
+      "purl": "pkg:composer/author3/mine3@0.4.1"
+    },
+    {
+      "bom-ref": "pkg:npm/mine1",
+      "type": "library",
+      "name": "mine1",
+      "licenses": [],
+      "purl": "pkg:npm/mine1"
+    },
+    {
+      "bom-ref": "pkg:nuget/mine2@3.2.5",
+      "type": "library",
+      "name": "mine2",
+      "version": "3.2.5",
+      "licenses": [],
+      "purl": "pkg:nuget/mine2@3.2.5"
+    }
+  ],
+  "vulnerabilities": [
+    {
+      "id": "OSV-1",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    },
+    {
+      "id": "OSV-2",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something less scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    },
+    {
+      "id": "OSV-3",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something mildly scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    },
+    {
+      "id": "OSV-5",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scarier!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    }
+  ]
+}
+
+---
+
 [TestPrintCycloneDX15Results_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 {
   "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
@@ -3912,6 +4499,79 @@
 
 ---
 
+[TestPrintCycloneDX15Results_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.5",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1@1.2.3",
+      "type": "library",
+      "name": "mine1",
+      "version": "1.2.3",
+      "licenses": [],
+      "purl": "pkg:npm/mine1@1.2.3"
+    }
+  ],
+  "vulnerabilities": [
+    {
+      "id": "OSV-1",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    }
+  ]
+}
+
+---
+
+[TestPrintCycloneDX15Results_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+{
+  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
+  "bomFormat": "CycloneDX",
+  "specVersion": "1.5",
+  "version": 1,
+  "components": [
+    {
+      "bom-ref": "pkg:npm/mine1",
+      "type": "library",
+      "name": "mine1",
+      "licenses": [],
+      "purl": "pkg:npm/mine1"
+    }
+  ],
+  "vulnerabilities": [
+    {
+      "id": "OSV-1",
+      "references": [],
+      "ratings": [
+        {
+          "vector": "1"
+        }
+      ],
+      "description": "Something scary!",
+      "advisories": [],
+      "credits": {
+        "organizations": []
+      },
+      "affects": []
+    }
+  ]
+}
+
+---
+
 [TestPrintCycloneDX15Results_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
 {
   "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
diff --git a/internal/output/__snapshots__/githubannotation_test.snap b/internal/output/__snapshots__/githubannotation_test.snap
index 81565f1a..171e3203 100755
--- a/internal/output/__snapshots__/githubannotation_test.snap
+++ b/internal/output/__snapshots__/githubannotation_test.snap
@@ -55,6 +55,14 @@
 ::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+------------------+------+-----------------+---------------+%0A+---------+------------------+------+-----------------+---------------+
 ---
 
+[TestPrintGHAnnotationReport_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
+::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+------------------+------+-----------------+---------------+%0A+---------+------------------+------+-----------------+---------------+
+---
+
+[TestPrintGHAnnotationReport_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+------------------+------+-----------------+---------------+%0A+---------+------------------+------+-----------------+---------------+
+---
+
 [TestPrintGHAnnotationReport_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 ::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+------------------+------+-----------------+---------------+%0A+---------+------------------+------+-----------------+---------------+::error file=path/to/my/second/lockfile::path/to/my/second/lockfile%0A+---------+------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+------------------+------+-----------------+---------------+%0A+---------+------------------+------+-----------------+---------------+
 ---
@@ -67,6 +75,10 @@
 ::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine1   | https://osv.dev/OSV-1 |      | 1.2.3           |               |%0A+---------+-----------------------+------+-----------------+---------------+::error file=path/to/my/second/lockfile::path/to/my/second/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine2   | https://osv.dev/OSV-2 |      | 3.2.5           |               |%0A+---------+-----------------------+------+-----------------+---------------+::error file=path/to/my/third/lockfile::path/to/my/third/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine1   | https://osv.dev/OSV-1 |      | 1.2.3           |               |%0A+---------+-----------------------+------+-----------------+---------------+
 ---
 
+[TestPrintGHAnnotationReport_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
+::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine1   | https://osv.dev/OSV-1 |      | 1.2.3           |               |%0A+---------+-----------------------+------+-----------------+---------------+::error file=path/to/my/second/lockfile::path/to/my/second/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine2   | https://osv.dev/OSV-2 |      |                 |               |%0A+---------+-----------------------+------+-----------------+---------------+::error file=path/to/my/third/lockfile::path/to/my/third/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine1   | https://osv.dev/OSV-1 |      | 1.2.3           |               |%0A+---------+-----------------------+------+-----------------+---------------+
+---
+
 [TestPrintGHAnnotationReport_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
 ::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine1   | https://osv.dev/OSV-1 |      | 1.2.3           |               |%0A+---------+-----------------------+------+-----------------+---------------+
 ---
@@ -107,6 +119,10 @@
 ::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------------+-----------------------+------+-----------------+---------------+%0A| PACKAGE       | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------------+-----------------------+------+-----------------+---------------+%0A| author1/mine1 | https://osv.dev/OSV-1 |      | 1.2.3           |               |%0A| author1/mine1 | https://osv.dev/OSV-5 |      | 1.2.3           |               |%0A| mine1         | https://osv.dev/OSV-1 |      | 1.2.2           |               |%0A+---------------+-----------------------+------+-----------------+---------------+::error file=path/to/my/second/lockfile::path/to/my/second/lockfile%0A+---------------+-----------------------+------+-----------------+---------------+%0A| PACKAGE       | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------------+-----------------------+------+-----------------+---------------+%0A| mine2         | https://osv.dev/OSV-2 |      | 3.2.5           |               |%0A| author3/mine3 | https://osv.dev/OSV-3 |      | 0.4.1           |               |%0A| author3/mine3 | https://osv.dev/OSV-5 |      | 0.4.1           |               |%0A+---------------+-----------------------+------+-----------------+---------------+
 ---
 
+[TestPrintGHAnnotationReport_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------------+-----------------------+------+-----------------+---------------+%0A| PACKAGE       | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------------+-----------------------+------+-----------------+---------------+%0A| author1/mine1 | https://osv.dev/OSV-1 |      | 1.2.3           |               |%0A| author1/mine1 | https://osv.dev/OSV-5 |      | 1.2.3           |               |%0A| mine1         | https://osv.dev/OSV-1 |      |                 |               |%0A+---------------+-----------------------+------+-----------------+---------------+::error file=path/to/my/second/lockfile::path/to/my/second/lockfile%0A+---------------+-----------------------+------+-----------------+---------------+%0A| PACKAGE       | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------------+-----------------------+------+-----------------+---------------+%0A| mine2         | https://osv.dev/OSV-2 |      | 3.2.5           |               |%0A| author3/mine3 | https://osv.dev/OSV-3 |      | 0.4.1           |               |%0A| author3/mine3 | https://osv.dev/OSV-5 |      | 0.4.1           |               |%0A+---------------+-----------------------+------+-----------------+---------------+
+---
+
 [TestPrintGHAnnotationReport_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 ::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+------------------+------+-----------------+---------------+%0A+---------+------------------+------+-----------------+---------------+::error file=path/to/my/second/lockfile::path/to/my/second/lockfile%0A+---------+------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+------------------+------+-----------------+---------------+%0A+---------+------------------+------+-----------------+---------------+::error file=path/to/my/third/lockfile::path/to/my/third/lockfile%0A+---------+------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+------------------+------+-----------------+---------------+%0A+---------+------------------+------+-----------------+---------------+
 ---
@@ -151,6 +167,14 @@
 ::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+--------------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID         | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+--------------------------+------+-----------------+---------------+%0A| mine1   | https://osv.dev/OSV-1    |      | 1.2.3           |               |%0A|         | https://osv.dev/GHSA-123 |      |                 |               |%0A+---------+--------------------------+------+-----------------+---------------+
 ---
 
+[TestPrintGHAnnotationReport_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
+::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine1   | https://osv.dev/OSV-1 |      | 1.2.3           |               |%0A+---------+-----------------------+------+-----------------+---------------+
+---
+
+[TestPrintGHAnnotationReport_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine1   | https://osv.dev/OSV-1 |      |                 |               |%0A+---------+-----------------------+------+-----------------+---------------+
+---
+
 [TestPrintGHAnnotationReport_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
 ::error file=path/to/my/first/lockfile::path/to/my/first/lockfile%0A+---------+-----------------------+------+-----------------+---------------+%0A| PACKAGE | VULNERABILITY ID      | CVSS | CURRENT VERSION | FIXED VERSION |%0A+---------+-----------------------+------+-----------------+---------------+%0A| mine1   | https://osv.dev/OSV-1 |      | 1.2.3           |               |%0A| mine3   | https://osv.dev/OSV-2 |      | 0.10.2-rc       |               |%0A+---------+-----------------------+------+-----------------+---------------+
 ---
diff --git a/internal/output/__snapshots__/machinejson_test.snap b/internal/output/__snapshots__/machinejson_test.snap
index 9c8f3a00..24fa2253 100755
--- a/internal/output/__snapshots__/machinejson_test.snap
+++ b/internal/output/__snapshots__/machinejson_test.snap
@@ -788,6 +788,82 @@
 
 ---
 
+[TestPrintJSONResults_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
+{
+  "results": [
+    {
+      "source": {
+        "path": "path/to/my/first/lockfile",
+        "type": ""
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "mine1",
+            "version": "1.2.3",
+            "ecosystem": "npm",
+            "commit": "abc123"
+          },
+          "licenses": [
+            "MIT"
+          ],
+          "license_violations": [
+            "MIT"
+          ]
+        }
+      ]
+    }
+  ],
+  "experimental_config": {
+    "licenses": {
+      "summary": false,
+      "allowlist": [
+        "ISC"
+      ]
+    }
+  }
+}
+
+---
+
+[TestPrintJSONResults_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+{
+  "results": [
+    {
+      "source": {
+        "path": "path/to/my/first/lockfile",
+        "type": ""
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "mine1",
+            "version": "",
+            "ecosystem": "npm",
+            "commit": "abc123"
+          },
+          "licenses": [
+            "MIT"
+          ],
+          "license_violations": [
+            "MIT"
+          ]
+        }
+      ]
+    }
+  ],
+  "experimental_config": {
+    "licenses": {
+      "summary": false,
+      "allowlist": [
+        "ISC"
+      ]
+    }
+  }
+}
+
+---
+
 [TestPrintJSONResults_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 {
   "results": [
@@ -1191,6 +1267,173 @@
 
 ---
 
+[TestPrintJSONResults_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
+{
+  "results": [
+    {
+      "source": {
+        "path": "path/to/my/first/lockfile",
+        "type": ""
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "mine1",
+            "version": "1.2.3",
+            "ecosystem": "npm",
+            "commit": "abcxzy"
+          },
+          "vulnerabilities": [
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-1",
+              "summary": "Something scary!",
+              "severity": [
+                {
+                  "type": "high",
+                  "score": "1"
+                }
+              ]
+            }
+          ],
+          "groups": [
+            {
+              "ids": [
+                "OSV-1"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            }
+          ],
+          "licenses": [
+            "MIT"
+          ],
+          "license_violations": [
+            "MIT"
+          ]
+        }
+      ]
+    },
+    {
+      "source": {
+        "path": "path/to/my/second/lockfile",
+        "type": ""
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "mine2",
+            "version": "",
+            "ecosystem": "npm",
+            "commit": "abc123"
+          },
+          "vulnerabilities": [
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-2",
+              "summary": "Something less scary!",
+              "severity": [
+                {
+                  "type": "low",
+                  "score": "1"
+                }
+              ]
+            }
+          ],
+          "groups": [
+            {
+              "ids": [
+                "OSV-2"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            }
+          ],
+          "licenses": [
+            "ISC"
+          ]
+        },
+        {
+          "package": {
+            "name": "mine3",
+            "version": "0.4.1",
+            "ecosystem": "npm"
+          },
+          "licenses": [
+            "ISC"
+          ]
+        }
+      ]
+    },
+    {
+      "source": {
+        "path": "path/to/my/third/lockfile",
+        "type": ""
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "mine1",
+            "version": "1.3.5",
+            "ecosystem": "npm"
+          },
+          "licenses": [
+            "MIT"
+          ],
+          "license_violations": [
+            "MIT"
+          ]
+        },
+        {
+          "package": {
+            "name": "mine1",
+            "version": "1.2.3",
+            "ecosystem": "npm"
+          },
+          "vulnerabilities": [
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-1",
+              "summary": "Something scary!",
+              "severity": [
+                {
+                  "type": "high",
+                  "score": "1"
+                }
+              ]
+            }
+          ],
+          "groups": [
+            {
+              "ids": [
+                "OSV-1"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            }
+          ],
+          "licenses": [
+            "Apache-2.0"
+          ],
+          "license_violations": [
+            "Apache-2.0"
+          ]
+        }
+      ]
+    }
+  ],
+  "experimental_config": {
+    "licenses": {
+      "summary": false,
+      "allowlist": [
+        "ISC"
+      ]
+    }
+  }
+}
+
+---
+
 [TestPrintJSONResults_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
 {
   "results": [
@@ -2437,6 +2680,196 @@
 
 ---
 
+[TestPrintJSONResults_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+{
+  "results": [
+    {
+      "source": {
+        "path": "path/to/my/first/lockfile",
+        "type": ""
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "author1/mine1",
+            "version": "1.2.3",
+            "ecosystem": "Packagist",
+            "commit": "123abc"
+          },
+          "vulnerabilities": [
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-1",
+              "summary": "Something scary!",
+              "severity": [
+                {
+                  "type": "high",
+                  "score": "1"
+                }
+              ]
+            },
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-5",
+              "summary": "Something scarier!",
+              "severity": [
+                {
+                  "type": "extreme",
+                  "score": "1"
+                }
+              ]
+            }
+          ],
+          "groups": [
+            {
+              "ids": [
+                "OSV-1"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            },
+            {
+              "ids": [
+                "OSV-5"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            }
+          ]
+        },
+        {
+          "package": {
+            "name": "mine1",
+            "version": "",
+            "ecosystem": "npm",
+            "commit": "abcxyz"
+          },
+          "vulnerabilities": [
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-1",
+              "summary": "Something scary!",
+              "severity": [
+                {
+                  "type": "high",
+                  "score": "1"
+                }
+              ]
+            }
+          ],
+          "groups": [
+            {
+              "ids": [
+                "OSV-1"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "source": {
+        "path": "path/to/my/second/lockfile",
+        "type": ""
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "mine2",
+            "version": "3.2.5",
+            "ecosystem": "NuGet"
+          },
+          "dependency_groups": [
+            "dev"
+          ],
+          "vulnerabilities": [
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-2",
+              "summary": "Something less scary!",
+              "severity": [
+                {
+                  "type": "low",
+                  "score": "1"
+                }
+              ]
+            }
+          ],
+          "groups": [
+            {
+              "ids": [
+                "OSV-2"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            }
+          ]
+        },
+        {
+          "package": {
+            "name": "author3/mine3",
+            "version": "0.4.1",
+            "ecosystem": "Packagist"
+          },
+          "dependency_groups": [
+            "build"
+          ],
+          "vulnerabilities": [
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-3",
+              "summary": "Something mildly scary!",
+              "severity": [
+                {
+                  "type": "medium",
+                  "score": "1"
+                }
+              ]
+            },
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-5",
+              "summary": "Something scarier!",
+              "severity": [
+                {
+                  "type": "extreme",
+                  "score": "1"
+                }
+              ]
+            }
+          ],
+          "groups": [
+            {
+              "ids": [
+                "OSV-3"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            },
+            {
+              "ids": [
+                "OSV-5"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            }
+          ]
+        }
+      ]
+    }
+  ],
+  "experimental_config": {
+    "licenses": {
+      "summary": false,
+      "allowlist": null
+    }
+  }
+}
+
+---
+
 [TestPrintJSONResults_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 {
   "results": [
@@ -2979,6 +3412,110 @@
 
 ---
 
+[TestPrintJSONResults_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
+{
+  "results": [
+    {
+      "source": {
+        "path": "path/to/my/first/lockfile",
+        "type": ""
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "mine1",
+            "version": "1.2.3",
+            "ecosystem": "npm",
+            "commit": "abc123"
+          },
+          "vulnerabilities": [
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-1",
+              "summary": "Something scary!",
+              "severity": [
+                {
+                  "type": "high",
+                  "score": "1"
+                }
+              ]
+            }
+          ],
+          "groups": [
+            {
+              "ids": [
+                "OSV-1"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            }
+          ]
+        }
+      ]
+    }
+  ],
+  "experimental_config": {
+    "licenses": {
+      "summary": false,
+      "allowlist": null
+    }
+  }
+}
+
+---
+
+[TestPrintJSONResults_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+{
+  "results": [
+    {
+      "source": {
+        "path": "path/to/my/first/lockfile",
+        "type": ""
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "mine1",
+            "version": "",
+            "ecosystem": "npm",
+            "commit": "abc123"
+          },
+          "vulnerabilities": [
+            {
+              "modified": "0001-01-01T00:00:00Z",
+              "id": "OSV-1",
+              "summary": "Something scary!",
+              "severity": [
+                {
+                  "type": "high",
+                  "score": "1"
+                }
+              ]
+            }
+          ],
+          "groups": [
+            {
+              "ids": [
+                "OSV-1"
+              ],
+              "aliases": null,
+              "max_severity": ""
+            }
+          ]
+        }
+      ]
+    }
+  ],
+  "experimental_config": {
+    "licenses": {
+      "summary": false,
+      "allowlist": null
+    }
+  }
+}
+
+---
+
 [TestPrintJSONResults_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
 {
   "results": [
diff --git a/internal/output/__snapshots__/markdowntable_test.snap b/internal/output/__snapshots__/markdowntable_test.snap
index 8b9f2784..e426c974 100755
--- a/internal/output/__snapshots__/markdowntable_test.snap
+++ b/internal/output/__snapshots__/markdowntable_test.snap
@@ -79,6 +79,20 @@
 
 ---
 
+[TestPrintMarkdownTableResults_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
+| License Violation | Ecosystem | Package | Version | Source |
+| --- | --- | --- | --- | --- |
+| MIT | npm | mine1 | 1.2.3 | path/to/my/first/lockfile |
+
+---
+
+[TestPrintMarkdownTableResults_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+| License Violation | Ecosystem | Package | Version | Source |
+| --- | --- | --- | --- | --- |
+| MIT | npm | mine1 |  | path/to/my/first/lockfile |
+
+---
+
 [TestPrintMarkdownTableResults_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 | License Violation | Ecosystem | Package | Version | Source |
 | --- | --- | --- | --- | --- |
@@ -115,6 +129,20 @@
 
 ---
 
+[TestPrintMarkdownTableResults_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
+| OSV URL | CVSS | Ecosystem | Package | Version | Source |
+| --- | --- | --- | --- | --- | --- |
+| https://osv.dev/OSV-1 |  | npm | mine1 | 1.2.3 | path/to/my/first/lockfile |
+| https://osv.dev/OSV-2 |  | npm | mine2 |  | path/to/my/second/lockfile |
+| https://osv.dev/OSV-1 |  | npm | mine1 | 1.2.3 | path/to/my/third/lockfile |
+| License Violation | Ecosystem | Package | Version | Source |
+| --- | --- | --- | --- | --- |
+| MIT | npm | mine1 | 1.2.3 | path/to/my/first/lockfile |
+| MIT | npm | mine1 | 1.3.5 | path/to/my/third/lockfile |
+| Apache-2.0 | npm | mine1 | 1.2.3 | path/to/my/third/lockfile |
+
+---
+
 [TestPrintMarkdownTableResults_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
 | OSV URL | CVSS | Ecosystem | Package | Version | Source |
 | --- | --- | --- | --- | --- | --- |
@@ -218,6 +246,18 @@
 
 ---
 
+[TestPrintMarkdownTableResults_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+| OSV URL | CVSS | Ecosystem | Package | Version | Source |
+| --- | --- | --- | --- | --- | --- |
+| https://osv.dev/OSV-1 |  | Packagist | author1/mine1 | 1.2.3 | path/to/my/first/lockfile |
+| https://osv.dev/OSV-5 |  | Packagist | author1/mine1 | 1.2.3 | path/to/my/first/lockfile |
+| https://osv.dev/OSV-1 |  | npm | mine1 |  | path/to/my/first/lockfile |
+| https://osv.dev/OSV-2 |  | NuGet | mine2 | 3.2.5 | path/to/my/second/lockfile |
+| https://osv.dev/OSV-3 |  | Packagist | author3/mine3 | 0.4.1 | path/to/my/second/lockfile |
+| https://osv.dev/OSV-5 |  | Packagist | author3/mine3 | 0.4.1 | path/to/my/second/lockfile |
+
+---
+
 [TestPrintMarkdownTableResults_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 
 ---
@@ -287,6 +327,20 @@
 
 ---
 
+[TestPrintMarkdownTableResults_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
+| OSV URL | CVSS | Ecosystem | Package | Version | Source |
+| --- | --- | --- | --- | --- | --- |
+| https://osv.dev/OSV-1 |  | npm | mine1 | 1.2.3 | path/to/my/first/lockfile |
+
+---
+
+[TestPrintMarkdownTableResults_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+| OSV URL | CVSS | Ecosystem | Package | Version | Source |
+| --- | --- | --- | --- | --- | --- |
+| https://osv.dev/OSV-1 |  | npm | mine1 |  | path/to/my/first/lockfile |
+
+---
+
 [TestPrintMarkdownTableResults_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
 | OSV URL | CVSS | Ecosystem | Package | Version | Source |
 | --- | --- | --- | --- | --- | --- |
diff --git a/internal/output/__snapshots__/output_result_test.snap b/internal/output/__snapshots__/output_result_test.snap
index 737630cb..1fc25b07 100755
--- a/internal/output/__snapshots__/output_result_test.snap
+++ b/internal/output/__snapshots__/output_result_test.snap
@@ -3334,6 +3334,592 @@
 
 ---
 
+[TestPrintOutputResults_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+{
+  "Ecosystems": [
+    {
+      "Name": "NuGet",
+      "Sources": [
+        {
+          "Name": ":path/to/my/second/lockfile",
+          "Type": "",
+          "Ecosystem": "NuGet",
+          "PackageTypeCount": {
+            "Regular": 1,
+            "Hidden": 0
+          },
+          "Packages": [
+            {
+              "Name": "mine2",
+              "OSPackageNames": [
+                ""
+              ],
+              "InstalledVersion": "3.2.5",
+              "Commit": "",
+              "FixedVersion": "No fix available",
+              "RegularVulns": [
+                {
+                  "ID": "OSV-2",
+                  "GroupIDs": [
+                    "OSV-2"
+                  ],
+                  "Aliases": null,
+                  "Description": "Something less scary!",
+                  "IsFixable": false,
+                  "FixedVersion": "No fix available",
+                  "VulnAnalysisType": 0,
+                  "SeverityRating": "UNKNOWN",
+                  "SeverityScore": "N/A"
+                }
+              ],
+              "HiddenVulns": [],
+              "LayerDetail": {
+                "LayerIndex": 0,
+                "LayerInfo": {
+                  "Index": 0,
+                  "LayerMetadata": {
+                    "diff_id": "",
+                    "command": "",
+                    "is_empty": false,
+                    "base_image_index": 0
+                  },
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                },
+                "BaseImageInfo": {
+                  "Index": 0,
+                  "BaseImageInfo": null,
+                  "AllLayers": null,
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                }
+              },
+              "VulnCount": {
+                "AnalysisCount": {
+                  "Regular": 1,
+                  "Hidden": 0
+                },
+                "SeverityCount": {
+                  "Critical": 0,
+                  "High": 0,
+                  "Medium": 0,
+                  "Low": 0,
+                  "Unknown": 1
+                },
+                "FixableCount": {
+                  "Fixed": 0,
+                  "UnFixed": 1
+                }
+              },
+              "Licenses": null,
+              "LicenseViolations": null
+            }
+          ],
+          "VulnCount": {
+            "AnalysisCount": {
+              "Regular": 1,
+              "Hidden": 0
+            },
+            "SeverityCount": {
+              "Critical": 0,
+              "High": 0,
+              "Medium": 0,
+              "Low": 0,
+              "Unknown": 1
+            },
+            "FixableCount": {
+              "Fixed": 0,
+              "UnFixed": 1
+            }
+          },
+          "LicenseViolationsCount": 0
+        }
+      ],
+      "IsOS": false
+    },
+    {
+      "Name": "Packagist",
+      "Sources": [
+        {
+          "Name": ":path/to/my/first/lockfile",
+          "Type": "",
+          "Ecosystem": "Packagist",
+          "PackageTypeCount": {
+            "Regular": 1,
+            "Hidden": 0
+          },
+          "Packages": [
+            {
+              "Name": "author1/mine1",
+              "OSPackageNames": [
+                ""
+              ],
+              "InstalledVersion": "1.2.3",
+              "Commit": "123abc",
+              "FixedVersion": "No fix available",
+              "RegularVulns": [
+                {
+                  "ID": "OSV-1",
+                  "GroupIDs": [
+                    "OSV-1"
+                  ],
+                  "Aliases": null,
+                  "Description": "Something scary!",
+                  "IsFixable": false,
+                  "FixedVersion": "No fix available",
+                  "VulnAnalysisType": 0,
+                  "SeverityRating": "UNKNOWN",
+                  "SeverityScore": "N/A"
+                },
+                {
+                  "ID": "OSV-5",
+                  "GroupIDs": [
+                    "OSV-5"
+                  ],
+                  "Aliases": null,
+                  "Description": "Something scarier!",
+                  "IsFixable": false,
+                  "FixedVersion": "No fix available",
+                  "VulnAnalysisType": 0,
+                  "SeverityRating": "UNKNOWN",
+                  "SeverityScore": "N/A"
+                }
+              ],
+              "HiddenVulns": [],
+              "LayerDetail": {
+                "LayerIndex": 0,
+                "LayerInfo": {
+                  "Index": 0,
+                  "LayerMetadata": {
+                    "diff_id": "",
+                    "command": "",
+                    "is_empty": false,
+                    "base_image_index": 0
+                  },
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                },
+                "BaseImageInfo": {
+                  "Index": 0,
+                  "BaseImageInfo": null,
+                  "AllLayers": null,
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                }
+              },
+              "VulnCount": {
+                "AnalysisCount": {
+                  "Regular": 2,
+                  "Hidden": 0
+                },
+                "SeverityCount": {
+                  "Critical": 0,
+                  "High": 0,
+                  "Medium": 0,
+                  "Low": 0,
+                  "Unknown": 2
+                },
+                "FixableCount": {
+                  "Fixed": 0,
+                  "UnFixed": 2
+                }
+              },
+              "Licenses": null,
+              "LicenseViolations": null
+            }
+          ],
+          "VulnCount": {
+            "AnalysisCount": {
+              "Regular": 2,
+              "Hidden": 0
+            },
+            "SeverityCount": {
+              "Critical": 0,
+              "High": 0,
+              "Medium": 0,
+              "Low": 0,
+              "Unknown": 2
+            },
+            "FixableCount": {
+              "Fixed": 0,
+              "UnFixed": 2
+            }
+          },
+          "LicenseViolationsCount": 0
+        },
+        {
+          "Name": ":path/to/my/second/lockfile",
+          "Type": "",
+          "Ecosystem": "Packagist",
+          "PackageTypeCount": {
+            "Regular": 1,
+            "Hidden": 0
+          },
+          "Packages": [
+            {
+              "Name": "author3/mine3",
+              "OSPackageNames": [
+                ""
+              ],
+              "InstalledVersion": "0.4.1",
+              "Commit": "",
+              "FixedVersion": "No fix available",
+              "RegularVulns": [
+                {
+                  "ID": "OSV-3",
+                  "GroupIDs": [
+                    "OSV-3"
+                  ],
+                  "Aliases": null,
+                  "Description": "Something mildly scary!",
+                  "IsFixable": false,
+                  "FixedVersion": "No fix available",
+                  "VulnAnalysisType": 0,
+                  "SeverityRating": "UNKNOWN",
+                  "SeverityScore": "N/A"
+                },
+                {
+                  "ID": "OSV-5",
+                  "GroupIDs": [
+                    "OSV-5"
+                  ],
+                  "Aliases": null,
+                  "Description": "Something scarier!",
+                  "IsFixable": false,
+                  "FixedVersion": "No fix available",
+                  "VulnAnalysisType": 0,
+                  "SeverityRating": "UNKNOWN",
+                  "SeverityScore": "N/A"
+                }
+              ],
+              "HiddenVulns": [],
+              "LayerDetail": {
+                "LayerIndex": 0,
+                "LayerInfo": {
+                  "Index": 0,
+                  "LayerMetadata": {
+                    "diff_id": "",
+                    "command": "",
+                    "is_empty": false,
+                    "base_image_index": 0
+                  },
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                },
+                "BaseImageInfo": {
+                  "Index": 0,
+                  "BaseImageInfo": null,
+                  "AllLayers": null,
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                }
+              },
+              "VulnCount": {
+                "AnalysisCount": {
+                  "Regular": 2,
+                  "Hidden": 0
+                },
+                "SeverityCount": {
+                  "Critical": 0,
+                  "High": 0,
+                  "Medium": 0,
+                  "Low": 0,
+                  "Unknown": 2
+                },
+                "FixableCount": {
+                  "Fixed": 0,
+                  "UnFixed": 2
+                }
+              },
+              "Licenses": null,
+              "LicenseViolations": null
+            }
+          ],
+          "VulnCount": {
+            "AnalysisCount": {
+              "Regular": 2,
+              "Hidden": 0
+            },
+            "SeverityCount": {
+              "Critical": 0,
+              "High": 0,
+              "Medium": 0,
+              "Low": 0,
+              "Unknown": 2
+            },
+            "FixableCount": {
+              "Fixed": 0,
+              "UnFixed": 2
+            }
+          },
+          "LicenseViolationsCount": 0
+        }
+      ],
+      "IsOS": false
+    },
+    {
+      "Name": "npm",
+      "Sources": [
+        {
+          "Name": ":path/to/my/first/lockfile",
+          "Type": "",
+          "Ecosystem": "npm",
+          "PackageTypeCount": {
+            "Regular": 1,
+            "Hidden": 0
+          },
+          "Packages": [
+            {
+              "Name": "mine1",
+              "OSPackageNames": [
+                ""
+              ],
+              "InstalledVersion": "",
+              "Commit": "abcxyz",
+              "FixedVersion": "No fix available",
+              "RegularVulns": [
+                {
+                  "ID": "OSV-1",
+                  "GroupIDs": [
+                    "OSV-1"
+                  ],
+                  "Aliases": null,
+                  "Description": "Something scary!",
+                  "IsFixable": false,
+                  "FixedVersion": "No fix available",
+                  "VulnAnalysisType": 0,
+                  "SeverityRating": "UNKNOWN",
+                  "SeverityScore": "N/A"
+                }
+              ],
+              "HiddenVulns": [],
+              "LayerDetail": {
+                "LayerIndex": 0,
+                "LayerInfo": {
+                  "Index": 0,
+                  "LayerMetadata": {
+                    "diff_id": "",
+                    "command": "",
+                    "is_empty": false,
+                    "base_image_index": 0
+                  },
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                },
+                "BaseImageInfo": {
+                  "Index": 0,
+                  "BaseImageInfo": null,
+                  "AllLayers": null,
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                }
+              },
+              "VulnCount": {
+                "AnalysisCount": {
+                  "Regular": 1,
+                  "Hidden": 0
+                },
+                "SeverityCount": {
+                  "Critical": 0,
+                  "High": 0,
+                  "Medium": 0,
+                  "Low": 0,
+                  "Unknown": 1
+                },
+                "FixableCount": {
+                  "Fixed": 0,
+                  "UnFixed": 1
+                }
+              },
+              "Licenses": null,
+              "LicenseViolations": null
+            }
+          ],
+          "VulnCount": {
+            "AnalysisCount": {
+              "Regular": 1,
+              "Hidden": 0
+            },
+            "SeverityCount": {
+              "Critical": 0,
+              "High": 0,
+              "Medium": 0,
+              "Low": 0,
+              "Unknown": 1
+            },
+            "FixableCount": {
+              "Fixed": 0,
+              "UnFixed": 1
+            }
+          },
+          "LicenseViolationsCount": 0
+        }
+      ],
+      "IsOS": false
+    }
+  ],
+  "IsContainerScanning": false,
+  "ImageInfo": {
+    "OS": "",
+    "AllLayers": null,
+    "AllBaseImages": null
+  },
+  "LicenseSummary": {
+    "Summary": false,
+    "ShowViolations": false,
+    "LicenseCount": null
+  },
+  "VulnTypeSummary": {
+    "All": 6,
+    "OS": 0,
+    "Project": 6,
+    "Hidden": 0
+  },
+  "PackageTypeCount": {
+    "Regular": 4,
+    "Hidden": 0
+  },
+  "VulnCount": {
+    "AnalysisCount": {
+      "Regular": 6,
+      "Hidden": 0
+    },
+    "SeverityCount": {
+      "Critical": 0,
+      "High": 0,
+      "Medium": 0,
+      "Low": 0,
+      "Unknown": 6
+    },
+    "FixableCount": {
+      "Fixed": 0,
+      "UnFixed": 6
+    }
+  }
+}
+
+---
+
 [TestPrintOutputResults_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 {
   "Ecosystems": [
@@ -3341,7 +3927,35 @@
       "Name": "",
       "Sources": [
         {
-          "Name": ":path/to/my/first/lockfile",
+          "Name": ":path/to/my/first/lockfile",
+          "Type": "",
+          "Ecosystem": "",
+          "PackageTypeCount": {
+            "Regular": 0,
+            "Hidden": 0
+          },
+          "Packages": [],
+          "VulnCount": {
+            "AnalysisCount": {
+              "Regular": 0,
+              "Hidden": 0
+            },
+            "SeverityCount": {
+              "Critical": 0,
+              "High": 0,
+              "Medium": 0,
+              "Low": 0,
+              "Unknown": 0
+            },
+            "FixableCount": {
+              "Fixed": 0,
+              "UnFixed": 0
+            }
+          },
+          "LicenseViolationsCount": 0
+        },
+        {
+          "Name": ":path/to/my/second/lockfile",
           "Type": "",
           "Ecosystem": "",
           "PackageTypeCount": {
@@ -3369,7 +3983,132 @@
           "LicenseViolationsCount": 0
         },
         {
-          "Name": ":path/to/my/second/lockfile",
+          "Name": ":path/to/my/third/lockfile",
+          "Type": "",
+          "Ecosystem": "",
+          "PackageTypeCount": {
+            "Regular": 0,
+            "Hidden": 0
+          },
+          "Packages": [],
+          "VulnCount": {
+            "AnalysisCount": {
+              "Regular": 0,
+              "Hidden": 0
+            },
+            "SeverityCount": {
+              "Critical": 0,
+              "High": 0,
+              "Medium": 0,
+              "Low": 0,
+              "Unknown": 0
+            },
+            "FixableCount": {
+              "Fixed": 0,
+              "UnFixed": 0
+            }
+          },
+          "LicenseViolationsCount": 0
+        }
+      ],
+      "IsOS": false
+    }
+  ],
+  "IsContainerScanning": false,
+  "ImageInfo": {
+    "OS": "",
+    "AllLayers": null,
+    "AllBaseImages": null
+  },
+  "LicenseSummary": {
+    "Summary": false,
+    "ShowViolations": false,
+    "LicenseCount": null
+  },
+  "VulnTypeSummary": {
+    "All": 0,
+    "OS": 0,
+    "Project": 0,
+    "Hidden": 0
+  },
+  "PackageTypeCount": {
+    "Regular": 0,
+    "Hidden": 0
+  },
+  "VulnCount": {
+    "AnalysisCount": {
+      "Regular": 0,
+      "Hidden": 0
+    },
+    "SeverityCount": {
+      "Critical": 0,
+      "High": 0,
+      "Medium": 0,
+      "Low": 0,
+      "Unknown": 0
+    },
+    "FixableCount": {
+      "Fixed": 0,
+      "UnFixed": 0
+    }
+  }
+}
+
+---
+
+[TestPrintOutputResults_WithVulnerabilities/no_sources - 1]
+{
+  "Ecosystems": null,
+  "IsContainerScanning": false,
+  "ImageInfo": {
+    "OS": "",
+    "AllLayers": null,
+    "AllBaseImages": null
+  },
+  "LicenseSummary": {
+    "Summary": false,
+    "ShowViolations": false,
+    "LicenseCount": null
+  },
+  "VulnTypeSummary": {
+    "All": 0,
+    "OS": 0,
+    "Project": 0,
+    "Hidden": 0
+  },
+  "PackageTypeCount": {
+    "Regular": 0,
+    "Hidden": 0
+  },
+  "VulnCount": {
+    "AnalysisCount": {
+      "Regular": 0,
+      "Hidden": 0
+    },
+    "SeverityCount": {
+      "Critical": 0,
+      "High": 0,
+      "Medium": 0,
+      "Low": 0,
+      "Unknown": 0
+    },
+    "FixableCount": {
+      "Fixed": 0,
+      "UnFixed": 0
+    }
+  }
+}
+
+---
+
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_no_packages - 1]
+{
+  "Ecosystems": [
+    {
+      "Name": "",
+      "Sources": [
+        {
+          "Name": ":path/to/my/first/lockfile",
           "Type": "",
           "Ecosystem": "",
           "PackageTypeCount": {
@@ -3393,18 +4132,152 @@
               "Fixed": 0,
               "UnFixed": 0
             }
-          },
-          "LicenseViolationsCount": 0
-        },
-        {
-          "Name": ":path/to/my/third/lockfile",
-          "Type": "",
-          "Ecosystem": "",
-          "PackageTypeCount": {
-            "Regular": 0,
-            "Hidden": 0
-          },
-          "Packages": [],
+          },
+          "LicenseViolationsCount": 0
+        }
+      ],
+      "IsOS": false
+    }
+  ],
+  "IsContainerScanning": false,
+  "ImageInfo": {
+    "OS": "",
+    "AllLayers": null,
+    "AllBaseImages": null
+  },
+  "LicenseSummary": {
+    "Summary": false,
+    "ShowViolations": false,
+    "LicenseCount": null
+  },
+  "VulnTypeSummary": {
+    "All": 0,
+    "OS": 0,
+    "Project": 0,
+    "Hidden": 0
+  },
+  "PackageTypeCount": {
+    "Regular": 0,
+    "Hidden": 0
+  },
+  "VulnCount": {
+    "AnalysisCount": {
+      "Regular": 0,
+      "Hidden": 0
+    },
+    "SeverityCount": {
+      "Critical": 0,
+      "High": 0,
+      "Medium": 0,
+      "Low": 0,
+      "Unknown": 0
+    },
+    "FixableCount": {
+      "Fixed": 0,
+      "UnFixed": 0
+    }
+  }
+}
+
+---
+
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package,_no_vulnerabilities - 1]
+{
+  "Ecosystems": [
+    {
+      "Name": "npm",
+      "Sources": [
+        {
+          "Name": ":path/to/my/first/lockfile",
+          "Type": "",
+          "Ecosystem": "npm",
+          "PackageTypeCount": {
+            "Regular": 0,
+            "Hidden": 0
+          },
+          "Packages": [
+            {
+              "Name": "mine1",
+              "OSPackageNames": [
+                ""
+              ],
+              "InstalledVersion": "1.2.3",
+              "Commit": "",
+              "FixedVersion": "No fix available",
+              "RegularVulns": [],
+              "HiddenVulns": [],
+              "LayerDetail": {
+                "LayerIndex": 0,
+                "LayerInfo": {
+                  "Index": 0,
+                  "LayerMetadata": {
+                    "diff_id": "",
+                    "command": "",
+                    "is_empty": false,
+                    "base_image_index": 0
+                  },
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                },
+                "BaseImageInfo": {
+                  "Index": 0,
+                  "BaseImageInfo": null,
+                  "AllLayers": null,
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                }
+              },
+              "VulnCount": {
+                "AnalysisCount": {
+                  "Regular": 0,
+                  "Hidden": 0
+                },
+                "SeverityCount": {
+                  "Critical": 0,
+                  "High": 0,
+                  "Medium": 0,
+                  "Low": 0,
+                  "Unknown": 0
+                },
+                "FixableCount": {
+                  "Fixed": 0,
+                  "UnFixed": 0
+                }
+              },
+              "Licenses": null,
+              "LicenseViolations": null
+            }
+          ],
           "VulnCount": {
             "AnalysisCount": {
               "Regular": 0,
@@ -3470,81 +4343,146 @@
 
 ---
 
-[TestPrintOutputResults_WithVulnerabilities/no_sources - 1]
-{
-  "Ecosystems": null,
-  "IsContainerScanning": false,
-  "ImageInfo": {
-    "OS": "",
-    "AllLayers": null,
-    "AllBaseImages": null
-  },
-  "LicenseSummary": {
-    "Summary": false,
-    "ShowViolations": false,
-    "LicenseCount": null
-  },
-  "VulnTypeSummary": {
-    "All": 0,
-    "OS": 0,
-    "Project": 0,
-    "Hidden": 0
-  },
-  "PackageTypeCount": {
-    "Regular": 0,
-    "Hidden": 0
-  },
-  "VulnCount": {
-    "AnalysisCount": {
-      "Regular": 0,
-      "Hidden": 0
-    },
-    "SeverityCount": {
-      "Critical": 0,
-      "High": 0,
-      "Medium": 0,
-      "Low": 0,
-      "Unknown": 0
-    },
-    "FixableCount": {
-      "Fixed": 0,
-      "UnFixed": 0
-    }
-  }
-}
-
----
-
-[TestPrintOutputResults_WithVulnerabilities/one_source_with_no_packages - 1]
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package,_one_uncalled_vulnerability,_and_one_called_vulnerability - 1]
 {
   "Ecosystems": [
     {
-      "Name": "",
+      "Name": "npm",
       "Sources": [
         {
           "Name": ":path/to/my/first/lockfile",
           "Type": "",
-          "Ecosystem": "",
+          "Ecosystem": "npm",
           "PackageTypeCount": {
-            "Regular": 0,
-            "Hidden": 0
+            "Regular": 1,
+            "Hidden": 1
           },
-          "Packages": [],
+          "Packages": [
+            {
+              "Name": "mine1",
+              "OSPackageNames": [
+                ""
+              ],
+              "InstalledVersion": "1.2.3",
+              "Commit": "",
+              "FixedVersion": "No fix available",
+              "RegularVulns": [
+                {
+                  "ID": "OSV-1",
+                  "GroupIDs": [
+                    "OSV-1"
+                  ],
+                  "Aliases": null,
+                  "Description": "Something scary!",
+                  "IsFixable": false,
+                  "FixedVersion": "No fix available",
+                  "VulnAnalysisType": 0,
+                  "SeverityRating": "UNKNOWN",
+                  "SeverityScore": "N/A"
+                }
+              ],
+              "HiddenVulns": [
+                {
+                  "ID": "GHSA-123",
+                  "GroupIDs": [
+                    "GHSA-123"
+                  ],
+                  "Aliases": null,
+                  "Description": "Something scarier!",
+                  "IsFixable": false,
+                  "FixedVersion": "No fix available",
+                  "VulnAnalysisType": 1,
+                  "SeverityRating": "UNKNOWN",
+                  "SeverityScore": "N/A"
+                }
+              ],
+              "LayerDetail": {
+                "LayerIndex": 0,
+                "LayerInfo": {
+                  "Index": 0,
+                  "LayerMetadata": {
+                    "diff_id": "",
+                    "command": "",
+                    "is_empty": false,
+                    "base_image_index": 0
+                  },
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                },
+                "BaseImageInfo": {
+                  "Index": 0,
+                  "BaseImageInfo": null,
+                  "AllLayers": null,
+                  "Count": {
+                    "AnalysisCount": {
+                      "Regular": 0,
+                      "Hidden": 0
+                    },
+                    "SeverityCount": {
+                      "Critical": 0,
+                      "High": 0,
+                      "Medium": 0,
+                      "Low": 0,
+                      "Unknown": 0
+                    },
+                    "FixableCount": {
+                      "Fixed": 0,
+                      "UnFixed": 0
+                    }
+                  }
+                }
+              },
+              "VulnCount": {
+                "AnalysisCount": {
+                  "Regular": 1,
+                  "Hidden": 1
+                },
+                "SeverityCount": {
+                  "Critical": 0,
+                  "High": 0,
+                  "Medium": 0,
+                  "Low": 0,
+                  "Unknown": 1
+                },
+                "FixableCount": {
+                  "Fixed": 0,
+                  "UnFixed": 1
+                }
+              },
+              "Licenses": null,
+              "LicenseViolations": null
+            }
+          ],
           "VulnCount": {
             "AnalysisCount": {
-              "Regular": 0,
-              "Hidden": 0
+              "Regular": 1,
+              "Hidden": 1
             },
             "SeverityCount": {
               "Critical": 0,
               "High": 0,
               "Medium": 0,
               "Low": 0,
-              "Unknown": 0
+              "Unknown": 1
             },
             "FixableCount": {
               "Fixed": 0,
-              "UnFixed": 0
+              "UnFixed": 1
             }
           },
           "LicenseViolationsCount": 0
@@ -3565,37 +4503,37 @@
     "LicenseCount": null
   },
   "VulnTypeSummary": {
-    "All": 0,
+    "All": 1,
     "OS": 0,
-    "Project": 0,
-    "Hidden": 0
+    "Project": 1,
+    "Hidden": 1
   },
   "PackageTypeCount": {
-    "Regular": 0,
-    "Hidden": 0
+    "Regular": 1,
+    "Hidden": 1
   },
   "VulnCount": {
     "AnalysisCount": {
-      "Regular": 0,
-      "Hidden": 0
+      "Regular": 1,
+      "Hidden": 1
     },
     "SeverityCount": {
       "Critical": 0,
       "High": 0,
       "Medium": 0,
       "Low": 0,
-      "Unknown": 0
+      "Unknown": 1
     },
     "FixableCount": {
       "Fixed": 0,
-      "UnFixed": 0
+      "UnFixed": 1
     }
   }
 }
 
 ---
 
-[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package,_no_vulnerabilities - 1]
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_one_called_vulnerability - 1]
 {
   "Ecosystems": [
     {
@@ -3606,7 +4544,7 @@
           "Type": "",
           "Ecosystem": "npm",
           "PackageTypeCount": {
-            "Regular": 0,
+            "Regular": 1,
             "Hidden": 0
           },
           "Packages": [
@@ -3615,10 +4553,24 @@
               "OSPackageNames": [
                 ""
               ],
-              "InstalledVersion": "1.2.3",
-              "Commit": "",
-              "FixedVersion": "No fix available",
-              "RegularVulns": [],
+              "InstalledVersion": "1.2.3",
+              "Commit": "",
+              "FixedVersion": "No fix available",
+              "RegularVulns": [
+                {
+                  "ID": "OSV-1",
+                  "GroupIDs": [
+                    "OSV-1"
+                  ],
+                  "Aliases": null,
+                  "Description": "Something scary!",
+                  "IsFixable": false,
+                  "FixedVersion": "No fix available",
+                  "VulnAnalysisType": 0,
+                  "SeverityRating": "UNKNOWN",
+                  "SeverityScore": "N/A"
+                }
+              ],
               "HiddenVulns": [],
               "LayerDetail": {
                 "LayerIndex": 0,
@@ -3673,7 +4625,7 @@
               },
               "VulnCount": {
                 "AnalysisCount": {
-                  "Regular": 0,
+                  "Regular": 1,
                   "Hidden": 0
                 },
                 "SeverityCount": {
@@ -3681,11 +4633,11 @@
                   "High": 0,
                   "Medium": 0,
                   "Low": 0,
-                  "Unknown": 0
+                  "Unknown": 1
                 },
                 "FixableCount": {
                   "Fixed": 0,
-                  "UnFixed": 0
+                  "UnFixed": 1
                 }
               },
               "Licenses": null,
@@ -3694,7 +4646,7 @@
           ],
           "VulnCount": {
             "AnalysisCount": {
-              "Regular": 0,
+              "Regular": 1,
               "Hidden": 0
             },
             "SeverityCount": {
@@ -3702,11 +4654,11 @@
               "High": 0,
               "Medium": 0,
               "Low": 0,
-              "Unknown": 0
+              "Unknown": 1
             },
             "FixableCount": {
               "Fixed": 0,
-              "UnFixed": 0
+              "UnFixed": 1
             }
           },
           "LicenseViolationsCount": 0
@@ -3727,18 +4679,18 @@
     "LicenseCount": null
   },
   "VulnTypeSummary": {
-    "All": 0,
+    "All": 1,
     "OS": 0,
-    "Project": 0,
+    "Project": 1,
     "Hidden": 0
   },
   "PackageTypeCount": {
-    "Regular": 0,
+    "Regular": 1,
     "Hidden": 0
   },
   "VulnCount": {
     "AnalysisCount": {
-      "Regular": 0,
+      "Regular": 1,
       "Hidden": 0
     },
     "SeverityCount": {
@@ -3746,18 +4698,18 @@
       "High": 0,
       "Medium": 0,
       "Low": 0,
-      "Unknown": 0
+      "Unknown": 1
     },
     "FixableCount": {
       "Fixed": 0,
-      "UnFixed": 0
+      "UnFixed": 1
     }
   }
 }
 
 ---
 
-[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package,_one_uncalled_vulnerability,_and_one_called_vulnerability - 1]
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_one_uncalled_vulnerability - 1]
 {
   "Ecosystems": [
     {
@@ -3768,7 +4720,7 @@
           "Type": "",
           "Ecosystem": "npm",
           "PackageTypeCount": {
-            "Regular": 1,
+            "Regular": 0,
             "Hidden": 1
           },
           "Packages": [
@@ -3780,7 +4732,8 @@
               "InstalledVersion": "1.2.3",
               "Commit": "",
               "FixedVersion": "No fix available",
-              "RegularVulns": [
+              "RegularVulns": [],
+              "HiddenVulns": [
                 {
                   "ID": "OSV-1",
                   "GroupIDs": [
@@ -3790,21 +4743,6 @@
                   "Description": "Something scary!",
                   "IsFixable": false,
                   "FixedVersion": "No fix available",
-                  "VulnAnalysisType": 0,
-                  "SeverityRating": "UNKNOWN",
-                  "SeverityScore": "N/A"
-                }
-              ],
-              "HiddenVulns": [
-                {
-                  "ID": "GHSA-123",
-                  "GroupIDs": [
-                    "GHSA-123"
-                  ],
-                  "Aliases": null,
-                  "Description": "Something scarier!",
-                  "IsFixable": false,
-                  "FixedVersion": "No fix available",
                   "VulnAnalysisType": 1,
                   "SeverityRating": "UNKNOWN",
                   "SeverityScore": "N/A"
@@ -3863,7 +4801,7 @@
               },
               "VulnCount": {
                 "AnalysisCount": {
-                  "Regular": 1,
+                  "Regular": 0,
                   "Hidden": 1
                 },
                 "SeverityCount": {
@@ -3871,11 +4809,11 @@
                   "High": 0,
                   "Medium": 0,
                   "Low": 0,
-                  "Unknown": 1
+                  "Unknown": 0
                 },
                 "FixableCount": {
                   "Fixed": 0,
-                  "UnFixed": 1
+                  "UnFixed": 0
                 }
               },
               "Licenses": null,
@@ -3884,7 +4822,7 @@
           ],
           "VulnCount": {
             "AnalysisCount": {
-              "Regular": 1,
+              "Regular": 0,
               "Hidden": 1
             },
             "SeverityCount": {
@@ -3892,11 +4830,11 @@
               "High": 0,
               "Medium": 0,
               "Low": 0,
-              "Unknown": 1
+              "Unknown": 0
             },
             "FixableCount": {
               "Fixed": 0,
-              "UnFixed": 1
+              "UnFixed": 0
             }
           },
           "LicenseViolationsCount": 0
@@ -3917,18 +4855,18 @@
     "LicenseCount": null
   },
   "VulnTypeSummary": {
-    "All": 1,
+    "All": 0,
     "OS": 0,
-    "Project": 1,
+    "Project": 0,
     "Hidden": 1
   },
   "PackageTypeCount": {
-    "Regular": 1,
+    "Regular": 0,
     "Hidden": 1
   },
   "VulnCount": {
     "AnalysisCount": {
-      "Regular": 1,
+      "Regular": 0,
       "Hidden": 1
     },
     "SeverityCount": {
@@ -3936,18 +4874,18 @@
       "High": 0,
       "Medium": 0,
       "Low": 0,
-      "Unknown": 1
+      "Unknown": 0
     },
     "FixableCount": {
       "Fixed": 0,
-      "UnFixed": 1
+      "UnFixed": 0
     }
   }
 }
 
 ---
 
-[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_one_called_vulnerability - 1]
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_one_vulnerability - 1]
 {
   "Ecosystems": [
     {
@@ -4123,7 +5061,7 @@
 
 ---
 
-[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_one_uncalled_vulnerability - 1]
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_one_vulnerability_(dev) - 1]
 {
   "Ecosystems": [
     {
@@ -4134,8 +5072,8 @@
           "Type": "",
           "Ecosystem": "npm",
           "PackageTypeCount": {
-            "Regular": 0,
-            "Hidden": 1
+            "Regular": 1,
+            "Hidden": 0
           },
           "Packages": [
             {
@@ -4146,8 +5084,7 @@
               "InstalledVersion": "1.2.3",
               "Commit": "",
               "FixedVersion": "No fix available",
-              "RegularVulns": [],
-              "HiddenVulns": [
+              "RegularVulns": [
                 {
                   "ID": "OSV-1",
                   "GroupIDs": [
@@ -4157,11 +5094,12 @@
                   "Description": "Something scary!",
                   "IsFixable": false,
                   "FixedVersion": "No fix available",
-                  "VulnAnalysisType": 1,
+                  "VulnAnalysisType": 0,
                   "SeverityRating": "UNKNOWN",
                   "SeverityScore": "N/A"
                 }
               ],
+              "HiddenVulns": [],
               "LayerDetail": {
                 "LayerIndex": 0,
                 "LayerInfo": {
@@ -4215,19 +5153,19 @@
               },
               "VulnCount": {
                 "AnalysisCount": {
-                  "Regular": 0,
-                  "Hidden": 1
+                  "Regular": 1,
+                  "Hidden": 0
                 },
                 "SeverityCount": {
                   "Critical": 0,
                   "High": 0,
                   "Medium": 0,
                   "Low": 0,
-                  "Unknown": 0
+                  "Unknown": 1
                 },
                 "FixableCount": {
                   "Fixed": 0,
-                  "UnFixed": 0
+                  "UnFixed": 1
                 }
               },
               "Licenses": null,
@@ -4236,19 +5174,19 @@
           ],
           "VulnCount": {
             "AnalysisCount": {
-              "Regular": 0,
-              "Hidden": 1
+              "Regular": 1,
+              "Hidden": 0
             },
             "SeverityCount": {
               "Critical": 0,
               "High": 0,
               "Medium": 0,
               "Low": 0,
-              "Unknown": 0
+              "Unknown": 1
             },
             "FixableCount": {
               "Fixed": 0,
-              "UnFixed": 0
+              "UnFixed": 1
             }
           },
           "LicenseViolationsCount": 0
@@ -4269,37 +5207,37 @@
     "LicenseCount": null
   },
   "VulnTypeSummary": {
-    "All": 0,
+    "All": 1,
     "OS": 0,
-    "Project": 0,
-    "Hidden": 1
+    "Project": 1,
+    "Hidden": 0
   },
   "PackageTypeCount": {
-    "Regular": 0,
-    "Hidden": 1
+    "Regular": 1,
+    "Hidden": 0
   },
   "VulnCount": {
     "AnalysisCount": {
-      "Regular": 0,
-      "Hidden": 1
+      "Regular": 1,
+      "Hidden": 0
     },
     "SeverityCount": {
       "Critical": 0,
       "High": 0,
       "Medium": 0,
       "Low": 0,
-      "Unknown": 0
+      "Unknown": 1
     },
     "FixableCount": {
       "Fixed": 0,
-      "UnFixed": 0
+      "UnFixed": 1
     }
   }
 }
 
 ---
 
-[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_one_vulnerability - 1]
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_two_aliases_of_a_single_uncalled_vulnerability - 1]
 {
   "Ecosystems": [
     {
@@ -4310,8 +5248,8 @@
           "Type": "",
           "Ecosystem": "npm",
           "PackageTypeCount": {
-            "Regular": 1,
-            "Hidden": 0
+            "Regular": 0,
+            "Hidden": 1
           },
           "Packages": [
             {
@@ -4322,22 +5260,25 @@
               "InstalledVersion": "1.2.3",
               "Commit": "",
               "FixedVersion": "No fix available",
-              "RegularVulns": [
+              "RegularVulns": [],
+              "HiddenVulns": [
                 {
                   "ID": "OSV-1",
                   "GroupIDs": [
-                    "OSV-1"
+                    "OSV-1",
+                    "GHSA-123"
+                  ],
+                  "Aliases": [
+                    "GHSA-123"
                   ],
-                  "Aliases": null,
                   "Description": "Something scary!",
                   "IsFixable": false,
                   "FixedVersion": "No fix available",
-                  "VulnAnalysisType": 0,
+                  "VulnAnalysisType": 1,
                   "SeverityRating": "UNKNOWN",
                   "SeverityScore": "N/A"
                 }
               ],
-              "HiddenVulns": [],
               "LayerDetail": {
                 "LayerIndex": 0,
                 "LayerInfo": {
@@ -4391,19 +5332,19 @@
               },
               "VulnCount": {
                 "AnalysisCount": {
-                  "Regular": 1,
-                  "Hidden": 0
+                  "Regular": 0,
+                  "Hidden": 1
                 },
                 "SeverityCount": {
                   "Critical": 0,
                   "High": 0,
                   "Medium": 0,
                   "Low": 0,
-                  "Unknown": 1
+                  "Unknown": 0
                 },
                 "FixableCount": {
                   "Fixed": 0,
-                  "UnFixed": 1
+                  "UnFixed": 0
                 }
               },
               "Licenses": null,
@@ -4412,19 +5353,19 @@
           ],
           "VulnCount": {
             "AnalysisCount": {
-              "Regular": 1,
-              "Hidden": 0
+              "Regular": 0,
+              "Hidden": 1
             },
             "SeverityCount": {
               "Critical": 0,
               "High": 0,
               "Medium": 0,
               "Low": 0,
-              "Unknown": 1
+              "Unknown": 0
             },
             "FixableCount": {
               "Fixed": 0,
-              "UnFixed": 1
+              "UnFixed": 0
             }
           },
           "LicenseViolationsCount": 0
@@ -4445,37 +5386,37 @@
     "LicenseCount": null
   },
   "VulnTypeSummary": {
-    "All": 1,
+    "All": 0,
     "OS": 0,
-    "Project": 1,
-    "Hidden": 0
+    "Project": 0,
+    "Hidden": 1
   },
   "PackageTypeCount": {
-    "Regular": 1,
-    "Hidden": 0
+    "Regular": 0,
+    "Hidden": 1
   },
   "VulnCount": {
     "AnalysisCount": {
-      "Regular": 1,
-      "Hidden": 0
+      "Regular": 0,
+      "Hidden": 1
     },
     "SeverityCount": {
       "Critical": 0,
       "High": 0,
       "Medium": 0,
       "Low": 0,
-      "Unknown": 1
+      "Unknown": 0
     },
     "FixableCount": {
       "Fixed": 0,
-      "UnFixed": 1
+      "UnFixed": 0
     }
   }
 }
 
 ---
 
-[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_one_vulnerability_(dev) - 1]
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_two_aliases_of_a_single_vulnerability - 1]
 {
   "Ecosystems": [
     {
@@ -4502,9 +5443,12 @@
                 {
                   "ID": "OSV-1",
                   "GroupIDs": [
-                    "OSV-1"
+                    "OSV-1",
+                    "GHSA-123"
+                  ],
+                  "Aliases": [
+                    "GHSA-123"
                   ],
-                  "Aliases": null,
                   "Description": "Something scary!",
                   "IsFixable": false,
                   "FixedVersion": "No fix available",
@@ -4651,7 +5595,7 @@
 
 ---
 
-[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_two_aliases_of_a_single_uncalled_vulnerability - 1]
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
 {
   "Ecosystems": [
     {
@@ -4662,8 +5606,8 @@
           "Type": "",
           "Ecosystem": "npm",
           "PackageTypeCount": {
-            "Regular": 0,
-            "Hidden": 1
+            "Regular": 1,
+            "Hidden": 0
           },
           "Packages": [
             {
@@ -4672,27 +5616,24 @@
                 ""
               ],
               "InstalledVersion": "1.2.3",
-              "Commit": "",
+              "Commit": "abc123",
               "FixedVersion": "No fix available",
-              "RegularVulns": [],
-              "HiddenVulns": [
+              "RegularVulns": [
                 {
                   "ID": "OSV-1",
                   "GroupIDs": [
-                    "OSV-1",
-                    "GHSA-123"
-                  ],
-                  "Aliases": [
-                    "GHSA-123"
+                    "OSV-1"
                   ],
+                  "Aliases": null,
                   "Description": "Something scary!",
                   "IsFixable": false,
                   "FixedVersion": "No fix available",
-                  "VulnAnalysisType": 1,
+                  "VulnAnalysisType": 0,
                   "SeverityRating": "UNKNOWN",
                   "SeverityScore": "N/A"
                 }
               ],
+              "HiddenVulns": [],
               "LayerDetail": {
                 "LayerIndex": 0,
                 "LayerInfo": {
@@ -4746,19 +5687,19 @@
               },
               "VulnCount": {
                 "AnalysisCount": {
-                  "Regular": 0,
-                  "Hidden": 1
+                  "Regular": 1,
+                  "Hidden": 0
                 },
                 "SeverityCount": {
                   "Critical": 0,
                   "High": 0,
                   "Medium": 0,
                   "Low": 0,
-                  "Unknown": 0
+                  "Unknown": 1
                 },
                 "FixableCount": {
                   "Fixed": 0,
-                  "UnFixed": 0
+                  "UnFixed": 1
                 }
               },
               "Licenses": null,
@@ -4767,19 +5708,19 @@
           ],
           "VulnCount": {
             "AnalysisCount": {
-              "Regular": 0,
-              "Hidden": 1
+              "Regular": 1,
+              "Hidden": 0
             },
             "SeverityCount": {
               "Critical": 0,
               "High": 0,
               "Medium": 0,
               "Low": 0,
-              "Unknown": 0
+              "Unknown": 1
             },
             "FixableCount": {
               "Fixed": 0,
-              "UnFixed": 0
+              "UnFixed": 1
             }
           },
           "LicenseViolationsCount": 0
@@ -4800,37 +5741,37 @@
     "LicenseCount": null
   },
   "VulnTypeSummary": {
-    "All": 0,
+    "All": 1,
     "OS": 0,
-    "Project": 0,
-    "Hidden": 1
+    "Project": 1,
+    "Hidden": 0
   },
   "PackageTypeCount": {
-    "Regular": 0,
-    "Hidden": 1
+    "Regular": 1,
+    "Hidden": 0
   },
   "VulnCount": {
     "AnalysisCount": {
-      "Regular": 0,
-      "Hidden": 1
+      "Regular": 1,
+      "Hidden": 0
     },
     "SeverityCount": {
       "Critical": 0,
       "High": 0,
       "Medium": 0,
       "Low": 0,
-      "Unknown": 0
+      "Unknown": 1
     },
     "FixableCount": {
       "Fixed": 0,
-      "UnFixed": 0
+      "UnFixed": 1
     }
   }
 }
 
 ---
 
-[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_and_two_aliases_of_a_single_vulnerability - 1]
+[TestPrintOutputResults_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
 {
   "Ecosystems": [
     {
@@ -4850,19 +5791,16 @@
               "OSPackageNames": [
                 ""
               ],
-              "InstalledVersion": "1.2.3",
-              "Commit": "",
+              "InstalledVersion": "",
+              "Commit": "abc123",
               "FixedVersion": "No fix available",
               "RegularVulns": [
                 {
                   "ID": "OSV-1",
                   "GroupIDs": [
-                    "OSV-1",
-                    "GHSA-123"
-                  ],
-                  "Aliases": [
-                    "GHSA-123"
+                    "OSV-1"
                   ],
+                  "Aliases": null,
                   "Description": "Something scary!",
                   "IsFixable": false,
                   "FixedVersion": "No fix available",
diff --git a/internal/output/__snapshots__/sarif_test.snap b/internal/output/__snapshots__/sarif_test.snap
index bd63f972..7994289b 100755
--- a/internal/output/__snapshots__/sarif_test.snap
+++ b/internal/output/__snapshots__/sarif_test.snap
@@ -435,6 +435,48 @@
 
 ---
 
+[TestPrintSARIFReport_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
+{
+  "version": "2.1.0",
+  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "tool": {
+        "driver": {
+          "informationUri": "https://github.com/google/osv-scanner",
+          "name": "osv-scanner",
+          "rules": [],
+          "version": "2.0.2"
+        }
+      },
+      "results": []
+    }
+  ]
+}
+
+---
+
+[TestPrintSARIFReport_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+{
+  "version": "2.1.0",
+  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "tool": {
+        "driver": {
+          "informationUri": "https://github.com/google/osv-scanner",
+          "name": "osv-scanner",
+          "rules": [],
+          "version": "2.0.2"
+        }
+      },
+      "results": []
+    }
+  ]
+}
+
+---
+
 [TestPrintSARIFReport_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 {
   "version": "2.1.0",
@@ -716,6 +758,136 @@
 
 ---
 
+[TestPrintSARIFReport_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
+{
+  "version": "2.1.0",
+  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "tool": {
+        "driver": {
+          "informationUri": "https://github.com/google/osv-scanner",
+          "name": "osv-scanner",
+          "rules": [
+            {
+              "id": "OSV-1",
+              "name": "OSV-1",
+              "shortDescription": {
+                "text": "OSV-1: Something scary!"
+              },
+              "fullDescription": {
+                "text": "",
+                "markdown": ""
+              },
+              "deprecatedIds": [
+                "OSV-1"
+              ],
+              "help": {
+                "text": "**Your dependency is vulnerable to [OSV-1](https://osv.dev/list?q=OSV-1)**.\n\n## [OSV-1](https://osv.dev/vulnerability/OSV-1)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | mine1 | abcxzy |\n| :path/to/my/third/lockfile | mine1 | 1.2.3 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n`path/to/my/third/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n",
+                "markdown": "**Your dependency is vulnerable to [OSV-1](https://osv.dev/list?q=OSV-1)**.\n\n## [OSV-1](https://osv.dev/vulnerability/OSV-1)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | mine1 | abcxzy |\n| :path/to/my/third/lockfile | mine1 | 1.2.3 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n`path/to/my/third/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n"
+              }
+            },
+            {
+              "id": "OSV-2",
+              "name": "OSV-2",
+              "shortDescription": {
+                "text": "OSV-2: Something less scary!"
+              },
+              "fullDescription": {
+                "text": "",
+                "markdown": ""
+              },
+              "deprecatedIds": [
+                "OSV-2"
+              ],
+              "help": {
+                "text": "**Your dependency is vulnerable to [OSV-2](https://osv.dev/list?q=OSV-2)**.\n\n## [OSV-2](https://osv.dev/vulnerability/OSV-2)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/second/lockfile | mine2 | abc123 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/second/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-2\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n",
+                "markdown": "**Your dependency is vulnerable to [OSV-2](https://osv.dev/list?q=OSV-2)**.\n\n## [OSV-2](https://osv.dev/vulnerability/OSV-2)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/second/lockfile | mine2 | abc123 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/second/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-2\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n"
+              }
+            }
+          ],
+          "version": "2.0.2"
+        }
+      },
+      "artifacts": [
+        {
+          "location": {
+            "uri": "path/to/my/first/lockfile"
+          },
+          "length": -1
+        },
+        {
+          "location": {
+            "uri": "path/to/my/third/lockfile"
+          },
+          "length": -1
+        },
+        {
+          "location": {
+            "uri": "path/to/my/second/lockfile"
+          },
+          "length": -1
+        }
+      ],
+      "results": [
+        {
+          "ruleId": "OSV-1",
+          "ruleIndex": 0,
+          "level": "warning",
+          "message": {
+            "text": "Package 'mine1@abcxzy' is vulnerable to 'OSV-1'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/first/lockfile"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "ruleId": "OSV-1",
+          "ruleIndex": 0,
+          "level": "warning",
+          "message": {
+            "text": "Package 'mine1@1.2.3' is vulnerable to 'OSV-1'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/third/lockfile"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "ruleId": "OSV-2",
+          "ruleIndex": 1,
+          "level": "warning",
+          "message": {
+            "text": "Package 'mine2@abc123' is vulnerable to 'OSV-2'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/second/lockfile"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
+---
+
 [TestPrintSARIFReport_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
 {
   "version": "2.1.0",
@@ -1975,6 +2147,217 @@
 
 ---
 
+[TestPrintSARIFReport_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+{
+  "version": "2.1.0",
+  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "tool": {
+        "driver": {
+          "informationUri": "https://github.com/google/osv-scanner",
+          "name": "osv-scanner",
+          "rules": [
+            {
+              "id": "OSV-1",
+              "name": "OSV-1",
+              "shortDescription": {
+                "text": "OSV-1: Something scary!"
+              },
+              "fullDescription": {
+                "text": "",
+                "markdown": ""
+              },
+              "deprecatedIds": [
+                "OSV-1"
+              ],
+              "help": {
+                "text": "**Your dependency is vulnerable to [OSV-1](https://osv.dev/list?q=OSV-1)**.\n\n## [OSV-1](https://osv.dev/vulnerability/OSV-1)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | author1/mine1 | 123abc |\n| :path/to/my/first/lockfile | mine1 | abcxyz |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n",
+                "markdown": "**Your dependency is vulnerable to [OSV-1](https://osv.dev/list?q=OSV-1)**.\n\n## [OSV-1](https://osv.dev/vulnerability/OSV-1)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | author1/mine1 | 123abc |\n| :path/to/my/first/lockfile | mine1 | abcxyz |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n"
+              }
+            },
+            {
+              "id": "OSV-2",
+              "name": "OSV-2",
+              "shortDescription": {
+                "text": "OSV-2: Something less scary!"
+              },
+              "fullDescription": {
+                "text": "",
+                "markdown": ""
+              },
+              "deprecatedIds": [
+                "OSV-2"
+              ],
+              "help": {
+                "text": "**Your dependency is vulnerable to [OSV-2](https://osv.dev/list?q=OSV-2)**.\n\n## [OSV-2](https://osv.dev/vulnerability/OSV-2)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/second/lockfile | mine2 | 3.2.5 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/second/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-2\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n",
+                "markdown": "**Your dependency is vulnerable to [OSV-2](https://osv.dev/list?q=OSV-2)**.\n\n## [OSV-2](https://osv.dev/vulnerability/OSV-2)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/second/lockfile | mine2 | 3.2.5 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/second/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-2\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n"
+              }
+            },
+            {
+              "id": "OSV-3",
+              "name": "OSV-3",
+              "shortDescription": {
+                "text": "OSV-3: Something mildly scary!"
+              },
+              "fullDescription": {
+                "text": "",
+                "markdown": ""
+              },
+              "deprecatedIds": [
+                "OSV-3"
+              ],
+              "help": {
+                "text": "**Your dependency is vulnerable to [OSV-3](https://osv.dev/list?q=OSV-3)**.\n\n## [OSV-3](https://osv.dev/vulnerability/OSV-3)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/second/lockfile | author3/mine3 | 0.4.1 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/second/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-3\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n",
+                "markdown": "**Your dependency is vulnerable to [OSV-3](https://osv.dev/list?q=OSV-3)**.\n\n## [OSV-3](https://osv.dev/vulnerability/OSV-3)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/second/lockfile | author3/mine3 | 0.4.1 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/second/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-3\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n"
+              }
+            },
+            {
+              "id": "OSV-5",
+              "name": "OSV-5",
+              "shortDescription": {
+                "text": "OSV-5: Something scarier!"
+              },
+              "fullDescription": {
+                "text": "",
+                "markdown": ""
+              },
+              "deprecatedIds": [
+                "OSV-5"
+              ],
+              "help": {
+                "text": "**Your dependency is vulnerable to [OSV-5](https://osv.dev/list?q=OSV-5)**.\n\n## [OSV-5](https://osv.dev/vulnerability/OSV-5)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | author1/mine1 | 123abc |\n| :path/to/my/second/lockfile | author3/mine3 | 0.4.1 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-5\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n`path/to/my/second/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-5\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n",
+                "markdown": "**Your dependency is vulnerable to [OSV-5](https://osv.dev/list?q=OSV-5)**.\n\n## [OSV-5](https://osv.dev/vulnerability/OSV-5)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | author1/mine1 | 123abc |\n| :path/to/my/second/lockfile | author3/mine3 | 0.4.1 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-5\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n`path/to/my/second/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-5\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n"
+              }
+            }
+          ],
+          "version": "2.0.2"
+        }
+      },
+      "artifacts": [
+        {
+          "location": {
+            "uri": "path/to/my/first/lockfile"
+          },
+          "length": -1
+        },
+        {
+          "location": {
+            "uri": "path/to/my/second/lockfile"
+          },
+          "length": -1
+        }
+      ],
+      "results": [
+        {
+          "ruleId": "OSV-1",
+          "ruleIndex": 0,
+          "level": "warning",
+          "message": {
+            "text": "Package 'author1/mine1@123abc' is vulnerable to 'OSV-1'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/first/lockfile"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "ruleId": "OSV-1",
+          "ruleIndex": 0,
+          "level": "warning",
+          "message": {
+            "text": "Package 'mine1@abcxyz' is vulnerable to 'OSV-1'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/first/lockfile"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "ruleId": "OSV-2",
+          "ruleIndex": 1,
+          "level": "warning",
+          "message": {
+            "text": "Package 'mine2@3.2.5' is vulnerable to 'OSV-2'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/second/lockfile"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "ruleId": "OSV-3",
+          "ruleIndex": 2,
+          "level": "warning",
+          "message": {
+            "text": "Package 'author3/mine3@0.4.1' is vulnerable to 'OSV-3'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/second/lockfile"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "ruleId": "OSV-5",
+          "ruleIndex": 3,
+          "level": "warning",
+          "message": {
+            "text": "Package 'author1/mine1@123abc' is vulnerable to 'OSV-5'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/first/lockfile"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "ruleId": "OSV-5",
+          "ruleIndex": 3,
+          "level": "warning",
+          "message": {
+            "text": "Package 'author3/mine3@0.4.1' is vulnerable to 'OSV-5'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/second/lockfile"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
+---
+
 [TestPrintSARIFReport_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 {
   "version": "2.1.0",
@@ -2592,6 +2975,138 @@
 
 ---
 
+[TestPrintSARIFReport_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
+{
+  "version": "2.1.0",
+  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "tool": {
+        "driver": {
+          "informationUri": "https://github.com/google/osv-scanner",
+          "name": "osv-scanner",
+          "rules": [
+            {
+              "id": "OSV-1",
+              "name": "OSV-1",
+              "shortDescription": {
+                "text": "OSV-1: Something scary!"
+              },
+              "fullDescription": {
+                "text": "",
+                "markdown": ""
+              },
+              "deprecatedIds": [
+                "OSV-1"
+              ],
+              "help": {
+                "text": "**Your dependency is vulnerable to [OSV-1](https://osv.dev/list?q=OSV-1)**.\n\n## [OSV-1](https://osv.dev/vulnerability/OSV-1)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | mine1 | abc123 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n",
+                "markdown": "**Your dependency is vulnerable to [OSV-1](https://osv.dev/list?q=OSV-1)**.\n\n## [OSV-1](https://osv.dev/vulnerability/OSV-1)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | mine1 | abc123 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n"
+              }
+            }
+          ],
+          "version": "2.0.2"
+        }
+      },
+      "artifacts": [
+        {
+          "location": {
+            "uri": "path/to/my/first/lockfile"
+          },
+          "length": -1
+        }
+      ],
+      "results": [
+        {
+          "ruleId": "OSV-1",
+          "ruleIndex": 0,
+          "level": "warning",
+          "message": {
+            "text": "Package 'mine1@abc123' is vulnerable to 'OSV-1'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/first/lockfile"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
+---
+
+[TestPrintSARIFReport_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+{
+  "version": "2.1.0",
+  "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json",
+  "runs": [
+    {
+      "tool": {
+        "driver": {
+          "informationUri": "https://github.com/google/osv-scanner",
+          "name": "osv-scanner",
+          "rules": [
+            {
+              "id": "OSV-1",
+              "name": "OSV-1",
+              "shortDescription": {
+                "text": "OSV-1: Something scary!"
+              },
+              "fullDescription": {
+                "text": "",
+                "markdown": ""
+              },
+              "deprecatedIds": [
+                "OSV-1"
+              ],
+              "help": {
+                "text": "**Your dependency is vulnerable to [OSV-1](https://osv.dev/list?q=OSV-1)**.\n\n## [OSV-1](https://osv.dev/vulnerability/OSV-1)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | mine1 | abc123 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n",
+                "markdown": "**Your dependency is vulnerable to [OSV-1](https://osv.dev/list?q=OSV-1)**.\n\n## [OSV-1](https://osv.dev/vulnerability/OSV-1)\n\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n\u003e \n\n\u003c/details\u003e\n\n---\n\n### Affected Packages\n\n| Source | Package Name | Package Version |\n| --- | --- | --- |\n| :path/to/my/first/lockfile | mine1 | abc123 |\n\n## Remediation\n\nIf you believe these vulnerabilities do not affect your code and wish to ignore them, add them to the ignore list in an\n`osv-scanner.toml` file located in the same directory as the lockfile containing the vulnerable dependency.\n\nSee the format and more options in our documentation here: https://google.github.io/osv-scanner/configuration/\n\nAdd or append these values to the following config files to ignore this vulnerability:\n\n`path/to/my/first/osv-scanner.toml`\n\n```\n[[IgnoredVulns]]\nid = \"OSV-1\"\nreason = \"Your reason for ignoring this vulnerability\"\n```\n"
+              }
+            }
+          ],
+          "version": "2.0.2"
+        }
+      },
+      "artifacts": [
+        {
+          "location": {
+            "uri": "path/to/my/first/lockfile"
+          },
+          "length": -1
+        }
+      ],
+      "results": [
+        {
+          "ruleId": "OSV-1",
+          "ruleIndex": 0,
+          "level": "warning",
+          "message": {
+            "text": "Package 'mine1@abc123' is vulnerable to 'OSV-1'."
+          },
+          "locations": [
+            {
+              "physicalLocation": {
+                "artifactLocation": {
+                  "uri": "path/to/my/first/lockfile"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
+
+---
+
 [TestPrintSARIFReport_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
 {
   "version": "2.1.0",
diff --git a/internal/output/__snapshots__/spdx_test.snap b/internal/output/__snapshots__/spdx_test.snap
index 10f0dd5a..be0ebbc6 100755
--- a/internal/output/__snapshots__/spdx_test.snap
+++ b/internal/output/__snapshots__/spdx_test.snap
@@ -104,7 +104,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -268,7 +268,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -432,7 +432,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -596,7 +596,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -760,7 +760,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -844,7 +844,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     }
@@ -878,7 +878,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     }
@@ -912,7 +912,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     }
@@ -962,7 +962,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1022,7 +1022,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1082,7 +1082,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1142,7 +1142,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1202,7 +1202,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1222,6 +1222,66 @@
 ---
 
 [TestPrintSPDXResults_WithLicenseViolations/one_source_with_one_package_and_one_license_violation_(dev) - 1]
+{
+  "spdxVersion": "SPDX-2.3",
+  "dataLicense": "CC0-1.0",
+  "SPDXID": "SPDXRef-DOCUMENT",
+  "name": "SCALIBR-generated SPDX",
+  "documentNamespace": "https://spdx.google/<uuid>",
+  "creationInfo": {
+    "creators": [
+      "Tool: SCALIBR"
+    ],
+    "created": "<timestamp>"
+  },
+  "packages": [
+    {
+      "name": "main",
+      "SPDXID": "SPDXRef-Package-main-<uuid>",
+      "versionInfo": "0",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false
+    },
+    {
+      "name": "mine1",
+      "SPDXID": "SPDXRef-Package-mine1-<uuid>",
+      "versionInfo": "1.2.3",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false,
+      "sourceInfo": "Identified by the javascript/packagelockjson extractor from path/to/my/first/lockfile",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceType": "purl",
+          "referenceLocator": "pkg:npm/mine1@1.2.3"
+        }
+      ]
+    }
+  ],
+  "relationships": [
+    {
+      "spdxElementId": "SPDXRef-DOCUMENT",
+      "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
+      "relationshipType": "DESCRIBES"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-main-<uuid>",
+      "relatedSpdxElement": "SPDXRef-Package-mine1-<uuid>",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-mine1-<uuid>",
+      "relatedSpdxElement": "NOASSERTION",
+      "relationshipType": "CONTAINS"
+    }
+  ]
+}
+
+---
+
+[TestPrintSPDXResults_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
 {
   "spdxVersion": "SPDX-2.3",
   "dataLicense": "CC0-1.0",
@@ -1281,6 +1341,40 @@
 
 ---
 
+[TestPrintSPDXResults_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+{
+  "spdxVersion": "SPDX-2.3",
+  "dataLicense": "CC0-1.0",
+  "SPDXID": "SPDXRef-DOCUMENT",
+  "name": "SCALIBR-generated SPDX",
+  "documentNamespace": "https://spdx.google/<uuid>",
+  "creationInfo": {
+    "creators": [
+      "Tool: SCALIBR"
+    ],
+    "created": "<timestamp>"
+  },
+  "packages": [
+    {
+      "name": "main",
+      "SPDXID": "SPDXRef-Package-main-<uuid>",
+      "versionInfo": "0",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false
+    }
+  ],
+  "relationships": [
+    {
+      "spdxElementId": "SPDXRef-Document",
+      "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
+      "relationshipType": "DESCRIBES"
+    }
+  ]
+}
+
+---
+
 [TestPrintSPDXResults_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 {
   "spdxVersion": "SPDX-2.3",
@@ -1338,7 +1432,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1472,7 +1566,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1636,7 +1730,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1695,7 +1789,7 @@
 
 ---
 
-[TestPrintSPDXResults_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
+[TestPrintSPDXResults_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
 {
   "spdxVersion": "SPDX-2.3",
   "dataLicense": "CC0-1.0",
@@ -1732,6 +1826,54 @@
           "referenceLocator": "pkg:npm/mine1@1.2.3"
         }
       ]
+    },
+    {
+      "name": "mine3",
+      "SPDXID": "SPDXRef-Package-mine3-<uuid>",
+      "versionInfo": "0.4.1",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false,
+      "sourceInfo": "Identified by the javascript/packagelockjson extractor from path/to/my/second/lockfile",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceType": "purl",
+          "referenceLocator": "pkg:npm/mine3@0.4.1"
+        }
+      ]
+    },
+    {
+      "name": "mine1",
+      "SPDXID": "SPDXRef-Package-mine1-<uuid>",
+      "versionInfo": "1.3.5",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false,
+      "sourceInfo": "Identified by the javascript/packagelockjson extractor from path/to/my/third/lockfile",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceType": "purl",
+          "referenceLocator": "pkg:npm/mine1@1.3.5"
+        }
+      ]
+    },
+    {
+      "name": "mine1",
+      "SPDXID": "SPDXRef-Package-mine1-<uuid>",
+      "versionInfo": "1.2.3",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false,
+      "sourceInfo": "Identified by the javascript/packagelockjson extractor from path/to/my/third/lockfile",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceType": "purl",
+          "referenceLocator": "pkg:npm/mine1@1.2.3"
+        }
+      ]
     }
   ],
   "relationships": [
@@ -1745,6 +1887,96 @@
       "relatedSpdxElement": "SPDXRef-Package-mine1-<uuid>",
       "relationshipType": "CONTAINS"
     },
+    {
+      "spdxElementId": "SPDXRef-Package-mine1-<uuid>",
+      "relatedSpdxElement": "NOASSERTION",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-main-<uuid>",
+      "relatedSpdxElement": "SPDXRef-Package-mine3-<uuid>",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-mine3-<uuid>",
+      "relatedSpdxElement": "NOASSERTION",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-main-<uuid>",
+      "relatedSpdxElement": "SPDXRef-Package-mine1-<uuid>",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-mine1-<uuid>",
+      "relatedSpdxElement": "NOASSERTION",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-main-<uuid>",
+      "relatedSpdxElement": "SPDXRef-Package-mine1-<uuid>",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-mine1-<uuid>",
+      "relatedSpdxElement": "NOASSERTION",
+      "relationshipType": "CONTAINS"
+    }
+  ]
+}
+
+---
+
+[TestPrintSPDXResults_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
+{
+  "spdxVersion": "SPDX-2.3",
+  "dataLicense": "CC0-1.0",
+  "SPDXID": "SPDXRef-DOCUMENT",
+  "name": "SCALIBR-generated SPDX",
+  "documentNamespace": "https://spdx.google/<uuid>",
+  "creationInfo": {
+    "creators": [
+      "Tool: SCALIBR"
+    ],
+    "created": "<timestamp>"
+  },
+  "packages": [
+    {
+      "name": "main",
+      "SPDXID": "SPDXRef-Package-main-<uuid>",
+      "versionInfo": "0",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false
+    },
+    {
+      "name": "mine1",
+      "SPDXID": "SPDXRef-Package-mine1-<uuid>",
+      "versionInfo": "1.2.3",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false,
+      "sourceInfo": "Identified by the javascript/packagelockjson extractor from path/to/my/first/lockfile",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceType": "purl",
+          "referenceLocator": "pkg:npm/mine1@1.2.3"
+        }
+      ]
+    }
+  ],
+  "relationships": [
+    {
+      "spdxElementId": "SPDXRef-DOCUMENT",
+      "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
+      "relationshipType": "DESCRIBES"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-main-<uuid>",
+      "relatedSpdxElement": "SPDXRef-Package-mine1-<uuid>",
+      "relationshipType": "CONTAINS"
+    },
     {
       "spdxElementId": "SPDXRef-Package-mine1-<uuid>",
       "relatedSpdxElement": "NOASSERTION",
@@ -1796,7 +2028,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1856,7 +2088,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -1932,7 +2164,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -2050,7 +2282,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -2188,7 +2420,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -2342,7 +2574,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -2506,7 +2738,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -2647,14 +2879,14 @@
         {
           "referenceCategory": "PACKAGE-MANAGER",
           "referenceType": "purl",
-          "referenceLocator": "pkg:npm/author3%2Fmine3@0.4.1"
+          "referenceLocator": "pkg:composer/author3%2Fmine3@0.4.1"
         }
       ]
     }
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -2792,7 +3024,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -2841,7 +3073,7 @@
 
 ---
 
-[TestPrintSPDXResults_WithVulnerabilities/multiple_sources_with_no_packages - 1]
+[TestPrintSPDXResults_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
 {
   "spdxVersion": "SPDX-2.3",
   "dataLicense": "CC0-1.0",
@@ -2862,6 +3094,54 @@
       "supplier": "NOASSERTION",
       "downloadLocation": "NOASSERTION",
       "filesAnalyzed": false
+    },
+    {
+      "name": "author1/mine1",
+      "SPDXID": "SPDXRef-Package-author1-mine1-<uuid>",
+      "versionInfo": "1.2.3",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false,
+      "sourceInfo": "Identified by the php/composerlock extractor from path/to/my/first/lockfile",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceType": "purl",
+          "referenceLocator": "pkg:composer/author1%2Fmine1@1.2.3"
+        }
+      ]
+    },
+    {
+      "name": "mine2",
+      "SPDXID": "SPDXRef-Package-mine2-<uuid>",
+      "versionInfo": "3.2.5",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false,
+      "sourceInfo": "Identified by the dotnet/pe extractor from path/to/my/second/lockfile",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceType": "purl",
+          "referenceLocator": "pkg:nuget/mine2@3.2.5"
+        }
+      ]
+    },
+    {
+      "name": "author3/mine3",
+      "SPDXID": "SPDXRef-Package-author3-mine3-<uuid>",
+      "versionInfo": "0.4.1",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false,
+      "sourceInfo": "Identified by the javascript/packagelockjson extractor from path/to/my/second/lockfile",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceType": "purl",
+          "referenceLocator": "pkg:npm/author3%2Fmine3@0.4.1"
+        }
+      ]
     }
   ],
   "relationships": [
@@ -2869,6 +3149,70 @@
       "spdxElementId": "SPDXRef-Document",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-main-<uuid>",
+      "relatedSpdxElement": "SPDXRef-Package-author1-mine1-<uuid>",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-author1-mine1-<uuid>",
+      "relatedSpdxElement": "NOASSERTION",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-main-<uuid>",
+      "relatedSpdxElement": "SPDXRef-Package-mine2-<uuid>",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-mine2-<uuid>",
+      "relatedSpdxElement": "NOASSERTION",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-main-<uuid>",
+      "relatedSpdxElement": "SPDXRef-Package-author3-mine3-<uuid>",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-author3-mine3-<uuid>",
+      "relatedSpdxElement": "NOASSERTION",
+      "relationshipType": "CONTAINS"
+    }
+  ]
+}
+
+---
+
+[TestPrintSPDXResults_WithVulnerabilities/multiple_sources_with_no_packages - 1]
+{
+  "spdxVersion": "SPDX-2.3",
+  "dataLicense": "CC0-1.0",
+  "SPDXID": "SPDXRef-DOCUMENT",
+  "name": "SCALIBR-generated SPDX",
+  "documentNamespace": "https://spdx.google/<uuid>",
+  "creationInfo": {
+    "creators": [
+      "Tool: SCALIBR"
+    ],
+    "created": "<timestamp>"
+  },
+  "packages": [
+    {
+      "name": "main",
+      "SPDXID": "SPDXRef-Package-main-<uuid>",
+      "versionInfo": "0",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false
+    }
+  ],
+  "relationships": [
+    {
+      "spdxElementId": "SPDXRef-DOCUMENT",
+      "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
+      "relationshipType": "DESCRIBES"
     }
   ]
 }
@@ -2900,7 +3244,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     }
@@ -2934,7 +3278,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     }
@@ -2984,7 +3328,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -3044,7 +3388,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -3104,7 +3448,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -3164,7 +3508,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -3224,7 +3568,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -3284,7 +3628,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -3344,7 +3688,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -3364,6 +3708,66 @@
 ---
 
 [TestPrintSPDXResults_WithVulnerabilities/one_source_with_one_package_and_two_aliases_of_a_single_vulnerability - 1]
+{
+  "spdxVersion": "SPDX-2.3",
+  "dataLicense": "CC0-1.0",
+  "SPDXID": "SPDXRef-DOCUMENT",
+  "name": "SCALIBR-generated SPDX",
+  "documentNamespace": "https://spdx.google/<uuid>",
+  "creationInfo": {
+    "creators": [
+      "Tool: SCALIBR"
+    ],
+    "created": "<timestamp>"
+  },
+  "packages": [
+    {
+      "name": "main",
+      "SPDXID": "SPDXRef-Package-main-<uuid>",
+      "versionInfo": "0",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false
+    },
+    {
+      "name": "mine1",
+      "SPDXID": "SPDXRef-Package-mine1-<uuid>",
+      "versionInfo": "1.2.3",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false,
+      "sourceInfo": "Identified by the javascript/packagelockjson extractor from path/to/my/first/lockfile",
+      "externalRefs": [
+        {
+          "referenceCategory": "PACKAGE-MANAGER",
+          "referenceType": "purl",
+          "referenceLocator": "pkg:npm/mine1@1.2.3"
+        }
+      ]
+    }
+  ],
+  "relationships": [
+    {
+      "spdxElementId": "SPDXRef-DOCUMENT",
+      "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
+      "relationshipType": "DESCRIBES"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-main-<uuid>",
+      "relatedSpdxElement": "SPDXRef-Package-mine1-<uuid>",
+      "relationshipType": "CONTAINS"
+    },
+    {
+      "spdxElementId": "SPDXRef-Package-mine1-<uuid>",
+      "relatedSpdxElement": "NOASSERTION",
+      "relationshipType": "CONTAINS"
+    }
+  ]
+}
+
+---
+
+[TestPrintSPDXResults_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
 {
   "spdxVersion": "SPDX-2.3",
   "dataLicense": "CC0-1.0",
@@ -3423,6 +3827,40 @@
 
 ---
 
+[TestPrintSPDXResults_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+{
+  "spdxVersion": "SPDX-2.3",
+  "dataLicense": "CC0-1.0",
+  "SPDXID": "SPDXRef-DOCUMENT",
+  "name": "SCALIBR-generated SPDX",
+  "documentNamespace": "https://spdx.google/<uuid>",
+  "creationInfo": {
+    "creators": [
+      "Tool: SCALIBR"
+    ],
+    "created": "<timestamp>"
+  },
+  "packages": [
+    {
+      "name": "main",
+      "SPDXID": "SPDXRef-Package-main-<uuid>",
+      "versionInfo": "0",
+      "supplier": "NOASSERTION",
+      "downloadLocation": "NOASSERTION",
+      "filesAnalyzed": false
+    }
+  ],
+  "relationships": [
+    {
+      "spdxElementId": "SPDXRef-Document",
+      "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
+      "relationshipType": "DESCRIBES"
+    }
+  ]
+}
+
+---
+
 [TestPrintSPDXResults_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
 {
   "spdxVersion": "SPDX-2.3",
@@ -3480,7 +3918,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -3566,7 +4004,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
@@ -3652,7 +4090,7 @@
   ],
   "relationships": [
     {
-      "spdxElementId": "SPDXRef-Document",
+      "spdxElementId": "SPDXRef-DOCUMENT",
       "relatedSpdxElement": "SPDXRef-Package-main-<uuid>",
       "relationshipType": "DESCRIBES"
     },
diff --git a/internal/output/__snapshots__/table_test.snap b/internal/output/__snapshots__/table_test.snap
index ee59d1a1..bc8e3a83 100755
--- a/internal/output/__snapshots__/table_test.snap
+++ b/internal/output/__snapshots__/table_test.snap
@@ -91,6 +91,24 @@
 
 ---
 
+[TestPrintTableResults_LongTerminalWidth_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
+╭───────────────────┬───────────┬─────────┬─────────┬───────────────────────────╮
+│ LICENSE VIOLATION │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                    │
+├───────────────────┼───────────┼─────────┼─────────┼───────────────────────────┤
+│ MIT               │ npm       │ mine1   │ 1.2.3   │ path/to/my/first/lockfile │
+╰───────────────────┴───────────┴─────────┴─────────┴───────────────────────────╯
+
+---
+
+[TestPrintTableResults_LongTerminalWidth_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+╭───────────────────┬───────────┬─────────┬─────────┬───────────────────────────╮
+│ LICENSE VIOLATION │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                    │
+├───────────────────┼───────────┼─────────┼─────────┼───────────────────────────┤
+│ MIT               │ npm       │ mine1   │         │ path/to/my/first/lockfile │
+╰───────────────────┴───────────┴─────────┴─────────┴───────────────────────────╯
+
+---
+
 [TestPrintTableResults_LongTerminalWidth_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 ╭───────────────────┬───────────┬─────────┬─────────┬───────────────────────────╮
 │ LICENSE VIOLATION │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                    │
@@ -139,6 +157,24 @@
 
 ---
 
+[TestPrintTableResults_LongTerminalWidth_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
+╭───────────────────────┬──────┬───────────┬─────────┬─────────┬────────────────────────────╮
+│ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                     │
+├───────────────────────┼──────┼───────────┼─────────┼─────────┼────────────────────────────┤
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1   │ 1.2.3   │ path/to/my/first/lockfile  │
+│ https://osv.dev/OSV-2 │      │ npm       │ mine2   │         │ path/to/my/second/lockfile │
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1   │ 1.2.3   │ path/to/my/third/lockfile  │
+╰───────────────────────┴──────┴───────────┴─────────┴─────────┴────────────────────────────╯
+╭───────────────────┬───────────┬─────────┬─────────┬───────────────────────────╮
+│ LICENSE VIOLATION │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                    │
+├───────────────────┼───────────┼─────────┼─────────┼───────────────────────────┤
+│ MIT               │ npm       │ mine1   │ 1.2.3   │ path/to/my/first/lockfile │
+│ MIT               │ npm       │ mine1   │ 1.3.5   │ path/to/my/third/lockfile │
+│ Apache-2.0        │ npm       │ mine1   │ 1.2.3   │ path/to/my/third/lockfile │
+╰───────────────────┴───────────┴─────────┴─────────┴───────────────────────────╯
+
+---
+
 [TestPrintTableResults_LongTerminalWidth_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
 ╭───────────────────────┬──────┬───────────┬─────────┬─────────┬───────────────────────────╮
 │ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                    │
@@ -271,6 +307,20 @@
 
 ---
 
+[TestPrintTableResults_LongTerminalWidth_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+╭───────────────────────┬──────┬───────────┬───────────────┬─────────┬────────────────────────────╮
+│ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE       │ VERSION │ SOURCE                     │
+├───────────────────────┼──────┼───────────┼───────────────┼─────────┼────────────────────────────┤
+│ https://osv.dev/OSV-1 │      │ Packagist │ author1/mine1 │ 1.2.3   │ path/to/my/first/lockfile  │
+│ https://osv.dev/OSV-5 │      │ Packagist │ author1/mine1 │ 1.2.3   │ path/to/my/first/lockfile  │
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1         │         │ path/to/my/first/lockfile  │
+│ https://osv.dev/OSV-2 │      │ NuGet     │ mine2         │ 3.2.5   │ path/to/my/second/lockfile │
+│ https://osv.dev/OSV-3 │      │ Packagist │ author3/mine3 │ 0.4.1   │ path/to/my/second/lockfile │
+│ https://osv.dev/OSV-5 │      │ Packagist │ author3/mine3 │ 0.4.1   │ path/to/my/second/lockfile │
+╰───────────────────────┴──────┴───────────┴───────────────┴─────────┴────────────────────────────╯
+
+---
+
 [TestPrintTableResults_LongTerminalWidth_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 
 ---
@@ -360,6 +410,24 @@
 
 ---
 
+[TestPrintTableResults_LongTerminalWidth_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
+╭───────────────────────┬──────┬───────────┬─────────┬─────────┬───────────────────────────╮
+│ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                    │
+├───────────────────────┼──────┼───────────┼─────────┼─────────┼───────────────────────────┤
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1   │ 1.2.3   │ path/to/my/first/lockfile │
+╰───────────────────────┴──────┴───────────┴─────────┴─────────┴───────────────────────────╯
+
+---
+
+[TestPrintTableResults_LongTerminalWidth_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+╭───────────────────────┬──────┬───────────┬─────────┬─────────┬───────────────────────────╮
+│ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                    │
+├───────────────────────┼──────┼───────────┼─────────┼─────────┼───────────────────────────┤
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1   │         │ path/to/my/first/lockfile │
+╰───────────────────────┴──────┴───────────┴─────────┴─────────┴───────────────────────────╯
+
+---
+
 [TestPrintTableResults_LongTerminalWidth_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
 ╭───────────────────────┬──────┬───────────┬─────────┬───────────┬───────────────────────────╮
 │ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION   │ SOURCE                    │
@@ -481,6 +549,24 @@
 
 ---
 
+[TestPrintTableResults_NoTerminalWidth_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
++-------------------+-----------+---------+---------+---------------------------+
+| LICENSE VIOLATION | ECOSYSTEM | PACKAGE | VERSION | SOURCE                    |
++-------------------+-----------+---------+---------+---------------------------+
+| MIT               | npm       | mine1   | 1.2.3   | path/to/my/first/lockfile |
++-------------------+-----------+---------+---------+---------------------------+
+
+---
+
+[TestPrintTableResults_NoTerminalWidth_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
++-------------------+-----------+---------+---------+---------------------------+
+| LICENSE VIOLATION | ECOSYSTEM | PACKAGE | VERSION | SOURCE                    |
++-------------------+-----------+---------+---------+---------------------------+
+| MIT               | npm       | mine1   |         | path/to/my/first/lockfile |
++-------------------+-----------+---------+---------+---------------------------+
+
+---
+
 [TestPrintTableResults_NoTerminalWidth_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 +-------------------+-----------+---------+---------+---------------------------+
 | LICENSE VIOLATION | ECOSYSTEM | PACKAGE | VERSION | SOURCE                    |
@@ -529,6 +615,24 @@
 
 ---
 
+[TestPrintTableResults_NoTerminalWidth_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
++-----------------------+------+-----------+---------+---------+----------------------------+
+| OSV URL               | CVSS | ECOSYSTEM | PACKAGE | VERSION | SOURCE                     |
++-----------------------+------+-----------+---------+---------+----------------------------+
+| https://osv.dev/OSV-1 |      | npm       | mine1   | 1.2.3   | path/to/my/first/lockfile  |
+| https://osv.dev/OSV-2 |      | npm       | mine2   |         | path/to/my/second/lockfile |
+| https://osv.dev/OSV-1 |      | npm       | mine1   | 1.2.3   | path/to/my/third/lockfile  |
++-----------------------+------+-----------+---------+---------+----------------------------+
++-------------------+-----------+---------+---------+---------------------------+
+| LICENSE VIOLATION | ECOSYSTEM | PACKAGE | VERSION | SOURCE                    |
++-------------------+-----------+---------+---------+---------------------------+
+| MIT               | npm       | mine1   | 1.2.3   | path/to/my/first/lockfile |
+| MIT               | npm       | mine1   | 1.3.5   | path/to/my/third/lockfile |
+| Apache-2.0        | npm       | mine1   | 1.2.3   | path/to/my/third/lockfile |
++-------------------+-----------+---------+---------+---------------------------+
+
+---
+
 [TestPrintTableResults_NoTerminalWidth_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
 +-----------------------+------+-----------+---------+---------+---------------------------+
 | OSV URL               | CVSS | ECOSYSTEM | PACKAGE | VERSION | SOURCE                    |
@@ -661,6 +765,20 @@
 
 ---
 
+[TestPrintTableResults_NoTerminalWidth_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
++-----------------------+------+-----------+---------------+---------+----------------------------+
+| OSV URL               | CVSS | ECOSYSTEM | PACKAGE       | VERSION | SOURCE                     |
++-----------------------+------+-----------+---------------+---------+----------------------------+
+| https://osv.dev/OSV-1 |      | Packagist | author1/mine1 | 1.2.3   | path/to/my/first/lockfile  |
+| https://osv.dev/OSV-5 |      | Packagist | author1/mine1 | 1.2.3   | path/to/my/first/lockfile  |
+| https://osv.dev/OSV-1 |      | npm       | mine1         |         | path/to/my/first/lockfile  |
+| https://osv.dev/OSV-2 |      | NuGet     | mine2         | 3.2.5   | path/to/my/second/lockfile |
+| https://osv.dev/OSV-3 |      | Packagist | author3/mine3 | 0.4.1   | path/to/my/second/lockfile |
+| https://osv.dev/OSV-5 |      | Packagist | author3/mine3 | 0.4.1   | path/to/my/second/lockfile |
++-----------------------+------+-----------+---------------+---------+----------------------------+
+
+---
+
 [TestPrintTableResults_NoTerminalWidth_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 
 ---
@@ -750,6 +868,24 @@
 
 ---
 
+[TestPrintTableResults_NoTerminalWidth_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
++-----------------------+------+-----------+---------+---------+---------------------------+
+| OSV URL               | CVSS | ECOSYSTEM | PACKAGE | VERSION | SOURCE                    |
++-----------------------+------+-----------+---------+---------+---------------------------+
+| https://osv.dev/OSV-1 |      | npm       | mine1   | 1.2.3   | path/to/my/first/lockfile |
++-----------------------+------+-----------+---------+---------+---------------------------+
+
+---
+
+[TestPrintTableResults_NoTerminalWidth_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
++-----------------------+------+-----------+---------+---------+---------------------------+
+| OSV URL               | CVSS | ECOSYSTEM | PACKAGE | VERSION | SOURCE                    |
++-----------------------+------+-----------+---------+---------+---------------------------+
+| https://osv.dev/OSV-1 |      | npm       | mine1   |         | path/to/my/first/lockfile |
++-----------------------+------+-----------+---------+---------+---------------------------+
+
+---
+
 [TestPrintTableResults_NoTerminalWidth_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
 +-----------------------+------+-----------+---------+-----------+---------------------------+
 | OSV URL               | CVSS | ECOSYSTEM | PACKAGE | VERSION   | SOURCE                    |
@@ -871,6 +1007,24 @@
 
 ---
 
+[TestPrintTableResults_StandardTerminalWidth_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
+╭───────────────────┬───────────┬─────────┬─────────┬───────────────────────── ≈
+│ LICENSE VIOLATION │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                   ≈
+├───────────────────┼───────────┼─────────┼─────────┼───────────────────────── ≈
+│ MIT               │ npm       │ mine1   │ 1.2.3   │ path/to/my/first/lockfil ≈
+╰───────────────────┴───────────┴─────────┴─────────┴───────────────────────── ≈
+
+---
+
+[TestPrintTableResults_StandardTerminalWidth_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+╭───────────────────┬───────────┬─────────┬─────────┬───────────────────────── ≈
+│ LICENSE VIOLATION │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                   ≈
+├───────────────────┼───────────┼─────────┼─────────┼───────────────────────── ≈
+│ MIT               │ npm       │ mine1   │         │ path/to/my/first/lockfil ≈
+╰───────────────────┴───────────┴─────────┴─────────┴───────────────────────── ≈
+
+---
+
 [TestPrintTableResults_StandardTerminalWidth_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
 ╭───────────────────┬───────────┬─────────┬─────────┬───────────────────────── ≈
 │ LICENSE VIOLATION │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                   ≈
@@ -919,6 +1073,24 @@
 
 ---
 
+[TestPrintTableResults_StandardTerminalWidth_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
+╭───────────────────────┬──────┬───────────┬─────────┬─────────┬────────────── ≈
+│ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE        ≈
+├───────────────────────┼──────┼───────────┼─────────┼─────────┼────────────── ≈
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1   │ 1.2.3   │ path/to/my/fi ≈
+│ https://osv.dev/OSV-2 │      │ npm       │ mine2   │         │ path/to/my/se ≈
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1   │ 1.2.3   │ path/to/my/th ≈
+╰───────────────────────┴──────┴───────────┴─────────┴─────────┴────────────── ≈
+╭───────────────────┬───────────┬─────────┬─────────┬───────────────────────── ≈
+│ LICENSE VIOLATION │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE                   ≈
+├───────────────────┼───────────┼─────────┼─────────┼───────────────────────── ≈
+│ MIT               │ npm       │ mine1   │ 1.2.3   │ path/to/my/first/lockfil ≈
+│ MIT               │ npm       │ mine1   │ 1.3.5   │ path/to/my/third/lockfil ≈
+│ Apache-2.0        │ npm       │ mine1   │ 1.2.3   │ path/to/my/third/lockfil ≈
+╰───────────────────┴───────────┴─────────┴─────────┴───────────────────────── ≈
+
+---
+
 [TestPrintTableResults_StandardTerminalWidth_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
 ╭───────────────────────┬──────┬───────────┬─────────┬─────────┬────────────── ≈
 │ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE        ≈
@@ -1051,6 +1223,20 @@
 
 ---
 
+[TestPrintTableResults_StandardTerminalWidth_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+╭───────────────────────┬──────┬───────────┬───────────────┬─────────┬──────── ≈
+│ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE       │ VERSION │ SOURCE  ≈
+├───────────────────────┼──────┼───────────┼───────────────┼─────────┼──────── ≈
+│ https://osv.dev/OSV-1 │      │ Packagist │ author1/mine1 │ 1.2.3   │ path/to ≈
+│ https://osv.dev/OSV-5 │      │ Packagist │ author1/mine1 │ 1.2.3   │ path/to ≈
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1         │         │ path/to ≈
+│ https://osv.dev/OSV-2 │      │ NuGet     │ mine2         │ 3.2.5   │ path/to ≈
+│ https://osv.dev/OSV-3 │      │ Packagist │ author3/mine3 │ 0.4.1   │ path/to ≈
+│ https://osv.dev/OSV-5 │      │ Packagist │ author3/mine3 │ 0.4.1   │ path/to ≈
+╰───────────────────────┴──────┴───────────┴───────────────┴─────────┴──────── ≈
+
+---
+
 [TestPrintTableResults_StandardTerminalWidth_WithVulnerabilities/multiple_sources_with_no_packages - 1]
 
 ---
@@ -1140,6 +1326,24 @@
 
 ---
 
+[TestPrintTableResults_StandardTerminalWidth_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
+╭───────────────────────┬──────┬───────────┬─────────┬─────────┬────────────── ≈
+│ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE        ≈
+├───────────────────────┼──────┼───────────┼─────────┼─────────┼────────────── ≈
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1   │ 1.2.3   │ path/to/my/fi ≈
+╰───────────────────────┴──────┴───────────┴─────────┴─────────┴────────────── ≈
+
+---
+
+[TestPrintTableResults_StandardTerminalWidth_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+╭───────────────────────┬──────┬───────────┬─────────┬─────────┬────────────── ≈
+│ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION │ SOURCE        ≈
+├───────────────────────┼──────┼───────────┼─────────┼─────────┼────────────── ≈
+│ https://osv.dev/OSV-1 │      │ npm       │ mine1   │         │ path/to/my/fi ≈
+╰───────────────────────┴──────┴───────────┴─────────┴─────────┴────────────── ≈
+
+---
+
 [TestPrintTableResults_StandardTerminalWidth_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
 ╭───────────────────────┬──────┬───────────┬─────────┬───────────┬──────────── ≈
 │ OSV URL               │ CVSS │ ECOSYSTEM │ PACKAGE │ VERSION   │ SOURCE      ≈
diff --git a/internal/output/__snapshots__/vertical_test.snap b/internal/output/__snapshots__/vertical_test.snap
index f48bbe7d..6fed5d72 100755
--- a/internal/output/__snapshots__/vertical_test.snap
+++ b/internal/output/__snapshots__/vertical_test.snap
@@ -289,6 +289,42 @@ npm
   1 license violation found in :path/to/my/first/lockfile
 
 
+---
+
+[TestPrintVerticalResults_WithLicenseViolations/one_source_with_one_package_with_both_a_version_and_a_commit_and_one_license_violation - 1]
+
+Total 0 packages affected by 0 known vulnerabilities (0 Critical, 0 High, 0 Medium, 0 Low, 0 Unknown) from 1 ecosystem.
+0 vulnerabilities can be fixed.
+
+npm
+
+:path/to/my/first/lockfile: found 0 packages with issues
+  no known vulnerabilities found
+
+  license violations found:
+    mine1@1.2.3 (MIT)
+
+  1 license violation found in :path/to/my/first/lockfile
+
+
+---
+
+[TestPrintVerticalResults_WithLicenseViolations/one_source_with_one_package_with_just_a_commit_and_one_license_violation - 1]
+
+Total 0 packages affected by 0 known vulnerabilities (0 Critical, 0 High, 0 Medium, 0 Low, 0 Unknown) from 1 ecosystem.
+0 vulnerabilities can be fixed.
+
+npm
+
+:path/to/my/first/lockfile: found 0 packages with issues
+  no known vulnerabilities found
+
+  license violations found:
+    mine1@ (MIT)
+
+  1 license violation found in :path/to/my/first/lockfile
+
+
 ---
 
 [TestPrintVerticalResults_WithLicenseViolations/two_sources_with_packages,_one_license_violation - 1]
@@ -397,6 +433,49 @@ npm
   2 license violations found in :path/to/my/third/lockfile
 
 
+---
+
+[TestPrintVerticalResults_WithMixedIssues/multiple_sources_with_a_mixed_count_of_packages_with_versions_and_commits,_some_vulnerabilities_and_license_violations - 1]
+
+Total 3 packages affected by 3 known vulnerabilities (0 Critical, 0 High, 0 Medium, 0 Low, 3 Unknown) from 1 ecosystem.
+0 vulnerabilities can be fixed.
+
+npm
+
+:path/to/my/first/lockfile: found 1 package with issues
+
+  mine1@1.2.3 has the following known vulnerabilities:
+    OSV-1: Something scary! (https://osv.dev/OSV-1)
+
+  1 known vulnerability found in :path/to/my/first/lockfile
+
+  license violations found:
+    mine1@1.2.3 (MIT)
+
+  1 license violation found in :path/to/my/first/lockfile
+
+:path/to/my/second/lockfile: found 1 package with issues
+
+  mine2@ has the following known vulnerabilities:
+    OSV-2: Something less scary! (https://osv.dev/OSV-2)
+
+  1 known vulnerability found in :path/to/my/second/lockfile
+  no license violations found
+
+:path/to/my/third/lockfile: found 1 package with issues
+
+  mine1@1.2.3 has the following known vulnerabilities:
+    OSV-1: Something scary! (https://osv.dev/OSV-1)
+
+  1 known vulnerability found in :path/to/my/third/lockfile
+
+  license violations found:
+    mine1@1.2.3 (Apache-2.0)
+    mine1@1.3.5 (MIT)
+
+  2 license violations found in :path/to/my/third/lockfile
+
+
 ---
 
 [TestPrintVerticalResults_WithMixedIssues/one_source_with_one_package,_one_called_vulnerability,_and_one_license_violation - 1]
@@ -691,6 +770,50 @@ npm
   1 known vulnerability found in :path/to/my/first/lockfile
 
 
+---
+
+[TestPrintVerticalResults_WithVulnerabilities/multiple_sources_with_a_mixed_count_of_packages_across_ecosystems_using_commits_and_version,_and_multiple_vulnerabilities - 1]
+
+Total 4 packages affected by 6 known vulnerabilities (0 Critical, 0 High, 0 Medium, 0 Low, 6 Unknown) from 3 ecosystems.
+0 vulnerabilities can be fixed.
+
+NuGet
+
+:path/to/my/second/lockfile: found 1 package with issues
+
+  mine2@3.2.5 has the following known vulnerabilities:
+    OSV-2: Something less scary! (https://osv.dev/OSV-2)
+
+  1 known vulnerability found in :path/to/my/second/lockfile
+
+Packagist
+
+:path/to/my/first/lockfile: found 1 package with issues
+
+  author1/mine1@1.2.3 has the following known vulnerabilities:
+    OSV-1: Something scary! (https://osv.dev/OSV-1)
+    OSV-5: Something scarier! (https://osv.dev/OSV-5)
+
+  2 known vulnerabilities found in :path/to/my/first/lockfile
+
+:path/to/my/second/lockfile: found 1 package with issues
+
+  author3/mine3@0.4.1 has the following known vulnerabilities:
+    OSV-3: Something mildly scary! (https://osv.dev/OSV-3)
+    OSV-5: Something scarier! (https://osv.dev/OSV-5)
+
+  2 known vulnerabilities found in :path/to/my/second/lockfile
+
+npm
+
+:path/to/my/first/lockfile: found 1 package with issues
+
+  mine1@ has the following known vulnerabilities:
+    OSV-1: Something scary! (https://osv.dev/OSV-1)
+
+  1 known vulnerability found in :path/to/my/first/lockfile
+
+
 ---
 
 [TestPrintVerticalResults_WithVulnerabilities/multiple_sources_with_no_packages - 1]
@@ -869,6 +992,40 @@ npm
   1 known vulnerability found in :path/to/my/first/lockfile
 
 
+---
+
+[TestPrintVerticalResults_WithVulnerabilities/one_source_with_one_package_with_both_a_version_and_commit_and_one_vulnerability - 1]
+
+Total 1 package affected by 1 known vulnerability (0 Critical, 0 High, 0 Medium, 0 Low, 1 Unknown) from 1 ecosystem.
+0 vulnerabilities can be fixed.
+
+npm
+
+:path/to/my/first/lockfile: found 1 package with issues
+
+  mine1@1.2.3 has the following known vulnerabilities:
+    OSV-1: Something scary! (https://osv.dev/OSV-1)
+
+  1 known vulnerability found in :path/to/my/first/lockfile
+
+
+---
+
+[TestPrintVerticalResults_WithVulnerabilities/one_source_with_one_package_with_just_a_commit_and_one_vulnerability - 1]
+
+Total 1 package affected by 1 known vulnerability (0 Critical, 0 High, 0 Medium, 0 Low, 1 Unknown) from 1 ecosystem.
+0 vulnerabilities can be fixed.
+
+npm
+
+:path/to/my/first/lockfile: found 1 package with issues
+
+  mine1@ has the following known vulnerabilities:
+    OSV-1: Something scary! (https://osv.dev/OSV-1)
+
+  1 known vulnerability found in :path/to/my/first/lockfile
+
+
 ---
 
 [TestPrintVerticalResults_WithVulnerabilities/one_source_with_vulnerabilities,_some_missing_content - 1]
diff --git a/pkg/osvscanner/osvscanner.go b/pkg/osvscanner/osvscanner.go
index d0cf696d..b85d9eac 100644
--- a/pkg/osvscanner/osvscanner.go
+++ b/pkg/osvscanner/osvscanner.go
@@ -157,7 +157,7 @@ func initializeExternalAccessors(actions ScannerActions) (ExternalAccessors, err
 	externalAccessors.MavenRegistryAPIClient, err = datasource.NewMavenRegistryAPIClient(datasource.MavenRegistry{
 		URL:             actions.TransitiveScanningActions.MavenRegistry,
 		ReleasesEnabled: true,
-	})
+	}, "")
 
 	if err != nil {
 		return ExternalAccessors{}, err
@@ -166,7 +166,7 @@ func initializeExternalAccessors(actions ScannerActions) (ExternalAccessors, err
 	if !actions.TransitiveScanningActions.NativeDataSource {
 		externalAccessors.DependencyClients[osvschema.EcosystemMaven], err = resolution.NewDepsDevClient(depsdev.DepsdevAPI, "osv-scanner_scan/"+version.OSVVersion)
 	} else {
-		externalAccessors.DependencyClients[osvschema.EcosystemMaven], err = resolution.NewMavenRegistryClient(actions.TransitiveScanningActions.MavenRegistry)
+		externalAccessors.DependencyClients[osvschema.EcosystemMaven], err = resolution.NewMavenRegistryClient(actions.TransitiveScanningActions.MavenRegistry, "")
 	}
 
 	if err != nil {
diff --git a/scripts/run_lints.sh b/scripts/run_lints.sh
index 9bcf2e6f..ee4a90e7 100755
--- a/scripts/run_lints.sh
+++ b/scripts/run_lints.sh
@@ -2,4 +2,4 @@
 
 set -ex
 
-go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.4 run ./...
+go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run ./...



Test patch:
diff --git a/internal/output/helpers_test.go b/internal/output/helpers_test.go
index 1892bfdd..0c16c953 100644
--- a/internal/output/helpers_test.go
+++ b/internal/output/helpers_test.go
@@ -8,6 +8,7 @@ import (
 	"github.com/google/osv-scalibr/extractor/filesystem/language/dotnet/packageslockjson"
 	"github.com/google/osv-scalibr/extractor/filesystem/language/javascript/packagelockjson"
 	"github.com/google/osv-scalibr/extractor/filesystem/language/php/composerlock"
+	"github.com/google/osv-scalibr/purl"
 	"github.com/google/osv-scanner/v2/pkg/models"
 	"github.com/ossf/osv-schema/bindings/go/osvschema"
 )
@@ -33,6 +34,19 @@ type pkginfo struct {
 	Extractor     extractor.Extractor
 }
 
+func resolvePURLType(eco string) string {
+	switch eco {
+	case "npm":
+		return purl.TypeNPM
+	case "NuGet":
+		return purl.TypeNuget
+	case "Packagist":
+		return purl.TypeComposer
+	}
+
+	panic("unknown PURL type for ecosystem " + eco)
+}
+
 func newPackageInfo(source string, pi pkginfo) models.PackageInfo {
 	info := models.PackageInfo{
 		Name:          pi.Name,
@@ -46,6 +60,7 @@ func newPackageInfo(source string, pi pkginfo) models.PackageInfo {
 			Version:   pi.Version,
 			Extractor: pi.Extractor,
 			Locations: []string{source},
+			PURLType:  resolvePURLType(pi.Ecosystem),
 		},
 	}
 
@@ -220,6 +235,67 @@ func testOutputWithVulnerabilities(t *testing.T, run outputTestRunner) {
 				},
 			},
 		},
+		{
+			name: "one source with one package with both a version and commit and one vulnerability",
+			args: outputTestCaseArgs{
+				vulnResult: &models.VulnerabilityResults{
+					Results: []models.PackageSource{
+						{
+							Source: models.SourceInfo{Path: "path/to/my/first/lockfile"},
+							Packages: []models.PackageVulns{
+								{
+									Package: newPackageInfo("path/to/my/first/lockfile", pkginfo{
+										Name:      "mine1",
+										Version:   "1.2.3",
+										Ecosystem: "npm",
+										Commit:    "abc123",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Groups: []models.GroupInfo{{IDs: []string{"OSV-1"}}},
+									Vulnerabilities: []osvschema.Vulnerability{
+										{
+											ID:       "OSV-1",
+											Summary:  "Something scary!",
+											Severity: []osvschema.Severity{{Type: "high", Score: "1"}},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "one source with one package with just a commit and one vulnerability",
+			args: outputTestCaseArgs{
+				vulnResult: &models.VulnerabilityResults{
+					Results: []models.PackageSource{
+						{
+							Source: models.SourceInfo{Path: "path/to/my/first/lockfile"},
+							Packages: []models.PackageVulns{
+								{
+									Package: newPackageInfo("path/to/my/first/lockfile", pkginfo{
+										Name:      "mine1",
+										Ecosystem: "npm",
+										Commit:    "abc123",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Groups: []models.GroupInfo{{IDs: []string{"OSV-1"}}},
+									Vulnerabilities: []osvschema.Vulnerability{
+										{
+											ID:       "OSV-1",
+											Summary:  "Something scary!",
+											Severity: []osvschema.Severity{{Type: "high", Score: "1"}},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 		{
 			name: "one source with one package and one called vulnerability",
 			args: outputTestCaseArgs{
@@ -938,6 +1014,108 @@ func testOutputWithVulnerabilities(t *testing.T, run outputTestRunner) {
 				},
 			},
 		},
+		{
+			name: "multiple sources with a mixed count of packages across ecosystems using commits and version, and multiple vulnerabilities",
+			args: outputTestCaseArgs{
+				vulnResult: &models.VulnerabilityResults{
+					Results: []models.PackageSource{
+						{
+							Source: models.SourceInfo{Path: "path/to/my/first/lockfile"},
+							Packages: []models.PackageVulns{
+								{
+									Package: newPackageInfo("path/to/my/first/lockfile", pkginfo{
+										Name:      "author1/mine1",
+										Version:   "1.2.3",
+										Ecosystem: "Packagist",
+										Commit:    "123abc",
+										Extractor: composerlock.Extractor{},
+									}),
+									Groups: []models.GroupInfo{
+										{IDs: []string{"OSV-1"}},
+										{IDs: []string{"OSV-5"}},
+									},
+									Vulnerabilities: []osvschema.Vulnerability{
+										{
+											ID:       "OSV-1",
+											Summary:  "Something scary!",
+											Severity: []osvschema.Severity{{Type: "high", Score: "1"}},
+										},
+										{
+											ID:       "OSV-5",
+											Summary:  "Something scarier!",
+											Severity: []osvschema.Severity{{Type: "extreme", Score: "1"}},
+										},
+									},
+								},
+								{
+									Package: newPackageInfo("path/to/my/first/lockfile", pkginfo{
+										Name:      "mine1",
+										Ecosystem: "npm",
+										Commit:    "abcxyz",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Groups: []models.GroupInfo{{IDs: []string{"OSV-1"}}},
+									Vulnerabilities: []osvschema.Vulnerability{
+										{
+											ID:       "OSV-1",
+											Summary:  "Something scary!",
+											Severity: []osvschema.Severity{{Type: "high", Score: "1"}},
+										},
+									},
+								},
+							},
+						},
+						{
+							Source: models.SourceInfo{Path: "path/to/my/second/lockfile"},
+							Packages: []models.PackageVulns{
+								{
+									Package: newPackageInfo("path/to/my/second/lockfile", pkginfo{
+										Name:      "mine2",
+										Version:   "3.2.5",
+										Ecosystem: "NuGet",
+										Extractor: dotnetpe.Extractor{},
+									}),
+									DepGroups: []string{"dev"},
+									Groups:    []models.GroupInfo{{IDs: []string{"OSV-2"}}},
+									Vulnerabilities: []osvschema.Vulnerability{
+										{
+											ID:       "OSV-2",
+											Summary:  "Something less scary!",
+											Severity: []osvschema.Severity{{Type: "low", Score: "1"}},
+										},
+									},
+								},
+								{
+									Package: newPackageInfo("path/to/my/second/lockfile", pkginfo{
+										Name:      "author3/mine3",
+										Version:   "0.4.1",
+										Ecosystem: "Packagist",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									DepGroups: []string{"build"},
+									Groups: []models.GroupInfo{
+										{IDs: []string{"OSV-3"}},
+										{IDs: []string{"OSV-5"}},
+									},
+									Vulnerabilities: []osvschema.Vulnerability{
+										{
+											ID:       "OSV-3",
+											Summary:  "Something mildly scary!",
+											Severity: []osvschema.Severity{{Type: "medium", Score: "1"}},
+										},
+										{
+											ID:       "OSV-5",
+											Summary:  "Something scarier!",
+											Severity: []osvschema.Severity{{Type: "extreme", Score: "1"}},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 		{
 			name: "multiple sources with a mixed count of packages across ecosystems, and multiple vulnerabilities, but some uncalled",
 			args: outputTestCaseArgs{
@@ -1330,6 +1508,57 @@ func testOutputWithLicenseViolations(t *testing.T, run outputTestRunner) {
 				},
 			},
 		},
+		{
+			name: "one source with one package with both a version and a commit and one license violation",
+			args: outputTestCaseArgs{
+				vulnResult: &models.VulnerabilityResults{
+					ExperimentalAnalysisConfig: experimentalAnalysisConfig,
+					Results: []models.PackageSource{
+						{
+							Source: models.SourceInfo{Path: "path/to/my/first/lockfile"},
+							Packages: []models.PackageVulns{
+								{
+									Package: newPackageInfo("path/to/my/first/lockfile", pkginfo{
+										Name:      "mine1",
+										Version:   "1.2.3",
+										Ecosystem: "npm",
+										Commit:    "abc123",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Licenses:          []models.License{"MIT"},
+									LicenseViolations: []models.License{"MIT"},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "one source with one package with just a commit and one license violation",
+			args: outputTestCaseArgs{
+				vulnResult: &models.VulnerabilityResults{
+					ExperimentalAnalysisConfig: experimentalAnalysisConfig,
+					Results: []models.PackageSource{
+						{
+							Source: models.SourceInfo{Path: "path/to/my/first/lockfile"},
+							Packages: []models.PackageVulns{
+								{
+									Package: newPackageInfo("path/to/my/first/lockfile", pkginfo{
+										Name:      "mine1",
+										Ecosystem: "npm",
+										Commit:    "abc123",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Licenses:          []models.License{"MIT"},
+									LicenseViolations: []models.License{"MIT"},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 		{
 			name: "one source with one package and one license violation (dev)",
 			args: outputTestCaseArgs{
@@ -2002,6 +2231,108 @@ func testOutputWithMixedIssues(t *testing.T, run outputTestRunner) {
 				},
 			},
 		},
+		{
+			name: "multiple sources with a mixed count of packages with versions and commits, some vulnerabilities and license violations",
+			args: outputTestCaseArgs{
+				vulnResult: &models.VulnerabilityResults{
+					ExperimentalAnalysisConfig: experimentalAnalysisConfig,
+					Results: []models.PackageSource{
+						{
+							Source: models.SourceInfo{Path: "path/to/my/first/lockfile"},
+							Packages: []models.PackageVulns{
+								{
+									Package: newPackageInfo("path/to/my/first/lockfile", pkginfo{
+										Name:      "mine1",
+										Version:   "1.2.3",
+										Ecosystem: "npm",
+										Commit:    "abcxzy",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Groups: []models.GroupInfo{{IDs: []string{"OSV-1"}}},
+									Vulnerabilities: []osvschema.Vulnerability{
+										{
+											ID:       "OSV-1",
+											Summary:  "Something scary!",
+											Severity: []osvschema.Severity{{Type: "high", Score: "1"}},
+										},
+									},
+									Licenses:          []models.License{"MIT"},
+									LicenseViolations: []models.License{"MIT"},
+								},
+							},
+						},
+						{
+							Source: models.SourceInfo{Path: "path/to/my/second/lockfile"},
+							Packages: []models.PackageVulns{
+								{
+									Package: newPackageInfo("path/to/my/second/lockfile", pkginfo{
+										Name:      "mine2",
+										Ecosystem: "npm",
+										Commit:    "abc123",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Groups: []models.GroupInfo{{IDs: []string{"OSV-2"}}},
+									Vulnerabilities: []osvschema.Vulnerability{
+										{
+											ID:       "OSV-2",
+											Summary:  "Something less scary!",
+											Severity: []osvschema.Severity{{Type: "low", Score: "1"}},
+										},
+									},
+									Licenses:          []models.License{"ISC"},
+									LicenseViolations: []models.License{},
+								},
+								{
+									Package: newPackageInfo("path/to/my/second/lockfile", pkginfo{
+										Name:      "mine3",
+										Version:   "0.4.1",
+										Ecosystem: "npm",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Vulnerabilities:   []osvschema.Vulnerability{},
+									Licenses:          []models.License{"ISC"},
+									LicenseViolations: []models.License{},
+								},
+							},
+						},
+						{
+							Source: models.SourceInfo{Path: "path/to/my/third/lockfile"},
+							Packages: []models.PackageVulns{
+								{
+									Package: newPackageInfo("path/to/my/third/lockfile", pkginfo{
+										Name:      "mine1",
+										Version:   "1.3.5",
+										Ecosystem: "npm",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Vulnerabilities:   []osvschema.Vulnerability{},
+									Licenses:          []models.License{"MIT"},
+									LicenseViolations: []models.License{"MIT"},
+								},
+								{
+									Package: newPackageInfo("path/to/my/third/lockfile", pkginfo{
+										Name:      "mine1",
+										Version:   "1.2.3",
+										Ecosystem: "npm",
+										Extractor: packagelockjson.Extractor{},
+									}),
+									Groups: []models.GroupInfo{{IDs: []string{"OSV-1"}}},
+									Vulnerabilities: []osvschema.Vulnerability{
+										{
+											ID:       "OSV-1",
+											Summary:  "Something scary!",
+											Severity: []osvschema.Severity{{Type: "high", Score: "1"}},
+										},
+									},
+									Licenses:          []models.License{"Apache-2.0"},
+									LicenseViolations: []models.License{"Apache-2.0"},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 		{
 			name: "multiple sources with a mixed count of packages, some called vulnerabilities and license violations",
 			args: outputTestCaseArgs{