Skip to content

Commit

Permalink
Merge branch 'notaryproject:main' into errMsg
Browse files Browse the repository at this point in the history
  • Loading branch information
Two-Hearts authored Sep 15, 2023
2 parents 2fe40b3 + 60d9cdc commit 5f49209
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 6 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/veraison/go-cose v1.1.0
golang.org/x/crypto v0.13.0
golang.org/x/mod v0.12.0
oras.land/oras-go/v2 v2.2.1
oras.land/oras-go/v2 v2.3.0
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
oras.land/oras-go/v2 v2.2.1 h1:3VJTYqy5KfelEF9c2jo1MLSpr+TM3mX8K42wzZcd6qE=
oras.land/oras-go/v2 v2.2.1/go.mod h1:GeAwLuC4G/JpNwkd+bSZ6SkDMGaaYglt6YK2WvZP7uQ=
oras.land/oras-go/v2 v2.3.0 h1:lqX1aXdN+DAmDTKjiDyvq85cIaI4RkIKp/PghWlAGIU=
oras.land/oras-go/v2 v2.3.0/go.mod h1:GeAwLuC4G/JpNwkd+bSZ6SkDMGaaYglt6YK2WvZP7uQ=
49 changes: 46 additions & 3 deletions registry/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
package registry

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"os"

Expand All @@ -24,6 +26,7 @@ import (
"oras.land/oras-go/v2"
"oras.land/oras-go/v2/content"
"oras.land/oras-go/v2/content/oci"
"oras.land/oras-go/v2/errdef"
"oras.land/oras-go/v2/registry"
)

Expand All @@ -32,6 +35,19 @@ const (
maxManifestSizeLimit = 4 * 1024 * 1024 // 4 MiB
)

var (
// notationEmptyConfigDesc is the descriptor of an empty notation manifest
// config
// reference: https://github.com/notaryproject/specifications/blob/v1.0.0/specs/signature-specification.md#storage
notationEmptyConfigDesc = ocispec.Descriptor{
MediaType: ArtifactTypeNotation,
Digest: ocispec.DescriptorEmptyJSON.Digest,
Size: ocispec.DescriptorEmptyJSON.Size,
}
// notationEmptyConfigData is the data of an empty notation manifest config
notationEmptyConfigData = ocispec.DescriptorEmptyJSON.Data
)

// RepositoryOptions provides user options when creating a Repository
// it is kept for future extensibility
type RepositoryOptions struct{}
Expand Down Expand Up @@ -187,13 +203,40 @@ func (c *repositoryClient) getSignatureBlobDesc(ctx context.Context, sigManifest

// uploadSignatureManifest uploads the signature manifest to the registry
func (c *repositoryClient) uploadSignatureManifest(ctx context.Context, subject, blobDesc ocispec.Descriptor, annotations map[string]string) (ocispec.Descriptor, error) {
opts := oras.PackOptions{
configDesc, err := pushNotationManifestConfig(ctx, c.GraphTarget)
if err != nil {
return ocispec.Descriptor{}, fmt.Errorf("failed to push notation manifest config: %w", err)
}

opts := oras.PackManifestOptions{
Subject: &subject,
ManifestAnnotations: annotations,
PackImageManifest: true,
Layers: []ocispec.Descriptor{blobDesc},
ConfigDescriptor: &configDesc,
}

return oras.PackManifest(ctx, c.GraphTarget, oras.PackManifestVersion1_1_RC4, "", opts)
}

// pushNotationManifestConfig pushes an empty notation manifest config, if it
// doesn't exist.
//
// if the config exists, it returns the descriptor of the config without error.
func pushNotationManifestConfig(ctx context.Context, pusher content.Storage) (ocispec.Descriptor, error) {
// check if the config exists
exists, err := pusher.Exists(ctx, notationEmptyConfigDesc)
if err != nil {
return ocispec.Descriptor{}, fmt.Errorf("unable to verify existence: %s: %s. Details: %w", notationEmptyConfigDesc.Digest.String(), notationEmptyConfigDesc.MediaType, err)
}
if exists {
return notationEmptyConfigDesc, nil
}

return oras.Pack(ctx, c.GraphTarget, ArtifactTypeNotation, []ocispec.Descriptor{blobDesc}, opts)
// return nil if the config pushed successfully or it already exists
if err := pusher.Push(ctx, notationEmptyConfigDesc, bytes.NewReader(notationEmptyConfigData)); err != nil && !errors.Is(err, errdef.ErrAlreadyExists) {
return ocispec.Descriptor{}, fmt.Errorf("unable to push: %s: %s. Details: %w", notationEmptyConfigDesc.Digest.String(), notationEmptyConfigDesc.MediaType, err)
}
return notationEmptyConfigDesc, nil
}

// signatureReferrers returns referrer nodes of desc in target filtered by
Expand Down
6 changes: 6 additions & 0 deletions registry/repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (

const (
zeroDigest = "sha256:0000000000000000000000000000000000000000000000000000000000000000"
emptyConfigDigest = "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
validDigest = "6c3c624b58dbbcd3c0dd82b4c53f04194d1247c6eebdaab7c610cf7d66709b3b"
validDigest2 = "1834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f2"
invalidDigest = "invaliddigest"
Expand Down Expand Up @@ -129,6 +130,11 @@ func (c mockRemoteClient) Do(req *http.Request) (*http.Response, error) {
"Docker-Content-Digest": {validDigestWithAlgo2},
},
}, nil
case "/v2/test/blobs/" + emptyConfigDigest:
return &http.Response{
StatusCode: http.StatusNotFound,
Body: io.NopCloser(bytes.NewReader([]byte{})),
}, nil
case "/v2/test/manifests/" + invalidDigest:
return &http.Response{}, fmt.Errorf(errMsg)
case "v2/test/manifest/" + validDigest2:
Expand Down

0 comments on commit 5f49209

Please sign in to comment.