Skip to content

Commit

Permalink
feat: update the implementation of pushing manifest for distribution-…
Browse files Browse the repository at this point in the history
…spec v1.1.0-rc3 (#557)

1. Support pushing image index with a subject
2. Check the "OCI-Subject" header

Resolves: #534
Signed-off-by: Lixia (Sylvia) Lei <lixlei@microsoft.com>
  • Loading branch information
Wwwsylvia committed Jul 26, 2023
1 parent 2c23ef6 commit 79d7081
Show file tree
Hide file tree
Showing 2 changed files with 658 additions and 32 deletions.
53 changes: 46 additions & 7 deletions registry/remote/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ const (
// Reference:
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers
headerOCIFiltersApplied = "OCI-Filters-Applied"

// headerOCISubject is the "OCI-Subject" header.
// If present on the response, it contains the digest of the subject,
// indicating that Referrers API is supported by the registry.
headerOCISubject = "OCI-Subject"
)

// filterTypeArtifactType is the "artifactType" filter applied on the list of
Expand Down Expand Up @@ -1276,14 +1281,26 @@ func (s *manifestStore) push(ctx context.Context, expected ocispec.Descriptor, c
if resp.StatusCode != http.StatusCreated {
return errutil.ParseErrorResponse(resp)
}
s.checkOCISubjectHeader(resp)
return verifyContentDigest(resp, expected.Digest)
}

// checkOCISubjectHeader checks the "OCI-Subject" header in the response and
// sets referrers capability accordingly.
// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pushing-manifests-with-subject
func (s *manifestStore) checkOCISubjectHeader(resp *http.Response) {
// Referrers capability is not set to false when the subject header is not
// present, as the server may still conform to an older version of the spec
if subjectHeader := resp.Header.Get(headerOCISubject); subjectHeader != "" {
s.repo.SetReferrersCapability(true)
}
}

// pushWithIndexing pushes the manifest content matching the expected descriptor,
// and indexes referrers for the manifest when needed.
func (s *manifestStore) pushWithIndexing(ctx context.Context, expected ocispec.Descriptor, r io.Reader, reference string) error {
switch expected.MediaType {
case spec.MediaTypeArtifactManifest, ocispec.MediaTypeImageManifest:
case spec.MediaTypeArtifactManifest, ocispec.MediaTypeImageManifest, ocispec.MediaTypeImageIndex:
if state := s.repo.loadReferrersState(); state == referrersStateSupported {
// referrers API is available, no client-side indexing needed
return s.push(ctx, expected, r, reference)
Expand All @@ -1299,15 +1316,22 @@ func (s *manifestStore) pushWithIndexing(ctx context.Context, expected ocispec.D
if err := s.push(ctx, expected, bytes.NewReader(manifestJSON), reference); err != nil {
return err
}
// check referrers API availability again after push
if state := s.repo.loadReferrersState(); state == referrersStateSupported {
return nil
}
return s.indexReferrersForPush(ctx, expected, manifestJSON)
default:
return s.push(ctx, expected, r, reference)
}
}

// indexReferrersForPush indexes referrers for image or artifact manifest with
// the subject field on manifest push.
// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#pushing-manifests-with-subject
// indexReferrersForPush indexes referrers for manifests with a subject field
// on manifest push.
//
// References:
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pushing-manifests-with-subject
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#pushing-manifests-with-subject
func (s *manifestStore) indexReferrersForPush(ctx context.Context, desc ocispec.Descriptor, manifestJSON []byte) error {
var subject ocispec.Descriptor
switch desc.MediaType {
Expand All @@ -1333,7 +1357,22 @@ func (s *manifestStore) indexReferrersForPush(ctx context.Context, desc ocispec.
return nil
}
subject = *manifest.Subject
desc.ArtifactType = manifest.Config.MediaType
desc.ArtifactType = manifest.ArtifactType
if desc.ArtifactType == "" {
desc.ArtifactType = manifest.Config.MediaType
}
desc.Annotations = manifest.Annotations
case ocispec.MediaTypeImageIndex:
var manifest ocispec.Index
if err := json.Unmarshal(manifestJSON, &manifest); err != nil {
return fmt.Errorf("failed to decode manifest: %s: %s: %w", desc.Digest, desc.MediaType, err)
}
if manifest.Subject == nil {
// no subject, no indexing needed
return nil
}
subject = *manifest.Subject
desc.ArtifactType = manifest.ArtifactType
desc.Annotations = manifest.Annotations
default:
return nil
Expand All @@ -1353,8 +1392,8 @@ func (s *manifestStore) indexReferrersForPush(ctx context.Context, desc ocispec.
// updateReferrersIndex updates the referrers index for desc referencing subject
// on manifest push and manifest delete.
// References:
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#pushing-manifests-with-subject
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#deleting-manifests
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#pushing-manifests-with-subject
// - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#deleting-manifests
func (s *manifestStore) updateReferrersIndex(ctx context.Context, subject ocispec.Descriptor, change referrerChange) (err error) {
referrersTag := buildReferrersTag(subject)

Expand Down
Loading

0 comments on commit 79d7081

Please sign in to comment.