Skip to content

Commit

Permalink
Merge pull request #2283 from puerco/read-provenance
Browse files Browse the repository at this point in the history
SLSA Compliance: Check provenance before accepting staged artifacts
  • Loading branch information
k8s-ci-robot authored Oct 7, 2021
2 parents f0afa1c + d14061d commit 6eea9b4
Show file tree
Hide file tree
Showing 13 changed files with 682 additions and 1 deletion.
7 changes: 7 additions & 0 deletions pkg/anago/anago.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,13 @@ func (r *Release) Run() error {
return errors.Wrap(err, "prepare workspace")
}

logger.WithStep().Info("Checking artifacts provenance")
if err := r.client.CheckProvenance(); err != nil {
// For now, we ony notify provenance errors as not to treat
// them as fatal while we finish testing SLSA compliance.
logrus.Warn(errors.Wrap(err, "checking provenance attestation"))
}

logger.WithStep().Info("Pushing artifacts")
if err := r.client.PushArtifacts(); err != nil {
return errors.Wrap(err, "push artifacts")
Expand Down
65 changes: 65 additions & 0 deletions pkg/anago/anagofakes/fake_release_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 76 additions & 0 deletions pkg/anago/anagofakes/fake_release_impl.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions pkg/anago/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ type releaseClient interface {
// bucket which should contain a copy of the repository.
PrepareWorkspace() error

// CheckProvenance downloads the artifacts from the staging bucket
// and verifies them against the provenance metadata.
CheckProvenance() error

// PushArtifacts pushes the generated artifacts to the release bucket and
// Google Container Registry for the specified release `versions`.
PushArtifacts() error
Expand Down Expand Up @@ -154,6 +158,7 @@ type releaseImpl interface {
gcsIndexRootPath, gcsReleaseNotesPath, version string,
) error
CreatePubBotBranchIssue(string) error
CheckStageProvenance(string, string) error
}

func (d *defaultReleaseImpl) Submit(options *gcb.Options) error {
Expand Down Expand Up @@ -621,3 +626,17 @@ func (d *DefaultRelease) Archive() error {

return nil
}

// CheckProvenance verifies the artifacts staged in the release bucket
// by verifying the provenance metadata generated during the stage run.
func (d *DefaultRelease) CheckProvenance() error {
return d.impl.CheckStageProvenance(d.options.Bucket(), d.options.BuildVersion)
}

func (d *defaultReleaseImpl) CheckStageProvenance(bucket, buildVersion string) error {
checker := release.NewProvenanceChecker(&release.ProvenanceCheckerOptions{
StageBucket: bucket,
})

return checker.CheckStageProvenance(buildVersion)
}
30 changes: 30 additions & 0 deletions pkg/anago/release_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -436,3 +436,33 @@ func TestUpdateGitHubPage(t *testing.T) {
}
}
}

func TestCheckProvenance(t *testing.T) {
for _, tc := range []struct {
prepare func(*anagofakes.FakeReleaseImpl)
shouldError bool
}{
{ // success
prepare: func(*anagofakes.FakeReleaseImpl) {},
shouldError: false,
},
{ // Provenance does not check
prepare: func(mock *anagofakes.FakeReleaseImpl) {
mock.CheckStageProvenanceReturns(err)
},
shouldError: true,
},
} {
opts := anago.DefaultReleaseOptions()
sut := anago.NewDefaultRelease(opts)
mock := &anagofakes.FakeReleaseImpl{}
tc.prepare(mock)
sut.SetImpl(mock)
err := sut.CheckProvenance()
if tc.shouldError {
require.NotNil(t, err)
} else {
require.Nil(t, err)
}
}
}
22 changes: 21 additions & 1 deletion pkg/provenance/provenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,30 @@ limitations under the License.
package provenance

import (
"encoding/json"
"os"

intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/pkg/errors"
)

// NewStatement creates a new attestation
// LoadStatement loads a statement from a json file
func LoadStatement(path string) (s *Statement, err error) {
statement := NewSLSAStatement()

jsonData, err := os.ReadFile(path)
if err != nil {
return nil, errors.Wrap(err, "opening stament JSON file")
}

if err := json.Unmarshal(jsonData, &statement); err != nil {
return nil, errors.Wrap(err, "decoding attestation JSON data")
}

return statement, nil
}

// NewSLSAStatement creates a new attestation
func NewSLSAStatement() *Statement {
return &Statement{

Expand Down
40 changes: 40 additions & 0 deletions pkg/provenance/provenance_unit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package provenance

import (
"testing"

"github.com/stretchr/testify/require"
)

const testProvenanceFile1 = "testdata/k8s-1.23.0-alpha.4-provenance.json"

func TestReadStatment(t *testing.T) {
s, err := LoadStatement(testProvenanceFile1)
require.Nil(t, err)
require.NotNil(t, s)

require.NotNil(t, s.Predicate)
require.NotNil(t, s.Predicate.Recipe)
require.Equal(t, 461, len(s.Subject))
require.Equal(t, s.Predicate.Builder.ID, "pkg:github/puerco/release@provenance")
require.Equal(t, s.Predicate.Recipe.Type, "https://cloudbuild.googleapis.com/CloudBuildYaml@v1")
require.Equal(t, 3, len(s.Predicate.Recipe.Arguments.(map[string]interface{})))
require.Equal(t, "94db9bed6b7c56420e722d1b15db4610c9cacd3f", s.Predicate.Materials[0].Digest["sha1"])
require.Equal(t, "git+https://github.com/kubernetes/kubernetes", s.Predicate.Materials[0].URI)
}
16 changes: 16 additions & 0 deletions pkg/provenance/provenancefakes/fake_predicate_implementation.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 6eea9b4

Please sign in to comment.