From d681a8db4013ede6b6ce0b2ba3fc1c421e2b95b9 Mon Sep 17 00:00:00 2001 From: Nathan Naveen <42319948+nathannaveen@users.noreply.github.com> Date: Wed, 4 Oct 2023 16:26:21 -0500 Subject: [PATCH] Include Timestamps for Verbs (#1338) * Included Timestamp for Verbs * Fixes https://github.com/guacsec/guac/issues/1030 Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Edited GraphQL Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Fixed some stuff Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Fixed SBOM issue Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Fixed tests Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Stored Times to UTC Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> * Updated spec Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> --------- Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com> --- cmd/guacgql/cmd/ingest.go | 5 + cmd/guacone/cmd/certify.go | 3 + internal/testing/testdata/testdata.go | 14 ++ pkg/assembler/backends/inmem/certifyBad.go | 24 ++- .../backends/inmem/certifyBad_test.go | 40 +++++ pkg/assembler/backends/inmem/certifyGood.go | 23 ++- .../backends/inmem/certifyGood_test.go | 40 +++++ pkg/assembler/backends/inmem/hasSBOM.go | 11 +- pkg/assembler/backends/inmem/hasSBOM_test.go | 34 ++++ pkg/assembler/clients/generated/operations.go | 156 ++++++++++++++++-- .../clients/operations/trees.graphql | 3 + .../graphql/examples/certify_bad.gql | 1 + .../graphql/examples/certify_good.gql | 1 + pkg/assembler/graphql/examples/has_sbom.gql | 1 + .../graphql/generated/artifact.generated.go | 6 + .../graphql/generated/certifyBad.generated.go | 72 +++++++- .../generated/certifyGood.generated.go | 72 +++++++- .../graphql/generated/hasSBOM.generated.go | 72 +++++++- .../graphql/generated/root_.generated.go | 43 +++++ pkg/assembler/graphql/model/nodes.go | 43 +++-- .../graphql/resolvers/certifyBad.resolvers.go | 10 ++ .../resolvers/certifyBad.resolvers_test.go | 5 + .../resolvers/certifyGood.resolvers.go | 10 ++ .../resolvers/certifyGood.resolvers_test.go | 2 + .../graphql/resolvers/hasSBOM.resolvers.go | 10 ++ .../resolvers/hasSBOM.resolvers_test.go | 9 +- .../graphql/schema/certifyBad.graphql | 6 + .../graphql/schema/certifyGood.graphql | 6 + pkg/assembler/graphql/schema/hasSBOM.graphql | 7 + pkg/guacanalytics/patchPlanning_test.go | 2 + pkg/ingestor/parser/common/helpers.go | 4 +- .../parser/cyclonedx/parser_cyclonedx.go | 18 +- pkg/ingestor/parser/spdx/parse_spdx.go | 7 +- 33 files changed, 704 insertions(+), 56 deletions(-) diff --git a/cmd/guacgql/cmd/ingest.go b/cmd/guacgql/cmd/ingest.go index a460032051..2ab2b36676 100644 --- a/cmd/guacgql/cmd/ingest.go +++ b/cmd/guacgql/cmd/ingest.go @@ -1965,6 +1965,7 @@ func ingestHashEqual(ctx context.Context, client graphql.Client) { func ingestHasSBOM(ctx context.Context, client graphql.Client) { logger := logging.FromContext(ctx) + tm, _ := time.Parse(time.RFC3339, "2022-11-21T17:45:50.52Z") opensslNs := "openssl.org" opensslVersion := "3.0.3" ingestHasSBOM := []struct { @@ -1989,6 +1990,7 @@ func ingestHasSBOM(ctx context.Context, client graphql.Client) { DownloadLocation: "uri: download location of the SBOM", Origin: "Demo ingestion", Collector: "Demo ingestion", + KnownSince: tm, }, }, { @@ -2004,6 +2006,7 @@ func ingestHasSBOM(ctx context.Context, client graphql.Client) { DownloadLocation: "uri: download location of the SBOM", Origin: "Demo ingestion", Collector: "Demo ingestion", + KnownSince: tm, }, }, { @@ -2022,6 +2025,7 @@ func ingestHasSBOM(ctx context.Context, client graphql.Client) { DownloadLocation: "uri: download location of the SBOM", Origin: "Demo ingestion", Collector: "Demo ingestion", + KnownSince: tm, }, }, { @@ -2037,6 +2041,7 @@ func ingestHasSBOM(ctx context.Context, client graphql.Client) { DownloadLocation: "uri: download location of the SBOM", Origin: "Demo ingestion", Collector: "Demo ingestion", + KnownSince: tm, }, }, } diff --git a/cmd/guacone/cmd/certify.go b/cmd/guacone/cmd/certify.go index 595524cef4..76e8b8305c 100644 --- a/cmd/guacone/cmd/certify.go +++ b/cmd/guacone/cmd/certify.go @@ -20,6 +20,7 @@ import ( "fmt" "os" "strings" + "time" "github.com/guacsec/guac/pkg/assembler" model "github.com/guacsec/guac/pkg/assembler/clients/generated" @@ -122,6 +123,7 @@ var certifyCmd = &cobra.Command{ Justification: opts.justification, Origin: "GUAC Certify CLI", Collector: "GUAC", + KnownSince: time.Now().UTC(), } preds.CertifyGood = append(preds.CertifyGood, *certifyGood) } else { @@ -140,6 +142,7 @@ var certifyCmd = &cobra.Command{ Justification: opts.justification, Origin: "GUAC Certify CLI", Collector: "GUAC", + KnownSince: time.Now().UTC(), } preds.CertifyBad = append(preds.CertifyBad, *certifyBad) } diff --git a/internal/testing/testdata/testdata.go b/internal/testing/testdata/testdata.go index be340d8ef1..f5feaee027 100644 --- a/internal/testing/testdata/testdata.go +++ b/internal/testing/testdata/testdata.go @@ -725,6 +725,8 @@ var ( }, } + spdxTime, _ = time.Parse(time.RFC3339, "2022-09-24T17:27:55.556104Z") + SpdxHasSBOM = []assembler.HasSBOMIngest{ { Pkg: topLevelPack, @@ -733,6 +735,7 @@ var ( Algorithm: "sha256", Digest: "8b5e8212cae084f92ff91f8625a50ea1070738cfc68ecca08bf04d64f64b9feb", DownloadLocation: "TestSource", + KnownSince: spdxTime, }, }, } @@ -852,6 +855,8 @@ var ( }, } + cdxTime, _ = time.Parse(time.RFC3339, "2022-10-08T10:01:23-04:00") + CdxHasSBOM = []assembler.HasSBOMIngest{ { Pkg: cdxTopLevelPack, @@ -860,6 +865,7 @@ var ( Algorithm: "sha256", Digest: "01942b5eefd3c15b50318c66d8d16627be573197c877e8a286a8cb12de7939cb", DownloadLocation: "TestSource", + KnownSince: cdxTime, }, }, } @@ -942,6 +948,8 @@ var ( }, } + cdxQuarkusTime, _ = time.Parse(time.RFC3339, "2022-11-09T11:14:31Z") + CdxQuarkusHasSBOM = []assembler.HasSBOMIngest{ { Pkg: cdxTopQuarkusPack, @@ -950,6 +958,7 @@ var ( Algorithm: "sha256", Digest: "036a9f51468f5ce6eec7c310583164ed0ab9f58d7c03380a3fe19d420609e3de", DownloadLocation: "TestSource", + KnownSince: cdxQuarkusTime, }, }, } @@ -977,6 +986,8 @@ var ( }, } + cdxNpmTime, _ = time.Parse(time.RFC3339, "2022-11-22T17:14:57Z") + CdxNpmHasSBOM = []assembler.HasSBOMIngest{ { Pkg: cdxWebAppPackage, @@ -985,6 +996,7 @@ var ( Algorithm: "sha256", Digest: "35363f03c80f26a88db6f2400771bdcc6624bb7b61b96da8503be0f757605fde", DownloadLocation: "TestSource", + KnownSince: cdxNpmTime, }, }, } @@ -995,6 +1007,7 @@ var ( } quarkusParentPackage, _ = asmhelpers.PurlToPkg("pkg:maven/io.quarkus/quarkus-parent@999-SNAPSHOT?type=pom") + quarkusTime, _ = time.Parse(time.RFC3339, "2023-02-16T21:52:02Z") quarkusParentPackageHasSBOM = []assembler.HasSBOMIngest{ { @@ -1004,6 +1017,7 @@ var ( Algorithm: "sha256", Digest: "fcd4d1f9c83c274fbc2dabdca4e7de749b23fab1aa15dc2854880a13479fa74e", DownloadLocation: "TestSource", + KnownSince: quarkusTime, }, }, } diff --git a/pkg/assembler/backends/inmem/certifyBad.go b/pkg/assembler/backends/inmem/certifyBad.go index 8247c3ea05..92924388f4 100644 --- a/pkg/assembler/backends/inmem/certifyBad.go +++ b/pkg/assembler/backends/inmem/certifyBad.go @@ -18,12 +18,15 @@ package inmem import ( "context" "strconv" + "time" "github.com/vektah/gqlparser/v2/gqlerror" "github.com/guacsec/guac/pkg/assembler/graphql/model" ) +// TODO: update the other backends to handle the new timestamp fields beacuse of: https://github.com/guacsec/guac/pull/1338/files#r1343080326 + // Internal data: link that a package/source/artifact is bad type badList []*badLink type badLink struct { @@ -34,6 +37,7 @@ type badLink struct { justification string origin string collector string + knownSince time.Time } func (n *badLink) ID() uint32 { return n.id } @@ -157,7 +161,8 @@ func (c *demoClient) ingestCertifyBad(ctx context.Context, subject model.Package subjectMatch = true } if subjectMatch && certifyBad.Justification == v.justification && - certifyBad.Origin == v.origin && certifyBad.Collector == v.collector { + certifyBad.Origin == v.origin && certifyBad.Collector == v.collector && + certifyBad.KnownSince.Equal(v.knownSince) { collectedCertifyBadLink = *v duplicate = true @@ -180,6 +185,7 @@ func (c *demoClient) ingestCertifyBad(ctx context.Context, subject model.Package justification: certifyBad.Justification, origin: certifyBad.Origin, collector: certifyBad.Collector, + knownSince: certifyBad.KnownSince.UTC(), } c.index[collectedCertifyBadLink.id] = &collectedCertifyBadLink c.certifyBads = append(c.certifyBads, &collectedCertifyBadLink) @@ -282,14 +288,13 @@ func (c *demoClient) addCBIfMatch(out []*model.CertifyBad, filter *model.CertifyBadSpec, link *badLink) ( []*model.CertifyBad, error) { - if filter != nil && noMatch(filter.Justification, link.justification) { - return out, nil - } - if filter != nil && noMatch(filter.Collector, link.collector) { - return out, nil - } - if filter != nil && noMatch(filter.Origin, link.origin) { - return out, nil + if filter != nil { + if noMatch(filter.Justification, link.justification) || + noMatch(filter.Collector, link.collector) || + noMatch(filter.Origin, link.origin) || + (filter.KnownSince != nil && filter.KnownSince.After(link.knownSince)) { + return out, nil + } } foundCertifyBad, err := c.buildCertifyBad(link, filter, false) @@ -379,6 +384,7 @@ func (c *demoClient) buildCertifyBad(link *badLink, filter *model.CertifyBadSpec Justification: link.justification, Origin: link.origin, Collector: link.collector, + KnownSince: link.knownSince.UTC(), } return &certifyBad, nil } diff --git a/pkg/assembler/backends/inmem/certifyBad_test.go b/pkg/assembler/backends/inmem/certifyBad_test.go index 4d5dd1cf74..87cd3ccac5 100644 --- a/pkg/assembler/backends/inmem/certifyBad_test.go +++ b/pkg/assembler/backends/inmem/certifyBad_test.go @@ -19,6 +19,7 @@ import ( "context" "strings" "testing" + "time" "github.com/google/go-cmp/cmp" "github.com/guacsec/guac/internal/testing/ptrfrom" @@ -28,6 +29,8 @@ import ( ) func TestCertifyBad(t *testing.T) { + curTime := time.Now() + timeAfterOneSecond := curTime.Add(time.Second) type call struct { Sub model.PackageSourceOrArtifactInput Match *model.MatchFlags @@ -170,6 +173,43 @@ func TestCertifyBad(t *testing.T) { }, }, }, + { + Name: "Query on KnownSince", + InPkg: []*model.PkgInputSpec{p1}, + Calls: []call{ + { + Sub: model.PackageSourceOrArtifactInput{ + Package: p1, + }, + Match: &model.MatchFlags{ + Pkg: model.PkgMatchTypeSpecificVersion, + }, + CB: &model.CertifyBadInputSpec{ + KnownSince: timeAfterOneSecond, + }, + }, + { + Sub: model.PackageSourceOrArtifactInput{ + Package: p1, + }, + Match: &model.MatchFlags{ + Pkg: model.PkgMatchTypeSpecificVersion, + }, + CB: &model.CertifyBadInputSpec{ + KnownSince: curTime, + }, + }, + }, + Query: &model.CertifyBadSpec{ + KnownSince: &timeAfterOneSecond, + }, + ExpCB: []*model.CertifyBad{ + { + Subject: p1out, + KnownSince: timeAfterOneSecond, + }, + }, + }, { Name: "Query on Package", InPkg: []*model.PkgInputSpec{p1, p2}, diff --git a/pkg/assembler/backends/inmem/certifyGood.go b/pkg/assembler/backends/inmem/certifyGood.go index 8b56072f29..1d8b93a84e 100644 --- a/pkg/assembler/backends/inmem/certifyGood.go +++ b/pkg/assembler/backends/inmem/certifyGood.go @@ -18,6 +18,7 @@ package inmem import ( "context" "strconv" + "time" "github.com/vektah/gqlparser/v2/gqlerror" @@ -34,6 +35,7 @@ type goodLink struct { justification string origin string collector string + knownSince time.Time } func (n *goodLink) ID() uint32 { return n.id } @@ -158,7 +160,8 @@ func (c *demoClient) ingestCertifyGood(ctx context.Context, subject model.Packag subjectMatch = true } if subjectMatch && certifyGood.Justification == v.justification && - certifyGood.Origin == v.origin && certifyGood.Collector == v.collector { + certifyGood.Origin == v.origin && certifyGood.Collector == v.collector && + certifyGood.KnownSince.Equal(v.knownSince) { collectedCertifyGoodLink = *v duplicate = true @@ -181,6 +184,7 @@ func (c *demoClient) ingestCertifyGood(ctx context.Context, subject model.Packag justification: certifyGood.Justification, origin: certifyGood.Origin, collector: certifyGood.Collector, + knownSince: certifyGood.KnownSince.UTC(), } c.index[collectedCertifyGoodLink.id] = &collectedCertifyGoodLink c.certifyGoods = append(c.certifyGoods, &collectedCertifyGoodLink) @@ -283,14 +287,14 @@ func (c *demoClient) addCGIfMatch(out []*model.CertifyGood, filter *model.CertifyGoodSpec, link *goodLink) ( []*model.CertifyGood, error) { - if filter != nil && noMatch(filter.Justification, link.justification) { - return out, nil - } - if filter != nil && noMatch(filter.Collector, link.collector) { - return out, nil - } - if filter != nil && noMatch(filter.Origin, link.origin) { - return out, nil + if filter != nil { + if noMatch(filter.Justification, link.justification) || + noMatch(filter.Collector, link.collector) || + noMatch(filter.Collector, link.collector) || + noMatch(filter.Origin, link.origin) || + filter.KnownSince != nil && filter.KnownSince.After(link.knownSince) { + return out, nil + } } foundCertifyGood, err := c.buildCertifyGood(link, filter, false) @@ -380,6 +384,7 @@ func (c *demoClient) buildCertifyGood(link *goodLink, filter *model.CertifyGoodS Justification: link.justification, Origin: link.origin, Collector: link.collector, + KnownSince: link.knownSince.UTC(), } return &certifyGood, nil } diff --git a/pkg/assembler/backends/inmem/certifyGood_test.go b/pkg/assembler/backends/inmem/certifyGood_test.go index 1ca8b73ffe..bebd34d28f 100644 --- a/pkg/assembler/backends/inmem/certifyGood_test.go +++ b/pkg/assembler/backends/inmem/certifyGood_test.go @@ -19,6 +19,7 @@ import ( "context" "strings" "testing" + "time" "github.com/google/go-cmp/cmp" "github.com/guacsec/guac/internal/testing/ptrfrom" @@ -28,6 +29,8 @@ import ( ) func TestCertifyGood(t *testing.T) { + curTime := time.Now() + timeAfterOneSecond := curTime.Add(time.Second) type call struct { Sub model.PackageSourceOrArtifactInput Match *model.MatchFlags @@ -170,6 +173,43 @@ func TestCertifyGood(t *testing.T) { }, }, }, + { + Name: "Query on KnownSince", + InPkg: []*model.PkgInputSpec{p1}, + Calls: []call{ + { + Sub: model.PackageSourceOrArtifactInput{ + Package: p1, + }, + Match: &model.MatchFlags{ + Pkg: model.PkgMatchTypeSpecificVersion, + }, + CG: &model.CertifyGoodInputSpec{ + KnownSince: timeAfterOneSecond, + }, + }, + { + Sub: model.PackageSourceOrArtifactInput{ + Package: p1, + }, + Match: &model.MatchFlags{ + Pkg: model.PkgMatchTypeSpecificVersion, + }, + CG: &model.CertifyGoodInputSpec{ + KnownSince: curTime, + }, + }, + }, + Query: &model.CertifyGoodSpec{ + KnownSince: &timeAfterOneSecond, + }, + ExpCG: []*model.CertifyGood{ + { + Subject: p1out, + KnownSince: timeAfterOneSecond, + }, + }, + }, { Name: "Query on Package", InPkg: []*model.PkgInputSpec{p1, p2}, diff --git a/pkg/assembler/backends/inmem/hasSBOM.go b/pkg/assembler/backends/inmem/hasSBOM.go index 0a7fb52236..0b0f786631 100644 --- a/pkg/assembler/backends/inmem/hasSBOM.go +++ b/pkg/assembler/backends/inmem/hasSBOM.go @@ -19,6 +19,7 @@ import ( "context" "strconv" "strings" + "time" "github.com/vektah/gqlparser/v2/gqlerror" @@ -36,6 +37,7 @@ type hasSBOMStruct struct { downloadLocation string origin string collector string + knownSince time.Time } func (n *hasSBOMStruct) ID() uint32 { return n.id } @@ -131,7 +133,8 @@ func (c *demoClient) ingestHasSbom(ctx context.Context, subject model.PackageOrA h.digest == digest && h.downloadLocation == input.DownloadLocation && h.origin == input.Origin && - h.collector == input.Collector { + h.collector == input.Collector && + input.KnownSince.Equal(h.knownSince) { return c.convHasSBOM(h) } } @@ -153,6 +156,7 @@ func (c *demoClient) ingestHasSbom(ctx context.Context, subject model.PackageOrA downloadLocation: input.DownloadLocation, origin: input.Origin, collector: input.Collector, + knownSince: input.KnownSince.UTC(), } c.index[h.id] = h c.hasSBOMs = append(c.hasSBOMs, h) @@ -173,6 +177,7 @@ func (c *demoClient) convHasSBOM(in *hasSBOMStruct) (*model.HasSbom, error) { DownloadLocation: in.downloadLocation, Origin: in.origin, Collector: in.collector, + KnownSince: in.knownSince.UTC(), } if in.pkg != 0 { p, err := c.buildPackageResponse(in.pkg, nil) @@ -260,6 +265,7 @@ func (c *demoClient) HasSBOM(ctx context.Context, filter *model.HasSBOMSpec) ([] } } } + return out, nil } @@ -273,7 +279,8 @@ func (c *demoClient) addHasSBOMIfMatch(out []*model.HasSbom, noMatch(toLower(filter.Digest), link.digest) || noMatch(filter.DownloadLocation, link.downloadLocation) || noMatch(filter.Origin, link.origin) || - noMatch(filter.Collector, link.collector) { + noMatch(filter.Collector, link.collector) || + (filter.KnownSince != nil && filter.KnownSince.After(link.knownSince)) { return out, nil } if filter.Subject != nil { diff --git a/pkg/assembler/backends/inmem/hasSBOM_test.go b/pkg/assembler/backends/inmem/hasSBOM_test.go index 85a138d395..76472d24fa 100644 --- a/pkg/assembler/backends/inmem/hasSBOM_test.go +++ b/pkg/assembler/backends/inmem/hasSBOM_test.go @@ -19,6 +19,7 @@ import ( "context" "strings" "testing" + "time" "github.com/google/go-cmp/cmp" "github.com/guacsec/guac/internal/testing/ptrfrom" @@ -28,6 +29,8 @@ import ( ) func TestHasSBOM(t *testing.T) { + curTime := time.Now() + timeAfterOneSecond := curTime.Add(time.Second) type call struct { Sub model.PackageOrArtifactInput HS *model.HasSBOMInputSpec @@ -127,6 +130,37 @@ func TestHasSBOM(t *testing.T) { }, }, }, + { + Name: "Query on KnownSince", + InPkg: []*model.PkgInputSpec{p1}, + Calls: []call{ + { + Sub: model.PackageOrArtifactInput{ + Package: p1, + }, + HS: &model.HasSBOMInputSpec{ + KnownSince: timeAfterOneSecond, + }, + }, + { + Sub: model.PackageOrArtifactInput{ + Package: p1, + }, + HS: &model.HasSBOMInputSpec{ + KnownSince: curTime, + }, + }, + }, + Query: &model.HasSBOMSpec{ + KnownSince: &timeAfterOneSecond, + }, + ExpHS: []*model.HasSbom{ + { + Subject: p1out, + KnownSince: timeAfterOneSecond, + }, + }, + }, { Name: "Query on Package", InPkg: []*model.PkgInputSpec{p1, p2}, diff --git a/pkg/assembler/clients/generated/operations.go b/pkg/assembler/clients/generated/operations.go index 0081dc08dd..042595f677 100644 --- a/pkg/assembler/clients/generated/operations.go +++ b/pkg/assembler/clients/generated/operations.go @@ -70,6 +70,7 @@ func (v *AllBuilderTree) GetUri() string { return v.Uri } type AllCertifyBad struct { Id string `json:"id"` Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` Subject AllCertifyBadSubjectPackageSourceOrArtifact `json:"-"` Origin string `json:"origin"` Collector string `json:"collector"` @@ -81,6 +82,9 @@ func (v *AllCertifyBad) GetId() string { return v.Id } // GetJustification returns AllCertifyBad.Justification, and is useful for accessing the field via an interface. func (v *AllCertifyBad) GetJustification() string { return v.Justification } +// GetKnownSince returns AllCertifyBad.KnownSince, and is useful for accessing the field via an interface. +func (v *AllCertifyBad) GetKnownSince() time.Time { return v.KnownSince } + // GetSubject returns AllCertifyBad.Subject, and is useful for accessing the field via an interface. func (v *AllCertifyBad) GetSubject() AllCertifyBadSubjectPackageSourceOrArtifact { return v.Subject } @@ -128,6 +132,8 @@ type __premarshalAllCertifyBad struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -148,6 +154,7 @@ func (v *AllCertifyBad) __premarshalJSON() (*__premarshalAllCertifyBad, error) { retval.Id = v.Id retval.Justification = v.Justification + retval.KnownSince = v.KnownSince { dst := &retval.Subject @@ -539,6 +546,7 @@ func (v *AllCertifyBadSubjectSource) __premarshalJSON() (*__premarshalAllCertify type AllCertifyGood struct { Id string `json:"id"` Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` Subject AllCertifyGoodSubjectPackageSourceOrArtifact `json:"-"` Origin string `json:"origin"` Collector string `json:"collector"` @@ -550,6 +558,9 @@ func (v *AllCertifyGood) GetId() string { return v.Id } // GetJustification returns AllCertifyGood.Justification, and is useful for accessing the field via an interface. func (v *AllCertifyGood) GetJustification() string { return v.Justification } +// GetKnownSince returns AllCertifyGood.KnownSince, and is useful for accessing the field via an interface. +func (v *AllCertifyGood) GetKnownSince() time.Time { return v.KnownSince } + // GetSubject returns AllCertifyGood.Subject, and is useful for accessing the field via an interface. func (v *AllCertifyGood) GetSubject() AllCertifyGoodSubjectPackageSourceOrArtifact { return v.Subject } @@ -597,6 +608,8 @@ type __premarshalAllCertifyGood struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -617,6 +630,7 @@ func (v *AllCertifyGood) __premarshalJSON() (*__premarshalAllCertifyGood, error) retval.Id = v.Id retval.Justification = v.Justification + retval.KnownSince = v.KnownSince { dst := &retval.Subject @@ -3060,6 +3074,8 @@ type AllHasSBOMTree struct { Origin string `json:"origin"` // GUAC collector for the document Collector string `json:"collector"` + // Timestamp for SBOM creation + KnownSince time.Time `json:"knownSince"` } // GetId returns AllHasSBOMTree.Id, and is useful for accessing the field via an interface. @@ -3086,6 +3102,9 @@ func (v *AllHasSBOMTree) GetOrigin() string { return v.Origin } // GetCollector returns AllHasSBOMTree.Collector, and is useful for accessing the field via an interface. func (v *AllHasSBOMTree) GetCollector() string { return v.Collector } +// GetKnownSince returns AllHasSBOMTree.KnownSince, and is useful for accessing the field via an interface. +func (v *AllHasSBOMTree) GetKnownSince() time.Time { return v.KnownSince } + func (v *AllHasSBOMTree) UnmarshalJSON(b []byte) error { if string(b) == "null" { @@ -3135,6 +3154,8 @@ type __premarshalAllHasSBOMTree struct { Origin string `json:"origin"` Collector string `json:"collector"` + + KnownSince time.Time `json:"knownSince"` } func (v *AllHasSBOMTree) MarshalJSON() ([]byte, error) { @@ -3167,6 +3188,7 @@ func (v *AllHasSBOMTree) __premarshalJSON() (*__premarshalAllHasSBOMTree, error) retval.DownloadLocation = v.DownloadLocation retval.Origin = v.Origin retval.Collector = v.Collector + retval.KnownSince = v.KnownSince return &retval, nil } @@ -6060,9 +6082,10 @@ func (v *CertifyBadArtifactsResponse) GetIngestCertifyBads() []string { return v // CertifyBadInputSpec represents the mutation input to ingest a CertifyBad // evidence. type CertifyBadInputSpec struct { - Justification string `json:"justification"` - Origin string `json:"origin"` - Collector string `json:"collector"` + Justification string `json:"justification"` + Origin string `json:"origin"` + Collector string `json:"collector"` + KnownSince time.Time `json:"knownSince"` } // GetJustification returns CertifyBadInputSpec.Justification, and is useful for accessing the field via an interface. @@ -6074,6 +6097,9 @@ func (v *CertifyBadInputSpec) GetOrigin() string { return v.Origin } // GetCollector returns CertifyBadInputSpec.Collector, and is useful for accessing the field via an interface. func (v *CertifyBadInputSpec) GetCollector() string { return v.Collector } +// GetKnownSince returns CertifyBadInputSpec.KnownSince, and is useful for accessing the field via an interface. +func (v *CertifyBadInputSpec) GetKnownSince() time.Time { return v.KnownSince } + // CertifyBadPkgResponse is returned by CertifyBadPkg on success. type CertifyBadPkgResponse struct { // Adds a certification that a package, source or artifact is considered bad. The returned ID can be empty string. @@ -6101,12 +6127,16 @@ func (v *CertifyBadPkgsResponse) GetIngestCertifyBads() []string { return v.Inge // // If a source is specified in the subject filter, then it must specify a name, // and optionally a tag and a commit. +// +// If KnownSince is specified, the returned value will be after or equal to the specified time. +// Any nodes time that is before KnownSince is excluded. type CertifyBadSpec struct { Id *string `json:"id"` Subject *PackageSourceOrArtifactSpec `json:"subject"` Justification *string `json:"justification"` Origin *string `json:"origin"` Collector *string `json:"collector"` + KnownSince *time.Time `json:"knownSince"` } // GetId returns CertifyBadSpec.Id, and is useful for accessing the field via an interface. @@ -6124,6 +6154,9 @@ func (v *CertifyBadSpec) GetOrigin() *string { return v.Origin } // GetCollector returns CertifyBadSpec.Collector, and is useful for accessing the field via an interface. func (v *CertifyBadSpec) GetCollector() *string { return v.Collector } +// GetKnownSince returns CertifyBadSpec.KnownSince, and is useful for accessing the field via an interface. +func (v *CertifyBadSpec) GetKnownSince() *time.Time { return v.KnownSince } + // CertifyBadSrcResponse is returned by CertifyBadSrc on success. type CertifyBadSrcResponse struct { // Adds a certification that a package, source or artifact is considered bad. The returned ID can be empty string. @@ -6166,6 +6199,9 @@ func (v *CertifyBadsCertifyBad) GetId() string { return v.AllCertifyBad.Id } // GetJustification returns CertifyBadsCertifyBad.Justification, and is useful for accessing the field via an interface. func (v *CertifyBadsCertifyBad) GetJustification() string { return v.AllCertifyBad.Justification } +// GetKnownSince returns CertifyBadsCertifyBad.KnownSince, and is useful for accessing the field via an interface. +func (v *CertifyBadsCertifyBad) GetKnownSince() time.Time { return v.AllCertifyBad.KnownSince } + // GetSubject returns CertifyBadsCertifyBad.Subject, and is useful for accessing the field via an interface. func (v *CertifyBadsCertifyBad) GetSubject() AllCertifyBadSubjectPackageSourceOrArtifact { return v.AllCertifyBad.Subject @@ -6207,6 +6243,8 @@ type __premarshalCertifyBadsCertifyBad struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -6227,6 +6265,7 @@ func (v *CertifyBadsCertifyBad) __premarshalJSON() (*__premarshalCertifyBadsCert retval.Id = v.AllCertifyBad.Id retval.Justification = v.AllCertifyBad.Justification + retval.KnownSince = v.AllCertifyBad.KnownSince { dst := &retval.Subject @@ -6273,9 +6312,10 @@ func (v *CertifyGoodArtifactsResponse) GetIngestCertifyGoods() []string { return // CertifyGoodInputSpec represents the mutation input to ingest a CertifyGood evidence. type CertifyGoodInputSpec struct { - Justification string `json:"justification"` - Origin string `json:"origin"` - Collector string `json:"collector"` + Justification string `json:"justification"` + Origin string `json:"origin"` + Collector string `json:"collector"` + KnownSince time.Time `json:"knownSince"` } // GetJustification returns CertifyGoodInputSpec.Justification, and is useful for accessing the field via an interface. @@ -6287,6 +6327,9 @@ func (v *CertifyGoodInputSpec) GetOrigin() string { return v.Origin } // GetCollector returns CertifyGoodInputSpec.Collector, and is useful for accessing the field via an interface. func (v *CertifyGoodInputSpec) GetCollector() string { return v.Collector } +// GetKnownSince returns CertifyGoodInputSpec.KnownSince, and is useful for accessing the field via an interface. +func (v *CertifyGoodInputSpec) GetKnownSince() time.Time { return v.KnownSince } + // CertifyGoodPkgResponse is returned by CertifyGoodPkg on success. type CertifyGoodPkgResponse struct { // Adds a certification that a package, source or artifact is considered good. The returned ID can be empty string. @@ -7339,12 +7382,13 @@ func (v *HasSBOMArtifactsResponse) GetIngestHasSBOMs() []string { return v.Inges // HasSBOMInputSpec is the same as HasSBOM but for mutation input. type HasSBOMInputSpec struct { - Uri string `json:"uri"` - Algorithm string `json:"algorithm"` - Digest string `json:"digest"` - DownloadLocation string `json:"downloadLocation"` - Origin string `json:"origin"` - Collector string `json:"collector"` + Uri string `json:"uri"` + Algorithm string `json:"algorithm"` + Digest string `json:"digest"` + DownloadLocation string `json:"downloadLocation"` + Origin string `json:"origin"` + Collector string `json:"collector"` + KnownSince time.Time `json:"knownSince"` } // GetUri returns HasSBOMInputSpec.Uri, and is useful for accessing the field via an interface. @@ -7365,6 +7409,9 @@ func (v *HasSBOMInputSpec) GetOrigin() string { return v.Origin } // GetCollector returns HasSBOMInputSpec.Collector, and is useful for accessing the field via an interface. func (v *HasSBOMInputSpec) GetCollector() string { return v.Collector } +// GetKnownSince returns HasSBOMInputSpec.KnownSince, and is useful for accessing the field via an interface. +func (v *HasSBOMInputSpec) GetKnownSince() time.Time { return v.KnownSince } + // HasSBOMPkgResponse is returned by HasSBOMPkg on success. type HasSBOMPkgResponse struct { // Certifies that a package or artifact has an SBOM. The returned ID can be empty string. @@ -8027,6 +8074,9 @@ func (v *NeighborsNeighborsCertifyBad) GetJustification() string { return v.AllCertifyBad.Justification } +// GetKnownSince returns NeighborsNeighborsCertifyBad.KnownSince, and is useful for accessing the field via an interface. +func (v *NeighborsNeighborsCertifyBad) GetKnownSince() time.Time { return v.AllCertifyBad.KnownSince } + // GetSubject returns NeighborsNeighborsCertifyBad.Subject, and is useful for accessing the field via an interface. func (v *NeighborsNeighborsCertifyBad) GetSubject() AllCertifyBadSubjectPackageSourceOrArtifact { return v.AllCertifyBad.Subject @@ -8070,6 +8120,8 @@ type __premarshalNeighborsNeighborsCertifyBad struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -8091,6 +8143,7 @@ func (v *NeighborsNeighborsCertifyBad) __premarshalJSON() (*__premarshalNeighbor retval.Typename = v.Typename retval.Id = v.AllCertifyBad.Id retval.Justification = v.AllCertifyBad.Justification + retval.KnownSince = v.AllCertifyBad.KnownSince { dst := &retval.Subject @@ -8138,6 +8191,9 @@ func (v *NeighborsNeighborsCertifyGood) GetJustification() string { return v.AllCertifyGood.Justification } +// GetKnownSince returns NeighborsNeighborsCertifyGood.KnownSince, and is useful for accessing the field via an interface. +func (v *NeighborsNeighborsCertifyGood) GetKnownSince() time.Time { return v.AllCertifyGood.KnownSince } + // GetSubject returns NeighborsNeighborsCertifyGood.Subject, and is useful for accessing the field via an interface. func (v *NeighborsNeighborsCertifyGood) GetSubject() AllCertifyGoodSubjectPackageSourceOrArtifact { return v.AllCertifyGood.Subject @@ -8181,6 +8237,8 @@ type __premarshalNeighborsNeighborsCertifyGood struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -8202,6 +8260,7 @@ func (v *NeighborsNeighborsCertifyGood) __premarshalJSON() (*__premarshalNeighbo retval.Typename = v.Typename retval.Id = v.AllCertifyGood.Id retval.Justification = v.AllCertifyGood.Justification + retval.KnownSince = v.AllCertifyGood.KnownSince { dst := &retval.Subject @@ -8867,6 +8926,9 @@ func (v *NeighborsNeighborsHasSBOM) GetOrigin() string { return v.AllHasSBOMTree // GetCollector returns NeighborsNeighborsHasSBOM.Collector, and is useful for accessing the field via an interface. func (v *NeighborsNeighborsHasSBOM) GetCollector() string { return v.AllHasSBOMTree.Collector } +// GetKnownSince returns NeighborsNeighborsHasSBOM.KnownSince, and is useful for accessing the field via an interface. +func (v *NeighborsNeighborsHasSBOM) GetKnownSince() time.Time { return v.AllHasSBOMTree.KnownSince } + func (v *NeighborsNeighborsHasSBOM) UnmarshalJSON(b []byte) error { if string(b) == "null" { @@ -8910,6 +8972,8 @@ type __premarshalNeighborsNeighborsHasSBOM struct { Origin string `json:"origin"` Collector string `json:"collector"` + + KnownSince time.Time `json:"knownSince"` } func (v *NeighborsNeighborsHasSBOM) MarshalJSON() ([]byte, error) { @@ -8943,6 +9007,7 @@ func (v *NeighborsNeighborsHasSBOM) __premarshalJSON() (*__premarshalNeighborsNe retval.DownloadLocation = v.AllHasSBOMTree.DownloadLocation retval.Origin = v.AllHasSBOMTree.Origin retval.Collector = v.AllHasSBOMTree.Collector + retval.KnownSince = v.AllHasSBOMTree.KnownSince return &retval, nil } @@ -11427,6 +11492,9 @@ func (v *NodeNodeCertifyBad) GetId() string { return v.AllCertifyBad.Id } // GetJustification returns NodeNodeCertifyBad.Justification, and is useful for accessing the field via an interface. func (v *NodeNodeCertifyBad) GetJustification() string { return v.AllCertifyBad.Justification } +// GetKnownSince returns NodeNodeCertifyBad.KnownSince, and is useful for accessing the field via an interface. +func (v *NodeNodeCertifyBad) GetKnownSince() time.Time { return v.AllCertifyBad.KnownSince } + // GetSubject returns NodeNodeCertifyBad.Subject, and is useful for accessing the field via an interface. func (v *NodeNodeCertifyBad) GetSubject() AllCertifyBadSubjectPackageSourceOrArtifact { return v.AllCertifyBad.Subject @@ -11470,6 +11538,8 @@ type __premarshalNodeNodeCertifyBad struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -11491,6 +11561,7 @@ func (v *NodeNodeCertifyBad) __premarshalJSON() (*__premarshalNodeNodeCertifyBad retval.Typename = v.Typename retval.Id = v.AllCertifyBad.Id retval.Justification = v.AllCertifyBad.Justification + retval.KnownSince = v.AllCertifyBad.KnownSince { dst := &retval.Subject @@ -11536,6 +11607,9 @@ func (v *NodeNodeCertifyGood) GetId() string { return v.AllCertifyGood.Id } // GetJustification returns NodeNodeCertifyGood.Justification, and is useful for accessing the field via an interface. func (v *NodeNodeCertifyGood) GetJustification() string { return v.AllCertifyGood.Justification } +// GetKnownSince returns NodeNodeCertifyGood.KnownSince, and is useful for accessing the field via an interface. +func (v *NodeNodeCertifyGood) GetKnownSince() time.Time { return v.AllCertifyGood.KnownSince } + // GetSubject returns NodeNodeCertifyGood.Subject, and is useful for accessing the field via an interface. func (v *NodeNodeCertifyGood) GetSubject() AllCertifyGoodSubjectPackageSourceOrArtifact { return v.AllCertifyGood.Subject @@ -11579,6 +11653,8 @@ type __premarshalNodeNodeCertifyGood struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -11600,6 +11676,7 @@ func (v *NodeNodeCertifyGood) __premarshalJSON() (*__premarshalNodeNodeCertifyGo retval.Typename = v.Typename retval.Id = v.AllCertifyGood.Id retval.Justification = v.AllCertifyGood.Justification + retval.KnownSince = v.AllCertifyGood.KnownSince { dst := &retval.Subject @@ -12247,6 +12324,9 @@ func (v *NodeNodeHasSBOM) GetOrigin() string { return v.AllHasSBOMTree.Origin } // GetCollector returns NodeNodeHasSBOM.Collector, and is useful for accessing the field via an interface. func (v *NodeNodeHasSBOM) GetCollector() string { return v.AllHasSBOMTree.Collector } +// GetKnownSince returns NodeNodeHasSBOM.KnownSince, and is useful for accessing the field via an interface. +func (v *NodeNodeHasSBOM) GetKnownSince() time.Time { return v.AllHasSBOMTree.KnownSince } + func (v *NodeNodeHasSBOM) UnmarshalJSON(b []byte) error { if string(b) == "null" { @@ -12290,6 +12370,8 @@ type __premarshalNodeNodeHasSBOM struct { Origin string `json:"origin"` Collector string `json:"collector"` + + KnownSince time.Time `json:"knownSince"` } func (v *NodeNodeHasSBOM) MarshalJSON() ([]byte, error) { @@ -12323,6 +12405,7 @@ func (v *NodeNodeHasSBOM) __premarshalJSON() (*__premarshalNodeNodeHasSBOM, erro retval.DownloadLocation = v.AllHasSBOMTree.DownloadLocation retval.Origin = v.AllHasSBOMTree.Origin retval.Collector = v.AllHasSBOMTree.Collector + retval.KnownSince = v.AllHasSBOMTree.KnownSince return &retval, nil } @@ -13875,6 +13958,9 @@ func (v *NodesNodesCertifyBad) GetId() string { return v.AllCertifyBad.Id } // GetJustification returns NodesNodesCertifyBad.Justification, and is useful for accessing the field via an interface. func (v *NodesNodesCertifyBad) GetJustification() string { return v.AllCertifyBad.Justification } +// GetKnownSince returns NodesNodesCertifyBad.KnownSince, and is useful for accessing the field via an interface. +func (v *NodesNodesCertifyBad) GetKnownSince() time.Time { return v.AllCertifyBad.KnownSince } + // GetSubject returns NodesNodesCertifyBad.Subject, and is useful for accessing the field via an interface. func (v *NodesNodesCertifyBad) GetSubject() AllCertifyBadSubjectPackageSourceOrArtifact { return v.AllCertifyBad.Subject @@ -13918,6 +14004,8 @@ type __premarshalNodesNodesCertifyBad struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -13939,6 +14027,7 @@ func (v *NodesNodesCertifyBad) __premarshalJSON() (*__premarshalNodesNodesCertif retval.Typename = v.Typename retval.Id = v.AllCertifyBad.Id retval.Justification = v.AllCertifyBad.Justification + retval.KnownSince = v.AllCertifyBad.KnownSince { dst := &retval.Subject @@ -13984,6 +14073,9 @@ func (v *NodesNodesCertifyGood) GetId() string { return v.AllCertifyGood.Id } // GetJustification returns NodesNodesCertifyGood.Justification, and is useful for accessing the field via an interface. func (v *NodesNodesCertifyGood) GetJustification() string { return v.AllCertifyGood.Justification } +// GetKnownSince returns NodesNodesCertifyGood.KnownSince, and is useful for accessing the field via an interface. +func (v *NodesNodesCertifyGood) GetKnownSince() time.Time { return v.AllCertifyGood.KnownSince } + // GetSubject returns NodesNodesCertifyGood.Subject, and is useful for accessing the field via an interface. func (v *NodesNodesCertifyGood) GetSubject() AllCertifyGoodSubjectPackageSourceOrArtifact { return v.AllCertifyGood.Subject @@ -14027,6 +14119,8 @@ type __premarshalNodesNodesCertifyGood struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -14048,6 +14142,7 @@ func (v *NodesNodesCertifyGood) __premarshalJSON() (*__premarshalNodesNodesCerti retval.Typename = v.Typename retval.Id = v.AllCertifyGood.Id retval.Justification = v.AllCertifyGood.Justification + retval.KnownSince = v.AllCertifyGood.KnownSince { dst := &retval.Subject @@ -14697,6 +14792,9 @@ func (v *NodesNodesHasSBOM) GetOrigin() string { return v.AllHasSBOMTree.Origin // GetCollector returns NodesNodesHasSBOM.Collector, and is useful for accessing the field via an interface. func (v *NodesNodesHasSBOM) GetCollector() string { return v.AllHasSBOMTree.Collector } +// GetKnownSince returns NodesNodesHasSBOM.KnownSince, and is useful for accessing the field via an interface. +func (v *NodesNodesHasSBOM) GetKnownSince() time.Time { return v.AllHasSBOMTree.KnownSince } + func (v *NodesNodesHasSBOM) UnmarshalJSON(b []byte) error { if string(b) == "null" { @@ -14740,6 +14838,8 @@ type __premarshalNodesNodesHasSBOM struct { Origin string `json:"origin"` Collector string `json:"collector"` + + KnownSince time.Time `json:"knownSince"` } func (v *NodesNodesHasSBOM) MarshalJSON() ([]byte, error) { @@ -14773,6 +14873,7 @@ func (v *NodesNodesHasSBOM) __premarshalJSON() (*__premarshalNodesNodesHasSBOM, retval.DownloadLocation = v.AllHasSBOMTree.DownloadLocation retval.Origin = v.AllHasSBOMTree.Origin retval.Collector = v.AllHasSBOMTree.Collector + retval.KnownSince = v.AllHasSBOMTree.KnownSince return &retval, nil } @@ -17329,6 +17430,9 @@ func (v *PathPathCertifyBad) GetId() string { return v.AllCertifyBad.Id } // GetJustification returns PathPathCertifyBad.Justification, and is useful for accessing the field via an interface. func (v *PathPathCertifyBad) GetJustification() string { return v.AllCertifyBad.Justification } +// GetKnownSince returns PathPathCertifyBad.KnownSince, and is useful for accessing the field via an interface. +func (v *PathPathCertifyBad) GetKnownSince() time.Time { return v.AllCertifyBad.KnownSince } + // GetSubject returns PathPathCertifyBad.Subject, and is useful for accessing the field via an interface. func (v *PathPathCertifyBad) GetSubject() AllCertifyBadSubjectPackageSourceOrArtifact { return v.AllCertifyBad.Subject @@ -17372,6 +17476,8 @@ type __premarshalPathPathCertifyBad struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -17393,6 +17499,7 @@ func (v *PathPathCertifyBad) __premarshalJSON() (*__premarshalPathPathCertifyBad retval.Typename = v.Typename retval.Id = v.AllCertifyBad.Id retval.Justification = v.AllCertifyBad.Justification + retval.KnownSince = v.AllCertifyBad.KnownSince { dst := &retval.Subject @@ -17438,6 +17545,9 @@ func (v *PathPathCertifyGood) GetId() string { return v.AllCertifyGood.Id } // GetJustification returns PathPathCertifyGood.Justification, and is useful for accessing the field via an interface. func (v *PathPathCertifyGood) GetJustification() string { return v.AllCertifyGood.Justification } +// GetKnownSince returns PathPathCertifyGood.KnownSince, and is useful for accessing the field via an interface. +func (v *PathPathCertifyGood) GetKnownSince() time.Time { return v.AllCertifyGood.KnownSince } + // GetSubject returns PathPathCertifyGood.Subject, and is useful for accessing the field via an interface. func (v *PathPathCertifyGood) GetSubject() AllCertifyGoodSubjectPackageSourceOrArtifact { return v.AllCertifyGood.Subject @@ -17481,6 +17591,8 @@ type __premarshalPathPathCertifyGood struct { Justification string `json:"justification"` + KnownSince time.Time `json:"knownSince"` + Subject json.RawMessage `json:"subject"` Origin string `json:"origin"` @@ -17502,6 +17614,7 @@ func (v *PathPathCertifyGood) __premarshalJSON() (*__premarshalPathPathCertifyGo retval.Typename = v.Typename retval.Id = v.AllCertifyGood.Id retval.Justification = v.AllCertifyGood.Justification + retval.KnownSince = v.AllCertifyGood.KnownSince { dst := &retval.Subject @@ -18149,6 +18262,9 @@ func (v *PathPathHasSBOM) GetOrigin() string { return v.AllHasSBOMTree.Origin } // GetCollector returns PathPathHasSBOM.Collector, and is useful for accessing the field via an interface. func (v *PathPathHasSBOM) GetCollector() string { return v.AllHasSBOMTree.Collector } +// GetKnownSince returns PathPathHasSBOM.KnownSince, and is useful for accessing the field via an interface. +func (v *PathPathHasSBOM) GetKnownSince() time.Time { return v.AllHasSBOMTree.KnownSince } + func (v *PathPathHasSBOM) UnmarshalJSON(b []byte) error { if string(b) == "null" { @@ -18192,6 +18308,8 @@ type __premarshalPathPathHasSBOM struct { Origin string `json:"origin"` Collector string `json:"collector"` + + KnownSince time.Time `json:"knownSince"` } func (v *PathPathHasSBOM) MarshalJSON() ([]byte, error) { @@ -18225,6 +18343,7 @@ func (v *PathPathHasSBOM) __premarshalJSON() (*__premarshalPathPathHasSBOM, erro retval.DownloadLocation = v.AllHasSBOMTree.DownloadLocation retval.Origin = v.AllHasSBOMTree.Origin retval.Collector = v.AllHasSBOMTree.Collector + retval.KnownSince = v.AllHasSBOMTree.KnownSince return &retval, nil } @@ -22277,6 +22396,7 @@ query CertifyBads ($filter: CertifyBadSpec!) { fragment AllCertifyBad on CertifyBad { id justification + knownSince subject { __typename ... on Package { @@ -24748,6 +24868,7 @@ fragment AllSLSATree on HasSLSA { fragment AllCertifyBad on CertifyBad { id justification + knownSince subject { __typename ... on Package { @@ -24766,6 +24887,7 @@ fragment AllCertifyBad on CertifyBad { fragment AllCertifyGood on CertifyGood { id justification + knownSince subject { __typename ... on Package { @@ -24807,6 +24929,7 @@ fragment AllHasSBOMTree on HasSBOM { downloadLocation origin collector + knownSince } fragment AllHasSourceAt on HasSourceAt { id @@ -25207,6 +25330,7 @@ fragment AllSLSATree on HasSLSA { fragment AllCertifyBad on CertifyBad { id justification + knownSince subject { __typename ... on Package { @@ -25225,6 +25349,7 @@ fragment AllCertifyBad on CertifyBad { fragment AllCertifyGood on CertifyGood { id justification + knownSince subject { __typename ... on Package { @@ -25266,6 +25391,7 @@ fragment AllHasSBOMTree on HasSBOM { downloadLocation origin collector + knownSince } fragment AllHasSourceAt on HasSourceAt { id @@ -25664,6 +25790,7 @@ fragment AllSLSATree on HasSLSA { fragment AllCertifyBad on CertifyBad { id justification + knownSince subject { __typename ... on Package { @@ -25682,6 +25809,7 @@ fragment AllCertifyBad on CertifyBad { fragment AllCertifyGood on CertifyGood { id justification + knownSince subject { __typename ... on Package { @@ -25723,6 +25851,7 @@ fragment AllHasSBOMTree on HasSBOM { downloadLocation origin collector + knownSince } fragment AllHasSourceAt on HasSourceAt { id @@ -26350,6 +26479,7 @@ fragment AllSLSATree on HasSLSA { fragment AllCertifyBad on CertifyBad { id justification + knownSince subject { __typename ... on Package { @@ -26368,6 +26498,7 @@ fragment AllCertifyBad on CertifyBad { fragment AllCertifyGood on CertifyGood { id justification + knownSince subject { __typename ... on Package { @@ -26409,6 +26540,7 @@ fragment AllHasSBOMTree on HasSBOM { downloadLocation origin collector + knownSince } fragment AllHasSourceAt on HasSourceAt { id diff --git a/pkg/assembler/clients/operations/trees.graphql b/pkg/assembler/clients/operations/trees.graphql index 6e10474b9f..866004363a 100644 --- a/pkg/assembler/clients/operations/trees.graphql +++ b/pkg/assembler/clients/operations/trees.graphql @@ -208,6 +208,7 @@ fragment AllCertifyLegalTree on CertifyLegal { fragment AllCertifyBad on CertifyBad { id justification + knownSince subject { __typename ... on Package { @@ -227,6 +228,7 @@ fragment AllCertifyBad on CertifyBad { fragment AllCertifyGood on CertifyGood { id justification + knownSince subject { __typename ... on Package { @@ -270,6 +272,7 @@ fragment AllHasSBOMTree on HasSBOM { downloadLocation origin collector + knownSince } fragment AllHasSourceAt on HasSourceAt { diff --git a/pkg/assembler/graphql/examples/certify_bad.gql b/pkg/assembler/graphql/examples/certify_bad.gql index 961cba58ed..944f6c1bcc 100644 --- a/pkg/assembler/graphql/examples/certify_bad.gql +++ b/pkg/assembler/graphql/examples/certify_bad.gql @@ -1,6 +1,7 @@ fragment allCertifyBadTree on CertifyBad { id justification + knownSince subject { __typename ... on Package { diff --git a/pkg/assembler/graphql/examples/certify_good.gql b/pkg/assembler/graphql/examples/certify_good.gql index 7a1c2147bd..0d7d4ab993 100644 --- a/pkg/assembler/graphql/examples/certify_good.gql +++ b/pkg/assembler/graphql/examples/certify_good.gql @@ -1,6 +1,7 @@ fragment allCertifyGoodTree on CertifyGood { id justification + knownSince subject { __typename ... on Package { diff --git a/pkg/assembler/graphql/examples/has_sbom.gql b/pkg/assembler/graphql/examples/has_sbom.gql index cc61c8171f..56d8502c64 100644 --- a/pkg/assembler/graphql/examples/has_sbom.gql +++ b/pkg/assembler/graphql/examples/has_sbom.gql @@ -35,6 +35,7 @@ fragment allHasSBOMTree on HasSBOM { downloadLocation origin collector + knownSince } query HasSBOMQ1 { diff --git a/pkg/assembler/graphql/generated/artifact.generated.go b/pkg/assembler/graphql/generated/artifact.generated.go index 84495986fb..1e9ec2c04e 100644 --- a/pkg/assembler/graphql/generated/artifact.generated.go +++ b/pkg/assembler/graphql/generated/artifact.generated.go @@ -4735,6 +4735,8 @@ func (ec *executionContext) fieldContext_Query_CertifyBad(ctx context.Context, f return ec.fieldContext_CertifyBad_origin(ctx, field) case "collector": return ec.fieldContext_CertifyBad_collector(ctx, field) + case "knownSince": + return ec.fieldContext_CertifyBad_knownSince(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type CertifyBad", field.Name) }, @@ -4802,6 +4804,8 @@ func (ec *executionContext) fieldContext_Query_CertifyGood(ctx context.Context, return ec.fieldContext_CertifyGood_origin(ctx, field) case "collector": return ec.fieldContext_CertifyGood_collector(ctx, field) + case "knownSince": + return ec.fieldContext_CertifyGood_knownSince(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type CertifyGood", field.Name) }, @@ -5232,6 +5236,8 @@ func (ec *executionContext) fieldContext_Query_HasSBOM(ctx context.Context, fiel return ec.fieldContext_HasSBOM_origin(ctx, field) case "collector": return ec.fieldContext_HasSBOM_collector(ctx, field) + case "knownSince": + return ec.fieldContext_HasSBOM_knownSince(ctx, field) } return nil, fmt.Errorf("no field named %q was found under type HasSBOM", field.Name) }, diff --git a/pkg/assembler/graphql/generated/certifyBad.generated.go b/pkg/assembler/graphql/generated/certifyBad.generated.go index ea433e4885..3619990082 100644 --- a/pkg/assembler/graphql/generated/certifyBad.generated.go +++ b/pkg/assembler/graphql/generated/certifyBad.generated.go @@ -9,6 +9,7 @@ import ( "strconv" "sync" "sync/atomic" + "time" "github.com/99designs/gqlgen/graphql" "github.com/guacsec/guac/pkg/assembler/graphql/model" @@ -249,6 +250,50 @@ func (ec *executionContext) fieldContext_CertifyBad_collector(ctx context.Contex return fc, nil } +func (ec *executionContext) _CertifyBad_knownSince(ctx context.Context, field graphql.CollectedField, obj *model.CertifyBad) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CertifyBad_knownSince(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.KnownSince, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CertifyBad_knownSince(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CertifyBad", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + // endregion **************************** field.gotpl ***************************** // region **************************** input.gotpl ***************************** @@ -260,7 +305,7 @@ func (ec *executionContext) unmarshalInputCertifyBadInputSpec(ctx context.Contex asMap[k] = v } - fieldsInOrder := [...]string{"justification", "origin", "collector"} + fieldsInOrder := [...]string{"justification", "origin", "collector", "knownSince"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -294,6 +339,15 @@ func (ec *executionContext) unmarshalInputCertifyBadInputSpec(ctx context.Contex return it, err } it.Collector = data + case "knownSince": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("knownSince")) + data, err := ec.unmarshalNTime2timeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.KnownSince = data } } @@ -307,7 +361,7 @@ func (ec *executionContext) unmarshalInputCertifyBadSpec(ctx context.Context, ob asMap[k] = v } - fieldsInOrder := [...]string{"id", "subject", "justification", "origin", "collector"} + fieldsInOrder := [...]string{"id", "subject", "justification", "origin", "collector", "knownSince"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -359,6 +413,15 @@ func (ec *executionContext) unmarshalInputCertifyBadSpec(ctx context.Context, ob return it, err } it.Collector = data + case "knownSince": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("knownSince")) + data, err := ec.unmarshalOTime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.KnownSince = data } } @@ -609,6 +672,11 @@ func (ec *executionContext) _CertifyBad(ctx context.Context, sel ast.SelectionSe if out.Values[i] == graphql.Null { out.Invalids++ } + case "knownSince": + out.Values[i] = ec._CertifyBad_knownSince(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } diff --git a/pkg/assembler/graphql/generated/certifyGood.generated.go b/pkg/assembler/graphql/generated/certifyGood.generated.go index ab14df762e..9e88812286 100644 --- a/pkg/assembler/graphql/generated/certifyGood.generated.go +++ b/pkg/assembler/graphql/generated/certifyGood.generated.go @@ -8,6 +8,7 @@ import ( "strconv" "sync" "sync/atomic" + "time" "github.com/99designs/gqlgen/graphql" "github.com/guacsec/guac/pkg/assembler/graphql/model" @@ -248,6 +249,50 @@ func (ec *executionContext) fieldContext_CertifyGood_collector(ctx context.Conte return fc, nil } +func (ec *executionContext) _CertifyGood_knownSince(ctx context.Context, field graphql.CollectedField, obj *model.CertifyGood) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CertifyGood_knownSince(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.KnownSince, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CertifyGood_knownSince(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CertifyGood", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + // endregion **************************** field.gotpl ***************************** // region **************************** input.gotpl ***************************** @@ -259,7 +304,7 @@ func (ec *executionContext) unmarshalInputCertifyGoodInputSpec(ctx context.Conte asMap[k] = v } - fieldsInOrder := [...]string{"justification", "origin", "collector"} + fieldsInOrder := [...]string{"justification", "origin", "collector", "knownSince"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -293,6 +338,15 @@ func (ec *executionContext) unmarshalInputCertifyGoodInputSpec(ctx context.Conte return it, err } it.Collector = data + case "knownSince": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("knownSince")) + data, err := ec.unmarshalNTime2timeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.KnownSince = data } } @@ -306,7 +360,7 @@ func (ec *executionContext) unmarshalInputCertifyGoodSpec(ctx context.Context, o asMap[k] = v } - fieldsInOrder := [...]string{"id", "subject", "justification", "origin", "collector"} + fieldsInOrder := [...]string{"id", "subject", "justification", "origin", "collector", "knownSince"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -358,6 +412,15 @@ func (ec *executionContext) unmarshalInputCertifyGoodSpec(ctx context.Context, o return it, err } it.Collector = data + case "knownSince": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("knownSince")) + data, err := ec.unmarshalOTime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.KnownSince = data } } @@ -408,6 +471,11 @@ func (ec *executionContext) _CertifyGood(ctx context.Context, sel ast.SelectionS if out.Values[i] == graphql.Null { out.Invalids++ } + case "knownSince": + out.Values[i] = ec._CertifyGood_knownSince(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } diff --git a/pkg/assembler/graphql/generated/hasSBOM.generated.go b/pkg/assembler/graphql/generated/hasSBOM.generated.go index 0b9714487b..529f4d6fbf 100644 --- a/pkg/assembler/graphql/generated/hasSBOM.generated.go +++ b/pkg/assembler/graphql/generated/hasSBOM.generated.go @@ -8,6 +8,7 @@ import ( "strconv" "sync" "sync/atomic" + "time" "github.com/99designs/gqlgen/graphql" "github.com/guacsec/guac/pkg/assembler/graphql/model" @@ -380,6 +381,50 @@ func (ec *executionContext) fieldContext_HasSBOM_collector(ctx context.Context, return fc, nil } +func (ec *executionContext) _HasSBOM_knownSince(ctx context.Context, field graphql.CollectedField, obj *model.HasSbom) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_HasSBOM_knownSince(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.KnownSince, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_HasSBOM_knownSince(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "HasSBOM", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + // endregion **************************** field.gotpl ***************************** // region **************************** input.gotpl ***************************** @@ -391,7 +436,7 @@ func (ec *executionContext) unmarshalInputHasSBOMInputSpec(ctx context.Context, asMap[k] = v } - fieldsInOrder := [...]string{"uri", "algorithm", "digest", "downloadLocation", "origin", "collector"} + fieldsInOrder := [...]string{"uri", "algorithm", "digest", "downloadLocation", "origin", "collector", "knownSince"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -452,6 +497,15 @@ func (ec *executionContext) unmarshalInputHasSBOMInputSpec(ctx context.Context, return it, err } it.Collector = data + case "knownSince": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("knownSince")) + data, err := ec.unmarshalNTime2timeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.KnownSince = data } } @@ -465,7 +519,7 @@ func (ec *executionContext) unmarshalInputHasSBOMSpec(ctx context.Context, obj i asMap[k] = v } - fieldsInOrder := [...]string{"id", "subject", "uri", "algorithm", "digest", "downloadLocation", "origin", "collector"} + fieldsInOrder := [...]string{"id", "subject", "uri", "algorithm", "digest", "downloadLocation", "origin", "collector", "knownSince"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -544,6 +598,15 @@ func (ec *executionContext) unmarshalInputHasSBOMSpec(ctx context.Context, obj i return it, err } it.Collector = data + case "knownSince": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("knownSince")) + data, err := ec.unmarshalOTime2ᚖtimeᚐTime(ctx, v) + if err != nil { + return it, err + } + it.KnownSince = data } } @@ -609,6 +672,11 @@ func (ec *executionContext) _HasSBOM(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { out.Invalids++ } + case "knownSince": + out.Values[i] = ec._HasSBOM_knownSince(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } diff --git a/pkg/assembler/graphql/generated/root_.generated.go b/pkg/assembler/graphql/generated/root_.generated.go index 7665457db5..99da8d1ff7 100644 --- a/pkg/assembler/graphql/generated/root_.generated.go +++ b/pkg/assembler/graphql/generated/root_.generated.go @@ -54,6 +54,7 @@ type ComplexityRoot struct { Collector func(childComplexity int) int ID func(childComplexity int) int Justification func(childComplexity int) int + KnownSince func(childComplexity int) int Origin func(childComplexity int) int Subject func(childComplexity int) int } @@ -62,6 +63,7 @@ type ComplexityRoot struct { Collector func(childComplexity int) int ID func(childComplexity int) int Justification func(childComplexity int) int + KnownSince func(childComplexity int) int Origin func(childComplexity int) int Subject func(childComplexity int) int } @@ -123,6 +125,7 @@ type ComplexityRoot struct { Digest func(childComplexity int) int DownloadLocation func(childComplexity int) int ID func(childComplexity int) int + KnownSince func(childComplexity int) int Origin func(childComplexity int) int Subject func(childComplexity int) int URI func(childComplexity int) int @@ -470,6 +473,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.CertifyBad.Justification(childComplexity), true + case "CertifyBad.knownSince": + if e.complexity.CertifyBad.KnownSince == nil { + break + } + + return e.complexity.CertifyBad.KnownSince(childComplexity), true + case "CertifyBad.origin": if e.complexity.CertifyBad.Origin == nil { break @@ -505,6 +515,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.CertifyGood.Justification(childComplexity), true + case "CertifyGood.knownSince": + if e.complexity.CertifyGood.KnownSince == nil { + break + } + + return e.complexity.CertifyGood.KnownSince(childComplexity), true + case "CertifyGood.origin": if e.complexity.CertifyGood.Origin == nil { break @@ -806,6 +823,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.HasSBOM.ID(childComplexity), true + case "HasSBOM.knownSince": + if e.complexity.HasSBOM.KnownSince == nil { + break + } + + return e.complexity.HasSBOM.KnownSince(childComplexity), true + case "HasSBOM.origin": if e.complexity.HasSBOM.Origin == nil { break @@ -2883,6 +2907,7 @@ type CertifyBad { justification: String! origin: String! collector: String! + knownSince: Time! } """ @@ -2895,6 +2920,9 @@ name and one of version, qualifiers, or subpath. If a source is specified in the subject filter, then it must specify a name, and optionally a tag and a commit. + +If KnownSince is specified, the returned value will be after or equal to the specified time. +Any nodes time that is before KnownSince is excluded. """ input CertifyBadSpec { id: ID @@ -2902,6 +2930,7 @@ input CertifyBadSpec { justification: String origin: String collector: String + knownSince: Time } """ @@ -2912,6 +2941,7 @@ input CertifyBadInputSpec { justification: String! origin: String! collector: String! + knownSince: Time! } """ @@ -2986,6 +3016,7 @@ type CertifyGood { justification: String! origin: String! collector: String! + knownSince: Time! } """ @@ -2998,6 +3029,9 @@ name and one of version, qualifiers, or subpath. If a source is specified in the subject filter, then it must specify a name, and optionally a tag and a commit. + +If KnownSince is specified, the returned value will be after or equal to the specified time. +Any nodes time that is before KnownSince is excluded. """ input CertifyGoodSpec { id: ID @@ -3005,6 +3039,7 @@ input CertifyGoodSpec { justification: String origin: String collector: String + knownSince: Time } """ @@ -3014,6 +3049,7 @@ input CertifyGoodInputSpec { justification: String! origin: String! collector: String! + knownSince: Time! } extend type Query { @@ -3686,12 +3722,17 @@ type HasSBOM { origin: String! "GUAC collector for the document" collector: String! + "Timestamp for SBOM creation" + knownSince: Time! } """ HasSBOMSpec allows filtering the list of HasSBOM to return. Only the package or artifact can be added, not both. + +If KnownSince is specified, the returned value will be after or equal to the specified time. +Any nodes time that is before KnownSince is excluded. """ input HasSBOMSpec { id: ID @@ -3702,6 +3743,7 @@ input HasSBOMSpec { downloadLocation: String origin: String collector: String + knownSince: Time } "HasSBOMInputSpec is the same as HasSBOM but for mutation input." @@ -3712,6 +3754,7 @@ input HasSBOMInputSpec { downloadLocation: String! origin: String! collector: String! + knownSince: Time! } extend type Query { diff --git a/pkg/assembler/graphql/model/nodes.go b/pkg/assembler/graphql/model/nodes.go index a68007b6e9..84aca2b89e 100644 --- a/pkg/assembler/graphql/model/nodes.go +++ b/pkg/assembler/graphql/model/nodes.go @@ -107,6 +107,7 @@ type CertifyBad struct { Justification string `json:"justification"` Origin string `json:"origin"` Collector string `json:"collector"` + KnownSince time.Time `json:"knownSince"` } func (CertifyBad) IsNode() {} @@ -114,9 +115,10 @@ func (CertifyBad) IsNode() {} // CertifyBadInputSpec represents the mutation input to ingest a CertifyBad // evidence. type CertifyBadInputSpec struct { - Justification string `json:"justification"` - Origin string `json:"origin"` - Collector string `json:"collector"` + Justification string `json:"justification"` + Origin string `json:"origin"` + Collector string `json:"collector"` + KnownSince time.Time `json:"knownSince"` } // CertifyBadSpec allows filtering the list of CertifyBad evidence to return in a @@ -128,12 +130,16 @@ type CertifyBadInputSpec struct { // // If a source is specified in the subject filter, then it must specify a name, // and optionally a tag and a commit. +// +// If KnownSince is specified, the returned value will be after or equal to the specified time. +// Any nodes time that is before KnownSince is excluded. type CertifyBadSpec struct { ID *string `json:"id,omitempty"` Subject *PackageSourceOrArtifactSpec `json:"subject,omitempty"` Justification *string `json:"justification,omitempty"` Origin *string `json:"origin,omitempty"` Collector *string `json:"collector,omitempty"` + KnownSince *time.Time `json:"knownSince,omitempty"` } // CertifyGood is an attestation that a package, source, or artifact is considered @@ -153,15 +159,17 @@ type CertifyGood struct { Justification string `json:"justification"` Origin string `json:"origin"` Collector string `json:"collector"` + KnownSince time.Time `json:"knownSince"` } func (CertifyGood) IsNode() {} // CertifyGoodInputSpec represents the mutation input to ingest a CertifyGood evidence. type CertifyGoodInputSpec struct { - Justification string `json:"justification"` - Origin string `json:"origin"` - Collector string `json:"collector"` + Justification string `json:"justification"` + Origin string `json:"origin"` + Collector string `json:"collector"` + KnownSince time.Time `json:"knownSince"` } // CertifyBadSpec allows filtering the list of CertifyBad evidence to return in a @@ -173,12 +181,16 @@ type CertifyGoodInputSpec struct { // // If a source is specified in the subject filter, then it must specify a name, // and optionally a tag and a commit. +// +// If KnownSince is specified, the returned value will be after or equal to the specified time. +// Any nodes time that is before KnownSince is excluded. type CertifyGoodSpec struct { ID *string `json:"id,omitempty"` Subject *PackageSourceOrArtifactSpec `json:"subject,omitempty"` Justification *string `json:"justification,omitempty"` Origin *string `json:"origin,omitempty"` Collector *string `json:"collector,omitempty"` + KnownSince *time.Time `json:"knownSince,omitempty"` } // CertifyLegal is an attestation to attach legal information to a package or source. @@ -435,23 +447,29 @@ type HasSbom struct { Origin string `json:"origin"` // GUAC collector for the document Collector string `json:"collector"` + // Timestamp for SBOM creation + KnownSince time.Time `json:"knownSince"` } func (HasSbom) IsNode() {} // HasSBOMInputSpec is the same as HasSBOM but for mutation input. type HasSBOMInputSpec struct { - URI string `json:"uri"` - Algorithm string `json:"algorithm"` - Digest string `json:"digest"` - DownloadLocation string `json:"downloadLocation"` - Origin string `json:"origin"` - Collector string `json:"collector"` + URI string `json:"uri"` + Algorithm string `json:"algorithm"` + Digest string `json:"digest"` + DownloadLocation string `json:"downloadLocation"` + Origin string `json:"origin"` + Collector string `json:"collector"` + KnownSince time.Time `json:"knownSince"` } // HasSBOMSpec allows filtering the list of HasSBOM to return. // // Only the package or artifact can be added, not both. +// +// If KnownSince is specified, the returned value will be after or equal to the specified time. +// Any nodes time that is before KnownSince is excluded. type HasSBOMSpec struct { ID *string `json:"id,omitempty"` Subject *PackageOrArtifactSpec `json:"subject,omitempty"` @@ -461,6 +479,7 @@ type HasSBOMSpec struct { DownloadLocation *string `json:"downloadLocation,omitempty"` Origin *string `json:"origin,omitempty"` Collector *string `json:"collector,omitempty"` + KnownSince *time.Time `json:"knownSince,omitempty"` } // HasSLSA records that a subject node has a SLSA attestation. diff --git a/pkg/assembler/graphql/resolvers/certifyBad.resolvers.go b/pkg/assembler/graphql/resolvers/certifyBad.resolvers.go index da61dafac5..8945816eb7 100644 --- a/pkg/assembler/graphql/resolvers/certifyBad.resolvers.go +++ b/pkg/assembler/graphql/resolvers/certifyBad.resolvers.go @@ -18,6 +18,9 @@ func (r *mutationResolver) IngestCertifyBad(ctx context.Context, subject model.P if err := helper.ValidatePackageSourceOrArtifactInput(&subject, funcName); err != nil { return "", gqlerror.Errorf("%v :: %s", funcName, err) } + if certifyBad.KnownSince.IsZero() { + return "", gqlerror.Errorf("certifyBad.KnownSince is a zero time") + } ingestedCertifyBad, err := r.Backend.IngestCertifyBad(ctx, subject, &pkgMatchType, certifyBad) if err != nil { return "", err @@ -51,6 +54,13 @@ func (r *mutationResolver) IngestCertifyBads(ctx context.Context, subjects model if valuesDefined != 1 { return ingestedCertifyBadsIDS, gqlerror.Errorf("%v :: must specify at most packages, artifacts or sources", funcName) } + + for _, certifyBad := range certifyBads { + if certifyBad.KnownSince.IsZero() { + return ingestedCertifyBadsIDS, gqlerror.Errorf("certifyBads contains a zero time") + } + } + ingestedCertifyBads, err := r.Backend.IngestCertifyBads(ctx, subjects, &pkgMatchType, certifyBads) if err == nil { for _, certifybad := range ingestedCertifyBads { diff --git a/pkg/assembler/graphql/resolvers/certifyBad.resolvers_test.go b/pkg/assembler/graphql/resolvers/certifyBad.resolvers_test.go index 9aa7ec2579..35dd7792ae 100644 --- a/pkg/assembler/graphql/resolvers/certifyBad.resolvers_test.go +++ b/pkg/assembler/graphql/resolvers/certifyBad.resolvers_test.go @@ -18,6 +18,7 @@ package resolvers_test import ( "context" "testing" + "time" "github.com/golang/mock/gomock" "github.com/guacsec/guac/internal/testing/mocks" @@ -27,6 +28,8 @@ import ( "github.com/guacsec/guac/pkg/assembler/graphql/resolvers" ) +var ZeroTime = time.Unix(0, 0) + func TestIngestCertifyBad(t *testing.T) { type call struct { Sub model.PackageSourceOrArtifactInput @@ -62,6 +65,7 @@ func TestIngestCertifyBad(t *testing.T) { }, CB: &model.CertifyBadInputSpec{ Justification: "test justification", + KnownSince: ZeroTime, }, }, }, @@ -189,6 +193,7 @@ func TestIngestCertifyBads(t *testing.T) { CB: []*model.CertifyBadInputSpec{ { Justification: "test justification", + KnownSince: ZeroTime, }, }, }, diff --git a/pkg/assembler/graphql/resolvers/certifyGood.resolvers.go b/pkg/assembler/graphql/resolvers/certifyGood.resolvers.go index a8b64b9ddd..2a53e37f28 100644 --- a/pkg/assembler/graphql/resolvers/certifyGood.resolvers.go +++ b/pkg/assembler/graphql/resolvers/certifyGood.resolvers.go @@ -18,6 +18,9 @@ func (r *mutationResolver) IngestCertifyGood(ctx context.Context, subject model. if err := helper.ValidatePackageSourceOrArtifactInput(&subject, funcName); err != nil { return "", err } + if certifyGood.KnownSince.IsZero() { + return "", gqlerror.Errorf("certifyGood.KnownSince is a zero time") + } ingestedCertifyGood, err := r.Backend.IngestCertifyGood(ctx, subject, &pkgMatchType, certifyGood) if err != nil { return "", err @@ -51,6 +54,13 @@ func (r *mutationResolver) IngestCertifyGoods(ctx context.Context, subjects mode if valuesDefined != 1 { return ingestedCertifyGoodsIDS, gqlerror.Errorf("%v :: must specify at most packages, artifacts or sources", funcName) } + + for _, certifyGood := range certifyGoods { + if certifyGood.KnownSince.IsZero() { + return ingestedCertifyGoodsIDS, gqlerror.Errorf("certifyGoods contains a zero time") + } + } + ingestedCertifyGoods, err := r.Backend.IngestCertifyGoods(ctx, subjects, &pkgMatchType, certifyGoods) if err == nil { for _, certifyGood := range ingestedCertifyGoods { diff --git a/pkg/assembler/graphql/resolvers/certifyGood.resolvers_test.go b/pkg/assembler/graphql/resolvers/certifyGood.resolvers_test.go index 644c673670..f728853884 100644 --- a/pkg/assembler/graphql/resolvers/certifyGood.resolvers_test.go +++ b/pkg/assembler/graphql/resolvers/certifyGood.resolvers_test.go @@ -62,6 +62,7 @@ func TestIngestCertifyGood(t *testing.T) { }, CG: &model.CertifyGoodInputSpec{ Justification: "test justification", + KnownSince: ZeroTime, }, }, }, @@ -189,6 +190,7 @@ func TestIngestCertifyGoods(t *testing.T) { CG: []*model.CertifyGoodInputSpec{ { Justification: "test justification", + KnownSince: ZeroTime, }, }, }, diff --git a/pkg/assembler/graphql/resolvers/hasSBOM.resolvers.go b/pkg/assembler/graphql/resolvers/hasSBOM.resolvers.go index 222d9196fb..7c8d2f37fc 100644 --- a/pkg/assembler/graphql/resolvers/hasSBOM.resolvers.go +++ b/pkg/assembler/graphql/resolvers/hasSBOM.resolvers.go @@ -18,6 +18,10 @@ func (r *mutationResolver) IngestHasSbom(ctx context.Context, subject model.Pack if err := helper.ValidatePackageOrArtifactInput(&subject, funcName); err != nil { return "", gqlerror.Errorf("%v :: %s", funcName, err) } + if hasSbom.KnownSince.IsZero() { + return "", gqlerror.Errorf("hasSbom.KnownSince is a zero time") + } + ingestedHasSbom, err := r.Backend.IngestHasSbom(ctx, subject, hasSbom) if err != nil { return "", err @@ -46,6 +50,12 @@ func (r *mutationResolver) IngestHasSBOMs(ctx context.Context, subjects model.Pa return ingestedHasSBOMSIDS, gqlerror.Errorf("%v :: must specify at most packages or artifacts for ingestion", funcName) } + for _, hasSbom := range hasSBOMs { + if hasSbom.KnownSince.IsZero() { + return ingestedHasSBOMSIDS, gqlerror.Errorf("hasSBOMS contains a zero time") + } + } + ingestedHasSBOMs, err := r.Backend.IngestHasSBOMs(ctx, subjects, hasSBOMs) if err == nil { for _, hasSBOM := range ingestedHasSBOMs { diff --git a/pkg/assembler/graphql/resolvers/hasSBOM.resolvers_test.go b/pkg/assembler/graphql/resolvers/hasSBOM.resolvers_test.go index cbec603564..a1feed2244 100644 --- a/pkg/assembler/graphql/resolvers/hasSBOM.resolvers_test.go +++ b/pkg/assembler/graphql/resolvers/hasSBOM.resolvers_test.go @@ -60,7 +60,8 @@ func TestIngestHasSbom(t *testing.T) { Package: testdata.P1, }, HS: &model.HasSBOMInputSpec{ - URI: "test uri", + URI: "test uri", + KnownSince: ZeroTime, }, }, }, @@ -147,7 +148,8 @@ func TestIngestHasSBOMs(t *testing.T) { }, HS: []*model.HasSBOMInputSpec{ { - URI: "test uri", + URI: "test uri", + KnownSince: ZeroTime, }, }, }, @@ -163,7 +165,8 @@ func TestIngestHasSBOMs(t *testing.T) { }, HS: []*model.HasSBOMInputSpec{ { - URI: "test uri", + URI: "test uri", + KnownSince: ZeroTime, }, }, }, diff --git a/pkg/assembler/graphql/schema/certifyBad.graphql b/pkg/assembler/graphql/schema/certifyBad.graphql index 91738b367c..4562b36a58 100644 --- a/pkg/assembler/graphql/schema/certifyBad.graphql +++ b/pkg/assembler/graphql/schema/certifyBad.graphql @@ -75,6 +75,7 @@ type CertifyBad { justification: String! origin: String! collector: String! + knownSince: Time! } """ @@ -87,6 +88,9 @@ name and one of version, qualifiers, or subpath. If a source is specified in the subject filter, then it must specify a name, and optionally a tag and a commit. + +If KnownSince is specified, the returned value will be after or equal to the specified time. +Any nodes time that is before KnownSince is excluded. """ input CertifyBadSpec { id: ID @@ -94,6 +98,7 @@ input CertifyBadSpec { justification: String origin: String collector: String + knownSince: Time } """ @@ -104,6 +109,7 @@ input CertifyBadInputSpec { justification: String! origin: String! collector: String! + knownSince: Time! } """ diff --git a/pkg/assembler/graphql/schema/certifyGood.graphql b/pkg/assembler/graphql/schema/certifyGood.graphql index 9427355d78..52e393b671 100644 --- a/pkg/assembler/graphql/schema/certifyGood.graphql +++ b/pkg/assembler/graphql/schema/certifyGood.graphql @@ -36,6 +36,7 @@ type CertifyGood { justification: String! origin: String! collector: String! + knownSince: Time! } """ @@ -48,6 +49,9 @@ name and one of version, qualifiers, or subpath. If a source is specified in the subject filter, then it must specify a name, and optionally a tag and a commit. + +If KnownSince is specified, the returned value will be after or equal to the specified time. +Any nodes time that is before KnownSince is excluded. """ input CertifyGoodSpec { id: ID @@ -55,6 +59,7 @@ input CertifyGoodSpec { justification: String origin: String collector: String + knownSince: Time } """ @@ -64,6 +69,7 @@ input CertifyGoodInputSpec { justification: String! origin: String! collector: String! + knownSince: Time! } extend type Query { diff --git a/pkg/assembler/graphql/schema/hasSBOM.graphql b/pkg/assembler/graphql/schema/hasSBOM.graphql index 757b14192a..5c1525e30d 100644 --- a/pkg/assembler/graphql/schema/hasSBOM.graphql +++ b/pkg/assembler/graphql/schema/hasSBOM.graphql @@ -33,12 +33,17 @@ type HasSBOM { origin: String! "GUAC collector for the document" collector: String! + "Timestamp for SBOM creation" + knownSince: Time! } """ HasSBOMSpec allows filtering the list of HasSBOM to return. Only the package or artifact can be added, not both. + +If KnownSince is specified, the returned value will be after or equal to the specified time. +Any nodes time that is before KnownSince is excluded. """ input HasSBOMSpec { id: ID @@ -49,6 +54,7 @@ input HasSBOMSpec { downloadLocation: String origin: String collector: String + knownSince: Time } "HasSBOMInputSpec is the same as HasSBOM but for mutation input." @@ -59,6 +65,7 @@ input HasSBOMInputSpec { downloadLocation: String! origin: String! collector: String! + knownSince: Time! } extend type Query { diff --git a/pkg/guacanalytics/patchPlanning_test.go b/pkg/guacanalytics/patchPlanning_test.go index 29860a60cf..533225b317 100644 --- a/pkg/guacanalytics/patchPlanning_test.go +++ b/pkg/guacanalytics/patchPlanning_test.go @@ -452,6 +452,7 @@ var ( }, CertifyGood: &model.CertifyGoodInputSpec{ Justification: "good package", + KnownSince: tm, }, }, { @@ -466,6 +467,7 @@ var ( }, CertifyGood: &model.CertifyGoodInputSpec{ Justification: "good package", + KnownSince: tm, }, }, }, diff --git a/pkg/ingestor/parser/common/helpers.go b/pkg/ingestor/parser/common/helpers.go index 0bc366c299..99cd866502 100644 --- a/pkg/ingestor/parser/common/helpers.go +++ b/pkg/ingestor/parser/common/helpers.go @@ -19,6 +19,7 @@ import ( "crypto/sha256" "encoding/hex" "reflect" + "time" "github.com/guacsec/guac/pkg/assembler" model "github.com/guacsec/guac/pkg/assembler/clients/generated" @@ -100,7 +101,7 @@ func CreateTopLevelIsDeps(topLevel *model.PkgInputSpec, packages map[string][]*m return isDeps } -func CreateTopLevelHasSBOM(topLevel *model.PkgInputSpec, sbomDoc *processor.Document) assembler.HasSBOMIngest { +func CreateTopLevelHasSBOM(topLevel *model.PkgInputSpec, sbomDoc *processor.Document, timeStamp time.Time) assembler.HasSBOMIngest { sha256sum := sha256.Sum256(sbomDoc.Blob) hash := hex.EncodeToString(sha256sum[:]) return assembler.HasSBOMIngest{ @@ -110,6 +111,7 @@ func CreateTopLevelHasSBOM(topLevel *model.PkgInputSpec, sbomDoc *processor.Docu Algorithm: "sha256", Digest: hash, DownloadLocation: sbomDoc.SourceInformation.Source, + KnownSince: timeStamp, }, } } diff --git a/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go b/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go index 5dc2b65ec6..346b5113d6 100644 --- a/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go +++ b/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go @@ -21,6 +21,7 @@ import ( "fmt" "reflect" "strings" + "time" jsoniter "github.com/json-iterator/go" @@ -37,6 +38,8 @@ var json = jsoniter.ConfigCompatibleWithStandardLibrary const topCdxPurlGuac string = "pkg:guac/cdx/" +var zeroTime = time.Unix(0, 0) + type cyclonedxParser struct { doc *processor.Document packagePackages map[string][]*model.PkgInputSpec @@ -214,8 +217,21 @@ func (c *cyclonedxParser) GetPredicates(ctx context.Context) *assembler.IngestPr // TODO: This is not based on the relationship so that can be inaccurate (can capture both direct and in-direct)...Remove this and be done below by the *c.cdxBom.Dependencies? // see https://github.com/CycloneDX/specification/issues/33 if toplevel != nil { + var timestamp time.Time + var err error + if c.cdxBom.Metadata.Timestamp == "" { + // set the time to zero time if timestamp is not provided + timestamp = zeroTime + } else { + timestamp, err = time.Parse(time.RFC3339, c.cdxBom.Metadata.Timestamp) + if err != nil { + logger.Errorf("SPDX document had invalid created time %q : %v", c.cdxBom.Metadata.Timestamp, err) + return nil + } + } + preds.IsDependency = append(preds.IsDependency, common.CreateTopLevelIsDeps(toplevel[0], c.packagePackages, nil, "top-level package GUAC heuristic connecting to each file/package")...) - preds.HasSBOM = append(preds.HasSBOM, common.CreateTopLevelHasSBOM(toplevel[0], c.doc)) + preds.HasSBOM = append(preds.HasSBOM, common.CreateTopLevelHasSBOM(toplevel[0], c.doc, timestamp)) } for id := range c.packagePackages { diff --git a/pkg/ingestor/parser/spdx/parse_spdx.go b/pkg/ingestor/parser/spdx/parse_spdx.go index c6dd87cb6b..a7479d7b08 100644 --- a/pkg/ingestor/parser/spdx/parse_spdx.go +++ b/pkg/ingestor/parser/spdx/parse_spdx.go @@ -243,8 +243,13 @@ func (s *spdxParser) GetPredicates(ctx context.Context) *assembler.IngestPredica return preds } else { // adding top level package edge manually for all depends on package + timestamp, err := time.Parse(time.RFC3339, s.spdxDoc.CreationInfo.Created) + if err != nil { + logger.Errorf("SPDX document had invalid created time %q : %w", s.spdxDoc.CreationInfo.Created, err) + return nil + } for _, topLevelPkg := range topLevel { - preds.HasSBOM = append(preds.HasSBOM, common.CreateTopLevelHasSBOM(topLevelPkg, s.doc)) + preds.HasSBOM = append(preds.HasSBOM, common.CreateTopLevelHasSBOM(topLevelPkg, s.doc, timestamp)) } if s.topLevelIsHeuristic {