Skip to content

Commit

Permalink
refactor: Provenance tests (#628)
Browse files Browse the repository at this point in the history
Refactors GHA provenance tests to use `testProvenance` which makes it clearer what is actually being tested. This will also make it easier to support `buildType` as a way to have different verification logic as the tests no longer rely on testdata with the `"https://github.com/Attestations/GitHubActionsWorkflow@v1"` build type, which isn't used by any supported builders.

A couple of updates to utilities:
- `VerifyTag` will now validate the ref returned by the `Provenance` instance.
- `VerifyBranch` will now validate the ref returned by the `Provenance` instance.
- `VerifyDigest` now supports the 160 bit `"sha1"` algo (FWIW) and will now search all subject entries even if one subject entry's algorithm does not match the expected algorithm.

---------

Signed-off-by: Ian Lewis <ianlewis@google.com>
  • Loading branch information
ianlewis authored Jun 2, 2023
1 parent 8fe8ee9 commit 9bfbc91
Show file tree
Hide file tree
Showing 43 changed files with 598 additions and 760 deletions.
14 changes: 7 additions & 7 deletions cli/slsa-verifier/main_regression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,14 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
source: "github.com/slsa-framework/example-package",
ptag: pString("v1.2.3"),
err: serrors.ErrorMismatchTag,
err: serrors.ErrorInvalidRef,
},
{
name: "versioned tag no match empty tag workflow_dispatch",
artifacts: []string{"binary-linux-amd64-workflow_dispatch"},
source: "github.com/slsa-framework/example-package",
pversiontag: pString("v1"),
err: serrors.ErrorInvalidSemver,
err: serrors.ErrorInvalidRef,
},
// Provenance contains tag = v13.0.30.
{
Expand Down Expand Up @@ -477,7 +477,7 @@ func Test_runVerifyGHAArtifactPath(t *testing.T) {
source: "github.com/asraa/slsa-on-github-test",
pversiontag: pString("v1.5.0"),
pbranch: pString("main"),
err: serrors.ErrorMismatchBranch,
err: serrors.ErrorInvalidRef,
noversion: true,
},
// Workflow inputs.
Expand Down Expand Up @@ -746,14 +746,14 @@ func Test_runVerifyGHAArtifactImage(t *testing.T) {
artifact: "container_workflow_dispatch",
source: "github.com/slsa-framework/example-package",
ptag: pString("v1.2.3"),
err: serrors.ErrorMismatchTag,
err: serrors.ErrorInvalidRef,
},
{
name: "versioned tag no match empty tag workflow_dispatch",
artifact: "container_workflow_dispatch",
source: "github.com/slsa-framework/example-package",
pversiontag: pString("v1"),
err: serrors.ErrorInvalidSemver,
err: serrors.ErrorInvalidRef,
},
}
for _, tt := range tests {
Expand Down Expand Up @@ -1327,14 +1327,14 @@ func Test_runVerifyGHAContainerBased(t *testing.T) {
artifacts: []string{"workflow_dispatch.main.default"},
source: "github.com/slsa-framework/example-package",
pversiontag: pString("v1"),
err: serrors.ErrorInvalidSemver,
err: serrors.ErrorInvalidRef,
},
{
name: "tag no match empty tag workflow_dispatch",
artifacts: []string{"workflow_dispatch.main.default"},
source: "github.com/slsa-framework/example-package",
ptag: pString("v1.2.3"),
err: serrors.ErrorMismatchTag,
err: serrors.ErrorInvalidRef,
},
{
name: "wrong branch master",
Expand Down
45 changes: 36 additions & 9 deletions verifiers/internal/gha/provenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,19 @@ func verifyDigest(prov slsaprovenance.Provenance, expectedHash string) error {
}

// 8 bit represented in hex, so 8/2=4.
l := len(expectedHash) * 4
bitLength := len(expectedHash) * 4
expectedAlgo := fmt.Sprintf("sha%v", bitLength)
// TODO(#630): Add subject digest minimum bit length check.
// sha1 is 160 bit (FWIW).
if bitLength == 160 {
expectedAlgo = "sha1"
}

for _, subject := range subjects {
digestSet := subject.Digest
hash, exists := digestSet[fmt.Sprintf("sha%v", l)]
hash, exists := digestSet[expectedAlgo]
if !exists {
return fmt.Errorf("%w: %s", serrors.ErrorInvalidDssePayload, fmt.Sprintf("no sha%v subject digest", l))
continue
}
if hash == expectedHash {
return nil
Expand Down Expand Up @@ -383,44 +390,64 @@ func VerifyWorkflowInputs(prov slsaprovenance.Provenance, inputs map[string]stri
return nil
}

// VerifyBranch verifies that the source branch in the provenance matches the
// expected value.
func VerifyBranch(prov slsaprovenance.Provenance, expectedBranch string) error {
branch, err := prov.GetBranch()
ref, err := prov.GetBranch()
if err != nil {
return err
}

expectedBranch = "refs/heads/" + expectedBranch
branch, err := utils.BranchFromGitRef(ref)
if err != nil {
return fmt.Errorf("verifying branch: %w", err)
}

if branch != expectedBranch {
return fmt.Errorf("expected branch '%s', got '%s': %w", expectedBranch, branch, serrors.ErrorMismatchBranch)
}

return nil
}

// VerifyTag verifies that the source tag in the provenance matches the
// expected value.
func VerifyTag(prov slsaprovenance.Provenance, expectedTag string) error {
tag, err := prov.GetTag()
ref, err := prov.GetTag()
if err != nil {
return err
}

expectedTag = "refs/tags/" + expectedTag
tag, err := utils.TagFromGitRef(ref)
if err != nil {
return fmt.Errorf("verifying tag: %w", err)
}

if tag != expectedTag {
return fmt.Errorf("expected tag '%s', got '%s': %w", expectedTag, tag, serrors.ErrorMismatchTag)
}

return nil
}

// VerifyVersionedTag verifies that the source tag in the provenance matches the
// expected semver value.
func VerifyVersionedTag(prov slsaprovenance.Provenance, expectedTag string) error {
// Retrieve, validate and canonicalize the provenance tag.
// Note: prerelease is validated as part of patch validation
// and must be equal. Build is discarded as per https://semver.org/:
// "Build metadata MUST be ignored when determining version precedence",
tag, err := prov.GetTag()
ref, err := prov.GetTag()
if err != nil {
return err
}
return utils.VerifyVersionedTag(strings.TrimPrefix(tag, "refs/tags/"), expectedTag)

tag, err := utils.TagFromGitRef(ref)
if err != nil {
return fmt.Errorf("verifying tag: %w", err)
}

return utils.VerifyVersionedTag(tag, expectedTag)
}

// hasCertInEnvelope checks if a valid x509 certificate is present in the
Expand Down
Loading

0 comments on commit 9bfbc91

Please sign in to comment.