Skip to content

Commit

Permalink
support user customizable predicates (#847)
Browse files Browse the repository at this point in the history
* support user customizable predicates

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* fix fmt

Signed-off-by: Jim Bugwadia <jim@nirmata.com>

* gen docs

Signed-off-by: Jim Bugwadia <jim@nirmata.com>
  • Loading branch information
JimBugwadia committed Oct 5, 2021
1 parent 75c326b commit e6d08d6
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 17 deletions.
7 changes: 6 additions & 1 deletion cmd/cosign/cli/attest/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"net/url"
"os"

"github.com/google/go-containerregistry/pkg/name"
Expand Down Expand Up @@ -74,7 +75,11 @@ func AttestCmd(ctx context.Context, ko sign.KeyOpts, regOpts options.RegistryOpt

predicateURI, ok := predicateTypeMap[predicateType]
if !ok {
return fmt.Errorf("invalid predicate type: %s", predicateType)
if _, err := url.ParseRequestURI(predicateType); err != nil {
return fmt.Errorf("invalid predicate type: %s", predicateType)
} else {
predicateURI = predicateType
}
}

ref, err := name.ParseReference(imageRef)
Expand Down
2 changes: 1 addition & 1 deletion cmd/cosign/cli/options/predicate.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ func (o *PredicateOptions) AddFlags(cmd *cobra.Command) {
"path to the predicate file.")

cmd.Flags().StringVar(&o.Type, "type", "custom",
"specify predicate type (default: custom) (slsaprovenance|link|spdx)")
"specify a predicate type (slsaprovenance|link|spdx|custom) or an URI")
}
2 changes: 1 addition & 1 deletion doc/cosign_attest.md

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

56 changes: 42 additions & 14 deletions pkg/cosign/attestation/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const (

// CosignPredicate specifies the format of the Custom Predicate.
type CosignPredicate struct {
Data string
Data interface{}
Timestamp string
}

Expand Down Expand Up @@ -63,22 +63,32 @@ func GenerateStatement(opts GenerateOpts) (interface{}, error) {
return nil, err
}
switch opts.Type {
case "custom":
if opts.Time == nil {
opts.Time = time.Now
}
now := opts.Time()
stamp := now.UTC().Format(time.RFC3339)
return generateCustomStatement(rawPayload, opts.Digest, opts.Repo, stamp)
case "slsaprovenance":
return generateSLSAProvenanceStatement(rawPayload, opts.Digest, opts.Repo)
case "spdx":
return generateSPDXStatement(rawPayload, opts.Digest, opts.Repo)
case "link":
return generateLinkStatement(rawPayload, opts.Digest, opts.Repo)
default:
return nil, fmt.Errorf("we don't know this predicate type: %q", opts.Type)
stamp := timestamp(opts)
predicateType := customType(opts)
return generateCustomStatement(rawPayload, predicateType, opts.Digest, opts.Repo, stamp)
}
}

func timestamp(opts GenerateOpts) string {
if opts.Time == nil {
opts.Time = time.Now
}
now := opts.Time()
return now.UTC().Format(time.RFC3339)
}

func customType(opts GenerateOpts) string {
if opts.Type != "custom" {
return opts.Type
}
return CosignCustomProvenanceV01
}

func generateStatementHeader(digest, repo, predicateType string) in_toto.StatementHeader {
Expand All @@ -97,14 +107,32 @@ func generateStatementHeader(digest, repo, predicateType string) in_toto.Stateme
}

//
func generateCustomStatement(rawPayload []byte, digest, repo, timestamp string) (interface{}, error) {
func generateCustomStatement(rawPayload []byte, customType, digest, repo, timestamp string) (interface{}, error) {
payload, err := generateCustomPredicate(rawPayload, customType, timestamp)
if err != nil {
return nil, err
}

return in_toto.Statement{
StatementHeader: generateStatementHeader(digest, repo, CosignCustomProvenanceV01),
Predicate: CosignPredicate{
StatementHeader: generateStatementHeader(digest, repo, customType),
Predicate: payload,
}, nil
}

func generateCustomPredicate(rawPayload []byte, customType, timestamp string) (interface{}, error) {
if customType == CosignCustomProvenanceV01 {
return &CosignPredicate{
Data: string(rawPayload),
Timestamp: timestamp,
},
}, nil
}, nil
}

var result map[string]interface{}
if err := json.Unmarshal(rawPayload, &result); err != nil {
return nil, errors.Wrapf(err, "invalid JSON payload for predicate type %s", customType)
}

return result, nil
}

func generateSLSAProvenanceStatement(rawPayload []byte, digest string, repo string) (interface{}, error) {
Expand Down

0 comments on commit e6d08d6

Please sign in to comment.