mirror of
https://github.com/slsa-framework/slsa-verifier.git
synced 2026-08-19 03:26:20 +00:00
✨ Add CLI tests (#23)
* draft * Fixes * Add option * comments * comments * comment
This commit is contained in:
@@ -31,6 +31,8 @@ $ go run . --help
|
||||
expected source repository that should have produced the binary, e.g. github.com/some/repo
|
||||
-tag string
|
||||
[optional] expected tag the binary was compiled from
|
||||
-versioned-tag string
|
||||
[optional] expected version the binary was compiled from. Uses semantic version to match the tag
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
@@ -37,7 +37,7 @@ var (
|
||||
var defaultRekorAddr = "https://rekor.sigstore.dev"
|
||||
|
||||
func verify(ctx context.Context,
|
||||
provenancePath, artifactHash, source, branch string,
|
||||
provenance []byte, artifactHash, source, branch string,
|
||||
tag, versiontag *string,
|
||||
) error {
|
||||
rClient, err := rekor.NewClient(defaultRekorAddr)
|
||||
@@ -51,11 +51,6 @@ func verify(ctx context.Context,
|
||||
return err
|
||||
}
|
||||
|
||||
provenance, err := os.ReadFile(provenancePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("os.ReadFile: %w", err)
|
||||
}
|
||||
|
||||
env, err := pkg.EnvelopeFromBytes(provenance)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -117,7 +112,7 @@ func main() {
|
||||
flag.StringVar(&source, "source", "", "expected source repository that should have produced the binary, e.g. github.com/some/repo")
|
||||
flag.StringVar(&branch, "branch", "main", "expected branch the binary was compiled from")
|
||||
flag.StringVar(&tag, "tag", "", "[optional] expected tag the binary was compiled from")
|
||||
// flag.StringVar(&versiontag, "versioned-tag", "", "[optional] expected version the binary was compiled from. Uses semantic version to match the tag")
|
||||
flag.StringVar(&versiontag, "versioned-tag", "", "[optional] expected version the binary was compiled from. Uses semantic version to match the tag")
|
||||
flag.Parse()
|
||||
|
||||
if provenancePath == "" || binaryPath == "" || source == "" {
|
||||
@@ -139,21 +134,7 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
f, err := os.Open(binaryPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
if err := verify(ctx, provenancePath,
|
||||
hex.EncodeToString(h.Sum(nil)),
|
||||
source, branch,
|
||||
if err := runVerify(binaryPath, provenancePath, source, branch,
|
||||
ptag, pversiontag); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -170,3 +151,29 @@ func isFlagPassed(name string) bool {
|
||||
})
|
||||
return found
|
||||
}
|
||||
|
||||
func runVerify(binaryPath, provenancePath, source, branch string,
|
||||
ptag, pversiontag *string,
|
||||
) error {
|
||||
f, err := os.Open(binaryPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
provenance, err := os.ReadFile(provenancePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h := sha256.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
return verify(ctx, provenance,
|
||||
hex.EncodeToString(h.Sum(nil)),
|
||||
source, branch,
|
||||
ptag, pversiontag)
|
||||
}
|
||||
|
||||
+311
@@ -0,0 +1,311 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
pkg "github.com/slsa-framework/slsa-verifier/pkg"
|
||||
)
|
||||
|
||||
func errCmp(e1, e2 error) bool {
|
||||
return errors.Is(e1, e2) || errors.Is(e2, e1)
|
||||
}
|
||||
|
||||
func pString(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
func Test_runVerify(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := []struct {
|
||||
name string
|
||||
artifact string
|
||||
source string
|
||||
branch string
|
||||
ptag *string
|
||||
pversiontag *string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "valid main branch default",
|
||||
artifact: "./testdata/binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
},
|
||||
{
|
||||
name: "valid main branch set",
|
||||
artifact: "./testdata/binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
branch: "main",
|
||||
},
|
||||
{
|
||||
name: "wrong branch master",
|
||||
artifact: "./testdata/binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
branch: "master",
|
||||
err: pkg.ErrorMismatchBranch,
|
||||
},
|
||||
{
|
||||
name: "wrong source append A",
|
||||
artifact: "./testdata/binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/laurentsimon/slsa-on-github-testA",
|
||||
err: pkg.ErrorMismatchRepository,
|
||||
},
|
||||
{
|
||||
name: "wrong source prepend A",
|
||||
artifact: "./testdata/binary-linux-amd64-workflow_dispatch",
|
||||
source: "Agithub.com/laurentsimon/slsa-on-github-test",
|
||||
err: pkg.ErrorMismatchRepository,
|
||||
},
|
||||
{
|
||||
name: "wrong source middle A",
|
||||
artifact: "./testdata/binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/Alaurentsimon/slsa-on-github-test",
|
||||
err: pkg.ErrorMismatchRepository,
|
||||
},
|
||||
{
|
||||
name: "tag no match empty tag workflow_dispatch",
|
||||
artifact: "./testdata/binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
ptag: pString("v1.2.3"),
|
||||
err: pkg.ErrorMismatchTag,
|
||||
},
|
||||
{
|
||||
name: "versioned tag no match empty tag workflow_dispatch",
|
||||
artifact: "./testdata/binary-linux-amd64-workflow_dispatch",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1"),
|
||||
err: pkg.ErrorInvalidSemver,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2.3 no match v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
ptag: pString("v1.2.3"),
|
||||
err: pkg.ErrorMismatchTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2 no match v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
ptag: pString("v1.2"),
|
||||
err: pkg.ErrorMismatchTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1 no match v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
ptag: pString("v1"),
|
||||
err: pkg.ErrorMismatchTag,
|
||||
},
|
||||
// Provenance contains tag = v1.2.4.
|
||||
{
|
||||
name: "versioned v1.2.4 match push-v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1.2.4"),
|
||||
},
|
||||
{
|
||||
name: "versioned v1.2 match push-v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1.2"),
|
||||
},
|
||||
{
|
||||
name: "versioned v1 match push-v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1"),
|
||||
},
|
||||
{
|
||||
name: "versioned v2 no match push-v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v0 no match push-v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v0"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v1.3 no match push-v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1.3"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v1.1 no match push-v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1.1"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v1.2.3 no match push-v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1.2.3"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v1.2.5 no match push-v1.2.4",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v1.2.4",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1.2.5"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
// Provenance contains tag = v2.
|
||||
{
|
||||
name: "versioned v2 match push-v2",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2"),
|
||||
},
|
||||
{
|
||||
name: "versioned v2.0 match push-v2",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2.0"),
|
||||
},
|
||||
{
|
||||
name: "versioned v2.1 no match push-v2",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2.1"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v1 no match push-v2",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v3 no match push-v2",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v3"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v1.2 no match push-v2",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1.2"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v3 no match push-v2",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v3"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v0 no match push-v2",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v0"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
// Provenance contains tag = v2.5.
|
||||
{
|
||||
name: "versioned v2.5 match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2.5"),
|
||||
},
|
||||
{
|
||||
name: "versioned v2.5.1 match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2.5.1"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v2.5.3 match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2.5.3"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v2 match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2"),
|
||||
},
|
||||
{
|
||||
name: "versioned v2.4 no match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2.4"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v2.4.1 no match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2.4.1"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v2.4.5 no match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v2.4.5"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v1 no match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v1"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v3 no match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v3"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "versioned v3.1 no match push-v2.5",
|
||||
artifact: "./testdata/binary-linux-amd64-push-v2.5",
|
||||
source: "github.com/laurentsimon/slsa-on-github-test",
|
||||
pversiontag: pString("v3.1"),
|
||||
err: pkg.ErrorMismatchVersionedTag,
|
||||
},
|
||||
}
|
||||
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()
|
||||
|
||||
branch := tt.branch
|
||||
if branch == "" {
|
||||
branch = "main"
|
||||
}
|
||||
|
||||
err := runVerify(tt.artifact,
|
||||
tt.artifact+".intoto.jsonl",
|
||||
tt.source, branch,
|
||||
tt.ptag, tt.pversiontag)
|
||||
|
||||
fmt.Println("err:", err)
|
||||
fmt.Println("tt.err:", tt.err)
|
||||
if !errCmp(err, tt.err) {
|
||||
t.Errorf(cmp.Diff(err, tt.err, cmpopts.EquateErrors()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+75
-31
@@ -47,13 +47,14 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
errorInvalidDssePayload = errors.New("invalid DSSE envelope payload")
|
||||
ErrorInvalidDssePayload = errors.New("invalid DSSE envelope payload")
|
||||
errorRekorSearch = errors.New("error searching rekor entries")
|
||||
errorMismatchHash = errors.New("binary artifact hash does not match provenance subject")
|
||||
errorMismatchBranch = errors.New("branch used to generate the binary does not match provenance")
|
||||
errorMismatchTag = errors.New("tag used to generate the binary does not match provenance")
|
||||
errorMismatchVersionedTag = errors.New("tag used to generate the binary does not match provenance")
|
||||
errorInvalidSemver = errors.New("invalid semantic version")
|
||||
ErrorMismatchBranch = errors.New("branch used to generate the binary does not match provenance")
|
||||
ErrorMismatchRepository = errors.New("repository used to generate the binary does not match provenance")
|
||||
ErrorMismatchTag = errors.New("tag used to generate the binary does not match provenance")
|
||||
ErrorMismatchVersionedTag = errors.New("tag used to generate the binary does not match provenance")
|
||||
ErrorInvalidSemver = errors.New("invalid semantic version")
|
||||
errorInvalidVersion = errors.New("invalid version")
|
||||
)
|
||||
|
||||
@@ -67,19 +68,19 @@ func EnvelopeFromBytes(payload []byte) (env *dsselib.Envelope, err error) {
|
||||
func getSha256Digest(env *dsselib.Envelope) (string, error) {
|
||||
pyld, err := base64.StdEncoding.DecodeString(env.Payload)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "decoding payload")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "decoding payload")
|
||||
}
|
||||
prov := &intoto.ProvenanceStatement{}
|
||||
if err := json.Unmarshal([]byte(pyld), prov); err != nil {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "unmarshalling json")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "unmarshalling json")
|
||||
}
|
||||
if len(prov.Subject) == 0 {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "no subjects")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "no subjects")
|
||||
}
|
||||
digestSet := prov.Subject[0].Digest
|
||||
hash, exists := digestSet["sha256"]
|
||||
if !exists {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "no sha256 subject digest")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "no sha256 subject digest")
|
||||
}
|
||||
return hash, nil
|
||||
}
|
||||
@@ -387,7 +388,7 @@ func VerifyWorkflowIdentity(id *WorkflowIdentity, source string) error {
|
||||
// The caller repository in the x509 extension is not fully qualified. It only contains
|
||||
// {org}/{repository}.
|
||||
if !strings.EqualFold(id.CallerRepository, strings.TrimPrefix(source, "github.com/")) {
|
||||
return fmt.Errorf("unexpected caller repository, got '%s'", id.CallerRepository)
|
||||
return fmt.Errorf("%w: '%s'", ErrorMismatchRepository, id.CallerRepository)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -413,7 +414,7 @@ func VerifyBranch(env *dsselib.Envelope, expectedBranch string) error {
|
||||
}
|
||||
|
||||
if !strings.EqualFold(branch, "refs/heads/"+expectedBranch) {
|
||||
return fmt.Errorf("branch '%s': %w", branch, errorMismatchBranch)
|
||||
return fmt.Errorf("branch '%s': %w", branch, ErrorMismatchBranch)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -426,7 +427,7 @@ func VerifyTag(env *dsselib.Envelope, expectedTag string) error {
|
||||
}
|
||||
|
||||
if !strings.EqualFold(tag, "refs/tags/"+expectedTag) {
|
||||
return fmt.Errorf("tag '%s': %w", tag, errorMismatchTag)
|
||||
return fmt.Errorf("tag '%s': %w", tag, ErrorMismatchTag)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -434,7 +435,7 @@ func VerifyTag(env *dsselib.Envelope, expectedTag string) error {
|
||||
|
||||
func VerifyVersionedTag(env *dsselib.Envelope, expectedTag string) error {
|
||||
if !semver.IsValid(expectedTag) {
|
||||
return fmt.Errorf("%s: %w", expectedTag, errorInvalidSemver)
|
||||
return fmt.Errorf("%s: %w", expectedTag, ErrorInvalidSemver)
|
||||
}
|
||||
|
||||
tag, err := getTag(env)
|
||||
@@ -442,29 +443,72 @@ func VerifyVersionedTag(env *dsselib.Envelope, expectedTag string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
semTag := strings.TrimPrefix(tag, "refs/tags/")
|
||||
semTag := semver.Canonical(strings.TrimPrefix(tag, "refs/tags/"))
|
||||
if !semver.IsValid(semTag) {
|
||||
return fmt.Errorf("%s: %w", expectedTag, errorInvalidSemver)
|
||||
return fmt.Errorf("%s: %w", expectedTag, ErrorInvalidSemver)
|
||||
}
|
||||
|
||||
if semver.Compare(semTag, expectedTag) < 0 {
|
||||
return errorMismatchVersionedTag
|
||||
// Major should always be the same.
|
||||
if semver.Major(semTag) != semver.Major(expectedTag) {
|
||||
return fmt.Errorf("%w: major version", ErrorMismatchVersionedTag)
|
||||
}
|
||||
|
||||
expectedMinor, err := minorVersion(expectedTag)
|
||||
if err == nil {
|
||||
// A minor version was provided by the user.
|
||||
minor, err := minorVersion(semTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if minor != expectedMinor {
|
||||
return ErrorMismatchVersionedTag
|
||||
}
|
||||
}
|
||||
|
||||
expectedPatch, err := patchVersion(expectedTag)
|
||||
if err == nil {
|
||||
// A patch version was provided by the user.
|
||||
patch, err := patchVersion(semTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if patch != expectedPatch {
|
||||
return ErrorMismatchVersionedTag
|
||||
}
|
||||
}
|
||||
|
||||
// Match.
|
||||
return nil
|
||||
}
|
||||
|
||||
func minorVersion(v string) (string, error) {
|
||||
return extractFromVersion(v, 1)
|
||||
}
|
||||
|
||||
func patchVersion(v string) (string, error) {
|
||||
return extractFromVersion(v, 2)
|
||||
}
|
||||
|
||||
func extractFromVersion(v string, i int) (string, error) {
|
||||
parts := strings.Split(v, ".")
|
||||
if len(parts) <= i {
|
||||
return "", fmt.Errorf("%s: %w", v, ErrorInvalidSemver)
|
||||
}
|
||||
return parts[i], nil
|
||||
}
|
||||
|
||||
func getAsInt(parameters map[string]interface{}, field string) (int, error) {
|
||||
value, ok := parameters[field]
|
||||
if !ok {
|
||||
return -1, fmt.Errorf("%w: %s", errorInvalidDssePayload,
|
||||
return -1, fmt.Errorf("%w: %s", ErrorInvalidDssePayload,
|
||||
fmt.Sprintf("parameters type for %s", field))
|
||||
}
|
||||
|
||||
i, ok := value.(float64)
|
||||
if !ok {
|
||||
return -1, fmt.Errorf("%w: %s", errorInvalidDssePayload, "parameters type float64")
|
||||
return -1, fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "parameters type float64")
|
||||
}
|
||||
return int(i), nil
|
||||
}
|
||||
@@ -472,13 +516,13 @@ func getAsInt(parameters map[string]interface{}, field string) (int, error) {
|
||||
func getAsString(parameters map[string]interface{}, field string) (string, error) {
|
||||
value, ok := parameters[field]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload,
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload,
|
||||
fmt.Sprintf("parameters type for %s", field))
|
||||
}
|
||||
|
||||
i, ok := value.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "parameters type string")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "parameters type string")
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
@@ -508,12 +552,12 @@ func getBaseRef(parameters map[string]interface{}) (string, error) {
|
||||
|
||||
eventPayload, ok := parameters["event_payload"]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "parameters type event payload")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "parameters type event payload")
|
||||
}
|
||||
|
||||
payload, ok := eventPayload.(map[string]interface{})
|
||||
if !ok {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "parameters type payload")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "parameters type payload")
|
||||
}
|
||||
|
||||
return getAsString(payload, "base_ref")
|
||||
@@ -523,17 +567,17 @@ func getBaseRef(parameters map[string]interface{}) (string, error) {
|
||||
func getTag(env *dsselib.Envelope) (string, error) {
|
||||
pyld, err := base64.StdEncoding.DecodeString(env.Payload)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "decoding payload")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "decoding payload")
|
||||
}
|
||||
|
||||
var prov intoto.ProvenanceStatement
|
||||
if err := json.Unmarshal([]byte(pyld), &prov); err != nil {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "unmarshalling json")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "unmarshalling json")
|
||||
}
|
||||
|
||||
parameters, ok := prov.Predicate.Invocation.Parameters.(map[string]interface{})
|
||||
if !ok {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "parameters type")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "parameters type")
|
||||
}
|
||||
|
||||
// Validate version.
|
||||
@@ -552,7 +596,7 @@ func getTag(env *dsselib.Envelope) (string, error) {
|
||||
case "tag":
|
||||
return getAsString(parameters, "ref")
|
||||
default:
|
||||
return "", fmt.Errorf("%w: %s %s", errorInvalidDssePayload,
|
||||
return "", fmt.Errorf("%w: %s %s", ErrorInvalidDssePayload,
|
||||
"unknown ref type", refType)
|
||||
}
|
||||
}
|
||||
@@ -561,17 +605,17 @@ func getTag(env *dsselib.Envelope) (string, error) {
|
||||
func getBranch(env *dsselib.Envelope) (string, error) {
|
||||
pyld, err := base64.StdEncoding.DecodeString(env.Payload)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "decoding payload")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "decoding payload")
|
||||
}
|
||||
|
||||
var prov intoto.ProvenanceStatement
|
||||
if err := json.Unmarshal([]byte(pyld), &prov); err != nil {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "unmarshalling json")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "unmarshalling json")
|
||||
}
|
||||
|
||||
parameters, ok := prov.Predicate.Invocation.Parameters.(map[string]interface{})
|
||||
if !ok {
|
||||
return "", fmt.Errorf("%w: %s", errorInvalidDssePayload, "parameters type")
|
||||
return "", fmt.Errorf("%w: %s", ErrorInvalidDssePayload, "parameters type")
|
||||
}
|
||||
|
||||
// Validate version.
|
||||
@@ -590,7 +634,7 @@ func getBranch(env *dsselib.Envelope) (string, error) {
|
||||
case "tag":
|
||||
return getBaseRef(parameters)
|
||||
default:
|
||||
return "", fmt.Errorf("%w: %s %s", errorInvalidDssePayload,
|
||||
return "", fmt.Errorf("%w: %s %s", ErrorInvalidDssePayload,
|
||||
"unknown ref type", refType)
|
||||
}
|
||||
}
|
||||
|
||||
+46
-23
@@ -107,19 +107,19 @@ func Test_VerifyProvenance(t *testing.T) {
|
||||
name: "invalid dsse: not SLSA predicate",
|
||||
path: "./testdata/dsse-not-slsa.intoto.jsonl",
|
||||
artifactHash: "0ae7e4fa71686538440012ee36a2634dbaa19df2dd16a466f52411fb348bbc4e",
|
||||
expected: errorInvalidDssePayload,
|
||||
expected: ErrorInvalidDssePayload,
|
||||
},
|
||||
{
|
||||
name: "invalid dsse: nil subject",
|
||||
path: "./testdata/dsse-no-subject.intoto.jsonl",
|
||||
artifactHash: "0ae7e4fa71686538440012ee36a2634dbaa19df2dd16a466f52411fb348bbc4e",
|
||||
expected: errorInvalidDssePayload,
|
||||
expected: ErrorInvalidDssePayload,
|
||||
},
|
||||
{
|
||||
name: "invalid dsse: no sha256 subject digest",
|
||||
path: "./testdata/dsse-no-subject-hash.intoto.jsonl",
|
||||
artifactHash: "0ae7e4fa71686538440012ee36a2634dbaa19df2dd16a466f52411fb348bbc4e",
|
||||
expected: errorInvalidDssePayload,
|
||||
expected: ErrorInvalidDssePayload,
|
||||
},
|
||||
{
|
||||
name: "mismatched artifact hash with env",
|
||||
@@ -270,7 +270,7 @@ func Test_VerifyBranch(t *testing.T) {
|
||||
{
|
||||
name: "invalid ref type",
|
||||
path: "./testdata/dsse-invalid-ref-type.intoto.jsonl",
|
||||
expected: errorInvalidDssePayload,
|
||||
expected: ErrorInvalidDssePayload,
|
||||
},
|
||||
{
|
||||
name: "invalid version",
|
||||
@@ -316,17 +316,17 @@ func Test_VerifyTag(t *testing.T) {
|
||||
{
|
||||
name: "ref main",
|
||||
path: "./testdata/dsse-main-ref.intoto.jsonl",
|
||||
expected: errorMismatchTag,
|
||||
expected: ErrorMismatchTag,
|
||||
},
|
||||
{
|
||||
name: "ref branch3",
|
||||
path: "./testdata/dsse-branch3-ref.intoto.jsonl",
|
||||
expected: errorMismatchTag,
|
||||
expected: ErrorMismatchTag,
|
||||
},
|
||||
{
|
||||
name: "invalid ref type",
|
||||
path: "./testdata/dsse-invalid-ref-type.intoto.jsonl",
|
||||
expected: errorInvalidDssePayload,
|
||||
expected: ErrorInvalidDssePayload,
|
||||
},
|
||||
{
|
||||
name: "invalid version",
|
||||
@@ -372,26 +372,25 @@ func Test_VerifyVersionedTag(t *testing.T) {
|
||||
{
|
||||
name: "ref main",
|
||||
path: "./testdata/dsse-main-ref.intoto.jsonl",
|
||||
expected: errorInvalidSemver,
|
||||
expected: ErrorInvalidSemver,
|
||||
tag: "v1.2.3",
|
||||
},
|
||||
{
|
||||
name: "ref branch3",
|
||||
path: "./testdata/dsse-branch3-ref.intoto.jsonl",
|
||||
expected: errorInvalidSemver,
|
||||
expected: ErrorInvalidSemver,
|
||||
tag: "v1.2.3",
|
||||
},
|
||||
{
|
||||
name: "tag v1.2 invalid versioning",
|
||||
path: "./testdata/dsse-v1.2-tag.intoto.jsonl",
|
||||
tag: "1.2",
|
||||
expected: errorInvalidSemver,
|
||||
expected: ErrorInvalidSemver,
|
||||
},
|
||||
|
||||
{
|
||||
name: "invalid ref",
|
||||
path: "./testdata/dsse-invalid-ref-type.intoto.jsonl",
|
||||
expected: errorInvalidDssePayload,
|
||||
expected: ErrorInvalidDssePayload,
|
||||
tag: "v1.2.3",
|
||||
},
|
||||
{
|
||||
@@ -404,13 +403,13 @@ func Test_VerifyVersionedTag(t *testing.T) {
|
||||
name: "tag vslsa1 invalid",
|
||||
path: "./testdata/dsse-vslsa1-tag.intoto.jsonl",
|
||||
tag: "vslsa1",
|
||||
expected: errorInvalidSemver,
|
||||
expected: ErrorInvalidSemver,
|
||||
},
|
||||
{
|
||||
name: "tag vslsa1 invalid semver",
|
||||
path: "./testdata/dsse-vslsa1-tag.intoto.jsonl",
|
||||
tag: "v1.2.3",
|
||||
expected: errorInvalidSemver,
|
||||
expected: ErrorInvalidSemver,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2.3 exact match",
|
||||
@@ -431,19 +430,25 @@ func Test_VerifyVersionedTag(t *testing.T) {
|
||||
name: "tag v1.2.3 no match v2",
|
||||
path: "./testdata/dsse-v1.2.3-tag.intoto.jsonl",
|
||||
tag: "v2",
|
||||
expected: errorMismatchVersionedTag,
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2.3 no match v1.3",
|
||||
path: "./testdata/dsse-v1.2.3-tag.intoto.jsonl",
|
||||
tag: "v1.3",
|
||||
expected: errorMismatchVersionedTag,
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2.3 no match v1.2.4",
|
||||
path: "./testdata/dsse-v1.2.3-tag.intoto.jsonl",
|
||||
tag: "v1.2.4",
|
||||
expected: errorMismatchVersionedTag,
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2.3 no match v1.2.2",
|
||||
path: "./testdata/dsse-v1.2.3-tag.intoto.jsonl",
|
||||
tag: "v1.2.2",
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2 exact v1.2",
|
||||
@@ -455,17 +460,29 @@ func Test_VerifyVersionedTag(t *testing.T) {
|
||||
path: "./testdata/dsse-v1.2-tag.intoto.jsonl",
|
||||
tag: "v1",
|
||||
},
|
||||
{
|
||||
name: "tag v1.1 no match v1.3",
|
||||
path: "./testdata/dsse-v1.2-tag.intoto.jsonl",
|
||||
tag: "v1.1",
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v0 no match v1.3",
|
||||
path: "./testdata/dsse-v1.2-tag.intoto.jsonl",
|
||||
tag: "v0",
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2 no match v1.3",
|
||||
path: "./testdata/dsse-v1.2-tag.intoto.jsonl",
|
||||
tag: "v1.3",
|
||||
expected: errorMismatchVersionedTag,
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2 no match v1.2.3",
|
||||
path: "./testdata/dsse-v1.2-tag.intoto.jsonl",
|
||||
tag: "v1.2.3",
|
||||
expected: errorMismatchVersionedTag,
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1.2 match v1.2.0",
|
||||
@@ -476,7 +493,7 @@ func Test_VerifyVersionedTag(t *testing.T) {
|
||||
name: "tag v1.2 no match v2",
|
||||
path: "./testdata/dsse-v1.2-tag.intoto.jsonl",
|
||||
tag: "v2",
|
||||
expected: errorMismatchVersionedTag,
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1 exact match",
|
||||
@@ -487,19 +504,25 @@ func Test_VerifyVersionedTag(t *testing.T) {
|
||||
name: "tag v1 no match v2",
|
||||
path: "./testdata/dsse-v1-tag.intoto.jsonl",
|
||||
tag: "v2",
|
||||
expected: errorMismatchVersionedTag,
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1 no match v1.2",
|
||||
path: "./testdata/dsse-v1-tag.intoto.jsonl",
|
||||
tag: "v1.2",
|
||||
expected: errorMismatchVersionedTag,
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1 no match v0",
|
||||
path: "./testdata/dsse-v1-tag.intoto.jsonl",
|
||||
tag: "v0",
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1 no match v1.2.3",
|
||||
path: "./testdata/dsse-v1-tag.intoto.jsonl",
|
||||
tag: "v1.2.3",
|
||||
expected: errorMismatchVersionedTag,
|
||||
expected: ErrorMismatchVersionedTag,
|
||||
},
|
||||
{
|
||||
name: "tag v1 match v1.0",
|
||||
|
||||
BIN
Binary file not shown.
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user