Skip to content

Commit

Permalink
Add negative tests for Provenance v1 protos
Browse files Browse the repository at this point in the history
Signed-off-by: Marcela Melara <[email protected]>
  • Loading branch information
marcelamelara committed Sep 25, 2023
1 parent 5e5cbba commit 5aea664
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 11 deletions.
26 changes: 15 additions & 11 deletions go/predicates/provenance/v1/provenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ package v1
import (
"errors"
"fmt"

"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/structpb"
)

// all of the following errors apply to SLSA Build L1 and above
var (
ErrBuilderRequired = errors.New("RunDetails.Builder required")
ErrBuilderIdRequired = errors.New("Builder.Id required")
ErrBuildDefinitionRequired = errors.New("BuildeDefinition required")
ErrBuildTypeRequired = errors.New("BuildDefinition.BuildType required")
ErrExternalParamsRequired = errors.New("BuildDefinition.ExternalParameters required")
ErrRunDetailsRequired = errors.New("RunDetails required")
ErrBuilderRequired = errors.New("runDetails.builder required")
ErrBuilderIdRequired = errors.New("runDetails.builder.id required")
ErrBuildDefinitionRequired = errors.New("buildDefinition required")
ErrBuildTypeRequired = errors.New("buildDefinition.buildType required")
ErrExternalParamsRequired = errors.New("buildDefinition.externalParameters required")
ErrRunDetailsRequired = errors.New("runDetails required")
)

func (m *BuildMetadata) Validate() error {
Expand Down Expand Up @@ -63,7 +66,8 @@ func (b *BuildDefinition) Validate() error {
}

// the externalParameters field is required for SLSA Build L1
if b.GetExternalParameters() == nil {
ext := b.GetExternalParameters()
if ext == nil || proto.Equal(ext, &structpb.Struct{}) {
return ErrExternalParamsRequired
}

Expand All @@ -83,7 +87,7 @@ func (b *BuildDefinition) Validate() error {
func (r *RunDetails) Validate() error {
// the builder field is required for SLSA Build L1
builder := r.GetBuilder()
if builder == nil {
if builder == nil || proto.Equal(builder, &Builder{}) {
return ErrBuilderRequired
}

Expand All @@ -94,7 +98,7 @@ func (r *RunDetails) Validate() error {

// check the Metadata, if present
metadata := r.GetMetadata()
if metadata != nil {
if metadata != nil && !proto.Equal(metadata, &BuildMetadata{}) {
if err := metadata.Validate(); err != nil {
return fmt.Errorf("Invalid RunDetails.Metadata: %w", err)
}
Expand All @@ -116,7 +120,7 @@ func (r *RunDetails) Validate() error {
func (p *Provenance) Validate() error {
// the buildDefinition field is required for SLSA Build L1
buildDef := p.GetBuildDefinition()
if buildDef == nil {
if buildDef == nil || proto.Equal(buildDef, &BuildDefinition{}) {
return ErrBuildDefinitionRequired
}

Expand All @@ -127,7 +131,7 @@ func (p *Provenance) Validate() error {

// the runDetails field is required for SLSA Build L1
runDetails := p.GetRunDetails()
if runDetails == nil {
if runDetails == nil || proto.Equal(runDetails, &RunDetails{}) {
return ErrRunDetailsRequired
}

Expand Down
67 changes: 67 additions & 0 deletions go/predicates/provenance/v1/provenance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Tests for SLSA Provenance v1 protos.
package v1

import (
"fmt"
"testing"

ita1 "github.com/in-toto/attestation/go/v1"
Expand Down Expand Up @@ -70,3 +71,69 @@ func TestJsonUnmarshalProvenance(t *testing.T) {
assert.NoError(t, err, "unexpected error during test Statement creation")
assert.True(t, proto.Equal(got, want), "protos do not match")
}

func TestBadProvenanceBuildDefinition(t *testing.T) {
tests := map[string]struct {
input string
err error
noErrMessage string
}{
"no buildDefinition": {
input: `{"buildDefinition":{},"runDetails":{"builder":{"id":"theId","version":{"theComponent":"v0.1"},"builderDependencies":[{"name":"theResource","digest":{"alg1":"abc123"}}]},"metadata":{"invocationId":"theInvocationId"},"byproducts":[{"name":"theResource","digest":{"alg1":"abc123"}}]}}`,
err: ErrBuildDefinitionRequired,
noErrMessage: "created malformed Provenance (empty buildDefinition)",
},
"buildDefinition missing buildType required field": {
input: `{"buildDefinition":{"externalParameters":{"param1":{"subKey":"subVal"}},"resolvedDependencies":[{"name":"theResource","digest":{"alg1":"abc123"}}]},"runDetails":{"builder":{"id":"theId","version":{"theComponent":"v0.1"},"builderDependencies":[{"name":"theResource","digest":{"alg1":"abc123"}}]},"metadata":{"invocationId":"theInvocationId"},"byproducts":[{"name":"theResource","digest":{"alg1":"abc123"}}]}}`,
err: ErrBuildTypeRequired,
noErrMessage: "created malformed Provenance (buildDefinition missing required buildType field)",
},
"buildDefinition missing externalParameters required field": {
input: `{"buildDefinition":{"buildType":"theBuildType","resolvedDependencies":[{"name":"theResource","digest":{"alg1":"abc123"}}]},"runDetails":{"builder":{"id":"theId","version":{"theComponent":"v0.1"},"builderDependencies":[{"name":"theResource","digest":{"alg1":"abc123"}}]},"metadata":{"invocationId":"theInvocationId"},"byproducts":[{"name":"theResource","digest":{"alg1":"abc123"}}]}}`,
err: ErrExternalParamsRequired,
noErrMessage: "created malformed Provenance (buildDefinition missing requried externalParameters field)",
},
}

for name, test := range tests {
got := &Provenance{}
err := protojson.Unmarshal([]byte(test.input), got)
assert.NoError(t, err, fmt.Sprintf("error during JSON unmarshalling in test '%s'", name))

err = got.Validate()
assert.ErrorIs(t, err, test.err, fmt.Sprintf("%s in test '%s'", test.noErrMessage, name))
}
}

func TestBadProvenanceRunDetails(t *testing.T) {
tests := map[string]struct {
input string
err error
noErrMessage string
}{
"no runDetails": {
input: `{"buildDefinition":{"buildType":"theBuildType","externalParameters":{"param1":{"subKey":"subVal"}},"resolvedDependencies":[{"name":"theResource","digest":{"alg1":"abc123"}}]},"runDetails":{}}`,
err: ErrRunDetailsRequired,
noErrMessage: "created malformed Provenance (empty runDetails)",
},
"runDetails missing builder required field": {
input: `{"buildDefinition":{"buildType":"theBuildType","externalParameters":{"param1":{"subKey":"subVal"}},"resolvedDependencies":[{"name":"theResource","digest":{"alg1":"abc123"}}]},"runDetails":{"builder":{},"metadata":{"invocationId":"theInvocationId"},"byproducts":[{"name":"theResource","digest":{"alg1":"abc123"}}]}}`,
err: ErrBuilderRequired,
noErrMessage: "created malformed Provenance (runDetails missing required builder field)",
},
"runDetails.builder missing id required field": {
input: `{"buildDefinition":{"buildType":"theBuildType","externalParameters":{"param1":{"subKey":"subVal"}},"resolvedDependencies":[{"name":"theResource","digest":{"alg1":"abc123"}}]},"runDetails":{"builder":{"id":"","version":{"theComponent":"v0.1"},"builderDependencies":[{"name":"theResource","digest":{"alg1":"abc123"}}]},"metadata":{"invocationId":"theInvocationId"},"byproducts":[{"name":"theResource","digest":{"alg1":"abc123"}}]}}`,
err: ErrBuilderIdRequired,
noErrMessage: "created malformed Provenance (runDetails.builder missing requried id field)",
},
}

for name, test := range tests {
got := &Provenance{}
err := protojson.Unmarshal([]byte(test.input), got)
assert.NoError(t, err, fmt.Sprintf("error during JSON unmarshalling in test '%s'", name))

err = got.Validate()
assert.ErrorIs(t, err, test.err, fmt.Sprintf("%s in test '%s'", test.noErrMessage, name))
}
}

0 comments on commit 5aea664

Please sign in to comment.