From 563ba76f52c702c2a4be8fbc79d9ca5b76f662c7 Mon Sep 17 00:00:00 2001 From: Marco Franssen Date: Mon, 25 Oct 2021 17:31:08 +0200 Subject: [PATCH] Refactor persisting provenance to environment --- cmd/slsa-provenance/cli/generate.go | 20 ++------------- lib/github/provenance.go | 38 ++++++++++++++++++++++++----- lib/github/provenance_test.go | 8 +----- lib/intoto/intoto.go | 1 + 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/cmd/slsa-provenance/cli/generate.go b/cmd/slsa-provenance/cli/generate.go index 76a8a8dc..1f87b9ba 100644 --- a/cmd/slsa-provenance/cli/generate.go +++ b/cmd/slsa-provenance/cli/generate.go @@ -80,25 +80,9 @@ func Generate(w io.Writer) *ffcli.Command { return errors.Wrap(err, "failed to generate provenance") } - // NOTE: At L1, writing the in-toto Statement type is sufficient but, at - // higher SLSA levels, the Statement must be encoded and wrapped in an - // Envelope to support attaching signatures. - payload, _ := json.MarshalIndent(stmt, "", " ") - fmt.Fprintf(w, "Saving provenance to %s:\n\n%s\n", *outputPath, string(payload)) + fmt.Fprintf(w, "Saving provenance to %s\n", *outputPath) - if err := os.WriteFile(*outputPath, payload, 0755); err != nil { - return errors.Wrap(err, "failed to write provenance") - } - - if renv, ok := env.(*github.ReleaseEnvironment); ok { - stmtFile, err := os.Open(*outputPath) - if err != nil { - return fmt.Errorf("failed to open provenance statement: %w", err) - } - renv.AttachProvenanceStatement(ctx, *tagName, stmtFile) - } - - return nil + return env.PersistProvenanceStatement(ctx, stmt, *outputPath) }, } } diff --git a/lib/github/provenance.go b/lib/github/provenance.go index 6bd35795..46faa76a 100644 --- a/lib/github/provenance.go +++ b/lib/github/provenance.go @@ -8,7 +8,6 @@ import ( "os" "strings" - "github.com/google/go-github/v39/github" "github.com/pkg/errors" "github.com/philips-labs/slsa-provenance-action/lib/intoto" @@ -52,6 +51,22 @@ func (e *Environment) GenerateProvenanceStatement(ctx context.Context, artifactP return stmt, nil } +// PersistProvenanceStatement writes the provenance statement at the given path +func (e *Environment) PersistProvenanceStatement(ctx context.Context, stmt *intoto.Statement, path string) error { + // NOTE: At L1, writing the in-toto Statement type is sufficient but, at + // higher SLSA levels, the Statement must be encoded and wrapped in an + // Envelope to support attaching signatures. + payload, err := json.MarshalIndent(stmt, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal provenance: %w", err) + } + if err := os.WriteFile(path, payload, 0755); err != nil { + return fmt.Errorf("failed to write provenance: %w", err) + } + + return nil +} + // ReleaseEnvironment implements intoto.Provenancer to Generate provenance based on a GitHub release type ReleaseEnvironment struct { *Environment @@ -106,15 +121,26 @@ func (e *ReleaseEnvironment) GenerateProvenanceStatement(ctx context.Context, ar return e.Environment.GenerateProvenanceStatement(ctx, artifactPath) } -// AttachProvenanceStatement attaches the provenance statement to the release -func (e *ReleaseEnvironment) AttachProvenanceStatement(ctx context.Context, file *os.File) (*github.ReleaseAsset, error) { +// PersistProvenanceStatement writes the provenance statement at the given path and uploads it to the GitHub release +func (e *ReleaseEnvironment) PersistProvenanceStatement(ctx context.Context, stmt *intoto.Statement, path string) error { + err := e.Environment.PersistProvenanceStatement(ctx, stmt, path) + if err != nil { + return err + } + + stmtFile, err := os.Open(path) + if err != nil { + return fmt.Errorf("failed to open provenance statement: %w", err) + } + owner := e.Context.RepositoryOwner repo := repositoryName(e.Context.Repository) - releaseID, err := e.GetReleaseID(ctx, e.tagName) + _, err = e.rc.AddProvenanceToRelease(ctx, owner, repo, e.releaseID, stmtFile) if err != nil { - return nil, err + return fmt.Errorf("failed to upload provenance to release: %w", err) } - return e.rc.AddProvenanceToRelease(ctx, owner, repo, releaseID, file) + + return nil } // GetReleaseID fetches a release and caches the releaseID in the environment diff --git a/lib/github/provenance_test.go b/lib/github/provenance_test.go index e8fae1cb..9c885a8d 100644 --- a/lib/github/provenance_test.go +++ b/lib/github/provenance_test.go @@ -2,7 +2,6 @@ package github_test import ( "context" - "encoding/json" "fmt" "os" "path" @@ -353,14 +352,9 @@ func TestGenerateProvenanceFromGitHubRelease(t *testing.T) { assertMetadata(assert, predicate.Metadata, ghContext, repoURL) assertRecipe(assert, predicate.Recipe) - payload, _ := json.MarshalIndent(stmt, "", " ") stmtPath := path.Join(artifactPath, "build.provenance") - err = os.WriteFile(stmtPath, payload, 0755) - assert.NoError(err) - stmtFile, err := os.Open(stmtPath) - assert.NoError(err) - _, err = env.AttachProvenanceStatement(ctx, stmtFile) + err = env.PersistProvenanceStatement(ctx, stmt, stmtPath) assert.NoError(err) } diff --git a/lib/intoto/intoto.go b/lib/intoto/intoto.go index d265755f..dd72bfac 100644 --- a/lib/intoto/intoto.go +++ b/lib/intoto/intoto.go @@ -16,6 +16,7 @@ const ( // Provenancer generates provenance statements for given artifacts type Provenancer interface { GenerateProvenanceStatement(ctx context.Context, artifactPath string) (*Statement, error) + PersistProvenanceStatement(ctx context.Context, stmt *Statement, path string) error } // Envelope wraps an in-toto statement to be able to attach signatures to the Statement