Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Add more ProvenanceFromEnvelope tests #640

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions verifiers/internal/gha/provenance_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package gha

import (
"os"
"testing"
"time"

Expand All @@ -12,7 +11,6 @@ import (
slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1"

serrors "github.com/slsa-framework/slsa-verifier/v2/errors"
"github.com/slsa-framework/slsa-verifier/v2/verifiers/internal/gha/slsaprovenance"
"github.com/slsa-framework/slsa-verifier/v2/verifiers/internal/gha/slsaprovenance/iface"
)

Expand Down Expand Up @@ -64,50 +62,6 @@ type testProvenanceV1 struct {

func (p *testProvenanceV1) Predicate() slsa1.ProvenancePredicate { return p.predicate }

func provenanceFromBytes(payload []byte) (iface.Provenance, error) {
env, err := EnvelopeFromBytes(payload)
if err != nil {
return nil, err
}
return slsaprovenance.ProvenanceFromEnvelope(env)
}

func Test_ProvenanceFromEnvelope(t *testing.T) {
t.Parallel()
tests := []struct {
name string
path string
expected error
}{
{
name: "invalid dsse: not SLSA predicate",
path: "./testdata/dsse-not-slsa.intoto.jsonl",
expected: serrors.ErrorInvalidDssePayload,
},
{
name: "slsa 1.0 invalid dsse: not SLSA predicate",
path: "./testdata/dsse-not-slsa-v1.intoto.jsonl",
expected: serrors.ErrorInvalidDssePayload,
},
// TODO(#573): add more compliance tests.
}
for _, tt := range tests {
tt := tt // Re-initializing variable so it is not changed while executing the closure below
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

content, err := os.ReadFile(tt.path)
if err != nil {
t.Fatalf("os.ReadFile: %v", err)
}
_, err = provenanceFromBytes(content)
if !errCmp(err, tt.expected) {
t.Errorf(cmp.Diff(err, tt.expected))
}
})
}
}

func Test_VerifyDigest(t *testing.T) {
t.Parallel()
tests := []struct {
Expand Down
19 changes: 9 additions & 10 deletions verifiers/internal/gha/slsaprovenance/slsaprovenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"

intoto "github.com/in-toto/in-toto-golang/in_toto"
slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1"
dsselib "github.com/secure-systems-lab/go-securesystemslib/dsse"

Expand All @@ -27,31 +28,29 @@ var predicateTypeMap = map[string]provenanceConstructor{

// ProvenanceFromEnvelope returns a Provenance instance for the given DSSE Envelope.
func ProvenanceFromEnvelope(env *dsselib.Envelope) (iface.Provenance, error) {
if env.PayloadType != "application/vnd.in-toto+json" {
return nil, fmt.Errorf("%w: expected payload type 'application/vnd.in-toto+json', got '%s'",
serrors.ErrorInvalidDssePayload, env.PayloadType)
if env.PayloadType != intoto.PayloadType {
return nil, fmt.Errorf("%w: expected payload type %q, got '%s'",
serrors.ErrorInvalidDssePayload, intoto.PayloadType, env.PayloadType)
}
pyld, err := base64.StdEncoding.DecodeString(env.Payload)
if err != nil {
return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, err.Error())
}

// Get the predicateType, a required field.
pred := struct {
PredicateType string `json:"predicateType"`
}{}
// Load the in-toto attestation statement header.
pred := intoto.StatementHeader{}
if err := json.Unmarshal(pyld, &pred); err != nil {
return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, err.Error())
return nil, fmt.Errorf("%w: decoding json: %v", serrors.ErrorInvalidDssePayload, err)
}

// Load the appropriate structure and unmarshal.
// Verify the predicate type is one we can handle.
newProv, ok := predicateTypeMap[pred.PredicateType]
if !ok {
return nil, fmt.Errorf("%w: unexpected predicate type '%s'", serrors.ErrorInvalidDssePayload, pred.PredicateType)
}
prov, err := newProv(pyld)
if err != nil {
return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, err.Error())
return nil, fmt.Errorf("%w: %v", serrors.ErrorInvalidDssePayload, err)
}

return prov, nil
Expand Down
110 changes: 110 additions & 0 deletions verifiers/internal/gha/slsaprovenance/slsaprovenance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package slsaprovenance

import (
"encoding/base64"
"encoding/json"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
intoto "github.com/in-toto/in-toto-golang/in_toto"
intoto_slsav1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1"
"github.com/secure-systems-lab/go-securesystemslib/dsse"

serrors "github.com/slsa-framework/slsa-verifier/v2/errors"
slsav1 "github.com/slsa-framework/slsa-verifier/v2/verifiers/internal/gha/slsaprovenance/v1.0"
)

func mustJSON(o any) string {
b, err := json.Marshal(o)
if err != nil {
panic(err)
}
return base64.StdEncoding.EncodeToString(b)
}

func Test_ProvenanceFromEnvelope(t *testing.T) {
t.Parallel()
tests := []struct {
name string
envelope *dsse.Envelope
path string
err error
}{
{
name: "valid dsse",
envelope: &dsse.Envelope{
PayloadType: intoto.PayloadType,
Payload: mustJSON(&slsav1.Attestation{
StatementHeader: intoto.StatementHeader{
PredicateType: intoto_slsav1.PredicateSLSAProvenance,
},
Predicate: intoto_slsav1.ProvenancePredicate{
BuildDefinition: intoto_slsav1.ProvenanceBuildDefinition{
BuildType: slsav1.BYOBBuildType,
},
},
}),
},
},
{
name: "invalid dsse: not SLSA predicate",
envelope: &dsse.Envelope{
PayloadType: intoto.PayloadType,
Payload: mustJSON(&intoto.StatementHeader{
// NOTE: Not a SLSA predicate type.
PredicateType: intoto.PredicateSPDX,
}),
},
err: serrors.ErrorInvalidDssePayload,
},
{
name: "invalid dsse: not base64",
envelope: &dsse.Envelope{
PayloadType: intoto.PayloadType,
// NOTE: Not valid base64.
Payload: "i&(*$(@&^&)))",
},
err: serrors.ErrorInvalidDssePayload,
},
{
name: "invalid dsse: not json",
envelope: &dsse.Envelope{
PayloadType: intoto.PayloadType,
// NOTE: Not valid JSON.
Payload: base64.StdEncoding.EncodeToString([]byte("{'not valid json'")),
},
err: serrors.ErrorInvalidDssePayload,
},
{
name: "invalid dsse: not in-toto",
envelope: &dsse.Envelope{
// NOTE: Not an in-toto attestation payload type,
PayloadType: "http://github.com/other/payload/type",
// NOTE: The rest of the payload should be valid.
Payload: mustJSON(&slsav1.Attestation{
StatementHeader: intoto.StatementHeader{
PredicateType: intoto_slsav1.PredicateSLSAProvenance,
},
Predicate: intoto_slsav1.ProvenancePredicate{
BuildDefinition: intoto_slsav1.ProvenanceBuildDefinition{
BuildType: slsav1.BYOBBuildType,
},
},
}),
},
err: serrors.ErrorInvalidDssePayload,
},
}
for _, tt := range tests {
tt := tt // Re-initializing variable so it is not changed while executing the closure below
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

_, err := ProvenanceFromEnvelope(tt.envelope)
if diff := cmp.Diff(tt.err, err, cmpopts.EquateErrors()); diff != "" {
t.Errorf("unexpected error (-want +got):\n%s", diff)
}
})
}
}
2 changes: 1 addition & 1 deletion verifiers/internal/gha/slsaprovenance/v0.2/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
type provenanceV02 struct {
// upperEnv specifies if environment fields are in uppercase.
upperEnv bool
prov *intotoAttestation
prov *Attestation
}

// Predicate implements provenanceV02.Predicate.
Expand Down
6 changes: 3 additions & 3 deletions verifiers/internal/gha/slsaprovenance/v0.2/provenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ var (
byobDelegatorBuildType = "https://github.com/slsa-framework/slsa-github-generator/delegator-generic@v0"
)

// intotoAttestation is a SLSA v0.2 in-toto attestation statement.
type intotoAttestation struct {
// Attestation is a SLSA v0.2 in-toto attestation statement.
type Attestation struct {
intoto.StatementHeader
Predicate slsa02.ProvenancePredicate `json:"predicate"`
}
Expand All @@ -46,7 +46,7 @@ func New(payload []byte) (iface.Provenance, error) {
dec := json.NewDecoder(bytes.NewReader(payload))
dec.DisallowUnknownFields()

a := &intotoAttestation{}
a := &Attestation{}
if err := dec.Decode(a); err != nil {
return nil, err
}
Expand Down
6 changes: 3 additions & 3 deletions verifiers/internal/gha/slsaprovenance/v1.0/byob.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import (
"github.com/slsa-framework/slsa-verifier/v2/verifiers/internal/gha/slsaprovenance/common"
)

// byobBuildType is the base build type for BYOB delegated builders.
var byobBuildType = "https://github.com/slsa-framework/slsa-github-generator/delegator-generic@v0"
// BYOBBuildType is the base build type for BYOB delegated builders.
var BYOBBuildType = "https://github.com/slsa-framework/slsa-github-generator/delegator-generic@v0"

// BYOBProvenance is SLSA v1.0 provenance for the slsa-github-generator BYOB build type.
type BYOBProvenance struct {
prov *intotoAttestation
prov *Attestation
}

// Predicate implements ProvenanceV02.Predicate.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package v1

// containerBasedBuildType is the build type for the container-based builder and is based on BYOB.
var containerBasedBuildType = "https://slsa.dev/container-based-build/v0.1?draft"
// ContainerBasedBuildType is the build type for the container-based builder and is based on BYOB.
var ContainerBasedBuildType = "https://slsa.dev/container-based-build/v0.1?draft"

// ContainerBasedProvenance is provenance generated by the container-based builder.
type ContainerBasedProvenance struct {
Expand Down
9 changes: 5 additions & 4 deletions verifiers/internal/gha/slsaprovenance/v1.0/provenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (
"github.com/slsa-framework/slsa-verifier/v2/verifiers/internal/gha/slsaprovenance/iface"
)

type intotoAttestation struct {
// Attestation is an in-toto SLSA v1.0 attestation statement.
type Attestation struct {
intoto.StatementHeader
Predicate slsa1.ProvenancePredicate `json:"predicate"`
}
Expand All @@ -30,17 +31,17 @@ func New(payload []byte) (iface.Provenance, error) {
dec := json.NewDecoder(bytes.NewReader(payload))
dec.DisallowUnknownFields()

a := &intotoAttestation{}
a := &Attestation{}
if err := dec.Decode(a); err != nil {
return nil, err
}

switch a.Predicate.BuildDefinition.BuildType {
case byobBuildType:
case BYOBBuildType:
return &BYOBProvenance{
prov: a,
}, nil
case containerBasedBuildType:
case ContainerBasedBuildType:
return &ContainerBasedProvenance{
BYOBProvenance: &BYOBProvenance{
prov: a,
Expand Down

This file was deleted.

10 changes: 0 additions & 10 deletions verifiers/internal/gha/testdata/dsse-not-slsa.intoto.jsonl

This file was deleted.