Add support to attestation command for more predicate types.
Before, we required all attestations have predicateType https://slsa.dev/provenance/v1. This allows you to use other predicate types, and adds the ability to filter responses from the API for a particular predicate type. Signed-off-by: Zach Steindler <steiza@github.com>
This commit is contained in:
parent
a76230454a
commit
643f4031b2
7 changed files with 51 additions and 41 deletions
|
|
@ -102,6 +102,7 @@ func NewDownloadCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Comman
|
|||
downloadCmd.Flags().StringVarP(&opts.Repo, "repo", "R", "", "Repository name in the format <owner>/<repo>")
|
||||
downloadCmd.MarkFlagsMutuallyExclusive("owner", "repo")
|
||||
downloadCmd.MarkFlagsOneRequired("owner", "repo")
|
||||
downloadCmd.Flags().StringVarP(&opts.PredicateType, "predicate-type", "", "", "Filter attestations by provided predicate type")
|
||||
cmdutil.StringEnumFlag(downloadCmd, &opts.DigestAlgorithm, "digest-alg", "d", "sha256", []string{"sha256", "sha512"}, "The algorithm used to compute a digest of the artifact")
|
||||
downloadCmd.Flags().IntVarP(&opts.Limit, "limit", "L", api.DefaultLimit, "Maximum number of attestations to fetch")
|
||||
|
||||
|
|
@ -132,6 +133,17 @@ func runDownload(opts *Options) error {
|
|||
return fmt.Errorf("failed to fetch attestations: %v", err)
|
||||
}
|
||||
|
||||
// Apply predicate type filter to returned attestations
|
||||
if opts.PredicateType != "" {
|
||||
filteredAttestations := verification.FilterAttestations(opts.PredicateType, attestations)
|
||||
|
||||
if len(filteredAttestations) == 0 {
|
||||
return fmt.Errorf("no attestations found with predicate type: %s", opts.PredicateType)
|
||||
}
|
||||
|
||||
attestations = filteredAttestations
|
||||
}
|
||||
|
||||
metadataFilePath, err := opts.Store.createMetadataFile(artifact.DigestWithAlg(), attestations)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write attestation: %v", err)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ type Options struct {
|
|||
Store MetadataStore
|
||||
OCIClient oci.Client
|
||||
Owner string
|
||||
PredicateType string
|
||||
Repo string
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package verification
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
|
@ -113,3 +114,27 @@ func GetRemoteAttestations(c FetchAttestationsConfig) ([]*api.Attestation, error
|
|||
}
|
||||
return nil, fmt.Errorf("owner or repo must be provided")
|
||||
}
|
||||
|
||||
type DssePayload struct {
|
||||
PredicateType string `json:"predicateType"`
|
||||
}
|
||||
|
||||
func FilterAttestations(predicateType string, attestations []*api.Attestation) []*api.Attestation {
|
||||
filteredAttestations := []*api.Attestation{}
|
||||
|
||||
for _, each := range attestations {
|
||||
dsseEnvelope := each.Bundle.GetDsseEnvelope()
|
||||
if dsseEnvelope != nil {
|
||||
var dssePayload DssePayload
|
||||
if err := json.Unmarshal([]byte(dsseEnvelope.Payload), &dssePayload); err != nil {
|
||||
// Don't fail just because a single entry can't be unmarshalled
|
||||
continue
|
||||
}
|
||||
if dssePayload.PredicateType == predicateType {
|
||||
filteredAttestations = append(filteredAttestations, each)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filteredAttestations
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ type Options struct {
|
|||
NoPublicGood bool
|
||||
OIDCIssuer string
|
||||
Owner string
|
||||
PredicateType string
|
||||
Repo string
|
||||
SAN string
|
||||
SANRegex string
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
const (
|
||||
GitHubOIDCIssuer = "https://token.actions.githubusercontent.com"
|
||||
SLSAPredicateType = "https://slsa.dev/provenance/v1"
|
||||
// represents the GitHub hosted runner in the certificate RunnerEnvironment extension
|
||||
GitHubRunner = "github-hosted"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package verify
|
||||
|
||||
import (
|
||||
// "encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
|
|
@ -17,8 +16,6 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var ErrNoMatchingSLSAPredicate = fmt.Errorf("the attestation does not have the expected SLSA predicate type: %s", SLSAPredicateType)
|
||||
|
||||
func NewVerifyCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command {
|
||||
opts := &Options{}
|
||||
verifyCmd := &cobra.Command{
|
||||
|
|
@ -120,6 +117,7 @@ func NewVerifyCmd(f *cmdutil.Factory, runF func(*Options) error) *cobra.Command
|
|||
verifyCmd.Flags().StringVarP(&opts.Repo, "repo", "R", "", "Repository name in the format <owner>/<repo>")
|
||||
verifyCmd.MarkFlagsMutuallyExclusive("owner", "repo")
|
||||
verifyCmd.MarkFlagsOneRequired("owner", "repo")
|
||||
verifyCmd.Flags().StringVarP(&opts.PredicateType, "predicate-type", "", "", "Filter attestations by provided predicate type")
|
||||
verifyCmd.Flags().BoolVarP(&opts.NoPublicGood, "no-public-good", "", false, "Only verify attestations signed with GitHub's Sigstore instance")
|
||||
verifyCmd.Flags().StringVarP(&opts.CustomTrustedRoot, "custom-trusted-root", "", "", "Path to a custom trustedroot.json file to use for verification")
|
||||
verifyCmd.Flags().IntVarP(&opts.Limit, "limit", "L", api.DefaultLimit, "Maximum number of attestations to fetch")
|
||||
|
|
@ -158,6 +156,17 @@ func runVerify(opts *Options) error {
|
|||
return fmt.Errorf("failed to fetch attestations for subject: %s", artifact.DigestWithAlg())
|
||||
}
|
||||
|
||||
// Apply predicate type filter to returned attestations
|
||||
if opts.PredicateType != "" {
|
||||
filteredAttestations := verification.FilterAttestations(opts.PredicateType, attestations)
|
||||
|
||||
if len(filteredAttestations) == 0 {
|
||||
return fmt.Errorf("no attestations found with predicate type: %s", opts.PredicateType)
|
||||
}
|
||||
|
||||
attestations = filteredAttestations
|
||||
}
|
||||
|
||||
policy, err := buildVerifyPolicy(opts, *artifact)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build policy: %v", err)
|
||||
|
|
@ -183,11 +192,6 @@ func runVerify(opts *Options) error {
|
|||
"Successfully verified all attestations against Sigstore!\n",
|
||||
))
|
||||
|
||||
// Try verifying the attestation's predicate type against the expect SLSA predicate type
|
||||
if err = verifySLSAPredicateType(opts.Logger, sigstoreRes.VerifyResults); err != nil {
|
||||
return fmt.Errorf("at least one attestation failed to verify predicate type verification: %v", err)
|
||||
}
|
||||
|
||||
opts.Logger.VerbosePrint(opts.Logger.ColorScheme.Green("Successfully verified the SLSA predicate type of all attestations!\n"))
|
||||
|
||||
opts.Logger.Println(opts.Logger.ColorScheme.Green("All attestations have been successfully verified!"))
|
||||
|
|
@ -202,15 +206,3 @@ func runVerify(opts *Options) error {
|
|||
// All attestations passed verification and policy evaluation
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifySLSAPredicateType(logger *io.Handler, apr []*verification.AttestationProcessingResult) error {
|
||||
logger.VerbosePrint("Evaluating attestations have valid SLSA predicate type")
|
||||
|
||||
for _, result := range apr {
|
||||
if result.VerificationResult.Statement.PredicateType != SLSAPredicateType {
|
||||
return ErrNoMatchingSLSAPredicate
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,6 @@ import (
|
|||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/in-toto/in-toto-golang/in_toto"
|
||||
"github.com/sigstore/sigstore-go/pkg/verify"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
|
@ -382,20 +379,3 @@ func TestRunVerify(t *testing.T) {
|
|||
require.Error(t, runVerify(&customOpts))
|
||||
})
|
||||
}
|
||||
|
||||
func TestVerifySLSAPredicateType_InvalidPredicate(t *testing.T) {
|
||||
statement := &in_toto.Statement{}
|
||||
statement.PredicateType = "some-other-predicate-type"
|
||||
|
||||
apr := []*verification.AttestationProcessingResult{
|
||||
{
|
||||
VerificationResult: &verify.VerificationResult{
|
||||
Statement: statement,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := verifySLSAPredicateType(io.NewTestHandler(), apr)
|
||||
require.Error(t, err)
|
||||
require.ErrorIs(t, err, ErrNoMatchingSLSAPredicate)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue