Expected behavior and actual behavior:
Expected: after a successful SBOM scan (scan_type: sbom), the artifact's SBOM should be visible in the Harbor UI ("SBOM" tab) and retrievable via GET /api/v2.0/projects/{project}/repositories/{repository}/artifacts/{reference}/additions/sbom.
Actual: the UI shows "No SBOM" and the API call above returns 400 "addition SBOM isn't supported", even though the SBOM scan job reports Success and the SBOM accessory is verifiably created and correctly linked in the database.
Root cause found: this is not a scan/registration failure. The SBOM manifest is pushed successfully to the registry (PUT .../manifests/sha256:<sbom-digest> → 201), and the accessory row is correctly written to artifact_accessory (type = 'sbom.harbor', correctly linked via subject_artifact_id to the parent artifact) — verified directly against the Harbor Postgres DB.
The actual bug is in the API response's addition_links for that artifact: GET .../artifacts/{digest}?with_accessory=true returns:
"addition_links": {
"build_history": {
"absolute": false,
"href": "/api/v2.0/projects/myproject/repositories/myrepo/artifacts/sha256:<image-digest>/additions/build_history"
},
"sboms": {
"absolute": false,
"href": "/api/v2.0/projects/myproject/repositories/myrepo/artifacts//additions/sbom"
},
"vulnerabilities": {
"absolute": false,
"href": "/api/v2.0/projects/myproject/repositories/myrepo/artifacts/sha256:<image-digest>/additions/vulnerabilities"
}
Note the sboms link is missing the artifact digest entirely (artifacts//additions/sbom), while the sibling build_history and vulnerabilities links in the same response correctly include it. Any client (including Harbor's own UI) following this malformed link hits an empty artifact reference, which explains both the UI's "No SBOM" and the 400 error — the SBOM genuinely exists and is only reachable by querying ?with_accessory=true directly and reading the accessories array, bypassing the broken addition_links.sboms href.
Steps to reproduce the problem:
- Push any image to a project with SBOM generation enabled (Trivy scanner adapter with SBOM capability).
- Trigger an SBOM scan:
POST /api/v2.0/projects/{project}/repositories/{repository}/artifacts/{reference}/scan with body {"scan_type": "sbom"}.
- Wait for the job to report
Success (a few seconds).
- Check the UI's SBOM tab for that artifact — it shows "No SBOM".
- Call
GET /api/v2.0/projects/{project}/repositories/{repository}/artifacts/{reference}/additions/sbom — returns 400 "addition SBOM isn't supported".
- Call
GET /api/v2.0/projects/{project}/repositories/{repository}/artifacts/{reference}?with_accessory=true instead — the SBOM accessory is present in the accessories array, but the addition_links.sboms.href field in the same response is missing the artifact digest (artifacts//additions/sbom), unlike build_history/vulnerabilities in the same payload.
- (Optional, confirms DB-level correctness) Query
artifact_accessory directly in the Harbor Postgres DB — the SBOM accessory row exists with type = 'sbom.harbor' and a correct subject_artifact_id.
Versions:
- harbor version: 2.15.1
- docker engine version: 29.6.1
- docker-compose version:v5.3.1
Additional context:
- Scanner: Trivy adapter v0.70.0, SBOM capability enabled (
produces_mime_types: application/vnd.security.sbom.report+json, sbom_media_types: application/spdx+json).
Expected behavior and actual behavior:
Expected: after a successful SBOM scan (
scan_type: sbom), the artifact's SBOM should be visible in the Harbor UI ("SBOM" tab) and retrievable viaGET /api/v2.0/projects/{project}/repositories/{repository}/artifacts/{reference}/additions/sbom.Actual: the UI shows "No SBOM" and the API call above returns
400 "addition SBOM isn't supported", even though the SBOM scan job reportsSuccessand the SBOM accessory is verifiably created and correctly linked in the database.Root cause found: this is not a scan/registration failure. The SBOM manifest is pushed successfully to the registry (
PUT .../manifests/sha256:<sbom-digest>→201), and the accessory row is correctly written toartifact_accessory(type = 'sbom.harbor', correctly linked viasubject_artifact_idto the parent artifact) — verified directly against the Harbor Postgres DB.The actual bug is in the API response's
addition_linksfor that artifact:GET .../artifacts/{digest}?with_accessory=truereturns:Note the
sbomslink is missing the artifact digest entirely (artifacts//additions/sbom), while the siblingbuild_historyandvulnerabilitieslinks in the same response correctly include it. Any client (including Harbor's own UI) following this malformed link hits an empty artifact reference, which explains both the UI's "No SBOM" and the400error — the SBOM genuinely exists and is only reachable by querying?with_accessory=truedirectly and reading theaccessoriesarray, bypassing the brokenaddition_links.sbomshref.Steps to reproduce the problem:
POST /api/v2.0/projects/{project}/repositories/{repository}/artifacts/{reference}/scanwith body{"scan_type": "sbom"}.Success(a few seconds).GET /api/v2.0/projects/{project}/repositories/{repository}/artifacts/{reference}/additions/sbom— returns400 "addition SBOM isn't supported".GET /api/v2.0/projects/{project}/repositories/{repository}/artifacts/{reference}?with_accessory=trueinstead — the SBOM accessory is present in theaccessoriesarray, but theaddition_links.sboms.hreffield in the same response is missing the artifact digest (artifacts//additions/sbom), unlikebuild_history/vulnerabilitiesin the same payload.artifact_accessorydirectly in the Harbor Postgres DB — the SBOM accessory row exists withtype = 'sbom.harbor'and a correctsubject_artifact_id.Versions:
Additional context:
produces_mime_types: application/vnd.security.sbom.report+json,sbom_media_types: application/spdx+json).