...

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

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

     1  // Copyright 2023 the Sigstore Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package platform
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	v1 "github.com/google/go-containerregistry/pkg/v1"
    22  	"github.com/sigstore/cosign/v2/pkg/oci"
    23  )
    24  
    25  type List []struct {
    26  	Hash     v1.Hash
    27  	Platform *v1.Platform
    28  }
    29  
    30  func (pl *List) String() string {
    31  	r := []string{}
    32  	for _, p := range *pl {
    33  		r = append(r, p.Platform.String())
    34  	}
    35  	return strings.Join(r, ", ")
    36  }
    37  
    38  func GetIndexPlatforms(idx oci.SignedImageIndex) (List, error) {
    39  	im, err := idx.IndexManifest()
    40  	if err != nil {
    41  		return nil, fmt.Errorf("fetching index manifest: %w", err)
    42  	}
    43  
    44  	platforms := List{}
    45  	for _, m := range im.Manifests {
    46  		if m.Platform == nil {
    47  			continue
    48  		}
    49  		platforms = append(platforms, struct {
    50  			Hash     v1.Hash
    51  			Platform *v1.Platform
    52  		}{m.Digest, m.Platform})
    53  	}
    54  	return platforms, nil
    55  }
    56  
    57  // matchPlatform filters a list of platforms returning only those matching
    58  // a base. "Based" on ko's internal equivalent while it moves to GGCR.
    59  // https://github.com/google/ko/blob/e6a7a37e26d82a8b2bb6df991c5a6cf6b2728794/pkg/build/gobuild.go#L1020
    60  func matchPlatform(base *v1.Platform, list List) List {
    61  	ret := List{}
    62  	for _, p := range list {
    63  		if base.OS != "" && base.OS != p.Platform.OS {
    64  			continue
    65  		}
    66  		if base.Architecture != "" && base.Architecture != p.Platform.Architecture {
    67  			continue
    68  		}
    69  		if base.Variant != "" && base.Variant != p.Platform.Variant {
    70  			continue
    71  		}
    72  
    73  		if base.OSVersion != "" && p.Platform.OSVersion != base.OSVersion {
    74  			if base.OS != "windows" {
    75  				continue
    76  			} else { //nolint: revive
    77  				if pcount, bcount := strings.Count(base.OSVersion, "."), strings.Count(p.Platform.OSVersion, "."); pcount == 2 && bcount == 3 {
    78  					if base.OSVersion != p.Platform.OSVersion[:strings.LastIndex(p.Platform.OSVersion, ".")] {
    79  						continue
    80  					}
    81  				} else {
    82  					continue
    83  				}
    84  			}
    85  		}
    86  		ret = append(ret, p)
    87  	}
    88  
    89  	return ret
    90  }
    91  
    92  func SignedEntityForPlatform(se oci.SignedEntity, platform string) (oci.SignedEntity, error) {
    93  	if platform == "" {
    94  		// Copy all platforms
    95  		return se, nil
    96  	}
    97  	idx, isIndex := se.(oci.SignedImageIndex)
    98  
    99  	// We only allow --platform on multiarch indexes
   100  	if !isIndex {
   101  		return nil, fmt.Errorf("specified reference is not a multiarch image")
   102  	}
   103  
   104  	targetPlatform, err := v1.ParsePlatform(platform)
   105  	if err != nil {
   106  		return nil, fmt.Errorf("parsing platform: %w", err)
   107  	}
   108  	platforms, err := GetIndexPlatforms(idx)
   109  	if err != nil {
   110  		return nil, fmt.Errorf("getting available platforms: %w", err)
   111  	}
   112  
   113  	platforms = matchPlatform(targetPlatform, platforms)
   114  	if len(platforms) == 0 {
   115  		return nil, fmt.Errorf("unable to find an entity for %s", targetPlatform.String())
   116  	}
   117  	if len(platforms) > 1 {
   118  		return nil, fmt.Errorf(
   119  			"platform spec matches more than one image architecture: %s",
   120  			platforms.String(),
   121  		)
   122  	}
   123  
   124  	nse, err := idx.SignedImage(platforms[0].Hash)
   125  	if err != nil {
   126  		return nil, fmt.Errorf("searching for %s image: %w", platforms[0].Hash.String(), err)
   127  	}
   128  	if nse == nil {
   129  		return nil, fmt.Errorf("unable to find image %s", platforms[0].Hash.String())
   130  	}
   131  
   132  	return nse, nil
   133  }
   134  

View as plain text