Skip to content

Commit

Permalink
Only store attestation data that is needed
Browse files Browse the repository at this point in the history
The whole attestation is being stored for each
component that is evaluated, but in most cases
only a subset of the attestation printed.
This change captures only the needed attestation
data based on the output selected at runtime.

https://issues.redhat.com/browse/EC-1026
  • Loading branch information
joejstuart committed Dec 8, 2024
1 parent 27b87f9 commit ce03e69
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 56 deletions.
15 changes: 11 additions & 4 deletions cmd/validate/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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" {
Expand Down
2 changes: 1 addition & 1 deletion cmd/validate/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
2 changes: 1 addition & 1 deletion cmd/validate/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
32 changes: 30 additions & 2 deletions internal/applicationsnapshot/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,43 @@ import (
"bytes"
"encoding/json"

"github.com/enterprise-contract/ec-cli/internal/attestation"
"github.com/enterprise-contract/ec-cli/internal/signature"
"github.com/in-toto/in-toto-golang/in_toto"
)

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)
}
}

Expand All @@ -40,7 +68,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
}
Expand Down
23 changes: 11 additions & 12 deletions internal/applicationsnapshot/attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ 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"
)
Expand Down Expand Up @@ -55,7 +54,7 @@ func TestAttestationReport(t *testing.T) {
SnapshotComponent: app.SnapshotComponent{
ContainerImage: "registry.io/repository/image:tag",
},
Attestations: []attestation.Attestation{
Attestations: []AttestationResult{
att("attestation1"),
},
},
Expand All @@ -68,7 +67,7 @@ func TestAttestationReport(t *testing.T) {
SnapshotComponent: app.SnapshotComponent{
ContainerImage: "registry.io/repository/image1:tag",
},
Attestations: []attestation.Attestation{
Attestations: []AttestationResult{
att("attestation1"),
att("attestation2"),
},
Expand All @@ -77,7 +76,7 @@ func TestAttestationReport(t *testing.T) {
SnapshotComponent: app.SnapshotComponent{
ContainerImage: "registry.io/repository/image2:tag",
},
Attestations: []attestation.Attestation{
Attestations: []AttestationResult{
att("attestation3"),
att("attestation4"),
},
Expand All @@ -91,7 +90,7 @@ func TestAttestationReport(t *testing.T) {
SnapshotComponent: app.SnapshotComponent{
ContainerImage: "registry.io/repository/image1:tag",
},
Attestations: []attestation.Attestation{
Attestations: []AttestationResult{
att("attestation1"),
},
},
Expand All @@ -104,7 +103,7 @@ func TestAttestationReport(t *testing.T) {
SnapshotComponent: app.SnapshotComponent{
ContainerImage: "registry.io/repository/image3:tag",
},
Attestations: []attestation.Attestation{
Attestations: []AttestationResult{
att("attestation2"),
att("attestation3"),
},
Expand Down Expand Up @@ -145,9 +144,9 @@ func TestAttestations(t *testing.T) {
Message: "violation1",
},
},
Attestations: []attestation.Attestation{
provenance{
data: data,
Attestations: []AttestationResult{
{
Statement: data,
},
},
},
Expand Down Expand Up @@ -183,8 +182,8 @@ 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),
}
}
3 changes: 1 addition & 2 deletions internal/applicationsnapshot/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 {
Expand Down
41 changes: 7 additions & 34 deletions internal/applicationsnapshot/vsa_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
{
Expand All @@ -70,9 +43,9 @@ func TestNewVSA(t *testing.T) {
Message: "violation1",
},
},
Attestations: []attestation.Attestation{
provenance{
statement: in_toto.Statement{},
Attestations: []AttestationResult{
{
Statement: []byte{},
},
},
},
Expand Down Expand Up @@ -110,6 +83,7 @@ func TestSubjects(t *testing.T) {
Digest: nil,
},
}

statement := in_toto.Statement{
StatementHeader: in_toto.StatementHeader{
Subject: expected,
Expand All @@ -126,10 +100,9 @@ func TestSubjects(t *testing.T) {
Message: "violation1",
},
},
Attestations: []attestation.Attestation{
provenance{
statement: statement,
data: data,
Attestations: []AttestationResult{
{
Statement: data,
},
},
},
Expand Down
4 changes: 4 additions & 0 deletions internal/attestation/slsa_provenance_02.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down

0 comments on commit ce03e69

Please sign in to comment.