Skip to content

Commit

Permalink
Rework methods for pulling artefacts
Browse files Browse the repository at this point in the history
  • Loading branch information
errordeveloper committed Sep 15, 2023
1 parent bc7dcb0 commit 8c87d5c
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 40 deletions.
87 changes: 59 additions & 28 deletions oci/artefact.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,49 +52,80 @@ type ArtefactInfo struct {
Annotations map[string]string
}

func (c *Client) GetArtefact(ctx context.Context, ref string) (*ArtefactInfo, error) {
artefacts, err := c.GetArtefacts(ctx, ref)
func (c *Client) SelectArtefacts(ctx context.Context, ref string, mediaTypes ...string) ([]*ArtefactInfo, error) {
image, layers, err := c.getArtefactLayers(ctx, ref)
if err != nil {
return nil, err
}
if len(artefacts) != 1 {

numMediaTypes := len(mediaTypes)
selectAll := numMediaTypes == 0

selector := make(map[string]struct{}, numMediaTypes)
for _, mediaType := range mediaTypes {
selector[mediaType] = struct{}{}
}

artefacts := []*ArtefactInfo{}
for _, layerDecriptor := range layers {
if !selectAll {
if _, ok := selector[string(layerDecriptor.MediaType)]; !ok {
continue
}
}
info, err := newArtifcatInfoFromLayerDescriptor(image, layerDecriptor)
if err != nil {
return nil, err
}
artefacts = append(artefacts, info)
}
if !selectAll && len(artefacts) == 0 {
return nil, fmt.Errorf("no artefacts found in image %q matching media types %q", ref, mediaTypes)
}
return artefacts, nil
}

func (c *Client) GetSingleArtefact(ctx context.Context, ref string) (*ArtefactInfo, error) {
image, layers, err := c.getArtefactLayers(ctx, ref)
if err != nil {
return nil, err
}
if len(layers) != 1 {
return nil, fmt.Errorf("multiple layers found in image %q", ref)
}
return artefacts[0], nil
return newArtifcatInfoFromLayerDescriptor(image, layers[0])
}

func (c *Client) GetArtefacts(ctx context.Context, ref string) ([]*ArtefactInfo, error) {
func newArtifcatInfoFromLayerDescriptor(image v1.Image, layerDecriptor v1.Descriptor) (*ArtefactInfo, error) {
layer, err := image.LayerByDigest(layerDecriptor.Digest)
if err != nil {
return nil, fmt.Errorf("fetching artefact image failed: %w", err)
}
blob, err := layer.Uncompressed()
if err != nil {
return nil, fmt.Errorf("extracting uncompressed aretefact image failed: %w", err)
}
info := &ArtefactInfo{
ReadCloser: blob,
MediaType: layerDecriptor.MediaType,
Annotations: layerDecriptor.Annotations,
}
return info, nil
}

func (c *Client) getArtefactLayers(ctx context.Context, ref string) (v1.Image, []v1.Descriptor, error) {
image, err := c.Pull(ctx, ref)
if err != nil {
return nil, fmt.Errorf("failed to pull %q: %w", ref, err)
return nil, nil, fmt.Errorf("failed to pull %q: %w", ref, err)
}
manifest, err := image.Manifest()
if err != nil {
return nil, fmt.Errorf("failed to get manifest of %q: %w", ref, err)
return nil, nil, fmt.Errorf("failed to get manifest of %q: %w", ref, err)
}
if len(manifest.Layers) < 1 {
return nil, fmt.Errorf("no layers found in image %q", ref)
}
artefacts := []*ArtefactInfo{}
for _, layerDecriptor := range manifest.Layers {
layer, err := image.LayerByDigest(layerDecriptor.Digest)
if err != nil {
return nil, fmt.Errorf("fetching aretefact image failed: %w", err)
}

blob, err := layer.Uncompressed()
if err != nil {
return nil, fmt.Errorf("extracting uncompressed aretefact image failed: %w", err)
}

info := &ArtefactInfo{
ReadCloser: blob,
MediaType: layerDecriptor.MediaType,
Annotations: layerDecriptor.Annotations,
}
artefacts = append(artefacts, info)
return nil, nil, fmt.Errorf("no layers found in image %q", ref)
}
return artefacts, nil
return image, manifest.Layers, nil
}

// based on https://github.com/fluxcd/pkg/blob/2a323d771e17af02dee2ccbbb9b445b78ab048e5/oci/client/push.go
Expand Down
4 changes: 0 additions & 4 deletions oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ func (c *Client) Index(ctx context.Context, ref string) (*v1.IndexManifest, erro
return v1.ParseIndexManifest(bytes.NewReader(data))
}

func (c *Client) PullArtefact(ctx context.Context, ref, dir string) (*Metadata, error) {
return c.Client.Pull(ctx, ref, dir)
}

func (c *Client) Pull(ctx context.Context, ref string) (v1.Image, error) {
return crane.Pull(ref, c.withContext(ctx)...)
}
Expand Down
12 changes: 4 additions & 8 deletions tape/app/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,16 +168,12 @@ func (c *TapeImagesCommand) CollectInfo(ctx context.Context, images *types.Image
}

ref := image.OriginalName + "@" + digest
artefacts, err := client.GetArtefacts(ctx, ref)
artefacts, err := client.SelectArtefacts(ctx, ref, "application/vnd.in-toto+json")
if err != nil {
return fmt.Errorf("failed to fetch inline attestation: %w", err)
}

for _, artefact := range artefacts {
if artefact.MediaType != "application/vnd.in-toto+json" {
return fmt.Errorf("unexpected media type of attestation in %q: %s", ref, artefact.MediaType)
}

doc := document{
MediaType: string(artefact.MediaType),
Object: &in_toto.Statement{},
Expand Down Expand Up @@ -225,7 +221,7 @@ func (c *TapeImagesCommand) CollectInfo(ctx context.Context, images *types.Image
ref := relatedImage.Ref(true)
switch {
case strings.HasSuffix(relatedImage.OriginalTag, ".att"):
artefact, err := client.GetArtefact(ctx, ref)
artefact, err := client.GetSingleArtefact(ctx, ref)
if err != nil {
return nil, fmt.Errorf("failed to fetch external attestation: %w", err)
}
Expand All @@ -245,7 +241,7 @@ func (c *TapeImagesCommand) CollectInfo(ctx context.Context, images *types.Image

info.ExternalAttestations[ref] = doc
case strings.HasSuffix(relatedImage.OriginalTag, ".sbom"):
artefact, err := client.GetArtefact(ctx, ref)
artefact, err := client.GetSingleArtefact(ctx, ref)
if err != nil {
return nil, fmt.Errorf("failed to fetch external attestation: %w", err)
}
Expand All @@ -272,7 +268,7 @@ func (c *TapeImagesCommand) CollectInfo(ctx context.Context, images *types.Image

info.ExternalSBOMs[ref] = doc
case strings.HasSuffix(relatedImage.OriginalTag, ".sig"):
artefact, err := client.GetArtefact(ctx, ref)
artefact, err := client.GetSingleArtefact(ctx, ref)
if err != nil {
return nil, fmt.Errorf("failed to fetch external signature: %w", err)
}
Expand Down

0 comments on commit 8c87d5c

Please sign in to comment.