diff --git a/pkg/assembler/assembler.go b/pkg/assembler/assembler.go index c20b7a215c..3a1bd63d72 100644 --- a/pkg/assembler/assembler.go +++ b/pkg/assembler/assembler.go @@ -29,6 +29,7 @@ type assembler struct{} //nolint: unused // ingested based on the GUAC ontology. It only has evidence trees as // ingestion of the software trees are implicit and handled by the // client library. +// TODO: fix typo in isDepedency type IngestPredicates struct { CertifyScorecard []CertifyScorecardIngest `json:"certifyScorecard,omitempty"` IsDependency []IsDependencyIngest `json:"isDepedency,omitempty"` @@ -43,6 +44,7 @@ type IngestPredicates struct { HashEqual []HashEqualIngest `json:"hashEqual,omitempty"` PkgEqual []PkgEqualIngest `json:"pkgEqual,omitempty"` Vex []VexIngest `json:"vex,omitempty"` + PointOfContact []PointOfContactIngest `json:"contact,omitempty"` } type CertifyScorecardIngest struct { @@ -146,6 +148,15 @@ type VexIngest struct { VexData *generated.VexStatementInputSpec `json:"vexData,omitempty"` } +type PointOfContactIngest struct { + // pointOfContact describes either pkg, src or artifact + Pkg *generated.PkgInputSpec `json:"pkg,omitempty"` + PkgMatchFlag generated.MatchFlags `json:"pkgMatchFlag,omitempty"` + Src *generated.SourceInputSpec `json:"src,omitempty"` + Artifact *generated.ArtifactInputSpec `json:"artifact,omitempty"` + PointOfContact *generated.PointOfContactInputSpec `json:"pointOfContact,omitempty"` +} + type HashEqualIngest struct { // HashEqualIngest describes two artifacts are the same Artifact *generated.ArtifactInputSpec `json:"artifact,omitempty"` @@ -233,6 +244,14 @@ func (i IngestPredicates) GetPackages(ctx context.Context) []*generated.PkgInput } } } + for _, poc := range i.PointOfContact { + if poc.Pkg != nil { + pkgPurl := helpers.PkgInputSpecToPurl(poc.Pkg) + if _, ok := packageMap[pkgPurl]; !ok { + packageMap[pkgPurl] = poc.Pkg + } + } + } for _, equal := range i.PkgEqual { if equal.Pkg != nil { pkgPurl := helpers.PkgInputSpecToPurl(equal.Pkg) @@ -297,6 +316,14 @@ func (i IngestPredicates) GetSources(ctx context.Context) []*generated.SourceInp } } } + for _, poc := range i.PointOfContact { + if poc.Src != nil { + sourceString := concatenateSourceInput(poc.Src) + if _, ok := sourceMap[sourceString]; !ok { + sourceMap[sourceString] = poc.Src + } + } + } sources := make([]*generated.SourceInputSpec, 0, len(sourceMap)) for _, source := range sourceMap { @@ -355,6 +382,14 @@ func (i IngestPredicates) GetArtifacts(ctx context.Context) []*generated.Artifac } } } + for _, poc := range i.PointOfContact { + if poc.Artifact != nil { + artifactString := poc.Artifact.Algorithm + ":" + poc.Artifact.Digest + if _, ok := artifactMap[artifactString]; !ok { + artifactMap[artifactString] = poc.Artifact + } + } + } for _, equal := range i.HashEqual { if equal.Artifact != nil { artifactString := equal.Artifact.Algorithm + ":" + equal.Artifact.Digest diff --git a/pkg/assembler/clients/helpers/assembler.go b/pkg/assembler/clients/helpers/assembler.go index 3621d45691..5e1072cc23 100644 --- a/pkg/assembler/clients/helpers/assembler.go +++ b/pkg/assembler/clients/helpers/assembler.go @@ -155,6 +155,13 @@ func GetAssembler(ctx context.Context, gqlclient graphql.Client) func([]assemble } } + logger.Infof("assembling PointOfContact: %v", len(p.PointOfContact)) + for _, poc := range p.PointOfContact { + if err := ingestPointOfContact(ctx, gqlclient, poc); err != nil { + return err + } + } + logger.Infof("assembling HasSBOM: %v", len(p.HasSBOM)) for _, hb := range p.HasSBOM { if err := ingestHasSBOM(ctx, gqlclient, hb); err != nil { @@ -319,7 +326,7 @@ func ingestCertifyBad(ctx context.Context, client graphql.Client, bad assembler. func ingestCertifyGood(ctx context.Context, client graphql.Client, good assembler.CertifyGoodIngest) error { if err := validatePackageSourceOrArtifactInput(good.Pkg, good.Src, good.Artifact, "certifyGood"); err != nil { - return fmt.Errorf("input validation failed for certifyBad: %w", err) + return fmt.Errorf("input validation failed for certifyGood: %w", err) } if good.Pkg != nil { @@ -334,6 +341,23 @@ func ingestCertifyGood(ctx context.Context, client graphql.Client, good assemble return err } +func ingestPointOfContact(ctx context.Context, client graphql.Client, poc assembler.PointOfContactIngest) error { + if err := validatePackageSourceOrArtifactInput(poc.Pkg, poc.Src, poc.Artifact, "pointOfContact"); err != nil { + return fmt.Errorf("input validation failed for pointOfContact: %w", err) + } + + if poc.Pkg != nil { + _, err := model.PointOfContactPkg(ctx, client, *poc.Pkg, &poc.PkgMatchFlag, *poc.PointOfContact) + return err + } + if poc.Src != nil { + _, err := model.PointOfContactSrc(ctx, client, *poc.Src, *poc.PointOfContact) + return err + } + _, err := model.PointOfContactArtifact(ctx, client, *poc.Artifact, *poc.PointOfContact) + return err +} + func ingestHasSBOM(ctx context.Context, client graphql.Client, hb assembler.HasSBOMIngest) error { if hb.Pkg != nil && hb.Artifact != nil { return fmt.Errorf("unable to create hasSBOM with both Pkg and Src subject specified") diff --git a/pkg/assembler/clients/helpers/bulk.go b/pkg/assembler/clients/helpers/bulk.go index eb3a485db2..37b99648a7 100644 --- a/pkg/assembler/clients/helpers/bulk.go +++ b/pkg/assembler/clients/helpers/bulk.go @@ -183,6 +183,15 @@ func GetBulkAssembler(ctx context.Context, gqlclient graphql.Client) func([]asse } } + // TODO: add bulk ingestion for PointOfContact + logger.Infof("assembling PointOfContact: %v", len(p.CertifyGood)) + for _, poc := range p.PointOfContact { + if err := ingestPointOfContact(ctx, gqlclient, poc); err != nil { + return fmt.Errorf("ingestPointOfContact failed with error: %w", err) + + } + } + // TODO(pxp928): add bulk ingestion for HasSBOM logger.Infof("assembling HasSBOM: %v", len(p.HasSBOM)) for _, hb := range p.HasSBOM { diff --git a/pkg/assembler/clients/helpers/parallel.go b/pkg/assembler/clients/helpers/parallel.go index 2cc2218c60..1868035fc4 100644 --- a/pkg/assembler/clients/helpers/parallel.go +++ b/pkg/assembler/clients/helpers/parallel.go @@ -206,6 +206,15 @@ func GetParallelAssembler(ctx context.Context, gqlclient graphql.Client) func([] verbs.Go(func() error { return ingestCertifyGood(errGroupVerbCtx, gqlclient, good) }) } + logger.Infof("assembling PointOfContact: %v", len(p.PointOfContact)) + for _, poc := range p.PointOfContact { + if errGroupVerbCtx.Err() != nil { + break + } + poc := poc + verbs.Go(func() error { return ingestPointOfContact(errGroupVerbCtx, gqlclient, poc) }) + } + logger.Infof("assembling HasSBOM: %v", len(p.HasSBOM)) for _, hb := range p.HasSBOM { if errGroupVerbCtx.Err() != nil {