1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
87
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
127
128
129
130 func TestErroringPayload(t *testing.T) {
131
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