Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for option in cosign attest and attest-blob to upload attestation as supported in Rekor #3466

Merged
merged 8 commits into from Jan 13, 2024
1 change: 1 addition & 0 deletions cmd/cosign/cli/attest.go
Expand Up @@ -95,6 +95,7 @@ func Attest() *cobra.Command {
Replace: o.Replace,
Timeout: ro.Timeout,
TlogUpload: o.TlogUpload,
RekorEntryType: o.RekorEntryType,
}

for _, img := range args {
Expand Down
30 changes: 20 additions & 10 deletions cmd/cosign/cli/attest/attest.go
Expand Up @@ -71,15 +71,16 @@ func uploadToTlog(ctx context.Context, sv *sign.SignerVerifier, rekorURL string,
type AttestCommand struct {
options.KeyOpts
options.RegistryOptions
CertPath string
CertChainPath string
NoUpload bool
PredicatePath string
PredicateType string
Replace bool
Timeout time.Duration
TlogUpload bool
TSAServerURL string
CertPath string
CertChainPath string
NoUpload bool
PredicatePath string
PredicateType string
Replace bool
Timeout time.Duration
TlogUpload bool
TSAServerURL string
RekorEntryType string
}

// nolint
Expand All @@ -93,6 +94,10 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error {
return fmt.Errorf("predicate cannot be empty")
}

if c.RekorEntryType != "dsse" && c.RekorEntryType != "intoto" {
return fmt.Errorf("unknown value for rekor-entry-type")
}

predicateURI, err := options.ParsePredicateType(c.PredicateType)
if err != nil {
return err
Expand Down Expand Up @@ -197,7 +202,12 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error {
}
if shouldUpload {
bundle, err := uploadToTlog(ctx, sv, c.RekorURL, func(r *client.Rekor, b []byte) (*models.LogEntryAnon, error) {
return cosign.TLogUploadDSSEEnvelope(ctx, r, signedPayload, b)
if c.RekorEntryType == "intoto" {
return cosign.TLogUploadInTotoAttestation(ctx, r, signedPayload, b)
} else {
return cosign.TLogUploadDSSEEnvelope(ctx, r, signedPayload, b)
}

})
if err != nil {
return err
Expand Down
15 changes: 14 additions & 1 deletion cmd/cosign/cli/attest/attest_blob.go
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/sigstore/cosign/v2/pkg/cosign/attestation"
cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle"
"github.com/sigstore/cosign/v2/pkg/types"
"github.com/sigstore/rekor/pkg/generated/models"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"github.com/sigstore/sigstore/pkg/signature"
"github.com/sigstore/sigstore/pkg/signature/dsse"
Expand All @@ -62,6 +63,8 @@ type AttestBlobCommand struct {
OutputSignature string
OutputAttestation string
OutputCertificate string

RekorEntryType string
}

// nolint
Expand All @@ -75,6 +78,10 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error
return fmt.Errorf("predicate cannot be empty")
}

if c.RekorEntryType != "dsse" && c.RekorEntryType != "intoto" {
return fmt.Errorf("unknown value for rekor-entry-type")
}

if c.Timeout != 0 {
var cancelFn context.CancelFunc
ctx, cancelFn = context.WithTimeout(ctx, c.Timeout)
Expand Down Expand Up @@ -182,7 +189,13 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error
if err != nil {
return err
}
entry, err := cosign.TLogUploadDSSEEnvelope(ctx, rekorClient, sig, rekorBytes)
var entry *models.LogEntryAnon
if c.RekorEntryType == "intoto" {
entry, err = cosign.TLogUploadInTotoAttestation(ctx, rekorClient, sig, rekorBytes)
} else {
entry, err = cosign.TLogUploadDSSEEnvelope(ctx, rekorClient, sig, rekorBytes)
}

if err != nil {
return err
}
Expand Down
32 changes: 32 additions & 0 deletions cmd/cosign/cli/attest/attest_blob_test.go
Expand Up @@ -261,3 +261,35 @@ func TestAttestBlob(t *testing.T) {
})
}
}

func TestBadRekorEntryType(t *testing.T) {
ctx := context.Background()
td := t.TempDir()

keys, _ := cosign.GenerateKeyPair(nil)
keyRef := writeFile(t, td, string(keys.PrivateBytes), "key.pem")

blob := []byte("foo")
blobPath := writeFile(t, td, string(blob), "foo.txt")

predicates := map[string]string{}
predicates["slsaprovenance"] = makeSLSA02PredicateFile(t, td)
predicates["slsaprovenance1"] = makeSLSA1PredicateFile(t, td)

for predicateType, predicatePath := range predicates {
t.Run(predicateType, func(t *testing.T) {
dssePath := filepath.Join(td, "dsse.intoto.jsonl")
at := AttestBlobCommand{
KeyOpts: options.KeyOpts{KeyRef: keyRef},
PredicatePath: predicatePath,
PredicateType: predicateType,
OutputSignature: dssePath,
RekorEntryType: "badvalue",
}
err := at.Exec(ctx, blobPath)
if err == nil || err.Error() != "unknown value for rekor-entry-type" {
t.Fatal("expected an error due to unknown rekor entry type")
}
})
}
}
1 change: 1 addition & 0 deletions cmd/cosign/cli/attest_blob.go
Expand Up @@ -85,6 +85,7 @@ func AttestBlob() *cobra.Command {
OutputAttestation: o.OutputAttestation,
OutputCertificate: o.OutputCertificate,
Timeout: ro.Timeout,
RekorEntryType: o.RekorEntryType,
}
return v.Exec(cmd.Context(), args[0])
},
Expand Down
4 changes: 4 additions & 0 deletions cmd/cosign/cli/options/attest.go
Expand Up @@ -30,6 +30,7 @@ type AttestOptions struct {
SkipConfirmation bool
TlogUpload bool
TSAServerURL string
RekorEntryType string

Rekor RekorOptions
Fulcio FulcioOptions
Expand Down Expand Up @@ -80,6 +81,9 @@ func (o *AttestOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().BoolVar(&o.TlogUpload, "tlog-upload", true,
"whether or not to upload to the tlog")

cmd.Flags().StringVar(&o.RekorEntryType, "rekor-entry-type", "dsse",
"specifies the type to be used for a rekor entry upload. Options are intoto or dsse (default). ")

cmd.Flags().StringVar(&o.TSAServerURL, "timestamp-server-url", "",
"url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr")
}
5 changes: 5 additions & 0 deletions cmd/cosign/cli/options/attest_blob.go
Expand Up @@ -37,6 +37,8 @@ type AttestBlobOptions struct {
OutputCertificate string
BundlePath string

RekorEntryType string

Rekor RekorOptions
Fulcio FulcioOptions
OIDC OIDCOptions
Expand Down Expand Up @@ -92,6 +94,9 @@ func (o *AttestBlobOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().BoolVar(&o.TlogUpload, "tlog-upload", true,
"whether or not to upload to the tlog")

cmd.Flags().StringVar(&o.RekorEntryType, "rekor-entry-type", "dsse",
"specifies the type to be used for a rekor entry upload. Options are intoto or dsse (default). ")

cmd.Flags().StringVar(&o.TSAServerURL, "timestamp-server-url", "",
"url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr")

Expand Down
1 change: 1 addition & 0 deletions doc/cosign_attest-blob.md

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

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.