...

Source file src/github.com/sigstore/cosign/v2/pkg/oci/remote/remote_test.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  	"errors"
    20  	"io"
    21  	"strings"
    22  	"testing"
    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/types"
    28  )
    29  
    30  func TestTagMethods(t *testing.T) {
    31  	rg := remoteGet
    32  	defer func() {
    33  		remoteGet = rg
    34  	}()
    35  	remoteGet = func(_ name.Reference, _ ...remote.Option) (*remote.Descriptor, error) {
    36  		return &remote.Descriptor{
    37  			Descriptor: v1.Descriptor{
    38  				Digest: v1.Hash{
    39  					Algorithm: "sha256",
    40  					// As of 2021-09-20:
    41  					// crane digest gcr.io/distroless/static:nonroot
    42  					Hex: "be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4",
    43  				},
    44  			},
    45  		}, nil
    46  	}
    47  
    48  	tests := []struct {
    49  		name string
    50  		fn   func(name.Reference, ...Option) (name.Tag, error)
    51  		ref  name.Reference
    52  		opts []Option
    53  		want name.Reference // Always a tag, but shorter to write things.
    54  	}{{
    55  		name: "signature passed a tag",
    56  		fn:   SignatureTag,
    57  		ref:  name.MustParseReference("gcr.io/distroless/static:nonroot"),
    58  		want: name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.sig"),
    59  	}, {
    60  		name: "signature passed a tag (w/ custom suffix)",
    61  		fn:   SignatureTag,
    62  		ref:  name.MustParseReference("gcr.io/distroless/static:nonroot"),
    63  		opts: []Option{WithSignatureSuffix("snowflake")},
    64  		want: name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.snowflake"),
    65  	}, {
    66  		name: "signature passed a digest",
    67  		fn:   SignatureTag,
    68  		ref:  name.MustParseReference("gcr.io/distroless/static@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4"),
    69  		want: name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.sig"),
    70  	}, {
    71  		name: "attestation passed a tag",
    72  		fn:   AttestationTag,
    73  		ref:  name.MustParseReference("gcr.io/distroless/static:nonroot"),
    74  		want: name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.att"),
    75  	}, {
    76  		name: "attestation passed a tag (w/ custom suffix)",
    77  		fn:   AttestationTag,
    78  		ref:  name.MustParseReference("gcr.io/distroless/static:nonroot"),
    79  		opts: []Option{WithAttestationSuffix("snowflake")},
    80  		want: name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.snowflake"),
    81  	}, {
    82  		name: "attestation passed a digest",
    83  		fn:   AttestationTag,
    84  		ref:  name.MustParseReference("gcr.io/distroless/static@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4"),
    85  		want: name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.att"),
    86  	}, {
    87  		name: "sbom passed a tag",
    88  		fn:   SBOMTag,
    89  		ref:  name.MustParseReference("gcr.io/distroless/static:nonroot"),
    90  		want: name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.sbom"),
    91  	}, {
    92  		name: "sbom passed a tag (w/ custom suffix)",
    93  		fn:   SBOMTag,
    94  		ref:  name.MustParseReference("gcr.io/distroless/static:nonroot"),
    95  		opts: []Option{WithSBOMSuffix("snowflake")},
    96  		want: name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.snowflake"),
    97  	}, {
    98  		name: "sbom passed a digest",
    99  		fn:   SBOMTag,
   100  		ref:  name.MustParseReference("gcr.io/distroless/static@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4"),
   101  		want: name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.sbom"),
   102  	}}
   103  
   104  	for _, test := range tests {
   105  		t.Run(test.name, func(t *testing.T) {
   106  			got, err := test.fn(test.ref, test.opts...)
   107  			if err != nil {
   108  				t.Fatalf("fn() = %v", err)
   109  			}
   110  			if got.String() != test.want.String() {
   111  				t.Errorf("fn() = %s, wanted %s", got.String(), test.want.String())
   112  			}
   113  		})
   114  	}
   115  }
   116  
   117  func TestTagMethodErrors(t *testing.T) {
   118  	rg := remoteGet
   119  	defer func() {
   120  		remoteGet = rg
   121  	}()
   122  	errRemoteGet := errors.New("remote.Get failure")
   123  	remoteGet = func(_ name.Reference, _ ...remote.Option) (*remote.Descriptor, error) {
   124  		return nil, errRemoteGet
   125  	}
   126  
   127  	tests := []struct {
   128  		name string
   129  		fn   func(name.Reference, ...Option) (name.Tag, error)
   130  		ref  name.Reference
   131  		want error
   132  	}{
   133  		{
   134  			name: "signature passed a tag",
   135  			fn:   SignatureTag,
   136  			ref:  name.MustParseReference("gcr.io/distroless/static:nonroot"),
   137  			want: errRemoteGet,
   138  		},
   139  	}
   140  
   141  	for _, test := range tests {
   142  		t.Run(test.name, func(t *testing.T) {
   143  			tag, got := test.fn(test.ref)
   144  			if got == nil {
   145  				t.Fatalf("fn() = %v, wanted %v", tag, test.want)
   146  			}
   147  			if got.Error() != test.want.Error() {
   148  				t.Errorf("fn() = %v, wanted %v", got, test.want)
   149  			}
   150  		})
   151  	}
   152  }
   153  
   154  func TestDockercontentDigest(t *testing.T) {
   155  	rg := remoteGet
   156  	defer func() {
   157  		remoteGet = rg
   158  	}()
   159  	remoteGet = func(_ name.Reference, _ ...remote.Option) (*remote.Descriptor, error) {
   160  		return &remote.Descriptor{
   161  			Descriptor: v1.Descriptor{
   162  				Digest: v1.Hash{
   163  					Algorithm: "sha256",
   164  					// As of 2021-09-20:
   165  					// crane digest gcr.io/distroless/static:nonroot
   166  					Hex: "be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4",
   167  				},
   168  			},
   169  		}, nil
   170  	}
   171  
   172  	repo, err := name.NewRepository("gcr.io/distroless/static")
   173  	if err != nil {
   174  		t.Fatalf("unexpected error: %v", err)
   175  	}
   176  	tests := []struct {
   177  		name    string
   178  		tag     name.Tag
   179  		wantTag name.Tag
   180  	}{
   181  		{
   182  			name:    "docker content digest for tag",
   183  			tag:     name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.sig").(name.Tag),
   184  			wantTag: repo.Tag("sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4"),
   185  		},
   186  		{
   187  			name:    "docker content digest for attestation",
   188  			tag:     name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.att").(name.Tag),
   189  			wantTag: repo.Tag("sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4"),
   190  		},
   191  		{
   192  			name:    "docker content digest for SBOM",
   193  			tag:     name.MustParseReference("gcr.io/distroless/static:sha256-be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4.sbom").(name.Tag),
   194  			wantTag: repo.Tag("sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4"),
   195  		},
   196  	}
   197  	for _, test := range tests {
   198  		t.Run(test.name, func(t *testing.T) {
   199  			gotTag, err := DockerContentDigest(test.tag)
   200  			if err != nil {
   201  				t.Fatalf("fn() = %v", err)
   202  			}
   203  			if gotTag != test.wantTag {
   204  				t.Errorf("fn() = %s, wanted %s", gotTag.String(), test.wantTag.String())
   205  			}
   206  		})
   207  	}
   208  }
   209  
   210  func TestPayload(t *testing.T) {
   211  	tests := []struct {
   212  		name      string
   213  		size      int64
   214  		env       map[string]string
   215  		wantError error
   216  	}{
   217  		{
   218  			name:      "within default limit",
   219  			size:      1000,
   220  			wantError: nil,
   221  		},
   222  		{
   223  			name:      "excceds default limit",
   224  			size:      1073741824,
   225  			wantError: errors.New("size of layer (1073741824) exceeded the limit (134217728)"),
   226  		},
   227  		{
   228  			name:      "exceeds overridden limit",
   229  			size:      5120,
   230  			env:       map[string]string{"COSIGN_MAX_ATTACHMENT_SIZE": "1KB"},
   231  			wantError: errors.New("size of layer (5120) exceeded the limit (1000)"),
   232  		},
   233  		{
   234  			name: "within overridden limit",
   235  			size: 5120,
   236  			env:  map[string]string{"COSIGN_MAX_ATTACHMENT_SIZE": "10KB"},
   237  		},
   238  	}
   239  	for _, test := range tests {
   240  		t.Run(test.name, func(t *testing.T) {
   241  			for k, v := range test.env {
   242  				t.Setenv(k, v)
   243  			}
   244  			a := attached{
   245  				layer: &mockLayer{
   246  					size: test.size,
   247  				},
   248  			}
   249  			_, err := a.Payload()
   250  			if test.wantError != nil && test.wantError.Error() != err.Error() {
   251  				t.Fatalf("Payload() = %v, wanted %v", err, test.wantError)
   252  			}
   253  			if test.wantError == nil && err != nil {
   254  				t.Fatalf("Payload() = %v, wanted %v", err, test.wantError)
   255  			}
   256  		})
   257  	}
   258  }
   259  
   260  type mockLayer struct {
   261  	size int64
   262  }
   263  
   264  func (m *mockLayer) Compressed() (io.ReadCloser, error) {
   265  	return io.NopCloser(strings.NewReader("test payload")), nil
   266  }
   267  
   268  func (m *mockLayer) Size() (int64, error) {
   269  	return m.size, nil
   270  }
   271  
   272  func (m *mockLayer) Digest() (v1.Hash, error)             { panic("not implemented") }
   273  func (m *mockLayer) DiffID() (v1.Hash, error)             { panic("not implemented") }
   274  func (m *mockLayer) Uncompressed() (io.ReadCloser, error) { panic("not implemented") }
   275  func (m *mockLayer) MediaType() (types.MediaType, error)  { panic("not implemented") }
   276  

View as plain text