...

Source file src/github.com/sigstore/cosign/v2/pkg/policy/attestation_test.go

Documentation: github.com/sigstore/cosign/v2/pkg/policy

     1  //
     2  // Copyright 2022 The Sigstore Authors.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package policy
    17  
    18  import (
    19  	"context"
    20  	"crypto/x509"
    21  	"encoding/json"
    22  	"fmt"
    23  	"io"
    24  	"os"
    25  	"strings"
    26  	"testing"
    27  
    28  	v1 "github.com/google/go-containerregistry/pkg/v1"
    29  	"github.com/google/go-containerregistry/pkg/v1/types"
    30  	"github.com/in-toto/in-toto-golang/in_toto"
    31  	"github.com/sigstore/cosign/v2/pkg/cosign/attestation"
    32  	"github.com/sigstore/cosign/v2/pkg/cosign/bundle"
    33  	"github.com/sigstore/cosign/v2/pkg/oci"
    34  	"github.com/sigstore/cosign/v2/pkg/oci/static"
    35  )
    36  
    37  type failingAttestation struct {
    38  }
    39  
    40  func (fa *failingAttestation) Payload() ([]byte, error) {
    41  	return nil, fmt.Errorf("inducing test failure")
    42  }
    43  func (fa *failingAttestation) Annotations() (map[string]string, error) {
    44  	return nil, fmt.Errorf("unimplemented")
    45  }
    46  func (fa *failingAttestation) Signature() ([]byte, error) {
    47  	return nil, fmt.Errorf("unimplemented")
    48  }
    49  func (fa *failingAttestation) Base64Signature() (string, error) {
    50  	return "", fmt.Errorf("unimplemented")
    51  }
    52  func (fa *failingAttestation) Cert() (*x509.Certificate, error) {
    53  	return nil, fmt.Errorf("unimplemented")
    54  }
    55  func (fa *failingAttestation) Chain() ([]*x509.Certificate, error) {
    56  	return nil, fmt.Errorf("unimplemented")
    57  }
    58  func (fa *failingAttestation) Bundle() (*bundle.RekorBundle, error) {
    59  	return nil, fmt.Errorf("unimplemented")
    60  }
    61  func (fa *failingAttestation) RFC3161Timestamp() (*bundle.RFC3161Timestamp, error) {
    62  	return nil, fmt.Errorf("unimplemented")
    63  }
    64  func (fa *failingAttestation) Digest() (v1.Hash, error) {
    65  	return v1.Hash{}, fmt.Errorf("unimplemented")
    66  }
    67  func (fa *failingAttestation) DiffID() (v1.Hash, error) {
    68  	return v1.Hash{}, fmt.Errorf("unimplemented")
    69  }
    70  func (fa *failingAttestation) Compressed() (io.ReadCloser, error) {
    71  	return nil, fmt.Errorf("unimplemented")
    72  }
    73  func (fa *failingAttestation) Uncompressed() (io.ReadCloser, error) {
    74  	return nil, fmt.Errorf("unimplemented")
    75  }
    76  func (fa *failingAttestation) Size() (int64, error) {
    77  	return 0, fmt.Errorf("unimplemented")
    78  }
    79  func (fa *failingAttestation) MediaType() (types.MediaType, error) {
    80  	return types.DockerConfigJSON, fmt.Errorf("unimplemented")
    81  }
    82  
    83  var _ oci.Signature = (*failingAttestation)(nil)
    84  
    85  const (
    86  	// Result of "echo 'nottotostatement' | base64"
    87  	//	invalidTotoStatement = "bm90dG90b3N0YXRlbWVudAo="
    88  	invalidTotoStatement = `{"payloadType":"application/vnd.in-toto+json","payload":"bm90dG90b3N0YXRlbWVudAo"}`
    89  )
    90  
    91  func checkFailure(t *testing.T, want string, err error) {
    92  	t.Helper()
    93  	if err == nil {
    94  		t.Fatalf("Expected error, got none")
    95  	}
    96  	if !strings.Contains(err.Error(), want) {
    97  		t.Errorf("Failed to get the expected error of %q, got: %s", want, err)
    98  	}
    99  }
   100  
   101  func TestFailures(t *testing.T) {
   102  	tests := []struct {
   103  		payload          string
   104  		predicateType    string
   105  		wantErrSubstring string
   106  	}{{payload: "", wantErrSubstring: "unmarshaling payload data"}, {payload: "{badness", wantErrSubstring: "unmarshaling payload data"},
   107  		{payload: `{"payloadType":"notmarshallable}`, wantErrSubstring: "unmarshaling payload data"},
   108  		{payload: `{"payload":"shou!ln'twork"}`, wantErrSubstring: "decoding payload"},
   109  		{payload: `{"payloadType":"finebutnopayload"}`, wantErrSubstring: "could not find payload"},
   110  		{payload: invalidTotoStatement, wantErrSubstring: "decoding payload: illegal base64"},
   111  	}
   112  	for _, tc := range tests {
   113  		att, err := static.NewSignature([]byte(tc.payload), "")
   114  		if err != nil {
   115  			t.Fatal("Failed to create static.NewSignature: ", err)
   116  		}
   117  		predicateType := tc.predicateType
   118  		if predicateType == "" {
   119  			predicateType = "custom"
   120  		}
   121  		_, _, err = AttestationToPayloadJSON(context.TODO(), predicateType, att)
   122  		checkFailure(t, tc.wantErrSubstring, err)
   123  	}
   124  }
   125  
   126  // TestMalformedPayload tests various non-predicate specific failures that
   127  // are done even before we start processing the payload.
   128  // This just stands alone since didn't want to complicate above tests with
   129  // constructing different attestations there.
   130  func TestErroringPayload(t *testing.T) {
   131  	// Payload() call fails
   132  	_, _, err := AttestationToPayloadJSON(context.TODO(), "custom", &failingAttestation{})
   133  	checkFailure(t, "inducing test failure", err)
   134  }
   135  func TestAttestationToPayloadJson(t *testing.T) {
   136  	dir := "valid"
   137  	files := getDirFiles(t, dir)
   138  	for _, fileName := range files {
   139  		bytes := readAttestationFromTestFile(t, dir, fileName)
   140  		ociSig, err := static.NewSignature(bytes, "")
   141  		if err != nil {
   142  			t.Fatal("Failed to create static.NewSignature: ", err)
   143  		}
   144  		jsonBytes, gotPredicateType, err := AttestationToPayloadJSON(context.TODO(), fileName, ociSig)
   145  		if err != nil {
   146  			t.Fatalf("Failed to convert : %s", err)
   147  		}
   148  		switch fileName {
   149  		case "custom":
   150  			var intoto in_toto.Statement
   151  			if err := json.Unmarshal(jsonBytes, &intoto); err != nil {
   152  				t.Fatalf("[%s] Wanted custom statement, can't unmarshal to it: %v", fileName, err)
   153  			}
   154  			checkPredicateType(t, attestation.CosignCustomProvenanceV01, intoto.PredicateType)
   155  			checkPredicateType(t, gotPredicateType, intoto.PredicateType)
   156  		case "vuln":
   157  			var vulnStatement attestation.CosignVulnStatement
   158  			if err := json.Unmarshal(jsonBytes, &vulnStatement); err != nil {
   159  				t.Fatalf("[%s] Wanted vuln statement, can't unmarshal to it: %v", fileName, err)
   160  			}
   161  			checkPredicateType(t, attestation.CosignVulnProvenanceV01, vulnStatement.PredicateType)
   162  			checkPredicateType(t, gotPredicateType, vulnStatement.PredicateType)
   163  		case "default":
   164  			t.Fatal("non supported predicate file")
   165  		}
   166  	}
   167  }
   168  
   169  func checkPredicateType(t *testing.T, want, got string) {
   170  	t.Helper()
   171  	if want != got {
   172  		t.Errorf("Did not get expected predicateType, want: %s got: %s", want, got)
   173  	}
   174  }
   175  
   176  func readAttestationFromTestFile(t *testing.T, dir, name string) []byte {
   177  	t.Helper()
   178  	b, err := os.ReadFile(fmt.Sprintf("testdata/%s/%s", dir, name))
   179  	if err != nil {
   180  		t.Fatalf("Failed to read file : %s ReadFile() = %s", name, err)
   181  	}
   182  	return b
   183  }
   184  
   185  func getDirFiles(t *testing.T, dir string) []string {
   186  	files, err := os.ReadDir(fmt.Sprintf("testdata/%s", dir))
   187  	if err != nil {
   188  		t.Fatalf("Failed to read dir : %s ReadFile() = %s", dir, err)
   189  	}
   190  	ret := []string{}
   191  	for _, file := range files {
   192  		ret = append(ret, file.Name())
   193  	}
   194  	return ret
   195  }
   196  

View as plain text