Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Link & SLSA attestor #149

Merged
merged 43 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
63410d4
Initial link attestor
jkjell Feb 3, 2024
7da776c
refactor: move gitoid code to cyrptoutil, use digestvalue everywhere …
mikhailswift Jan 29, 2024
924eb1f
chore: bump actions/upload-artifact from 4.2.0 to 4.3.0 (#142)
dependabot[bot] Jan 29, 2024
856b500
chore: bump github/codeql-action from 3.23.1 to 3.23.2 (#143)
dependabot[bot] Jan 30, 2024
315793e
Adding job to auto cut releases (#141)
ChaosInTheCRD Jan 30, 2024
ad61b8a
fixing error in github actions workflow (#147)
ChaosInTheCRD Feb 1, 2024
ed1dfef
RunAttestors refactor (#131)
ChaosInTheCRD Feb 2, 2024
ed519d1
Adding workaround due to failing workflows (#145)
ChaosInTheCRD Feb 3, 2024
04a8ef4
Checking policy signature against cert constraints (#144)
ChaosInTheCRD Feb 3, 2024
3cff01c
[StepSecurity] ci: Harden GitHub Actions (#148)
step-security-bot Feb 3, 2024
3d7747b
Add import for init and export variables
jkjell Feb 3, 2024
7a1a1f7
Add mulitple results to run to allow exporting attestors to indivudal…
jkjell Feb 4, 2024
fb27f55
Add collection to result array
jkjell Feb 4, 2024
af0470f
Replace export parameters in run with attestor option
jkjell Feb 5, 2024
8e2aaa4
Fix golang lint isues
jkjell Feb 5, 2024
bb8a962
Merge branch 'main' into link-attestor
jkjell Feb 5, 2024
62057c3
Update link attestor testing
jkjell Feb 12, 2024
bb035a0
Merge branch 'main' into link-attestor
jkjell Mar 22, 2024
b11d528
Add SLSA attestor
jkjell Mar 23, 2024
ae52a37
Add interface for product attestor
jkjell Mar 23, 2024
8f016d9
Add more attestor interfaces
jkjell Mar 23, 2024
885a436
Address some review feedback, licenses, and golanglint
jkjell Mar 25, 2024
0bf0842
More golangcilint errors
jkjell Mar 25, 2024
21006a2
WIP - Improve testing interfaces for exposing data fields
jkjell Apr 2, 2024
74a58da
Merge branch 'main' into link-attestor
jkjell Apr 2, 2024
420a746
Merge branch 'link-attestor' of github.com:in-toto/go-witness into li…
ChaosInTheCRD Apr 4, 2024
61e8165
added changes
ChaosInTheCRD Apr 4, 2024
b8923d2
adding changes to merge into main PR
ChaosInTheCRD Apr 4, 2024
4d86ee9
Link attestor proposed changes (#204)
ChaosInTheCRD Apr 4, 2024
1d19081
Merge branch 'link-attestor' of github.com:in-toto/go-witness into li…
ChaosInTheCRD Apr 5, 2024
690505e
Merge branch 'main' into link-attestor
jkjell Apr 6, 2024
450a306
Passing SLSA Attest tests for GitHub and GitLab
jkjell Apr 6, 2024
33f3905
Clean up
jkjell Apr 6, 2024
dba3c39
Add attestation test for link attestor
jkjell Apr 7, 2024
4e37a04
Add data function for git interface and remove unused code
jkjell Apr 10, 2024
f6b9f69
Merge branch 'link-attestor' of github.com:in-toto/go-witness into li…
ChaosInTheCRD Apr 10, 2024
bb842ee
adding warning mesage for slsa attestor
ChaosInTheCRD Apr 10, 2024
ec4f58a
Try to gracefully handle gitlab jwt
jkjell Apr 19, 2024
b2322d9
Merge branch 'main' into link-attestor
jkjell May 2, 2024
5ce8543
Merge branch 'main' into link-attestor
ChaosInTheCRD May 8, 2024
0f6805d
ran go mod tidy
ChaosInTheCRD May 8, 2024
86d4e22
ensuring link and slsa attestation exporting is optional
ChaosInTheCRD May 8, 2024
0afae1b
Merge branch 'main' into link-attestor
jkjell May 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -92,14 +92,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 @@ -112,6 +113,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 @@ -209,6 +211,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
Loading