Files
slsa-verifier/verifiers/utils/builder_test.go
laurentsimon 533d347a4b feat: support builderID matching with or without semver for GHA (#257)
* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update
2022-09-15 14:32:03 -07:00

302 lines
7.8 KiB
Go

package utils
import (
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
serrors "github.com/slsa-framework/slsa-verifier/errors"
)
func Test_ParseBuilderID(t *testing.T) {
t.Parallel()
tests := []struct {
name string
builderID string
needVersion bool
builderName string
builderVersion string
err error
}{
{
name: "valid builder with version - need version",
builderID: "some/name@v1.2.3",
needVersion: true,
builderName: "some/name",
builderVersion: "v1.2.3",
},
{
name: "valid builder with version - no need version",
builderID: "some/name@v1.2.3",
builderName: "some/name",
builderVersion: "v1.2.3",
},
{
name: "valid builder without version - no need version",
builderID: "some/name",
builderName: "some/name",
},
{
name: "no version ID - need version",
needVersion: true,
err: serrors.ErrorInvalidFormat,
},
{
name: "too many '@' - need version",
builderID: "some/name@vla@blo",
needVersion: true,
err: serrors.ErrorInvalidFormat,
},
{
name: "too many '@' - no need version",
builderID: "some/name@vla@blo",
err: serrors.ErrorInvalidFormat,
},
{
name: "empty version - need version",
builderID: "some/name@",
needVersion: true,
err: serrors.ErrorInvalidFormat,
},
{
name: "empty version - no need version",
builderID: "some/name@",
err: serrors.ErrorInvalidFormat,
},
}
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()
name, version, err := ParseBuilderID(tt.builderID, tt.needVersion)
if !cmp.Equal(err, tt.err, cmpopts.EquateErrors()) {
t.Errorf(cmp.Diff(err, tt.err))
}
if err != nil {
return
}
if name != tt.builderName {
t.Errorf(cmp.Diff(name, tt.builderName))
}
if version != tt.builderVersion {
t.Errorf(cmp.Diff(version, tt.builderVersion))
}
})
}
}
func Test_BuilderIDNew(t *testing.T) {
t.Parallel()
tests := []struct {
name string
trustedBuilderID string
builderName string
builderVersion string
err error
}{
{
name: "valid",
trustedBuilderID: "some/name@v1.2.3",
builderName: "some/name",
builderVersion: "v1.2.3",
},
{
name: "empty version",
trustedBuilderID: "some/name@",
err: serrors.ErrorInvalidFormat,
},
{
name: "too many '@' - need version",
trustedBuilderID: "some/name@vla@blo",
err: serrors.ErrorInvalidFormat,
},
{
name: "too many '@' - no need version",
trustedBuilderID: "some/name@vla@blo",
err: serrors.ErrorInvalidFormat,
},
}
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()
trustedBuilderID, err := TrustedBuilderIDNew(tt.trustedBuilderID)
if !cmp.Equal(err, tt.err, cmpopts.EquateErrors()) {
t.Errorf(cmp.Diff(err, tt.err))
}
if err != nil {
return
}
name := trustedBuilderID.Name()
version := trustedBuilderID.Version()
full := trustedBuilderID.String()
if name != tt.builderName {
t.Errorf(cmp.Diff(tt.builderName, name))
}
if version != tt.builderVersion {
t.Errorf(cmp.Diff(tt.builderVersion, version))
}
if full != tt.trustedBuilderID {
t.Errorf(cmp.Diff(tt.trustedBuilderID, full))
}
})
}
}
func Test_Matches(t *testing.T) {
t.Parallel()
tests := []struct {
name string
trustedBuilderID string
allowRef bool
match string
err error
}{
{
name: "match full",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@v1.2.3",
},
{
name: "match name",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name",
},
{
name: "mismatch name",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name2",
err: serrors.ErrorMismatchBuilderID,
},
{
name: "mismatch version",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@v1.2.4",
err: serrors.ErrorMismatchBuilderID,
},
{
name: "invalid empty version",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@",
err: serrors.ErrorInvalidFormat,
},
{
name: "too many '@' - need version",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@vla@blo",
err: serrors.ErrorInvalidFormat,
},
{
name: "too many '@' - no need version",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@vla@blo",
err: serrors.ErrorInvalidFormat,
},
// Same as above with `allowRef: true`.
{
name: "match full",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@v1.2.3",
allowRef: true,
},
{
name: "match name",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name",
allowRef: true,
},
{
name: "mismatch name",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name2",
allowRef: true,
err: serrors.ErrorMismatchBuilderID,
},
{
name: "mismatch version",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@v1.2.4",
allowRef: true,
err: serrors.ErrorMismatchBuilderID,
},
{
name: "invalid empty version",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@",
allowRef: true,
err: serrors.ErrorInvalidFormat,
},
{
name: "too many '@' - need version",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@vla@blo",
allowRef: true,
err: serrors.ErrorInvalidFormat,
},
{
name: "too many '@' - no need version",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@vla@blo",
allowRef: true,
err: serrors.ErrorInvalidFormat,
},
// Mismatch of tag length.
{
name: "match long tag match short",
trustedBuilderID: "some/name@refs/tags/v1.2.3",
match: "some/name@v1.2.3",
allowRef: true,
},
{
name: "long tag match short no ref",
trustedBuilderID: "some/name@refs/tags/v1.2.3",
match: "some/name@v1.2.3",
err: serrors.ErrorMismatchBuilderID,
},
{
name: "match long tags",
trustedBuilderID: "some/name@refs/tags/v1.2.3",
match: "some/name@refs/tags/v1.2.3",
allowRef: true,
},
{
name: "mismatch tag length",
trustedBuilderID: "some/name@refs/tags/v1.2.3",
match: "some/name@v1.2.3",
err: serrors.ErrorMismatchBuilderID,
},
{
name: "mismatch tag length inversed",
trustedBuilderID: "some/name@v1.2.3",
match: "some/name@refs/tags/v1.2.3",
err: serrors.ErrorMismatchBuilderID,
},
}
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()
trustedBuilderID, err := TrustedBuilderIDNew(tt.trustedBuilderID)
if err != nil {
panic(fmt.Errorf("BuilderIDNew: %w", err))
}
err = trustedBuilderID.Matches(tt.match, tt.allowRef)
if !cmp.Equal(err, tt.err, cmpopts.EquateErrors()) {
t.Errorf(cmp.Diff(err, tt.err))
}
})
}
}