From 838ea59fee299e4d7b8e9cc84768b03e11ac4023 Mon Sep 17 00:00:00 2001 From: rbehjati Date: Thu, 20 Oct 2022 17:52:06 +0100 Subject: [PATCH] Fix validation against amber provenance (#143) * Fix tests and the dependency to the schema for the amber provenances * Fix linting * Fix test size --- internal/common/BUILD | 1 - internal/common/common_test.go | 14 +---- internal/testutil/util.go | 7 --- internal/verifier/BUILD | 3 +- internal/verifier/verifier.go | 16 +++++ internal/verifier/verifier_test.go | 61 ++++++------------- pkg/amber/BUILD | 5 +- pkg/amber/provenance.go | 15 ++--- pkg/amber/provenance_test.go | 12 +--- .../amber/schema}/v1/provenance.json | 0 schema/amber-slsa-buildtype/v1/BUILD | 1 - 11 files changed, 47 insertions(+), 88 deletions(-) rename {schema/amber-slsa-buildtype => pkg/amber/schema}/v1/provenance.json (100%) diff --git a/internal/common/BUILD b/internal/common/BUILD index bbd6e765..f6c45b7a 100644 --- a/internal/common/BUILD +++ b/internal/common/BUILD @@ -36,7 +36,6 @@ go_test( srcs = ["common_test.go"], data = [ "//schema/amber-slsa-buildtype/v1:example.json", - "//schema/amber-slsa-buildtype/v1:provenance.json", "//testdata:build.toml", "//testdata:provenance.json", "//testdata:static.txt", diff --git a/internal/common/common_test.go b/internal/common/common_test.go index e0e9ad14..8da1322e 100644 --- a/internal/common/common_test.go +++ b/internal/common/common_test.go @@ -16,7 +16,6 @@ package common import ( "fmt" - "os" "path/filepath" "testing" @@ -27,7 +26,7 @@ import ( const ( testdataPath = "../../testdata/" - provenanceExamplePath = "testdata/provenance.json" + provenanceExamplePath = "provenance.json" wantTOMLHash = "322527c0260e25f0e9a2595bd0d71a52294fe2397a7af76165190fd98de8920d" wantBuilderImageID = "6e5beabe4ace0e3aaa01ce497f5f1ef30fed7c18c596f35621751176b1ab583d" wantSHA1HexDigitLength = 40 @@ -55,16 +54,9 @@ func TestLoadBuildConfigFromFile(t *testing.T) { } func TestLoadBuildConfigFromProvenance(t *testing.T) { - // The path to provenance is specified relative to the root of the repo, so we need to go one level up. - // Get the current directory before that to restore the path at the end of the test. - currentDir, err := os.Getwd() - if err != nil { - t.Fatalf("couldn't get current directory: %v", err) - } - defer testutil.Chdir(t, currentDir) - testutil.Chdir(t, "../../") + path := filepath.Join(testdataPath, provenanceExamplePath) - provenance, err := amber.ParseProvenanceFile(provenanceExamplePath) + provenance, err := amber.ParseProvenanceFile(path) if err != nil { t.Fatalf("couldn't parse the provenance file: %v", err) } diff --git a/internal/testutil/util.go b/internal/testutil/util.go index 5c3122ce..08c470cc 100644 --- a/internal/testutil/util.go +++ b/internal/testutil/util.go @@ -15,16 +15,9 @@ package testutil import ( - "os" "testing" ) -func Chdir(t *testing.T, dir string) { - if err := os.Chdir(dir); err != nil { - t.Fatalf("couldn't change directory to %s: %v", dir, err) - } -} - func AssertEq[T comparable](t *testing.T, name string, got, want T) { if got != want { t.Errorf("Unexpected %s: got %v, want %v", name, got, want) diff --git a/internal/verifier/BUILD b/internal/verifier/BUILD index bfd576aa..1c7edaca 100644 --- a/internal/verifier/BUILD +++ b/internal/verifier/BUILD @@ -31,11 +31,10 @@ go_library( go_test( name = "verifier_test", - size = "enormous", + size = "small", srcs = ["verifier_test.go"], data = [ "//schema/amber-slsa-buildtype/v1:example.json", - "//schema/amber-slsa-buildtype/v1:provenance.json", "//testdata:provenance.json", "//testdata:bad_command_provenance.json", "//testdata:invalid_hash_provenance.json", diff --git a/internal/verifier/verifier.go b/internal/verifier/verifier.go index b87820a0..73d4517b 100644 --- a/internal/verifier/verifier.go +++ b/internal/verifier/verifier.go @@ -17,6 +17,8 @@ package verify import ( "fmt" + "log" + "os" slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" "github.com/project-oak/transparent-release/internal/common" @@ -45,6 +47,14 @@ type ReproducibleProvenanceVerifier struct { // different returns an error, otherwise returns nil. // TODO(#126): Refactor and separate verification logic from the logic for reading the file. func (verifier *ReproducibleProvenanceVerifier) Verify(provenanceFilePath string) error { + // Below we change directory to the root of the Git repo. We have to change directory back to + // the current directory when we are done. + currentDir, err := os.Getwd() + if err != nil { + return fmt.Errorf("couldn't get current directory: %v", err) + } + defer chdir(currentDir) + provenance, err := amber.ParseProvenanceFile(provenanceFilePath) if err != nil { return fmt.Errorf("couldn't load the provenance file from %s: %v", provenanceFilePath, err) @@ -78,6 +88,12 @@ func (verifier *ReproducibleProvenanceVerifier) Verify(provenanceFilePath string return nil } +func chdir(dir string) { + if err := os.Chdir(dir); err != nil { + log.Printf("Couldn't change directory to %s: %v", dir, err) + } +} + // AmberProvenanceMetadataVerifier verifies Amber provenances by comparing the // content of the provenance predicate against a given set of expected values. type AmberProvenanceMetadataVerifier struct { diff --git a/internal/verifier/verifier_test.go b/internal/verifier/verifier_test.go index 96c9512a..b9053315 100644 --- a/internal/verifier/verifier_test.go +++ b/internal/verifier/verifier_test.go @@ -15,83 +15,60 @@ package verify import ( - "os" + "path/filepath" "strings" "testing" - - "github.com/project-oak/transparent-release/internal/testutil" ) -const validProvenancePath = "testdata/provenance.json" -const invalidHashProvenancePath = "testdata/invalid_hash_provenance.json" -const badCommandProvenancePath = "testdata/bad_command_provenance.json" +const ( + testdataPath = "../../testdata/" + validProvenancePath = "provenance.json" + invalidHashProvenancePath = "invalid_hash_provenance.json" + badCommandProvenancePath = "bad_command_provenance.json" +) func TestReproducibleProvenanceVerifier_validProvenance(t *testing.T) { - // The path to provenance is specified relative to the root of the repo, so we need to go one level up. - // Get the current directory before that to restore the path at the end of the test. - currentDir, err := os.Getwd() - if err != nil { - t.Fatalf("couldn't get current directory: %v", err) - } - defer testutil.Chdir(t, currentDir) - testutil.Chdir(t, "../../") + path := filepath.Join(testdataPath, validProvenancePath) + verifier := ReproducibleProvenanceVerifier{} - if err := verifier.Verify(validProvenancePath); err != nil { + if err := verifier.Verify(path); err != nil { t.Fatalf("couldn't verify the provenance file: %v", err) } } // TODO(#126): Update the test once Verify is refactored. func TestReproducibleProvenanceVerifier_invalidHash(t *testing.T) { - // The path to provenance is specified relative to the root of the repo, so we need to go one level up. - // Get the current directory before that to restore the path at the end of the test. - currentDir, err := os.Getwd() - if err != nil { - t.Fatalf("couldn't get current directory: %v", err) - } - defer testutil.Chdir(t, currentDir) - testutil.Chdir(t, "../../") + path := filepath.Join(testdataPath, invalidHashProvenancePath) + verifier := ReproducibleProvenanceVerifier{} want := "failed to verify the hash of the built binary" - if got := verifier.Verify(invalidHashProvenancePath); !strings.Contains(got.Error(), want) { + if got := verifier.Verify(path); !strings.Contains(got.Error(), want) { t.Fatalf("got %v, want error message containing %q,", got, want) } } // TODO(#126): Update the test once Verify is refactored. func TestReproducibleProvenanceVerifier_badCommand(t *testing.T) { - // The path to provenance is specified relative to the root of the repo, so we need to go one level up. - // Get the current directory before that to restore the path at the end of the test. - currentDir, err := os.Getwd() - if err != nil { - t.Fatalf("couldn't get current directory: %v", err) - } - defer testutil.Chdir(t, currentDir) - testutil.Chdir(t, "../../") + path := filepath.Join(testdataPath, badCommandProvenancePath) + verifier := ReproducibleProvenanceVerifier{} want := "couldn't build the binary" - if got := verifier.Verify(badCommandProvenancePath); !strings.Contains(got.Error(), want) { + if got := verifier.Verify(path); !strings.Contains(got.Error(), want) { t.Fatalf("got %v, want error message containing %q,", got, want) } } func TestAmberProvenanceMetadataVerifier(t *testing.T) { - // The path to provenance is specified relative to the root of the repo, so we need to go one level up. - // Get the current directory before that to restore the path at the end of the test. - currentDir, err := os.Getwd() - if err != nil { - t.Fatalf("couldn't get current directory: %v", err) - } - defer testutil.Chdir(t, currentDir) - testutil.Chdir(t, "../../") + path := filepath.Join(testdataPath, validProvenancePath) + verifier := AmberProvenanceMetadataVerifier{} - if err := verifier.Verify(validProvenancePath); err != nil { + if err := verifier.Verify(path); err != nil { t.Fatalf("couldn't verify the provenance file: %v", err) } } diff --git a/pkg/amber/BUILD b/pkg/amber/BUILD index bef81953..1cabb74c 100644 --- a/pkg/amber/BUILD +++ b/pkg/amber/BUILD @@ -25,9 +25,7 @@ go_library( "endorsement.go", "provenance.go", ], - data = [ - "//schema/amber-slsa-buildtype/v1:provenance.json", - ], + embedsrcs = ["schema/v1/provenance.json"], importpath = "github.com/project-oak/transparent-release/pkg/amber", deps = [ "@com_github_in_toto_in_toto_golang//in_toto:go_default_library", @@ -43,7 +41,6 @@ go_test( data = [ "//schema/amber-claim/v1:example.json", "//schema/amber-slsa-buildtype/v1:example.json", - "//schema/amber-slsa-buildtype/v1:provenance.json", ], embed = [":amber"], deps = [ diff --git a/pkg/amber/provenance.go b/pkg/amber/provenance.go index 71334ec9..a6acb1ba 100644 --- a/pkg/amber/provenance.go +++ b/pkg/amber/provenance.go @@ -28,16 +28,18 @@ import ( intoto "github.com/in-toto/in-toto-golang/in_toto" slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" "github.com/xeipuuv/gojsonschema" + + _ "embed" ) const ( // AmberBuildTypeV1 is the SLSA BuildType for Amber builds. AmberBuildTypeV1 = "https://github.com/project-oak/transparent-release/schema/amber-slsa-buildtype/v1/provenance.json" - - // SchemaPath is the path to Amber SLSA buildType schema. - SchemaPath = "schema/amber-slsa-buildtype/v1/provenance.json" ) +//go:embed schema/v1/provenance.json +var schema []byte + // BuildConfig represents the BuildConfig in the SLSA Provenance predicate. See the corresponding // JSON key in the Amber buildType schema. type BuildConfig struct { @@ -83,12 +85,7 @@ func (p *ValidatedProvenance) GetBinaryName() string { } func validateSLSAProvenanceJSON(provenanceFile []byte) error { - schemaFile, err := os.ReadFile(SchemaPath) - if err != nil { - return err - } - - schemaLoader := gojsonschema.NewStringLoader(string(schemaFile)) + schemaLoader := gojsonschema.NewStringLoader(string(schema)) provenanceLoader := gojsonschema.NewStringLoader(string(provenanceFile)) result, err := gojsonschema.Validate(schemaLoader, provenanceLoader) diff --git a/pkg/amber/provenance_test.go b/pkg/amber/provenance_test.go index eb853cb2..c0beaae4 100644 --- a/pkg/amber/provenance_test.go +++ b/pkg/amber/provenance_test.go @@ -16,7 +16,6 @@ package amber import ( "fmt" - "os" "testing" slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" @@ -24,21 +23,12 @@ import ( ) const ( - provenanceExamplePath = "schema/amber-slsa-buildtype/v1/example.json" + provenanceExamplePath = "../../schema/amber-slsa-buildtype/v1/example.json" wantSHA1HexDigitLength = 40 wantSHA256HexDigitLength = 64 ) func TestExampleProvenance(t *testing.T) { - // The path to provenance is specified relative to the root of the repo, so we need to go one level up. - // Get the current directory before that to restore the path at the end of the test. - currentDir, err := os.Getwd() - if err != nil { - t.Fatalf("couldn't get current directory: %v", err) - } - defer testutil.Chdir(t, currentDir) - testutil.Chdir(t, "../../") - // Parses the provenance and validates it against the schema. validatedProvenance, err := ParseProvenanceFile(provenanceExamplePath) if err != nil { diff --git a/schema/amber-slsa-buildtype/v1/provenance.json b/pkg/amber/schema/v1/provenance.json similarity index 100% rename from schema/amber-slsa-buildtype/v1/provenance.json rename to pkg/amber/schema/v1/provenance.json diff --git a/schema/amber-slsa-buildtype/v1/BUILD b/schema/amber-slsa-buildtype/v1/BUILD index 509ca101..47aa961f 100644 --- a/schema/amber-slsa-buildtype/v1/BUILD +++ b/schema/amber-slsa-buildtype/v1/BUILD @@ -19,6 +19,5 @@ package(default_visibility = ["//:__subpackages__"]) licenses(["notice"]) exports_files([ - "provenance.json", "example.json", ])