Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions pkg/oci/remote/signatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/partial"
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
payloadsize "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload/size"
"github.com/sigstore/cosign/v3/pkg/oci"
"github.com/sigstore/cosign/v3/pkg/oci/empty"
"github.com/sigstore/cosign/v3/pkg/oci/internal/signature"
Expand Down Expand Up @@ -72,6 +73,13 @@ func Bundle(ref name.Reference, opts ...Option) (*sgbundle.Bundle, error) {
if !strings.HasPrefix(string(mediaType), "application/vnd.dev.sigstore.bundle") {
return nil, errors.New("expected bundle layer")
}
size, err := layers[0].Size()
if err != nil {
return nil, err
}
if err := payloadsize.CheckSize(uint64(size)); err != nil {
return nil, err
}
layer0, err := layers[0].Uncompressed()
if err != nil {
return nil, err
Expand Down
45 changes: 45 additions & 0 deletions pkg/oci/remote/signatures_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,61 @@ package remote

import (
"errors"
"io"
"net/http"
"strings"
"testing"

"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/fake"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
"github.com/google/go-containerregistry/pkg/v1/types"
)

// oversizeLayer reports a huge Size() but its Uncompressed() must never be
// reached once Bundle() enforces the size cap.
type oversizeLayer struct {
size int64
}

func (l *oversizeLayer) Digest() (v1.Hash, error) { return v1.Hash{}, nil }
func (l *oversizeLayer) DiffID() (v1.Hash, error) { return v1.Hash{}, nil }
func (l *oversizeLayer) Size() (int64, error) { return l.size, nil }
func (l *oversizeLayer) MediaType() (types.MediaType, error) {
return "application/vnd.dev.sigstore.bundle+json", nil
}
func (l *oversizeLayer) Compressed() (io.ReadCloser, error) {
return nil, errors.New("Compressed should not be called")
}
func (l *oversizeLayer) Uncompressed() (io.ReadCloser, error) {
return nil, errors.New("Uncompressed should not be called once size is capped")
}

func TestBundleRejectsOversizeLayer(t *testing.T) {
ri := remote.Image

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to be patching other modules as part of a unit test - maybe this would be better off in e2e_test.go where we have a container registry running?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved it to e2e_test.go as TestBundleLayerSizeCap, so it runs against the real registry from reg(t) and drops the fake oversizeLayer / remoteImage patching. It signs a new-format bundle, then lowers COSIGN_MAX_ATTACHMENT_SIZE below the layer size and checks ociremote.Bundle returns the limit error. Fails on main (the read path is reached), passes with the cap in place.

t.Cleanup(func() {
remoteImage = ri
})

remoteImage = func(_ name.Reference, _ ...remote.Option) (v1.Image, error) {
return &fake.FakeImage{
LayersStub: func() ([]v1.Layer, error) {
return []v1.Layer{&oversizeLayer{size: 200 * 1024 * 1024}}, nil
},
}, nil
}

_, err := Bundle(name.MustParseReference("gcr.io/distroless/static:sha256-deadbeef.sig"))
if err == nil {
t.Fatal("Bundle() = nil, wanted size limit error")
}
if !strings.Contains(err.Error(), "exceeded the limit") {
t.Fatalf("Bundle() = %v, wanted size limit error", err)
}
}

func TestSignaturesErrors(t *testing.T) {
ri := remote.Image
t.Cleanup(func() {
Expand Down