github / github/artifact-attestations-opa-provider

Referrers pagination is not followed; attestations beyond the first page are never fetched

Open
#196 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Go
Stars
26
Forks
13
Avg merge
18h 43m
Merged PRs (30d)
23

Description

## Summary

When fetching the attestations for an image, the provider issues a single request to the registry's Referrers API and uses only that one response. If the registry returns the referrers list across multiple pages, the provider silently ignores every page after the first. As a result, an attestation that would satisfy a policy may never be fetched, producing a **false negative** (the image is treated as unsigned or as missing the required attestation even though a valid one exists).

## Where

`DoBundleFromName` in `pkg/fetcher/bundle.go` retrieves referrers via `go-containerregistry`'s `remote.Referrers`:

```go
referrers, err := remote.Referrers(digest, opts...)
...
refManifest, err := referrers.IndexManifest()
...
descriptors := selectBundleDescriptors(refManifest.Manifests, PredicateType)
```

`remote.Referrers` (go-containerregistry `v0.21.7`) performs a single `GET /v2//referrers/` and reads exactly one image-index body. It does **not** inspect or follow the `Link: <...>; rel="next"` response header, so `refManifest.Manifests` only ever contains the first page of referrers.

Notably, the same library **does** implement `Link`-header pagination for tag listing and catalog listing (`getNextPageURL` / `getNextPageURLForRegistry`), but that pagination logic was never wired into the referrers code path.

## Impact

- **False negatives.** If the specific attestation required by policy is on a page after the first, it is never downloaded and never verified. Depending on the code path this surfaces as `image_unsigned` (when the first page contains no Sigstore bundles at all) or as a policy failure (a matching bundle exists but was never seen).
- **Nondeterministic and silent.** Behavior depends on how many referrers an image has and on page ordering. Images with few referrers work fine; images with many can fail. No error is raised — the provider simply operates on a truncated list, which makes this hard to notice and hard to debug.
- **Registry-dependent, but not vendor-specific.** Any registry that paginates the referrers response is affected. Azure Container Registry (ACR) is a notable registry that paginates and would trigger this today.

## Is referrers pagination OCI-standard or registry-specific?

**It is part of the OCI Distribution Specification — not a registry-specific extension.** The [Listing Referrers](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers) section (added in distribution-spec 1.1) states:

> A `Link` header MUST be included in the response when the descriptor list cannot be returned in a single manifest. Each response is an image index with different descriptors in the `manifests` field. The `Link` header MUST be set according to [RFC 5988](https://www.rfc-editor.org/rfc/rfc5988) with the Relation Type `rel="next"`.

So a registry that splits referrers across pages (like ACR) is behaving as a conformant OCI implementation, and a spec-compliant client **must** follow the `rel="next"` link until it is exhausted, accumulating the `manifests` from every page. Our provider currently does not, which is the bug.

## Suggested direction

Follow the `Link: ...; rel="next"` header for the referrers endpoint and merge the `manifests` from all pages before selecting bundle descriptors. Because upstream `go-containerregistry`'s `remote.Referrers` does not paginate, this likely means either:

- driving the referrers request(s) directly and paginating over the `Link` header ourselves (validating that each next-page URL stays on the same registry, as the library already does for tags/catalog to avoid SSRF), or
- upstreaming referrers pagination into go-containerregistry.

Regression coverage should include a registry that returns a paginated referrers response and assert that a bundle on a non-first page is fetched and verified.

Contributor guide

Open the contributing guide

Research direction

Start in pkg/fetcher/bundle.go at DoBundleFromName and trace the remote.Referrers call through IndexManifest and selectBundleDescriptors. Read the referrers pagination behavior in go-containerregistry and the existing registry pagination helpers, then run the current tests. Done means a paginated referrers response causes a bundle on a later page to be fetched and verified, with regression coverage.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.