Skip to content

Commit

Permalink
Refactor GenerateProvenanceStatement to github package
Browse files Browse the repository at this point in the history
  • Loading branch information
marcofranssen committed Oct 26, 2021
1 parent e36abf1 commit cfc33c2
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 77 deletions.
8 changes: 6 additions & 2 deletions cmd/slsa-provenance/cli/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/pkg/errors"

"github.com/philips-labs/slsa-provenance-action/lib/github"
"github.com/philips-labs/slsa-provenance-action/lib/slsa"
)

// RequiredFlagError creates a required flag error for the given flag name
Expand Down Expand Up @@ -69,6 +68,11 @@ func Generate(w io.Writer) *ffcli.Command {
return errors.Wrap(err, "failed to unmarshal runner context json")
}

environment := github.Environment{
Context: &gh,
Runner: &runner,
}

if *tagName != "" {
ghToken := os.Getenv("GITHUB_TOKEN")
if ghToken == "" {
Expand Down Expand Up @@ -109,7 +113,7 @@ func Generate(w io.Writer) *ffcli.Command {
}()
}

stmt, err := slsa.GenerateProvenanceStatement(ctx, gh, runner, *artifactPath)
stmt, err := environment.GenerateProvenanceStatement(ctx, *artifactPath)
if err != nil {
return errors.Wrap(err, "failed to generate provenance")
}
Expand Down
30 changes: 29 additions & 1 deletion lib/github/github.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
package github

import "encoding/json"
import (
"encoding/json"
"os"
)

const (
// HostedIDSuffix the GitHub hosted attestation type
HostedIDSuffix = "/Attestations/GitHubHostedActions@v1"
// SelfHostedIDSuffix the GitHub self hosted attestation type
SelfHostedIDSuffix = "/Attestations/SelfHostedActions@v1"
// RecipeType the attestion type for a recipe
RecipeType = "https://github.com/Attestations/GitHubActionsWorkflow@v1"
// PayloadContentType used to define the Envelope content type
// See: https://github.com/in-toto/attestation#provenance-example
PayloadContentType = "application/vnd.in-toto+json"
)

func builderID(repoURI string) string {
if os.Getenv("GITHUB_ACTIONS") == "true" {
return repoURI + HostedIDSuffix
}
return repoURI + SelfHostedIDSuffix
}

// Environment the environment from which provenance is generated.
type Environment struct {
Context *Context `json:"github,omitempty"`
Runner *RunnerContext `json:"runner,omitempty"`
}

// Context holds all the information set on Github runners in relation to the job
//
Expand Down
50 changes: 50 additions & 0 deletions lib/github/provenance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package github

import (
"context"
"encoding/json"
"fmt"
"os"

"github.com/pkg/errors"

"github.com/philips-labs/slsa-provenance-action/lib/intoto"
)

// GenerateProvenanceStatement generates provenance from the provided artifactPath
//
// The artifactPath can be a file or a directory.
func (e *Environment) GenerateProvenanceStatement(ctx context.Context, artifactPath string) (*intoto.Statement, error) {
subjects, err := intoto.Subjects(artifactPath)
if os.IsNotExist(err) {
return nil, fmt.Errorf("resource path not found: [provided=%s]", artifactPath)
} else if err != nil {
return nil, err
}

repoURI := "https://github.com/" + e.Context.Repository

event := AnyEvent{}
if err := json.Unmarshal(e.Context.Event, &event); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal github context event json")
}

stmt := intoto.SLSAProvenanceStatement(
intoto.WithSubject(subjects),
intoto.WithBuilder(builderID(repoURI)),
// NOTE: Re-runs are not uniquely identified and can cause run ID collisions.
intoto.WithMetadata(fmt.Sprintf("%s/actions/runs/%s", repoURI, e.Context.RunID)),
// NOTE: This is inexact as multiple workflows in a repo can have the same name.
// See https://github.com/github/feedback/discussions/4188
intoto.WithRecipe(
RecipeType,
e.Context.Workflow,
nil,
event.Inputs,
[]intoto.Item{
{URI: "git+" + repoURI, Digest: intoto.DigestSet{"sha1": e.Context.SHA}},
},
))

return stmt, nil
}
19 changes: 12 additions & 7 deletions lib/slsa/provenance_test.go → lib/github/provenance_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package slsa_test
package github_test

import (
"context"
Expand All @@ -13,10 +13,10 @@ import (

"github.com/philips-labs/slsa-provenance-action/lib/github"
"github.com/philips-labs/slsa-provenance-action/lib/intoto"
"github.com/philips-labs/slsa-provenance-action/lib/slsa"
)

const pushGitHubEvent = `{
const (
pushGitHubEvent = `{
"after": "c4f679f131dfb7f810fd411ac9475549d1c393df",
"base_ref": null,
"before": "715b4daa0f750f420635ee488ef37a2433608438",
Expand Down Expand Up @@ -225,6 +225,7 @@ const pushGitHubEvent = `{
"url": "https://api.github.com/users/john-doe"
}
}`
)

func TestGenerateProvenance(t *testing.T) {
assert := assert.New(t)
Expand All @@ -251,7 +252,11 @@ func TestGenerateProvenance(t *testing.T) {
rootDir := path.Join(path.Dir(filename), "../..")
artifactPath := path.Join(rootDir, "bin")

stmt, err := slsa.GenerateProvenanceStatement(ctx, gh, runner, artifactPath)
env := github.Environment{
Context: &gh,
Runner: &runner,
}
stmt, err := env.GenerateProvenanceStatement(ctx, artifactPath)
if !assert.NoError(err) {
return
}
Expand All @@ -266,16 +271,16 @@ func TestGenerateProvenance(t *testing.T) {
assert.Equal(intoto.StatementType, stmt.Type)

predicate := stmt.Predicate
assert.Equal(fmt.Sprintf("%s%s", repoURL, slsa.GitHubHostedIDSuffix), predicate.ID)
assert.Equal(fmt.Sprintf("%s%s", repoURL, github.HostedIDSuffix), predicate.ID)
assert.Equal(materials, predicate.Materials)
assert.Equal(fmt.Sprintf("%s%s", repoURL, slsa.GitHubHostedIDSuffix), predicate.Builder.ID)
assert.Equal(fmt.Sprintf("%s%s", repoURL, github.HostedIDSuffix), predicate.Builder.ID)

assertMetadata(assert, predicate.Metadata, gh, repoURL)
assertRecipe(assert, predicate.Recipe)
}

func assertRecipe(assert *assert.Assertions, recipe intoto.Recipe) {
assert.Equal(slsa.RecipeType, recipe.Type)
assert.Equal(github.RecipeType, recipe.Type)
assert.Equal(0, recipe.DefinedInMaterial)
assert.Equal("", recipe.EntryPoint)
assert.Nil(recipe.Environment)
Expand Down
67 changes: 0 additions & 67 deletions lib/slsa/provenance.go

This file was deleted.

0 comments on commit cfc33c2

Please sign in to comment.