diff --git a/cmd/validate/image.go b/cmd/validate/image.go index 68cc2b117..f471bbc63 100644 --- a/cmd/validate/image.go +++ b/cmd/validate/image.go @@ -364,10 +364,17 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command { } res.component.Signatures = out.Signatures - res.component.Attestations = out.Attestations + // Create a new result object for attestations. The point is to only keep the data that's needed. + // For example, the Statement is only needed when the full attestation is printed. + for _, att := range out.Attestations { + attResult := applicationsnapshot.NewAttestationResult(att) + if containsOutput(data.output, "attestation") { + attResult.Statement = att.Statement() + } + res.component.Attestations = append(res.component.Attestations, attResult) + } res.component.ContainerImage = out.ImageURL res.data = out.Data - res.component.Attestations = out.Attestations res.policyInput = out.PolicyInput } res.component.Success = err == nil && len(res.component.Violations) == 0 @@ -411,7 +418,7 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command { } else { components = append(components, r.component) // evaluator data is duplicated per component, so only collect it once. - if len(evaluatorData) == 0 && containsData(data.output) { + if len(evaluatorData) == 0 && containsOutput(data.output, "data") { evaluatorData = append(evaluatorData, r.data) } manyPolicyInput = append(manyPolicyInput, r.policyInput) @@ -543,7 +550,7 @@ func validateImageCmd(validate imageValidationFunc) *cobra.Command { } // find if the slice contains "data" output -func containsData(data []string) bool { +func containsOutput(data []string, value string) bool { for _, item := range data { newItem := strings.Split(item, "=") if newItem[0] == "data" { diff --git a/cmd/validate/image_test.go b/cmd/validate/image_test.go index b7ad09d3f..a6c93b337 100644 --- a/cmd/validate/image_test.go +++ b/cmd/validate/image_test.go @@ -1322,7 +1322,7 @@ func TestContainsData(t *testing.T) { } for _, test := range tests { - result := containsData(test.input) + result := containsOutput(test.input, "data") assert.Equal(t, test.expected, result, test.name) } } diff --git a/cmd/validate/input.go b/cmd/validate/input.go index e9550c6ff..d5c36d275 100644 --- a/cmd/validate/input.go +++ b/cmd/validate/input.go @@ -177,7 +177,7 @@ func validateInputCmd(validate InputValidationFunc) *cobra.Command { } else { inputs = append(inputs, r.input) // evaluator data is duplicated per component, so only collect it once. - if len(evaluatorData) == 0 && containsData(data.output) { + if len(evaluatorData) == 0 && containsOutput(data.output, "data") { evaluatorData = append(evaluatorData, r.data) } manyPolicyInput = append(manyPolicyInput, r.policyInput) diff --git a/internal/applicationsnapshot/attestation.go b/internal/applicationsnapshot/attestation.go index 220e40958..152b1609b 100644 --- a/internal/applicationsnapshot/attestation.go +++ b/internal/applicationsnapshot/attestation.go @@ -21,14 +21,43 @@ import ( "encoding/json" "github.com/in-toto/in-toto-golang/in_toto" + + "github.com/enterprise-contract/ec-cli/internal/attestation" + "github.com/enterprise-contract/ec-cli/internal/signature" ) +type SLSAProvenance interface { + attestation.Attestation + PredicateBuildType() string +} + +type AttestationResult struct { + Type string `json:"type"` + PredicateType string `json:"predicateType"` + PredicateBuildType string `json:"predicateBuildType"` + Signatures []signature.EntitySignature `json:"signatures"` + Statement []byte `json:"statement"` +} + +func NewAttestationResult(att attestation.Attestation) AttestationResult { + attResult := AttestationResult{ + Type: att.Type(), + PredicateType: att.PredicateType(), + Signatures: att.Signatures(), + } + if value, ok := att.(SLSAProvenance); ok { + attResult.PredicateBuildType = value.PredicateBuildType() + + } + return attResult +} + func (r *Report) renderAttestations() ([]byte, error) { byts := make([][]byte, 0, len(r.Components)*2) for _, c := range r.Components { for _, a := range c.Attestations { - byts = append(byts, a.Statement()) + byts = append(byts, a.Statement) } } @@ -40,7 +69,7 @@ func (r *Report) attestations() ([]in_toto.Statement, error) { for _, c := range r.Components { for _, a := range c.Attestations { var statement in_toto.Statement - err := json.Unmarshal(a.Statement(), &statement) + err := json.Unmarshal(a.Statement, &statement) if err != nil { return []in_toto.Statement{}, nil } diff --git a/internal/applicationsnapshot/attestation_test.go b/internal/applicationsnapshot/attestation_test.go index d5703870f..af9e7b338 100644 --- a/internal/applicationsnapshot/attestation_test.go +++ b/internal/applicationsnapshot/attestation_test.go @@ -27,9 +27,7 @@ import ( app "github.com/konflux-ci/application-api/api/v1alpha1" "github.com/stretchr/testify/assert" - "github.com/enterprise-contract/ec-cli/internal/attestation" "github.com/enterprise-contract/ec-cli/internal/evaluator" - "github.com/enterprise-contract/ec-cli/internal/signature" ) func TestAttestationReport(t *testing.T) { @@ -55,7 +53,7 @@ func TestAttestationReport(t *testing.T) { SnapshotComponent: app.SnapshotComponent{ ContainerImage: "registry.io/repository/image:tag", }, - Attestations: []attestation.Attestation{ + Attestations: []AttestationResult{ att("attestation1"), }, }, @@ -68,7 +66,7 @@ func TestAttestationReport(t *testing.T) { SnapshotComponent: app.SnapshotComponent{ ContainerImage: "registry.io/repository/image1:tag", }, - Attestations: []attestation.Attestation{ + Attestations: []AttestationResult{ att("attestation1"), att("attestation2"), }, @@ -77,7 +75,7 @@ func TestAttestationReport(t *testing.T) { SnapshotComponent: app.SnapshotComponent{ ContainerImage: "registry.io/repository/image2:tag", }, - Attestations: []attestation.Attestation{ + Attestations: []AttestationResult{ att("attestation3"), att("attestation4"), }, @@ -91,7 +89,7 @@ func TestAttestationReport(t *testing.T) { SnapshotComponent: app.SnapshotComponent{ ContainerImage: "registry.io/repository/image1:tag", }, - Attestations: []attestation.Attestation{ + Attestations: []AttestationResult{ att("attestation1"), }, }, @@ -104,7 +102,7 @@ func TestAttestationReport(t *testing.T) { SnapshotComponent: app.SnapshotComponent{ ContainerImage: "registry.io/repository/image3:tag", }, - Attestations: []attestation.Attestation{ + Attestations: []AttestationResult{ att("attestation2"), att("attestation3"), }, @@ -145,9 +143,9 @@ func TestAttestations(t *testing.T) { Message: "violation1", }, }, - Attestations: []attestation.Attestation{ - provenance{ - data: data, + Attestations: []AttestationResult{ + { + Statement: data, }, }, }, @@ -159,32 +157,8 @@ func TestAttestations(t *testing.T) { assert.Equal(t, []in_toto.Statement{statement}, att) } -type mockAttestation struct { - data string -} - -func (a mockAttestation) Type() string { - return "type" -} - -func (a mockAttestation) PredicateType() string { - return "predicateType" -} - -func (a mockAttestation) Statement() []byte { - return []byte(a.data) -} - -func (a mockAttestation) Signatures() []signature.EntitySignature { - return nil -} - -func (a mockAttestation) Subject() []in_toto.Subject { - return []in_toto.Subject{} -} - -func att(data string) attestation.Attestation { - return &mockAttestation{ - data: data, +func att(data string) AttestationResult { + return AttestationResult{ + Statement: []byte(data), } } diff --git a/internal/applicationsnapshot/report.go b/internal/applicationsnapshot/report.go index f25a272b5..d41eb7e4f 100644 --- a/internal/applicationsnapshot/report.go +++ b/internal/applicationsnapshot/report.go @@ -29,7 +29,6 @@ import ( app "github.com/konflux-ci/application-api/api/v1alpha1" "sigs.k8s.io/yaml" - "github.com/enterprise-contract/ec-cli/internal/attestation" "github.com/enterprise-contract/ec-cli/internal/evaluator" "github.com/enterprise-contract/ec-cli/internal/format" "github.com/enterprise-contract/ec-cli/internal/policy" @@ -46,7 +45,7 @@ type Component struct { Success bool `json:"success"` SuccessCount int `json:"-"` Signatures []signature.EntitySignature `json:"signatures,omitempty"` - Attestations []attestation.Attestation `json:"attestations,omitempty"` + Attestations []AttestationResult `json:"attestations,omitempty"` } type Report struct { diff --git a/internal/applicationsnapshot/vsa_test.go b/internal/applicationsnapshot/vsa_test.go index 522d960f0..69c2a06f2 100644 --- a/internal/applicationsnapshot/vsa_test.go +++ b/internal/applicationsnapshot/vsa_test.go @@ -29,38 +29,11 @@ import ( app "github.com/konflux-ci/application-api/api/v1alpha1" "github.com/stretchr/testify/assert" - "github.com/enterprise-contract/ec-cli/internal/attestation" "github.com/enterprise-contract/ec-cli/internal/evaluator" "github.com/enterprise-contract/ec-cli/internal/policy" - "github.com/enterprise-contract/ec-cli/internal/signature" "github.com/enterprise-contract/ec-cli/internal/utils" ) -type provenance struct { - statement in_toto.Statement - data []byte -} - -func (p provenance) Type() string { - return in_toto.StatementInTotoV01 -} - -func (p provenance) PredicateType() string { - return p.statement.StatementHeader.PredicateType -} - -func (p provenance) Statement() []byte { - return p.data -} - -func (p provenance) Signatures() []signature.EntitySignature { - return []signature.EntitySignature{} -} - -func (p provenance) Subject() []in_toto.Subject { - return p.statement.Subject -} - func TestNewVSA(t *testing.T) { components := []Component{ { @@ -70,9 +43,9 @@ func TestNewVSA(t *testing.T) { Message: "violation1", }, }, - Attestations: []attestation.Attestation{ - provenance{ - statement: in_toto.Statement{}, + Attestations: []AttestationResult{ + { + Statement: []byte{}, }, }, }, @@ -110,6 +83,7 @@ func TestSubjects(t *testing.T) { Digest: nil, }, } + statement := in_toto.Statement{ StatementHeader: in_toto.StatementHeader{ Subject: expected, @@ -126,10 +100,9 @@ func TestSubjects(t *testing.T) { Message: "violation1", }, }, - Attestations: []attestation.Attestation{ - provenance{ - statement: statement, - data: data, + Attestations: []AttestationResult{ + { + Statement: data, }, }, }, diff --git a/internal/attestation/slsa_provenance_02.go b/internal/attestation/slsa_provenance_02.go index fd769f6d9..9b2ce28bb 100644 --- a/internal/attestation/slsa_provenance_02.go +++ b/internal/attestation/slsa_provenance_02.go @@ -86,6 +86,10 @@ func (a slsaProvenance) Statement() []byte { return a.data } +func (a slsaProvenance) PredicateBuildType() string { + return a.statement.Predicate.BuildType +} + func (a slsaProvenance) Signatures() []signature.EntitySignature { return a.signatures }