Skip to content

Conversation

@dmcgowan
Copy link
Member

@dmcgowan dmcgowan commented Sep 17, 2025

Adds an implementation of the referrers API from OCI distribution-spec 1.1.

Update from #7644

* **OCI Referrers Support** ([#12309](https://github.com/containerd/containerd/pull/12309))

  Adds new referrers fetcher to remote registry interface using the [new referrers endpoint added in OCI distribution-spec 1.1](https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#listing-referrers)

desc.Size = cl
// Digest is not known ahead of time and there is nothing in the distribution
// specification defining an HTTP header to return the digest on referrers.
return rc, desc, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this descriptor? What's the use case of returning Descriptor without a Digest (other than hoping to cause a panic in the caller)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original idea was the caller would fill this in and use it to save the referrers index, however I think we discussed that we probably don't want to save the referrers index at all. We could return the index directly, we just don't currently use those parsed objects at this level of the interface normally.

And other places we do use partial descriptors for content verification, it can certainly be a trap for callers though.

defer rc.Close()

var index ocispec.Index
if err := json.NewDecoder(io.LimitReader(rc, size)).Decode(&index); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Safe usage of json.NewDecoder requires calling smth like

	if _, err := dec.Token(); !errors.Is(err, io.EOF) {
		return nil, errors.Errorf("unexpected data after JSON object")
	}

after Decode. No actual security issue in here, just potentially not validating garbage data from registry.

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)

func (r dockerFetcher) FetchReferrers(ctx context.Context, dgst digest.Digest, artifactTypes ...string) ([]ocispec.Descriptor, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you change this to take descriptor instead of digest I could avoid defining https://github.com/containerd/containerd/compare/main...tonistiigi:containerd:referrers-wip?expand=1#diff-85dea1ce2bec55085339d4ec90127de60f896bae284b627e7c03c1ff7bcb6533R214 and just use remotes. ReferrersFetcher as input to puller/exporter etc. Ok if you wish to keep them separate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, when are the artifact types injected?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The callbacks in client will always set it to empty (as containerd library should not be opinionated about what referrers should be included) but provider interface implementation can add its own filters. I you prefer to keep callback interface separate (and without the artifacttype), then that is fine by me.

}
}

for i, host := range fallbackHosts {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally there should be a way to opt-out of this fallback mechanism as eventually this should die and polluting repositories with these tags should stop. Maybe an item in ResolverOptions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could just avoid populating the fallback hosts if there are any referrers hosts

if err := json.NewDecoder(io.LimitReader(rc, size)).Decode(&index); err != nil {
return nil, fmt.Errorf("failed to decode referrers index: %w", err)
}
return index.Manifests, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As matching the artifactType is not guaranteed, then this should reapply the filter manually before returning.

Copy link
Member Author

@dmcgowan dmcgowan Sep 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, if artifact is missing from a descriptor, it will include

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why skip the filter the user asked for, if not defined? Btw, the spec defines some response headers for this as well https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers (I don't quite get what benefit they provide).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to omit empty artifact types when artifact filters provided

If filtering is requested and applied, the response MUST include a header OCI-Filters-Applied: artifactType denoting that an artifactType filter was applied. If multiple filters are applied, the header MUST contain a comma separated list of applied filters.

I don't think there is anything we would want to do with this on our side, maybe just useful for caching or head requests.

@dmcgowan dmcgowan added this to the 2.2 milestone Sep 19, 2025
@dmcgowan dmcgowan moved this from Needs Triage to Review In Progress in Pull Request Review Sep 22, 2025
@dmcgowan dmcgowan requested review from estesp and fuweid September 24, 2025 18:27
Copy link
Member

@estesp estesp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit about an error message, but otherwise LGTM

dmcgowan and others added 4 commits September 24, 2025 17:59
Adds an implementation of the referrers API from
OCI distribution-spec 1.1.

Signed-off-by: Derek McGowan <derek@mcg.dev>
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Derek McGowan <derek@mcg.dev>
Signed-off-by: Derek McGowan <derek@mcg.dev>
@fuweid fuweid added this pull request to the merge queue Sep 26, 2025
Merged via the queue into containerd:main with commit 1b613ba Sep 26, 2025
130 of 137 checks passed
@github-project-automation github-project-automation bot moved this from Review In Progress to Done in Pull Request Review Sep 26, 2025
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)

func (r dockerFetcher) FetchReferrers(ctx context.Context, dgst digest.Digest, artifactTypes ...string) ([]ocispec.Descriptor, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dmcgowan Has the FetchReferrers function not been called yet? I don't see any references to it (except for the test function).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently being used by BuildKit. How we want to integrate it into transfer service and image validation still needs to be decided.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

6 participants