From 260c7a17a46e5a80ed60990d6f1627ecde605084 Mon Sep 17 00:00:00 2001 From: nathannaveen <42319948+nathannaveen@users.noreply.github.com> Date: Fri, 4 Aug 2023 10:37:10 -0500 Subject: [PATCH] Added non-nil dereferencing to SLSA parser * Added nil check to `stmt.Predicate.Metadata` * Wrote tests for fillSLSA01 * fixes #1059 * Changed `inp.StartedOn = stmt.Predicate.Metadata.BuildStartedOn` to `inp.FinishedOn = stmt.Predicate.Metadata.BuildFinishedOn` on line 211. Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> --- pkg/ingestor/parser/slsa/parser_slsa.go | 18 ++++- pkg/ingestor/parser/slsa/parser_slsa_test.go | 70 ++++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/pkg/ingestor/parser/slsa/parser_slsa.go b/pkg/ingestor/parser/slsa/parser_slsa.go index 91dde01421..37a68669e5 100644 --- a/pkg/ingestor/parser/slsa/parser_slsa.go +++ b/pkg/ingestor/parser/slsa/parser_slsa.go @@ -18,6 +18,7 @@ package slsa import ( "context" "encoding/json" + "errors" "fmt" "strings" @@ -39,6 +40,9 @@ import ( // - A artifact for each digest information // - a pkg or source depending on what is represented by the name/URI // - An IsOccurence input spec which will generate a predicate for each occurence + +var ErrMetadataNil = errors.New("SLSA01 Metadata is nil") + type slsaEntity struct { artifacts []*model.ArtifactInputSpec occurence *model.IsOccurrenceInputSpec @@ -194,14 +198,20 @@ func getSlsaEntity(name string, digests scommon.DigestSet) (*slsaEntity, error) return nil, fmt.Errorf("%w unable to get Guac Generic Purl, this should not happen", err) } -func fillSLSA01(inp *model.SLSAInputSpec, stmt *in_toto.ProvenanceStatementSLSA01) { +func fillSLSA01(inp *model.SLSAInputSpec, stmt *in_toto.ProvenanceStatementSLSA01) error { inp.BuildType = stmt.Predicate.Recipe.Type + + if stmt.Predicate.Metadata == nil { + return ErrMetadataNil + } if stmt.Predicate.Metadata.BuildStartedOn != nil { inp.StartedOn = stmt.Predicate.Metadata.BuildStartedOn } if stmt.Predicate.Metadata.BuildFinishedOn != nil { - inp.FinishedOn = stmt.Predicate.Metadata.BuildStartedOn + inp.FinishedOn = stmt.Predicate.Metadata.BuildFinishedOn } + + return nil } func fillSLSA02(inp *model.SLSAInputSpec, stmt *in_toto.ProvenanceStatementSLSA02) { @@ -232,7 +242,9 @@ func (s *slsaParser) getSLSA() error { var pred any switch s.header.PredicateType { case slsa01.PredicateSLSAProvenance: - fillSLSA01(inp, s.s01smt) + if err := fillSLSA01(inp, s.s01smt); err != nil { + return fmt.Errorf("could not fill SLSA01: %w", err) + } pred = s.s01smt.Predicate case slsa02.PredicateSLSAProvenance: fillSLSA02(inp, s.s02smt) diff --git a/pkg/ingestor/parser/slsa/parser_slsa_test.go b/pkg/ingestor/parser/slsa/parser_slsa_test.go index 9f0b968e6d..9289f3e343 100644 --- a/pkg/ingestor/parser/slsa/parser_slsa_test.go +++ b/pkg/ingestor/parser/slsa/parser_slsa_test.go @@ -18,10 +18,16 @@ package slsa import ( "context" "testing" + "time" + + slsa01 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1" + + "github.com/in-toto/in-toto-golang/in_toto" "github.com/google/go-cmp/cmp" "github.com/guacsec/guac/internal/testing/testdata" "github.com/guacsec/guac/pkg/assembler" + model "github.com/guacsec/guac/pkg/assembler/clients/generated" "github.com/guacsec/guac/pkg/handler/processor" "github.com/guacsec/guac/pkg/logging" ) @@ -67,3 +73,67 @@ func Test_slsaParser(t *testing.T) { }) } } + +func Test_fillSLSA01(t *testing.T) { + startTime := time.Now() + endTime := time.Now() + type args struct { + inp *model.SLSAInputSpec + stmt *in_toto.ProvenanceStatementSLSA01 + } + tests := []struct { + name string + args args + err error + }{ + { + name: "default", + args: args{ + inp: &model.SLSAInputSpec{}, + stmt: &in_toto.ProvenanceStatementSLSA01{ + Predicate: slsa01.ProvenancePredicate{ + Metadata: &slsa01.ProvenanceMetadata{ + BuildStartedOn: &startTime, + BuildFinishedOn: &endTime, + }, + Recipe: slsa01.ProvenanceRecipe{ + Type: "test", + }, + }, + }, + }, + }, + { + name: "stmt predicate metadata is nil", + args: args{ + inp: &model.SLSAInputSpec{}, + stmt: &in_toto.ProvenanceStatementSLSA01{}, + }, + err: ErrMetadataNil, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := fillSLSA01(test.args.inp, test.args.stmt) + if err != test.err { + t.Fatalf("fillSLSA01() error = %v, expected error %v", err, test.err) + } + if err != nil { + // if the error is equal to the expected error, we can return + // we know that the error is equal to the expected error because we checked if it wasn't equal above + // if err == nil then we know that the function didn't throw an error, and we have to check the values + return + } + + if test.args.inp.BuildType != test.args.stmt.Predicate.Recipe.Type { + t.Errorf("fillSLSA01() inp.BuildType not equal to stmt.Predicate.Recipe.Type") + } + if test.args.inp.StartedOn != test.args.stmt.Predicate.Metadata.BuildStartedOn { + t.Errorf("fillSLSA01() inp.BuildStartedOn not equal to stmt.Predicate.Metadata.BuildStartedOn") + } + if test.args.inp.FinishedOn != test.args.stmt.Predicate.Metadata.BuildFinishedOn { + t.Errorf("fillSLSA01() inp.BuildFinishedOn not equal to stmt.Predicate.Metadata.BuildFinishedOn") + } + }) + } +}