Skip to content

Commit

Permalink
feat: support builderID matching with or without semver for GCB (#256)
Browse files Browse the repository at this point in the history
* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update
  • Loading branch information
laurentsimon authored Sep 13, 2022
1 parent d12dce9 commit b58e752
Show file tree
Hide file tree
Showing 14 changed files with 531 additions and 122 deletions.
105 changes: 76 additions & 29 deletions cli/slsa-verifier/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (

"github.com/slsa-framework/slsa-verifier/cli/slsa-verifier/verify"
serrors "github.com/slsa-framework/slsa-verifier/errors"
"github.com/slsa-framework/slsa-verifier/verifiers/container"
"github.com/slsa-framework/slsa-verifier/verifiers/utils/container"
)

func errCmp(e1, e2 error) bool {
Expand Down Expand Up @@ -511,10 +511,14 @@ func Test_runVerifyArtifactPath(t *testing.T) {
return
}

if tt.outBuilderID != "" && outBuilderID != tt.outBuilderID {
t.Errorf(cmp.Diff(outBuilderID, tt.outBuilderID))
// Validate against test's expected builderID, if provided.
if tt.outBuilderID != "" {
if err := outBuilderID.Matches(tt.outBuilderID); err != nil {
t.Errorf(fmt.Sprintf("matches failed: %v", err))
}
}

// TODO: verify using Matches().
}
})
}
Expand Down Expand Up @@ -675,9 +679,14 @@ func Test_runVerifyGHAArtifactImage(t *testing.T) {
return
}

if tt.outBuilderID != "" && outBuilderID != tt.outBuilderID {
t.Errorf(cmp.Diff(outBuilderID, tt.outBuilderID))
// Validate against test's expected builderID, if provided.
if tt.outBuilderID != "" {
if err := outBuilderID.Matches(tt.outBuilderID); err != nil {
t.Errorf(fmt.Sprintf("matches failed: %v", err))
}
}

// TODO: verify using Matches().
}
})
}
Expand Down Expand Up @@ -729,6 +738,29 @@ func Test_runVerifyGCBArtifactImage(t *testing.T) {
provenance: "gcloud-container-github.json",
source: "github.com/laurentsimon/gcb-tests",
},
{
name: "mismatch input builder version",
artifact: "gcloud-container-github",
provenance: "gcloud-container-github.json",
source: "github.com/laurentsimon/gcb-tests",
pBuilderID: pString(builder + "@v0.4"),
err: serrors.ErrorMismatchBuilderID,
},
{
name: "unsupported builder",
artifact: "gcloud-container-github",
provenance: "gcloud-container-github.json",
source: "github.com/laurentsimon/gcb-tests",
pBuilderID: pString(builder + "a"),
err: serrors.ErrorVerifierNotSupported,
},
{
name: "match output builder name",
artifact: "gcloud-container-github",
provenance: "gcloud-container-github.json",
source: "github.com/laurentsimon/gcb-tests",
outBuilderID: builder,
},
{
name: "invalid repo name",
artifact: "gcloud-container-github",
Expand Down Expand Up @@ -858,17 +890,20 @@ func Test_runVerifyGCBArtifactImage(t *testing.T) {

for _, v := range checkVersions {
semver := path.Base(v)
builderID := pString(builder + "@" + semver)
// For each test, we run 2 sub-tests:
// 1. With the the full builderID including the semver.
// 2. With only the name of the builder.
builderIDs := []string{builder + "@" + semver, builder}
provenance := filepath.Clean(filepath.Join(TEST_DIR, v, tt.provenance))
image := tt.artifact
var fn verify.ComputeDigestFn

// If builder ID is set, use it.
if tt.pBuilderID != nil {
if !tt.noversion {
panic("builderID set but not noversion option")
}
builderID = tt.pBuilderID
// if !tt.noversion {
// panic("builderID set but not noversion option")
// }
builderIDs = []string{*tt.pBuilderID}
}

// Select the right image according to the builder version we are testing.
Expand All @@ -889,30 +924,42 @@ func Test_runVerifyGCBArtifactImage(t *testing.T) {
fn = localDigestComputeFn
}

cmd := verify.VerifyImageCommand{
SourceURI: tt.source,
SourceBranch: nil,
BuilderID: builderID,
SourceTag: nil,
SourceVersionTag: nil,
DigestFn: fn,
ProvenancePath: &provenance,
}
// We run the test for each builderID, in order to test
// a builderID provided by name and one containing both the name
// and semver.
for _, bid := range builderIDs {
cmd := verify.VerifyImageCommand{
SourceURI: tt.source,
SourceBranch: nil,
BuilderID: &bid,
SourceTag: nil,
SourceVersionTag: nil,
DigestFn: fn,
ProvenancePath: &provenance,
}

outBuilderID, err := cmd.Exec(context.Background(), []string{image})
outBuilderID, err := cmd.Exec(context.Background(), []string{image})

if !errCmp(err, tt.err) {
t.Errorf(cmp.Diff(err, tt.err, cmpopts.EquateErrors()))
}
if !errCmp(err, tt.err) {
t.Errorf(cmp.Diff(err, tt.err, cmpopts.EquateErrors()))
}

if err != nil {
return
}
if err != nil {
return
}

if tt.outBuilderID != "" && outBuilderID != tt.outBuilderID {
t.Errorf(cmp.Diff(outBuilderID, tt.outBuilderID))
}
// Validate against test's expected builderID, if provided.
if tt.outBuilderID != "" {
if err := outBuilderID.Matches(tt.outBuilderID); err != nil {
t.Errorf(fmt.Sprintf("matches failed: %v", err))
}
}

// Validate against builderID we generated automatically.
if err := outBuilderID.Matches(bid); err != nil {
t.Errorf(fmt.Sprintf("matches failed: %v", err))
}
}
}
})
}
Expand Down
9 changes: 5 additions & 4 deletions cli/slsa-verifier/verify/verify_artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

"github.com/slsa-framework/slsa-verifier/options"
"github.com/slsa-framework/slsa-verifier/verifiers"
"github.com/slsa-framework/slsa-verifier/verifiers/utils"
)

// Note: nil branch, tag, version-tag and builder-id means we ignore them during verification.
Expand All @@ -38,10 +39,10 @@ type VerifyArtifactCommand struct {
PrintProvenance bool
}

func (c *VerifyArtifactCommand) Exec(ctx context.Context, artifacts []string) (string, error) {
func (c *VerifyArtifactCommand) Exec(ctx context.Context, artifacts []string) (*utils.BuilderID, error) {
artifactHash, err := getArtifactHash(artifacts[0])
if err != nil {
return "", err
return nil, err
}

provenanceOpts := &options.ProvenanceOpts{
Expand All @@ -59,12 +60,12 @@ func (c *VerifyArtifactCommand) Exec(ctx context.Context, artifacts []string) (s

provenance, err := os.ReadFile(c.ProvenancePath)
if err != nil {
return "", err
return nil, err
}

verifiedProvenance, outBuilderID, err := verifiers.VerifyArtifact(ctx, provenance, artifactHash, provenanceOpts, builderOpts)
if err != nil {
return "", err
return nil, err
}

if c.PrintProvenance {
Expand Down
13 changes: 7 additions & 6 deletions cli/slsa-verifier/verify/verify_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import (

"github.com/slsa-framework/slsa-verifier/options"
"github.com/slsa-framework/slsa-verifier/verifiers"
"github.com/slsa-framework/slsa-verifier/verifiers/container"
"github.com/slsa-framework/slsa-verifier/verifiers/utils"
"github.com/slsa-framework/slsa-verifier/verifiers/utils/container"
)

type ComputeDigestFn func(string) (string, error)
Expand All @@ -40,20 +41,20 @@ type VerifyImageCommand struct {
DigestFn ComputeDigestFn
}

func (c *VerifyImageCommand) Exec(ctx context.Context, artifacts []string) (string, error) {
func (c *VerifyImageCommand) Exec(ctx context.Context, artifacts []string) (*utils.BuilderID, error) {
artifactImage := artifacts[0]
// Retrieve the image digest.
if c.DigestFn == nil {
c.DigestFn = container.GetImageDigest
}
digest, err := c.DigestFn(artifactImage)
if err != nil {
return "", err
return nil, err
}

// Verify that the reference is immutable.
if err := container.ValidateArtifactReference(artifactImage, digest); err != nil {
return "", err
return nil, err
}

provenanceOpts := &options.ProvenanceOpts{
Expand All @@ -73,13 +74,13 @@ func (c *VerifyImageCommand) Exec(ctx context.Context, artifacts []string) (stri
if c.ProvenancePath != nil {
provenance, err = os.ReadFile(*c.ProvenancePath)
if err != nil {
return "", err
return nil, err
}
}

verifiedProvenance, outBuilderID, err := verifiers.VerifyImage(ctx, artifacts[0], provenance, provenanceOpts, builderOpts)
if err != nil {
return "", err
return nil, err
}

if c.PrintProvenance {
Expand Down
2 changes: 1 addition & 1 deletion experimental/rest/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func verifyHandlerV1(r *http.Request) *v1Result {
results = results.withIntotoStatement(p)
}

return results.withBuilderID(builderID).withValidation(validationSuccess)
return results.withBuilderID(builderID.String()).withValidation(validationSuccess)
}

func queryFromString(content []byte) (*v1Query, error) {
Expand Down
7 changes: 4 additions & 3 deletions register/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"

"github.com/slsa-framework/slsa-verifier/options"
"github.com/slsa-framework/slsa-verifier/verifiers/utils"
)

var SLSAVerifiers = make(map[string]SLSAVerifier)
Expand All @@ -12,21 +13,21 @@ type SLSAVerifier interface {
// IsAuthoritativeFor checks whether a verifier can
// verify provenance for a given builder identified by its
// `BuilderID`.
IsAuthoritativeFor(builderID string) bool
IsAuthoritativeFor(builderIDName string) bool

// VerifyArtifact verifies a provenance for a supplied artifact.
VerifyArtifact(ctx context.Context,
provenance []byte, artifactHash string,
provenanceOpts *options.ProvenanceOpts,
builderOpts *options.BuilderOpts,
) ([]byte, string, error)
) ([]byte, *utils.BuilderID, error)

// VerifyImage verifies a provenance for a supplied OCI image.
VerifyImage(ctx context.Context,
provenance []byte, artifactImage string,
provenanceOpts *options.ProvenanceOpts,
builderOpts *options.BuilderOpts,
) ([]byte, string, error)
) ([]byte, *utils.BuilderID, error)
}

func RegisterVerifier(name string, verifier SLSAVerifier) {
Expand Down
Loading

0 comments on commit b58e752

Please sign in to comment.