PopulateReferrers runs two goroutines that add entries keyed by the same digest. The index walker expands each vnd.docker.reference.type=attestation-manifest entry into "sbom" and "attestation" rows, storing the SBOM row under the attestation manifest digest. The platform walker calls the referrers API for each platform manifest, which on Docker Hub returns the same attestation manifests as generic "attestation" rows. addReferrer keeps the first row per digest, so whenever the referrers call finishes before the manifest fetch, the SBOM row is dropped and the score reports "SBOM absent". Reproducible on index.docker.io/grepular/pdns-recursor-trimmed:latest: /api/inspect sometimes lists one "sbom" row and sometimes none, while docker buildx imagetools inspect --format '{{json .SBOM}}' returns an SPDX document for both platforms every time. Suggested fix: key expanded layer rows by layer digest, or let the expanded rows replace a generic row for the same manifest.
PopulateReferrers runs two goroutines that add entries keyed by the same digest. The index walker expands each
vnd.docker.reference.type=attestation-manifestentry into "sbom" and "attestation" rows, storing the SBOM row under the attestation manifest digest. The platform walker calls the referrers API for each platform manifest, which on Docker Hub returns the same attestation manifests as generic "attestation" rows. addReferrer keeps the first row per digest, so whenever the referrers call finishes before the manifest fetch, the SBOM row is dropped and the score reports "SBOM absent". Reproducible onindex.docker.io/grepular/pdns-recursor-trimmed:latest: /api/inspect sometimes lists one "sbom" row and sometimes none, whiledocker buildx imagetools inspect --format '{{json .SBOM}}'returns an SPDX document for both platforms every time. Suggested fix: key expanded layer rows by layer digest, or let the expanded rows replace a generic row for the same manifest.