diff --git a/cmd/docker-nv2/pull.go b/cmd/docker-nv2/pull.go index 1b9545484..035ba173c 100644 --- a/cmd/docker-nv2/pull.go +++ b/cmd/docker-nv2/pull.go @@ -4,10 +4,13 @@ import ( "context" "errors" "fmt" + "os" "github.com/docker/distribution/reference" "github.com/notaryproject/notary/v2" + "github.com/notaryproject/nv2/cmd/docker-nv2/config" "github.com/notaryproject/nv2/cmd/docker-nv2/docker" + ios "github.com/notaryproject/nv2/internal/os" "github.com/opencontainers/go-digest" oci "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" @@ -62,11 +65,7 @@ func verifyRemoteImage(ctx context.Context, ref string) (string, error) { fmt.Println(manifestRef, "digest:", manifestDesc.Digest, "size:", manifestDesc.Size) fmt.Println("Looking up for signatures") - client, err := docker.GetSignatureRepository(ctx, ref) - if err != nil { - return "", err - } - sigDigests, err := client.Lookup(ctx, manifestDesc.Digest) + sigDigests, err := downloadSignatures(ctx, ref, manifestDesc.Digest) if err != nil { return "", err } @@ -77,13 +76,7 @@ func verifyRemoteImage(ctx context.Context, ref string) (string, error) { fmt.Println("Found", n, "signatures") } - sigDigest, originRefs, err := verifySignatures( - ctx, - service, - client, - sigDigests, - manifestDesc, - ) + sigDigest, originRefs, err := verifySignatures(ctx, service, sigDigests, manifestDesc) if err != nil { return "", fmt.Errorf("none of the signatures are valid: %v", err) } @@ -98,19 +91,48 @@ func verifyRemoteImage(ctx context.Context, ref string) (string, error) { return fmt.Sprintf("%s@%s", named.Name(), manifestDesc.Digest), nil } +func downloadSignatures(ctx context.Context, ref string, manifestDigest digest.Digest) ([]digest.Digest, error) { + client, err := docker.GetSignatureRepository(ctx, ref) + if err != nil { + return nil, err + } + sigDigests, err := client.Lookup(ctx, manifestDigest) + if err != nil { + return nil, err + } + + for _, sigDigest := range sigDigests { + sigPath := config.SignaturePath(manifestDigest, sigDigest) + if _, err := os.Stat(sigPath); err == nil { + continue + } else if !os.IsNotExist(err) { + return nil, err + } + + sig, err := client.Get(ctx, sigDigest) + if err != nil { + return nil, err + } + if err := ios.WriteFile(sigPath, sig); err != nil { + return nil, err + } + } + + return sigDigests, nil +} + func verifySignatures( ctx context.Context, service notary.SigningService, - client notary.SignatureRepository, digests []digest.Digest, desc oci.Descriptor, ) (digest.Digest, []string, error) { var lastError error for _, digest := range digests { - sig, err := client.Get(ctx, digest) + path := config.SignaturePath(desc.Digest, digest) + sig, err := os.ReadFile(path) if err != nil { - lastError = err - continue + return "", nil, err } references, err := service.Verify(ctx, desc, sig)