Skip to content

Commit

Permalink
Link & SLSA attestor (#149)
Browse files Browse the repository at this point in the history
* Initial link attestor

Signed-off-by: John Kjell <[email protected]>

* refactor: move gitoid code to cyrptoutil, use digestvalue everywhere (#139)

When the functionality to calculate gitoids was added, there was a bit
of tech debt incurred since they didn't implement hash.Hash. This
remedies this with an admitedly hacky implementation of hash.Hash that
wraps the gitoid code. This also standardizes our cryptoutil fucntions
around the DigestValue struct that was added around this time to
differentiate between gitoids and regular hash functions.

Signed-off-by: Mikhail Swift <[email protected]>
Signed-off-by: John Kjell <[email protected]>

* chore: bump actions/upload-artifact from 4.2.0 to 4.3.0 (#142)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@694cdab...26f96df)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: John Kjell <[email protected]>

* chore: bump github/codeql-action from 3.23.1 to 3.23.2 (#143)

Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.23.1 to 3.23.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@0b21cf2...b7bf0a3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tom Meadows <[email protected]>
Signed-off-by: John Kjell <[email protected]>

* Adding job to auto cut releases (#141)

adding job to auto cut releases

Signed-off-by: chaosinthecrd <[email protected]>
Signed-off-by: John Kjell <[email protected]>

* fixing error in github actions workflow (#147)

fixing error in workflow

Signed-off-by: chaosinthecrd <[email protected]>
Signed-off-by: John Kjell <[email protected]>

* RunAttestors refactor (#131)

* improving run attestors

Signed-off-by: chaosinthecrd <[email protected]>

* finalising changes.

Signed-off-by: chaosinthecrd <[email protected]>

* improving run attestors

Signed-off-by: chaosinthecrd <[email protected]>

* finalising changes.

Signed-off-by: chaosinthecrd <[email protected]>

* addressing review, restoring run type order

Signed-off-by: chaosinthecrd <[email protected]>

* updating error handling logic

Signed-off-by: chaosinthecrd <[email protected]>

* updating to go 1.21 for errors.Join

Signed-off-by: chaosinthecrd <[email protected]>

---------

Signed-off-by: chaosinthecrd <[email protected]>
Signed-off-by: Tom Meadows <[email protected]>
Signed-off-by: John Kjell <[email protected]>

* Adding workaround due to failing workflows (#145)

adding workaround due to failing workflows

Signed-off-by: chaosinthecrd <[email protected]>
Signed-off-by: John Kjell <[email protected]>

* Checking policy signature against cert constraints (#144)

* adding logic so policy signature can be checked against constraints
* threaded options into policy validation functionary
---------

Signed-off-by: chaosinthecrd <[email protected]>
Signed-off-by: John Kjell <[email protected]>
Co-authored-by: John Kjell <[email protected]>
Signed-off-by: John Kjell <[email protected]>

* [StepSecurity] ci: Harden GitHub Actions (#148)

Signed-off-by: StepSecurity Bot <[email protected]>
Signed-off-by: John Kjell <[email protected]>

* Add import for init and export variables

Signed-off-by: John Kjell <[email protected]>

* Add mulitple results to run to allow exporting attestors to indivudal files

Signed-off-by: John Kjell <[email protected]>

* Add collection to result array

Signed-off-by: John Kjell <[email protected]>

* Replace export parameters in run with attestor option

Signed-off-by: John Kjell <[email protected]>

* Fix golang lint isues

Signed-off-by: John Kjell <[email protected]>

* Update link attestor testing

Signed-off-by: John Kjell <[email protected]>

* Add SLSA attestor

Signed-off-by: John Kjell <[email protected]>

* Add interface for product attestor

Signed-off-by: John Kjell <[email protected]>

* Add more attestor interfaces

Signed-off-by: John Kjell <[email protected]>

* Address some review feedback, licenses, and golanglint

Signed-off-by: John Kjell <[email protected]>

* More golangcilint errors

Signed-off-by: John Kjell <[email protected]>

* WIP - Improve testing interfaces for exposing data fields

Signed-off-by: John Kjell <[email protected]>

* added changes

* adding changes to merge into main PR

* Link attestor proposed changes  (#204)

* unmarshal the time in the attestation collection correctly (#203)
* add StepName to AttestorContext
* use CollectionAttestion to properly set start/end times
---------

Signed-off-by: John Kjell <[email protected]>
Co-authored-by: Cole Kennedy <[email protected]>
Co-authored-by: Cole <[email protected]>
Co-authored-by: John Kjell <[email protected]>

* Passing SLSA Attest tests for GitHub and GitLab

Signed-off-by: John Kjell <[email protected]>

* Clean up

Signed-off-by: John Kjell <[email protected]>

* Add attestation test for link attestor

Signed-off-by: John Kjell <[email protected]>

* Add data function for git interface and remove unused code

Signed-off-by: John Kjell <[email protected]>

* adding warning mesage for slsa attestor

Signed-off-by: chaosinthecrd <[email protected]>

* Try to gracefully handle gitlab jwt

Signed-off-by: John Kjell <[email protected]>

* ran go mod tidy

Signed-off-by: chaosinthecrd <[email protected]>

* ensuring link and slsa attestation exporting is optional

Signed-off-by: chaosinthecrd <[email protected]>

---------

Signed-off-by: John Kjell <[email protected]>
Signed-off-by: Mikhail Swift <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]>
Signed-off-by: chaosinthecrd <[email protected]>
Signed-off-by: Tom Meadows <[email protected]>
Signed-off-by: StepSecurity Bot <[email protected]>
Co-authored-by: Mikhail Swift <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tom Meadows <[email protected]>
Co-authored-by: StepSecurity Bot <[email protected]>
Co-authored-by: Cole Kennedy <[email protected]>
Co-authored-by: Cole <[email protected]>
  • Loading branch information
7 people authored May 9, 2024
1 parent 3e62eab commit 87975b4
Show file tree
Hide file tree
Showing 32 changed files with 1,667 additions and 43 deletions.
5 changes: 2 additions & 3 deletions attestation/aws-iid/aws-iid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,10 @@ func TestAttestor_Attest(t *testing.T) {
conf: conf,
}

ctx, err := attestation.NewContext([]attestation.Attestor{a})
ctx, err := attestation.NewContext("test", []attestation.Attestor{a})
require.NoError(t, err)
err = a.Attest(ctx)
require.NoError(t, err)

}

func TestAttestor_getIID(t *testing.T) {
Expand Down Expand Up @@ -154,7 +153,7 @@ func TestAttestor_Subjects(t *testing.T) {
conf: conf,
}

ctx, err := attestation.NewContext([]attestation.Attestor{a})
ctx, err := attestation.NewContext("test", []attestation.Attestor{a})
require.NoError(t, err)
err = a.Attest(ctx)
require.NoError(t, err)
Expand Down
14 changes: 14 additions & 0 deletions attestation/commandrun/commandrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,18 @@ const (
// doesn't implement the expected interfaces.
var (
_ attestation.Attestor = &CommandRun{}
_ CommandRunAttestor = &CommandRun{}
)

type CommandRunAttestor interface {
// Attestor
Name() string
Type() string
RunType() attestation.RunType
Attest(ctx *attestation.AttestationContext) error
Data() *CommandRun
}

func init() {
attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor {
return New()
Expand Down Expand Up @@ -129,6 +139,10 @@ func (rc *CommandRun) Attest(ctx *attestation.AttestationContext) error {
return nil
}

func (rc *CommandRun) Data() *CommandRun {
return rc
}

func (rc *CommandRun) Name() string {
return Name
}
Expand Down
8 changes: 7 additions & 1 deletion attestation/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,15 @@ type AttestationContext struct {
completedAttestors []CompletedAttestor
products map[string]Product
materials map[string]cryptoutil.DigestSet
stepName string
}

type Product struct {
MimeType string `json:"mime_type"`
Digest cryptoutil.DigestSet `json:"digest"`
}

func NewContext(attestors []Attestor, opts ...AttestationContextOption) (*AttestationContext, error) {
func NewContext(stepName string, attestors []Attestor, opts ...AttestationContextOption) (*AttestationContext, error) {
wd, err := os.Getwd()
if err != nil {
return nil, err
Expand All @@ -117,6 +118,7 @@ func NewContext(attestors []Attestor, opts ...AttestationContextOption) (*Attest
hashes: []cryptoutil.DigestValue{{Hash: crypto.SHA256}, {Hash: crypto.SHA256, GitOID: true}, {Hash: crypto.SHA1, GitOID: true}},
materials: make(map[string]cryptoutil.DigestSet),
products: make(map[string]Product),
stepName: stepName,
}

for _, opt := range opts {
Expand Down Expand Up @@ -219,6 +221,10 @@ func (ctx *AttestationContext) Products() map[string]Product {
return out
}

func (ctx *AttestationContext) StepName() string {
return ctx.stepName
}

func (ctx *AttestationContext) addMaterials(materialer Materialer) {
newMats := materialer.Materials()
for k, v := range newMats {
Expand Down
14 changes: 14 additions & 0 deletions attestation/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,18 @@ const (
// doesn't implement the expected interfaces.
var (
_ attestation.Attestor = &Attestor{}
_ EnvironmentAttestor = &Attestor{}
)

type EnvironmentAttestor interface {
// Attestor
Name() string
Type() string
RunType() attestation.RunType
Attest(ctx *attestation.AttestationContext) error
Data() *Attestor
}

func init() {
attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor {
return New()
Expand Down Expand Up @@ -101,6 +111,10 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error {
return nil
}

func (a *Attestor) Data() *Attestor {
return a
}

// splitVariable splits a string representing an environment variable in the format of
// "KEY=VAL" and returns the key and val separately.
func splitVariable(v string) (key, val string) {
Expand Down
2 changes: 1 addition & 1 deletion attestation/environment/environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (

func TestEnvironment(t *testing.T) {
attestor := New()
ctx, err := attestation.NewContext([]attestation.Attestor{attestor})
ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor})
require.NoError(t, err)

t.Setenv("AWS_ACCESS_KEY_ID", "super secret")
Expand Down
5 changes: 5 additions & 0 deletions attestation/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ type Producer interface {
Products() map[string]Product
}

// Exporter allows attestors to export their attestations for separation from the collection.
type Exporter interface {
Export() bool
}

// BackReffer allows attestors to indicate which of their subjects are good candidates
// to find related attestations. For example the git attestor's commit hash subject
// is a good candidate to find all attestation collections that also refer to a specific
Expand Down
30 changes: 30 additions & 0 deletions attestation/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,24 @@ var (
_ attestation.Attestor = &Attestor{}
_ attestation.Subjecter = &Attestor{}
_ attestation.BackReffer = &Attestor{}
_ GitAttestor = &Attestor{}
)

type GitAttestor interface {
// Attestor
Name() string
Type() string
RunType() attestation.RunType
Attest(ctx *attestation.AttestationContext) error
Data() *Attestor

// Subjecter
Subjects() map[string]cryptoutil.DigestSet

// Backreffer
BackRefs() map[string]cryptoutil.DigestSet
}

func init() {
attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor {
return New()
Expand Down Expand Up @@ -75,6 +91,7 @@ type Attestor struct {
ParentHashes []string `json:"parenthashes,omitempty"`
TreeHash string `json:"treehash,omitempty"`
Refs []string `json:"refs,omitempty"`
Remotes []string `json:"remotes,omitempty"`
Tags []Tag `json:"tags,omitempty"`
}

Expand Down Expand Up @@ -125,6 +142,15 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error {
}: commit.Hash.String(),
}

remotes, err := repo.Remotes()
if err != nil {
return err
}

for _, remote := range remotes {
a.Remotes = append(a.Remotes, remote.Config().URLs...)
}

//get all the refs for the repo
refs, err := repo.References()
if err != nil {
Expand Down Expand Up @@ -218,6 +244,10 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error {
return nil
}

func (a *Attestor) Data() *Attestor {
return a
}

func (a *Attestor) Subjects() map[string]cryptoutil.DigestSet {
subjects := make(map[string]cryptoutil.DigestSet)
hashes := []cryptoutil.DigestValue{{Hash: crypto.SHA256}}
Expand Down
4 changes: 2 additions & 2 deletions attestation/git/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestRunWorksWithCommits(t *testing.T) {
_, dir, cleanup := createTestRepo(t, true)
defer cleanup()

ctx, err := attestation.NewContext([]attestation.Attestor{attestor}, attestation.WithWorkingDir(dir))
ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}, attestation.WithWorkingDir(dir))
require.NoError(t, err, "Expected no error from NewContext")

err = ctx.RunAttestors()
Expand Down Expand Up @@ -146,7 +146,7 @@ func TestRunWorksWithoutCommits(t *testing.T) {
_, dir, cleanup := createTestRepo(t, false)
defer cleanup()

ctx, err := attestation.NewContext([]attestation.Attestor{attestor}, attestation.WithWorkingDir(dir))
ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}, attestation.WithWorkingDir(dir))
require.NoError(t, err, "Expected no error from NewContext")

err = ctx.RunAttestors()
Expand Down
30 changes: 25 additions & 5 deletions attestation/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,36 @@ var (
_ attestation.Attestor = &Attestor{}
_ attestation.Subjecter = &Attestor{}
_ attestation.BackReffer = &Attestor{}
_ GitHubAttestor = &Attestor{}
)

type GitHubAttestor interface {
// Attestor
Name() string
Type() string
RunType() attestation.RunType
Attest(ctx *attestation.AttestationContext) error
Data() *Attestor

// Subjecter
Subjects() map[string]cryptoutil.DigestSet

// Backreffer
BackRefs() map[string]cryptoutil.DigestSet
}

// init registers the github attestor.
func init() {
attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor {
return New()
})
}

// ErrNotGitlab is an error type that indicates the environment is not a github ci job.
type ErrNotGitlab struct{}
// ErrNotGitHub is an error type that indicates the environment is not a github ci job.
type ErrNotGitHub struct{}

// Error returns the error message for ErrNotGitlab.
func (e ErrNotGitlab) Error() string {
// Error returns the error message for ErrNotGitHub.
func (e ErrNotGitHub) Error() string {
return "not in a github ci job"
}

Expand Down Expand Up @@ -111,7 +127,7 @@ func (a *Attestor) RunType() attestation.RunType {
// Attest performs the attestation for the github environment.
func (a *Attestor) Attest(ctx *attestation.AttestationContext) error {
if os.Getenv("GITHUB_ACTIONS") != "true" {
return ErrNotGitlab{}
return ErrNotGitHub{}
}

jwtString, err := fetchToken(a.tokenURL, os.Getenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN"), "witness")
Expand Down Expand Up @@ -142,6 +158,10 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error {
return nil
}

func (a *Attestor) Data() *Attestor {
return a
}

// Subjects returns a map of subjects and their corresponding digest sets.
func (a *Attestor) Subjects() map[string]cryptoutil.DigestSet {
subjects := make(map[string]cryptoutil.DigestSet)
Expand Down
26 changes: 24 additions & 2 deletions attestation/gitlab/gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,24 @@ var (
_ attestation.Attestor = &Attestor{}
_ attestation.Subjecter = &Attestor{}
_ attestation.BackReffer = &Attestor{}
_ GitLabAttestor = &Attestor{}
)

type GitLabAttestor interface {
// Attestor
Name() string
Type() string
RunType() attestation.RunType
Attest(ctx *attestation.AttestationContext) error
Data() *Attestor

// Subjecter
Subjects() map[string]cryptoutil.DigestSet

// Backreffer
BackRefs() map[string]cryptoutil.DigestSet
}

func init() {
attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor {
return New()
Expand Down Expand Up @@ -91,13 +107,15 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error {
}

a.CIServerUrl = os.Getenv("CI_SERVER_URL")
jwksUrl := fmt.Sprintf("%s/-/jwks", a.CIServerUrl)
jwtString := os.Getenv("CI_JOB_JWT")
jwksUrl := fmt.Sprintf("%s/oauth/discovery/keys", a.CIServerUrl)
jwtString := os.Getenv("ID_TOKEN")
if jwtString != "" {
a.JWT = jwt.New(jwt.WithToken(jwtString), jwt.WithJWKSUrl(jwksUrl))
if err := a.JWT.Attest(ctx); err != nil {
return err
}
} else {
log.Warn("(attestation/gitlab) no jwt token found in environment")
}

a.CIConfigPath = os.Getenv("CI_CONFIG_PATH")
Expand All @@ -116,6 +134,10 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error {
return nil
}

func (a *Attestor) Data() *Attestor {
return a
}

func (a *Attestor) Subjects() map[string]cryptoutil.DigestSet {
subjects := make(map[string]cryptoutil.DigestSet)
hashes := []cryptoutil.DigestValue{{Hash: crypto.SHA256}}
Expand Down
Loading

0 comments on commit 87975b4

Please sign in to comment.