...

Source file src/github.com/sigstore/cosign/v2/pkg/oci/remote/write.go

Documentation: github.com/sigstore/cosign/v2/pkg/oci/remote

     1  //
     2  // Copyright 2021 The Sigstore Authors.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package remote
    17  
    18  import (
    19  	"bytes"
    20  	"encoding/json"
    21  	"fmt"
    22  	"os"
    23  
    24  	"github.com/google/go-containerregistry/pkg/name"
    25  	v1 "github.com/google/go-containerregistry/pkg/v1"
    26  	"github.com/google/go-containerregistry/pkg/v1/remote"
    27  	"github.com/google/go-containerregistry/pkg/v1/static"
    28  	"github.com/google/go-containerregistry/pkg/v1/types"
    29  	ociexperimental "github.com/sigstore/cosign/v2/internal/pkg/oci/remote"
    30  	"github.com/sigstore/cosign/v2/pkg/oci"
    31  	ctypes "github.com/sigstore/cosign/v2/pkg/types"
    32  )
    33  
    34  // WriteSignedImageIndexImages writes the images within the image index
    35  // This includes the signed image and associated signatures in the image index
    36  // TODO (priyawadhwa@): write the `index.json` itself to the repo as well
    37  // TODO (priyawadhwa@): write the attestations
    38  func WriteSignedImageIndexImages(ref name.Reference, sii oci.SignedImageIndex, opts ...Option) error {
    39  	repo := ref.Context()
    40  	o := makeOptions(repo, opts...)
    41  
    42  	// write the image index if there is one
    43  	ii, err := sii.SignedImageIndex(v1.Hash{})
    44  	if err != nil {
    45  		return fmt.Errorf("signed image index: %w", err)
    46  	}
    47  	if ii != nil {
    48  		if err := remote.WriteIndex(ref, ii, o.ROpt...); err != nil {
    49  			return fmt.Errorf("writing index: %w", err)
    50  		}
    51  	}
    52  
    53  	// write the image if there is one
    54  	si, err := sii.SignedImage(v1.Hash{})
    55  	if err != nil {
    56  		return fmt.Errorf("signed image: %w", err)
    57  	}
    58  	if si != nil {
    59  		if err := remoteWrite(ref, si, o.ROpt...); err != nil {
    60  			return fmt.Errorf("remote write: %w", err)
    61  		}
    62  	}
    63  
    64  	// write the signatures
    65  	sigs, err := sii.Signatures()
    66  	if err != nil {
    67  		return err
    68  	}
    69  	if sigs != nil { // will be nil if there are no associated signatures
    70  		sigsTag, err := SignatureTag(ref, opts...)
    71  		if err != nil {
    72  			return fmt.Errorf("sigs tag: %w", err)
    73  		}
    74  		if err := remoteWrite(sigsTag, sigs, o.ROpt...); err != nil {
    75  			return err
    76  		}
    77  	}
    78  
    79  	// write the attestations
    80  	atts, err := sii.Attestations()
    81  	if err != nil {
    82  		return err
    83  	}
    84  	if atts != nil { // will be nil if there are no associated attestations
    85  		attsTag, err := AttestationTag(ref, opts...)
    86  		if err != nil {
    87  			return fmt.Errorf("sigs tag: %w", err)
    88  		}
    89  		return remoteWrite(attsTag, atts, o.ROpt...)
    90  	}
    91  	return nil
    92  }
    93  
    94  // WriteSignature publishes the signatures attached to the given entity
    95  // into the provided repository.
    96  func WriteSignatures(repo name.Repository, se oci.SignedEntity, opts ...Option) error {
    97  	o := makeOptions(repo, opts...)
    98  
    99  	// Access the signature list to publish
   100  	sigs, err := se.Signatures()
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	// Determine the tag to which these signatures should be published.
   106  	h, err := se.Digest()
   107  	if err != nil {
   108  		return err
   109  	}
   110  	tag := o.TargetRepository.Tag(normalize(h, o.TagPrefix, o.SignatureSuffix))
   111  
   112  	// Write the Signatures image to the tag, with the provided remote.Options
   113  	return remoteWrite(tag, sigs, o.ROpt...)
   114  }
   115  
   116  // WriteAttestations publishes the attestations attached to the given entity
   117  // into the provided repository.
   118  func WriteAttestations(repo name.Repository, se oci.SignedEntity, opts ...Option) error {
   119  	o := makeOptions(repo, opts...)
   120  
   121  	// Access the signature list to publish
   122  	atts, err := se.Attestations()
   123  	if err != nil {
   124  		return err
   125  	}
   126  
   127  	// Determine the tag to which these signatures should be published.
   128  	h, err := se.Digest()
   129  	if err != nil {
   130  		return err
   131  	}
   132  	tag := o.TargetRepository.Tag(normalize(h, o.TagPrefix, o.AttestationSuffix))
   133  
   134  	// Write the Signatures image to the tag, with the provided remote.Options
   135  	return remoteWrite(tag, atts, o.ROpt...)
   136  }
   137  
   138  // WriteSignaturesExperimentalOCI publishes the signatures attached to the given entity
   139  // into the provided repository (using OCI 1.1 methods).
   140  func WriteSignaturesExperimentalOCI(d name.Digest, se oci.SignedEntity, opts ...Option) error {
   141  	o := makeOptions(d.Repository, opts...)
   142  	signTarget := d.String()
   143  	ref, err := name.ParseReference(signTarget, o.NameOpts...)
   144  	if err != nil {
   145  		return err
   146  	}
   147  	desc, err := remote.Head(ref, o.ROpt...)
   148  	if err != nil {
   149  		return err
   150  	}
   151  	sigs, err := se.Signatures()
   152  	if err != nil {
   153  		return err
   154  	}
   155  
   156  	// Write the signature blobs
   157  	s, err := sigs.Get()
   158  	if err != nil {
   159  		return err
   160  	}
   161  	for _, v := range s {
   162  		if err := remote.WriteLayer(d.Repository, v, o.ROpt...); err != nil {
   163  			return err
   164  		}
   165  	}
   166  
   167  	// Write the config
   168  	configBytes, err := sigs.RawConfigFile()
   169  	if err != nil {
   170  		return err
   171  	}
   172  	var configDesc v1.Descriptor
   173  	if err := json.Unmarshal(configBytes, &configDesc); err != nil {
   174  		return err
   175  	}
   176  	configLayer := static.NewLayer(configBytes, configDesc.MediaType)
   177  	if err := remote.WriteLayer(d.Repository, configLayer, o.ROpt...); err != nil {
   178  		return err
   179  	}
   180  
   181  	// Write the manifest containing a subject
   182  	b, err := sigs.RawManifest()
   183  	if err != nil {
   184  		return err
   185  	}
   186  	var m v1.Manifest
   187  	if err := json.Unmarshal(b, &m); err != nil {
   188  		return err
   189  	}
   190  
   191  	artifactType := ociexperimental.ArtifactType("sig")
   192  	m.Config.MediaType = types.MediaType(artifactType)
   193  	m.Subject = desc
   194  	b, err = json.Marshal(&m)
   195  	if err != nil {
   196  		return err
   197  	}
   198  	digest, _, err := v1.SHA256(bytes.NewReader(b))
   199  	if err != nil {
   200  		return err
   201  	}
   202  	targetRef, err := name.ParseReference(fmt.Sprintf("%s/%s@%s", d.RegistryStr(), d.RepositoryStr(), digest.String()))
   203  	if err != nil {
   204  		return err
   205  	}
   206  	// TODO: use ui.Infof
   207  	fmt.Fprintf(os.Stderr, "Uploading signature for [%s] to [%s] with config.mediaType [%s] layers[0].mediaType [%s].\n",
   208  		d.String(), targetRef.String(), artifactType, ctypes.SimpleSigningMediaType)
   209  	return remote.Put(targetRef, &taggableManifest{raw: b, mediaType: m.MediaType}, o.ROpt...)
   210  }
   211  
   212  type taggableManifest struct {
   213  	raw       []byte
   214  	mediaType types.MediaType
   215  }
   216  
   217  func (taggable taggableManifest) RawManifest() ([]byte, error) {
   218  	return taggable.raw, nil
   219  }
   220  
   221  func (taggable taggableManifest) MediaType() (types.MediaType, error) {
   222  	return taggable.mediaType, nil
   223  }
   224  

View as plain text