Skip to content

Commit

Permalink
feat: replace option for same attestation
Browse files Browse the repository at this point in the history
Signed-off-by: Furkan <[email protected]>
Signed-off-by: Batuhan Apaydın <[email protected]>
  • Loading branch information
Dentrax authored and developer-guy committed Nov 12, 2021
1 parent 84c94b6 commit cb65a3d
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 3 deletions.
2 changes: 1 addition & 1 deletion cmd/cosign/cli/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func Attest() *cobra.Command {
}
for _, img := range args {
if err := attest.AttestCmd(cmd.Context(), ko, o.Registry, img, o.Cert, o.NoUpload,
o.Predicate.Path, o.Force, o.Predicate.Type, o.Timeout); err != nil {
o.Predicate.Path, o.Force, o.Predicate.Type,o.Replace, o.Timeout); err != nil {
return errors.Wrapf(err, "signing %s", img)
}
}
Expand Down
14 changes: 12 additions & 2 deletions cmd/cosign/cli/attest/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import (

//nolint
func AttestCmd(ctx context.Context, ko sign.KeyOpts, regOpts options.RegistryOptions, imageRef string, certPath string,
noUpload bool, predicatePath string, force bool, predicateType string, timeout time.Duration) error {
noUpload bool, predicatePath string, force bool, predicateType string, replace bool, timeout time.Duration) error {
// A key file or token is required unless we're in experimental mode!
if options.EnableExperimental() {
if options.NOf(ko.KeyRef, ko.Sk) > 1 {
Expand Down Expand Up @@ -148,8 +148,18 @@ func AttestCmd(ctx context.Context, ko sign.KeyOpts, regOpts options.RegistryOpt
return err
}


signOpts := []mutate.SignOption{
mutate.WithDupeDetector(dd),
}

if replace {
ro := cremote.NewReplaceOp(predicateURI)
signOpts = append(signOpts,mutate.WithReplaceOp(ro))
}

// Attach the attestation to the entity.
newSE, err := mutate.AttachAttestationToEntity(se, sig, mutate.WithDupeDetector(dd))
newSE, err := mutate.AttachAttestationToEntity(se, sig, signOpts...)
if err != nil {
return err
}
Expand Down
5 changes: 5 additions & 0 deletions cmd/cosign/cli/options/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type AttestOptions struct {
NoUpload bool
Force bool
Recursive bool
Replace bool
Timeout time.Duration

Rekor RekorOptions
Expand Down Expand Up @@ -64,6 +65,10 @@ func (o *AttestOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().BoolVarP(&o.Recursive, "recursive", "r", false,
"if a multi-arch image is specified, additionally sign each discrete image")


cmd.Flags().BoolVarP(&o.Replace, "replace", "", false,
"")

cmd.Flags().DurationVar(&o.Timeout, "timeout", time.Second*30,
"HTTP Timeout defaults to 30 seconds")
}
1 change: 1 addition & 0 deletions doc/cosign_attest.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

64 changes: 64 additions & 0 deletions pkg/cosign/remote/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package remote
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"

"github.com/sigstore/cosign/pkg/oci"
"github.com/sigstore/cosign/pkg/oci/mutate"
Expand All @@ -31,11 +33,21 @@ func NewDupeDetector(v signature.Verifier) mutate.DupeDetector {
return &dd{verifier: v}
}

func NewReplaceOp(predicateURI string) mutate.ReplaceOp {
return &ro{predicateURI: predicateURI}
}

type dd struct {
verifier signature.Verifier
}

type ro struct {
predicateURI string
replace bool
}

var _ mutate.DupeDetector = (*dd)(nil)
var _ mutate.ReplaceOp = (*ro)(nil)

func (dd *dd) Find(sigImage oci.Signatures, newSig oci.Signature) (oci.Signature, error) {
newDigest, err := newSig.Digest()
Expand Down Expand Up @@ -97,3 +109,55 @@ LayerLoop:
}
return nil, nil
}

func (r *ro) Replace(signatures oci.Signatures, o oci.Signature) (oci.Signatures, error) {
sigs, err := signatures.Get()
if err != nil {
return nil, err
}

ros := &replaceOCISignatures{Signatures: signatures}

sigsCopy := make([]oci.Signature, 0, len(sigs))
sigsCopy = append(sigsCopy, o)

if len(sigs) == 0 {
ros.attestations = append(ros.attestations, sigsCopy...)
return ros,nil
}

for _, s := range sigs {
var payloadData map[string]interface{}

p, err := s.Payload()
if err != nil {
return nil, fmt.Errorf("could not get payload: %w", err)
}

err = json.Unmarshal(p, &payloadData)
if err != nil {
return nil, fmt.Errorf("unmarshal payload data: %w", err)
}

if r.predicateURI == payloadData["payloadType"] {
fmt.Println("same found")
continue
} else {
fmt.Println("adding")
sigsCopy = append(sigsCopy, s)
}
}

ros.attestations = append(ros.attestations, sigsCopy...)

return ros, nil
}

type replaceOCISignatures struct {
oci.Signatures
attestations []oci.Signature
}

func (r *replaceOCISignatures) Get() ([]oci.Signature, error) {
return r.attestations, nil
}
24 changes: 24 additions & 0 deletions pkg/oci/mutate/mutate.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,13 @@ func (si *signedImage) Attestations() (oci.Signatures, error) {
return base, nil
}
}
if si.so.ro != nil {
if replace, err := si.so.ro.Replace(base, si.att); err != nil {
return nil, err
}else {
return AppendSignatures(replace)
}
}
return AppendSignatures(base, si.att)
}

Expand Down Expand Up @@ -281,6 +288,23 @@ func (sii *signedImageIndex) Attestations() (oci.Signatures, error) {
return base, nil
}
}
if sii.so.ro != nil {
if replace, err := sii.so.ro.Replace(base, sii.att); err != nil {
return nil, err
}else {
//sigs, err := base.Get()
//if err != nil {
// return nil, err
//}
//
//if len(sigs) == 0 {
// return AppendSignatures(replace,sii.att)
//}else{
// return ReplaceSignatures(replace)
//}
return ReplaceSignatures(replace)
}
}
return AppendSignatures(base, sii.att)
}

Expand Down
11 changes: 11 additions & 0 deletions pkg/oci/mutate/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ type DupeDetector interface {
Find(oci.Signatures, oci.Signature) (oci.Signature, error)
}

type ReplaceOp interface {
Replace(oci.Signatures, oci.Signature) (oci.Signatures, error)
}

type SignOption func(*signOpts)

type signOpts struct {
dd DupeDetector
ro ReplaceOp
}

func makeSignOpts(opts ...SignOption) *signOpts {
Expand All @@ -43,3 +48,9 @@ func WithDupeDetector(dd DupeDetector) SignOption {
so.dd = dd
}
}

func WithReplaceOp(ro ReplaceOp) SignOption {
return func(so *signOpts) {
so.ro = ro
}
}
38 changes: 38 additions & 0 deletions pkg/oci/mutate/signatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package mutate

import (
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/sigstore/cosign/pkg/oci"
)
Expand Down Expand Up @@ -46,6 +47,43 @@ func AppendSignatures(base oci.Signatures, sigs ...oci.Signature) (oci.Signature
}, nil
}

// ReplaceSignatures produces a new oci.Signatures provided by the base signatures
// replaced with the new oci.Signatures.
func ReplaceSignatures(base oci.Signatures) (oci.Signatures, error) {
sigs, err := base.Get()
if err != nil {
return nil, err
}
adds := make([]mutate.Addendum, 0, len(sigs))
for _, sig := range sigs {
ann, err := sig.Annotations()
if err != nil {
return nil, err
}
adds = append(adds, mutate.Addendum{
Layer: sig,
Annotations: ann,
})
}
img, err := mutate.Append(empty.Image, adds...)
if err != nil {
return nil, err
}
return &sigAppender{
Image: img,
base: base,
sigs: sigs,
}, nil
}

//func SetSignatures(base oci.Signatures, sigs ...oci.Signature) oci.Signatures {
// return &sigAppender{
// Image: img,
// base: base,
// sigs: sigs,
// }
//}

type sigAppender struct {
v1.Image
base oci.Signatures
Expand Down

0 comments on commit cb65a3d

Please sign in to comment.