mirror of
https://github.com/slsa-framework/slsa-verifier.git
synced 2026-05-09 10:06:37 +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
|
||||
|
||||
51
main.go
51
main.go
@@ -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
main_test.go
Normal file
311
main_test.go
Normal file
@@ -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()))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
testdata/binary-linux-amd64-push-v1.2.4
vendored
Normal file
BIN
testdata/binary-linux-amd64-push-v1.2.4
vendored
Normal file
Binary file not shown.
1
testdata/binary-linux-amd64-push-v1.2.4.intoto.jsonl
vendored
Normal file
1
testdata/binary-linux-amd64-push-v1.2.4.intoto.jsonl
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
testdata/binary-linux-amd64-push-v2
vendored
Normal file
BIN
testdata/binary-linux-amd64-push-v2
vendored
Normal file
Binary file not shown.
BIN
testdata/binary-linux-amd64-push-v2.5
vendored
Normal file
BIN
testdata/binary-linux-amd64-push-v2.5
vendored
Normal file
Binary file not shown.
1
testdata/binary-linux-amd64-push-v2.5.intoto.jsonl
vendored
Normal file
1
testdata/binary-linux-amd64-push-v2.5.intoto.jsonl
vendored
Normal file
File diff suppressed because one or more lines are too long
1
testdata/binary-linux-amd64-push-v2.intoto.jsonl
vendored
Normal file
1
testdata/binary-linux-amd64-push-v2.intoto.jsonl
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
testdata/binary-linux-amd64-workflow_dispatch
vendored
Normal file
BIN
testdata/binary-linux-amd64-workflow_dispatch
vendored
Normal file
Binary file not shown.
1
testdata/binary-linux-amd64-workflow_dispatch.intoto.jsonl
vendored
Normal file
1
testdata/binary-linux-amd64-workflow_dispatch.intoto.jsonl
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user