github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/client/download_sbom.go (about)

     1  package client
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/buildpacks/lifecycle/layers"
     7  	"github.com/buildpacks/lifecycle/platform"
     8  	"github.com/buildpacks/lifecycle/platform/files"
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/buildpacks/pack/pkg/dist"
    12  	"github.com/buildpacks/pack/pkg/image"
    13  )
    14  
    15  type DownloadSBOMOptions struct {
    16  	Daemon         bool
    17  	DestinationDir string
    18  }
    19  
    20  // Deserialize just the subset of fields we need to avoid breaking changes
    21  type sbomMetadata struct {
    22  	BOM *files.LayerMetadata `json:"sbom" toml:"sbom"`
    23  }
    24  
    25  func (s *sbomMetadata) isMissing() bool {
    26  	return s == nil ||
    27  		s.BOM == nil ||
    28  		s.BOM.SHA == ""
    29  }
    30  
    31  const (
    32  	Local = iota
    33  	Remote
    34  )
    35  
    36  // DownloadSBOM pulls SBOM layer from an image.
    37  // It reads the SBOM metadata of an image then
    38  // pulls the corresponding diffId, if it exists
    39  func (c *Client) DownloadSBOM(name string, options DownloadSBOMOptions) error {
    40  	img, err := c.imageFetcher.Fetch(context.Background(), name, image.FetchOptions{Daemon: options.Daemon, PullPolicy: image.PullNever})
    41  	if err != nil {
    42  		if errors.Cause(err) == image.ErrNotFound {
    43  			c.logger.Warnf("if the image is saved on a registry run with the flag '--remote', for example: 'pack sbom download --remote %s'", name)
    44  			return errors.Wrapf(image.ErrNotFound, "image '%s' cannot be found", name)
    45  		}
    46  		return err
    47  	}
    48  
    49  	var sbomMD sbomMetadata
    50  	if _, err := dist.GetLabel(img, platform.LifecycleMetadataLabel, &sbomMD); err != nil {
    51  		return err
    52  	}
    53  
    54  	if sbomMD.isMissing() {
    55  		return errors.Errorf("could not find SBoM information on '%s'", name)
    56  	}
    57  
    58  	rc, err := img.GetLayer(sbomMD.BOM.SHA)
    59  	if err != nil {
    60  		return err
    61  	}
    62  	defer rc.Close()
    63  
    64  	return layers.Extract(rc, options.DestinationDir)
    65  }