@@ -21,21 +21,33 @@ import (
2121 "time"
2222
2323 v1 "github.com/chainloop-dev/chainloop/app/cli/api/attestation/v1"
24+ "github.com/secure-systems-lab/go-securesystemslib/dsse"
2425
26+ crv1 "github.com/google/go-containerregistry/pkg/v1"
2527 "github.com/in-toto/in-toto-golang/in_toto"
2628 slsacommon "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common"
2729)
2830
29- // // Replace custom material type with https://github.com/in-toto/attestation/blob/main/spec/v1.0/resource_descriptor.md
30- // const ChainloopPredicateTypeV02 = "chainloop.dev/attestation/v0.2"
31-
3231// TODO: Figure out a more appropriate meaning
3332const chainloopBuildType = "chainloop.dev/workflowrun/v0.1"
3433
3534const builderIDFmt = "chainloop.dev/cli/%s@%s"
3635
37- type ProvenancePredicateVersions struct {
38- V01 * ProvenancePredicateV01
36+ // NormalizablePredicate represents a common interface of how to extract materials and env vars
37+ type NormalizablePredicate interface {
38+ GetEnvVars () map [string ]string
39+ GetMaterials () []* NormalizedMaterial
40+ }
41+
42+ type NormalizedMaterial struct {
43+ // Name of the Material
44+ Name string
45+ // Type of the Material
46+ Type string
47+ // Either the fileName or the actual string content
48+ Value string
49+ // Hash of the Material
50+ Hash * crv1.Hash
3951}
4052
4153type ProvenancePredicateCommon struct {
@@ -101,6 +113,55 @@ func getChainloopMeta(att *v1.Attestation) *Metadata {
101113 }
102114}
103115
116+ func ExtractStatement (envelope * dsse.Envelope ) (* in_toto.Statement , error ) {
117+ decodedPayload , err := envelope .DecodeB64Payload ()
118+ if err != nil {
119+ return nil , err
120+ }
121+
122+ // 1 - Extract the in-toto statement
123+ statement := & in_toto.Statement {}
124+ if err := json .Unmarshal (decodedPayload , statement ); err != nil {
125+ return nil , fmt .Errorf ("un-marshaling predicate: %w" , err )
126+ }
127+
128+ return statement , nil
129+ }
130+
131+ // Extract the Chainloop attestation predicate from an encoded DSSE envelope
132+ // NOTE: We return a NormalizablePredicate interface to allow for future versions
133+ // of the predicate to be extracted without updating the consumer.
134+ // Yes, having the producer define and return an interface is an anti-pattern.
135+ // but it greatly simplifies the code since there are multiple consumers at different layers of the app
136+ // and we expect predicates to evolve quickly
137+ func ExtractPredicate (envelope * dsse.Envelope ) (NormalizablePredicate , error ) {
138+ // 1 - Extract the in-toto statement
139+ statement , err := ExtractStatement (envelope )
140+ if err != nil {
141+ return nil , fmt .Errorf ("extracting statement: %w" , err )
142+ }
143+
144+ // 2 - Extract the Chainloop predicate from the in-toto statement
145+ switch statement .PredicateType {
146+ case PredicateTypeV01 :
147+ var predicate * ProvenancePredicateV01
148+ if err = extractPredicate (statement , & predicate ); err != nil {
149+ return nil , fmt .Errorf ("extracting predicate: %w" , err )
150+ }
151+
152+ return predicate , nil
153+ case PredicateTypeV02 :
154+ var predicate * ProvenancePredicateV02
155+ if err = extractPredicate (statement , & predicate ); err != nil {
156+ return nil , fmt .Errorf ("extracting predicate: %w" , err )
157+ }
158+
159+ return predicate , nil
160+ default :
161+ return nil , fmt .Errorf ("unsupported predicate type: %s" , statement .PredicateType )
162+ }
163+ }
164+
104165func extractPredicate (statement * in_toto.Statement , v any ) error {
105166 jsonPredicate , err := json .Marshal (statement .Predicate )
106167 if err != nil {
@@ -113,3 +174,8 @@ func extractPredicate(statement *in_toto.Statement, v any) error {
113174
114175 return nil
115176}
177+
178+ // Implement NormalizablePredicate interface
179+ func (p * ProvenancePredicateCommon ) GetEnvVars () map [string ]string {
180+ return p .Env
181+ }
0 commit comments