Skip to content

Commit

Permalink
Add support for timestamps in the cosign custom predicate, and docume…
Browse files Browse the repository at this point in the history
…nt it. (#533)

Signed-off-by: Dan Lorenc <[email protected]>
  • Loading branch information
dlorenc authored Aug 11, 2021
1 parent 4c76ff3 commit 61b103b
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 8 deletions.
27 changes: 19 additions & 8 deletions pkg/cosign/attestation/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"path/filepath"
"reflect"
"strings"
"time"

"github.com/in-toto/in-toto-golang/in_toto"
"github.com/pkg/errors"
Expand All @@ -32,9 +33,10 @@ const (
CosignCustomProvenanceV01 = "cosign.sigstore.dev/attestation/v1"
)

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

// GenerateOpts specifies the options of the Statement generator.
Expand All @@ -48,6 +50,9 @@ type GenerateOpts struct {
Digest string
// Repo context of the reference.
Repo string

// Function to return the time to set
Time func() time.Time
}

// GenerateStatement returns corresponding Predicate (custom|provenance|spdx|link)
Expand All @@ -59,7 +64,12 @@ func GenerateStatement(opts GenerateOpts) (interface{}, error) {
}
switch opts.Type {
case "custom":
return generateCustomStatement(rawPayload, opts.Digest, opts.Repo)
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 "provenance":
return generateProvenanceStatement(rawPayload, opts.Digest, opts.Repo)
case "spdx":
Expand Down Expand Up @@ -87,11 +97,12 @@ func generateStatementHeader(digest, repo, predicateType string) in_toto.Stateme
}

//
func generateCustomStatement(rawPayload []byte, digest, repo string) (interface{}, error) {
func generateCustomStatement(rawPayload []byte, digest, repo, timestamp string) (interface{}, error) {
return in_toto.Statement{
StatementHeader: generateStatementHeader(digest, repo, CosignCustomProvenanceV01),
Predicate: CosignAttestation{
Data: string(rawPayload),
Predicate: CosignPredicate{
Data: string(rawPayload),
Timestamp: timestamp,
},
}, nil
}
Expand Down Expand Up @@ -131,7 +142,7 @@ func generateLinkStatement(rawPayload []byte, digest string, repo string) (inter
func generateSPDXStatement(rawPayload []byte, digest string, repo string) (interface{}, error) {
return in_toto.SPDXStatement{
StatementHeader: generateStatementHeader(digest, repo, in_toto.PredicateSPDX),
Predicate: CosignAttestation{
Predicate: CosignPredicate{
Data: string(rawPayload),
},
}, nil
Expand Down
31 changes: 31 additions & 0 deletions specs/COSIGN_PREDICATE_SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Cosign Generic Predicate Specification

`Cosign` supports working with [In-Toto Attestations](https://github.com/in-toto/attestation) using the predicate model.
Several well-known predicates are supported natively, but `cosign` also supports a simple, generic, format for data that
doesn't fit well into other types.

The format for this is defined as follows:

`data`: Raw data to place in the attestation. This is a base64-encoded string of bytes.
`timestamp`: The timestamp the attestion was generated at in the RFC3339 format in the UTC timezone.

Here is an example attestation containing a data file containing `foo`:

```json
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicateType": "cosign.sigstore.dev/attestation/v1",
"subject": [
{
"name": "us.gcr.io/dlorenc-vmtest2/demo",
"digest": {
"sha256": "124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155"
}
}
],
"predicate": {
"Data": "foo\n",
"Timestamp": "2021-08-11T14:51:09Z"
}
}
```

0 comments on commit 61b103b

Please sign in to comment.