From 8d63acb85f81aaa4f5023bab2772e7bca0fe10d7 Mon Sep 17 00:00:00 2001 From: Steve Menezes Date: Wed, 23 Aug 2023 15:35:39 -0700 Subject: [PATCH 01/11] cdx-vex parser init Signed-off-by: stevemenezes --- pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go | 207 ++++++++++++++++++ .../parser/cdx_vex/parser_cdx_vex_test.go | 1 + pkg/ingestor/parser/parser.go | 3 + 3 files changed, 211 insertions(+) create mode 100644 pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go create mode 100644 pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go new file mode 100644 index 0000000000..2aea28b818 --- /dev/null +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go @@ -0,0 +1,207 @@ +// +// Copyright 2022 The GUAC Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cdx_vex + +import ( + "context" + "encoding/json" + "fmt" + "time" + + cdx "github.com/CycloneDX/cyclonedx-go" + "github.com/guacsec/guac/pkg/assembler" + "github.com/guacsec/guac/pkg/assembler/clients/generated" + "github.com/guacsec/guac/pkg/assembler/helpers" + "github.com/guacsec/guac/pkg/handler/processor" + "github.com/guacsec/guac/pkg/ingestor/parser/common" + "github.com/guacsec/guac/pkg/logging" + "strings" +) + +var vexStatusMap = map[cdx.ImpactAnalysisState]generated.VexStatus{ + "resolved": generated.VexStatusFixed, + "exploitable": generated.VexStatusAffected, + "in_triage": generated.VexStatusUnderInvestigation, + "not_affected": generated.VexStatusNotAffected, +} + +var justificationsMap = map[cdx.ImpactAnalysisJustification]generated.VexJustification{ + "code_not_present": generated.VexJustificationVulnerableCodeNotPresent, + "code_not_reachable": generated.VexJustificationVulnerableCodeNotInExecutePath, +} + +type cdxVexParser struct { + doc *processor.Document + identifierStrings *common.IdentifierStrings + cdxBom *cdx.BOM +} + +func NewCdxVexParser() common.DocumentParser { + return &cdxVexParser{ + identifierStrings: &common.IdentifierStrings{}, + } +} + +// Parse breaks out the document into the graph components +func (c *cdxVexParser) Parse(ctx context.Context, doc *processor.Document) error { + c.doc = doc + err := json.Unmarshal(doc.Blob, &c.cdxBom) + if err != nil { + return fmt.Errorf("unable to unmarshal CDX VEX document: %w", err) + } + + return nil +} + +// GetIdentities gets the identity node from the document if they exist +func (c *cdxVexParser) GetIdentities(ctx context.Context) []common.TrustInformation { + return nil +} + +func (c *cdxVexParser) GetIdentifiers(ctx context.Context) (*common.IdentifierStrings, error) { + return nil, fmt.Errorf("not yet implemented") +} + +func generateVexIngest(ctx context.Context) *assembler.VexIngest { + return nil +} + +// Get package name and range versions to create package input spec for the affected packages. +func getAffectedPackages(ctx context.Context, vulnInput *generated.VulnerabilityInputSpec, vexData generated.VexStatementInputSpec, affectsObj cdx.Affects) *[]assembler.VexIngest { + logger := logging.FromContext(ctx) + var pkgRef string + // TODO: retrieve purl from metadata if present - https://github.com/guacsec/guac/blob/main/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go#L76 + if affectsObj.Ref != "" { + pkgRef = affectsObj.Ref + } else { + logger.Warnf("[cdx vex] package reference not found") + return nil + } + + // split ref using # as delimiter. + pkgRefInfo := strings.Split(pkgRef, "#") + if len(pkgRefInfo) != 2 { + logger.Warnf("[cdx vex] malformed package reference: %q", affectsObj.Ref) + return nil + } + pkgURL := pkgRefInfo[1] + + // multiple package versions do not exist, resolve to using ref directly. + if affectsObj.Range == nil { + pkg, err := helpers.PurlToPkg(pkgURL) + if err != nil { + logger.Warnf("[cdx vex] unable to create package input spec: %v", err) + return nil + } + + return &[]assembler.VexIngest{{VexData: &vexData, Vulnerability: vulnInput, Pkg: pkg}} + } + + // split pkgURL using @ as delimiter. + pkgURLInfo := strings.Split(pkgURL, "@") + if len(pkgURLInfo) != 2 { + logger.Warnf("[cdx vex] malformed package url info: %q", pkgURL) + return nil + } + + pkgName := pkgURLInfo[0] + var viList []assembler.VexIngest + for _, affect := range *affectsObj.Range { + // TODO: Handle package range versions (see - https://github.com/CycloneDX/bom-examples/blob/master/VEX/CISA-Use-Cases/Case-8/vex.json#L42) + if affect.Version == "" { + continue + } + vi := &assembler.VexIngest{ + VexData: &vexData, + Vulnerability: vulnInput, + } + + pkg, err := helpers.PurlToPkg(fmt.Sprintf("%s@%s", pkgName, affect.Version)) + if err != nil { + logger.Warnf("[cdx vex] unable to create package input spec from purl: %v", err) + return nil + } + vi.Pkg = pkg + viList = append(viList, *vi) + } + + return &viList +} + +func (c *cdxVexParser) GetPredicates(ctx context.Context) *assembler.IngestPredicates { + layout := "2006-01-02T15:04:05.000Z" + pred := &assembler.IngestPredicates{} + + var vex []assembler.VexIngest + var certifyVuln []assembler.CertifyVulnIngest + var status generated.VexStatus + var justification generated.VexJustification + var publishedTime time.Time + + for _, vulnerability := range *c.cdxBom.Vulnerabilities { + vuln, err := helpers.CreateVulnInput(vulnerability.ID) + if err != nil { + return nil + } + + if vexStatus, ok := vexStatusMap[vulnerability.Analysis.State]; ok { + status = vexStatus + } + + if vexJustification, ok := justificationsMap[vulnerability.Analysis.Justification]; ok { + justification = vexJustification + } + + time, err := time.Parse(layout, vulnerability.Published) + if err == nil { + publishedTime = time + } + + vd := generated.VexStatementInputSpec{ + // is origin the same as vulnerability.ID? + Origin: vulnerability.ID, + Status: status, + VexJustification: justification, + KnownSince: publishedTime, + Statement: vulnerability.Analysis.Detail, + } + + for _, affect := range *vulnerability.Affects { + vi := getAffectedPackages(ctx, vuln, vd, affect) + if vi == nil { + continue + } + vex = append(vex, *vi...) + + for _, v := range *vi { + if status == generated.VexStatusAffected || status == generated.VexStatusUnderInvestigation { + cv := assembler.CertifyVulnIngest{ + Vulnerability: vuln, + VulnData: &generated.ScanMetadataInput{ + TimeScanned: publishedTime, + }, + Pkg: v.Pkg, + } + certifyVuln = append(certifyVuln, cv) + } + } + } + } + + pred.Vex = vex + pred.CertifyVuln = certifyVuln + return pred +} diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go new file mode 100644 index 0000000000..b637ef685e --- /dev/null +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go @@ -0,0 +1 @@ +package cdx_vex diff --git a/pkg/ingestor/parser/parser.go b/pkg/ingestor/parser/parser.go index 0641276e2b..5f3c2c743e 100644 --- a/pkg/ingestor/parser/parser.go +++ b/pkg/ingestor/parser/parser.go @@ -21,9 +21,11 @@ import ( "fmt" uuid "github.com/gofrs/uuid" + "github.com/guacsec/guac/pkg/assembler" "github.com/guacsec/guac/pkg/emitter" "github.com/guacsec/guac/pkg/handler/processor" + cdxVex "github.com/guacsec/guac/pkg/ingestor/parser/cdx_vex" "github.com/guacsec/guac/pkg/ingestor/parser/common" "github.com/guacsec/guac/pkg/ingestor/parser/csaf" "github.com/guacsec/guac/pkg/ingestor/parser/cyclonedx" @@ -45,6 +47,7 @@ func init() { _ = RegisterDocumentParser(scorecard.NewScorecardParser, processor.DocumentScorecard) _ = RegisterDocumentParser(deps_dev.NewDepsDevParser, processor.DocumentDepsDev) _ = RegisterDocumentParser(csaf.NewCsafParser, processor.DocumentCsaf) + _ = RegisterDocumentParser(cdxVex.NewCdxVexParser, processor.DocumentCycloneDX) } var ( From 44e8cf4f2d957326fefb15f45d93f5e5665b5bbd Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Fri, 25 Aug 2023 12:36:19 -0700 Subject: [PATCH 02/11] adds guesser and processor for cdx-vex along with vuln metadata Signed-off-by: stevemenezes --- pkg/assembler/clients/generated/operations.go | 29 +++++++---- .../graphql/generated/root_.generated.go | 13 +++++ pkg/assembler/graphql/model/nodes.go | 48 ++++++++++++++----- .../schema/certifyVEXStatement.graphql | 9 ++++ .../graphql/schema/vulnMetadata.graphql | 4 ++ pkg/handler/processor/cdx_vex/cdx_vex.go | 40 ++++++++++++++++ pkg/handler/processor/guesser/type_cdx_vex.go | 23 +++++++++ .../processor/guesser/type_cyclonedx.go | 3 ++ pkg/handler/processor/guesser/type_guesser.go | 1 + pkg/handler/processor/process/process.go | 2 + pkg/handler/processor/processor.go | 1 + pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go | 42 +++++++++++----- pkg/ingestor/parser/common/graph_builder.go | 10 ++++ pkg/ingestor/parser/parser.go | 2 +- 14 files changed, 195 insertions(+), 32 deletions(-) create mode 100644 pkg/handler/processor/cdx_vex/cdx_vex.go create mode 100644 pkg/handler/processor/guesser/type_cdx_vex.go diff --git a/pkg/assembler/clients/generated/operations.go b/pkg/assembler/clients/generated/operations.go index 782c2152f5..5d247c0e7e 100644 --- a/pkg/assembler/clients/generated/operations.go +++ b/pkg/assembler/clients/generated/operations.go @@ -22845,6 +22845,13 @@ const ( VexJustificationVulnerableCodeCannotBeControlledByAdversary VexJustification = "VULNERABLE_CODE_CANNOT_BE_CONTROLLED_BY_ADVERSARY" VexJustificationInlineMitigationsAlreadyExist VexJustification = "INLINE_MITIGATIONS_ALREADY_EXIST" VexJustificationNotProvided VexJustification = "NOT_PROVIDED" + VexJustificationRequiresConfiguration VexJustification = "REQUIRES_CONFIGURATION" + VexJustificationRequiresDependency VexJustification = "REQUIRES_DEPENDENCY" + VexJustificationRequiresEnvironment VexJustification = "REQUIRES_ENVIRONMENT" + VexJustificationProtectedByCompiler VexJustification = "PROTECTED_BY_COMPILER" + VexJustificationProtectedAtRuntime VexJustification = "PROTECTED_AT_RUNTIME" + VexJustificationProtectedAtPerimeter VexJustification = "PROTECTED_AT_PERIMETER" + VexJustificationProtectedByMitigatingControl VexJustification = "PROTECTED_BY_MITIGATING_CONTROL" ) // VexStatementInputSpec represents the input to ingest VEX statements. @@ -22883,10 +22890,12 @@ func (v *VexStatementInputSpec) GetCollector() string { return v.Collector } type VexStatus string const ( - VexStatusNotAffected VexStatus = "NOT_AFFECTED" - VexStatusAffected VexStatus = "AFFECTED" - VexStatusFixed VexStatus = "FIXED" - VexStatusUnderInvestigation VexStatus = "UNDER_INVESTIGATION" + VexStatusNotAffected VexStatus = "NOT_AFFECTED" + VexStatusAffected VexStatus = "AFFECTED" + VexStatusFixed VexStatus = "FIXED" + VexStatusUnderInvestigation VexStatus = "UNDER_INVESTIGATION" + VexStatusResolvedWithPedigree VexStatus = "RESOLVED_WITH_PEDIGREE" + VexStatusFalsePositive VexStatus = "FALSE_POSITIVE" ) // VulnEqualIngestVulnEqual includes the requested fields of the GraphQL type VulnEqual. @@ -23366,10 +23375,14 @@ func (v *VulnerabilityMetadataInputSpec) GetCollector() string { return v.Collec type VulnerabilityScoreType string const ( - VulnerabilityScoreTypeCvssv2 VulnerabilityScoreType = "CVSSv2" - VulnerabilityScoreTypeCvssv3 VulnerabilityScoreType = "CVSSv3" - VulnerabilityScoreTypeEpssv1 VulnerabilityScoreType = "EPSSv1" - VulnerabilityScoreTypeEpssv2 VulnerabilityScoreType = "EPSSv2" + VulnerabilityScoreTypeCvssv2 VulnerabilityScoreType = "CVSSv2" + VulnerabilityScoreTypeCvssv3 VulnerabilityScoreType = "CVSSv3" + VulnerabilityScoreTypeEpssv1 VulnerabilityScoreType = "EPSSv1" + VulnerabilityScoreTypeEpssv2 VulnerabilityScoreType = "EPSSv2" + VulnerabilityScoreTypeCvssv31 VulnerabilityScoreType = "CVSSv31" + VulnerabilityScoreTypeCvssv4 VulnerabilityScoreType = "CVSSv4" + VulnerabilityScoreTypeOwasp VulnerabilityScoreType = "OWASP" + VulnerabilityScoreTypeSsvc VulnerabilityScoreType = "SSVC" ) // VulnerabilitySpec allows filtering the list of vulnerabilities to return in a query. diff --git a/pkg/assembler/graphql/generated/root_.generated.go b/pkg/assembler/graphql/generated/root_.generated.go index ab24454976..c0af2c8a2e 100644 --- a/pkg/assembler/graphql/generated/root_.generated.go +++ b/pkg/assembler/graphql/generated/root_.generated.go @@ -2926,6 +2926,8 @@ enum VexStatus { AFFECTED FIXED UNDER_INVESTIGATION + RESOLVED_WITH_PEDIGREE + FALSE_POSITIVE } "Records the justification included in the VEX statement." @@ -2936,6 +2938,13 @@ enum VexJustification { VULNERABLE_CODE_CANNOT_BE_CONTROLLED_BY_ADVERSARY INLINE_MITIGATIONS_ALREADY_EXIST NOT_PROVIDED + REQUIRES_CONFIGURATION + REQUIRES_DEPENDENCY + REQUIRES_ENVIRONMENT + PROTECTED_BY_COMPILER + PROTECTED_AT_RUNTIME + PROTECTED_AT_PERIMETER + PROTECTED_BY_MITIGATING_CONTROL } """ @@ -4507,6 +4516,10 @@ enum VulnerabilityScoreType { CVSSv3 EPSSv1 EPSSv2 + CVSSv31 + CVSSv4 + OWASP + SSVC } "The Comparator is used by the vulnerability score filter on ranges" diff --git a/pkg/assembler/graphql/model/nodes.go b/pkg/assembler/graphql/model/nodes.go index c6b6be8e3d..abe57f0698 100644 --- a/pkg/assembler/graphql/model/nodes.go +++ b/pkg/assembler/graphql/model/nodes.go @@ -1672,6 +1672,13 @@ const ( VexJustificationVulnerableCodeCannotBeControlledByAdversary VexJustification = "VULNERABLE_CODE_CANNOT_BE_CONTROLLED_BY_ADVERSARY" VexJustificationInlineMitigationsAlreadyExist VexJustification = "INLINE_MITIGATIONS_ALREADY_EXIST" VexJustificationNotProvided VexJustification = "NOT_PROVIDED" + VexJustificationRequiresConfiguration VexJustification = "REQUIRES_CONFIGURATION" + VexJustificationRequiresDependency VexJustification = "REQUIRES_DEPENDENCY" + VexJustificationRequiresEnvironment VexJustification = "REQUIRES_ENVIRONMENT" + VexJustificationProtectedByCompiler VexJustification = "PROTECTED_BY_COMPILER" + VexJustificationProtectedAtRuntime VexJustification = "PROTECTED_AT_RUNTIME" + VexJustificationProtectedAtPerimeter VexJustification = "PROTECTED_AT_PERIMETER" + VexJustificationProtectedByMitigatingControl VexJustification = "PROTECTED_BY_MITIGATING_CONTROL" ) var AllVexJustification = []VexJustification{ @@ -1681,11 +1688,18 @@ var AllVexJustification = []VexJustification{ VexJustificationVulnerableCodeCannotBeControlledByAdversary, VexJustificationInlineMitigationsAlreadyExist, VexJustificationNotProvided, + VexJustificationRequiresConfiguration, + VexJustificationRequiresDependency, + VexJustificationRequiresEnvironment, + VexJustificationProtectedByCompiler, + VexJustificationProtectedAtRuntime, + VexJustificationProtectedAtPerimeter, + VexJustificationProtectedByMitigatingControl, } func (e VexJustification) IsValid() bool { switch e { - case VexJustificationComponentNotPresent, VexJustificationVulnerableCodeNotPresent, VexJustificationVulnerableCodeNotInExecutePath, VexJustificationVulnerableCodeCannotBeControlledByAdversary, VexJustificationInlineMitigationsAlreadyExist, VexJustificationNotProvided: + case VexJustificationComponentNotPresent, VexJustificationVulnerableCodeNotPresent, VexJustificationVulnerableCodeNotInExecutePath, VexJustificationVulnerableCodeCannotBeControlledByAdversary, VexJustificationInlineMitigationsAlreadyExist, VexJustificationNotProvided, VexJustificationRequiresConfiguration, VexJustificationRequiresDependency, VexJustificationRequiresEnvironment, VexJustificationProtectedByCompiler, VexJustificationProtectedAtRuntime, VexJustificationProtectedAtPerimeter, VexJustificationProtectedByMitigatingControl: return true } return false @@ -1716,10 +1730,12 @@ func (e VexJustification) MarshalGQL(w io.Writer) { type VexStatus string const ( - VexStatusNotAffected VexStatus = "NOT_AFFECTED" - VexStatusAffected VexStatus = "AFFECTED" - VexStatusFixed VexStatus = "FIXED" - VexStatusUnderInvestigation VexStatus = "UNDER_INVESTIGATION" + VexStatusNotAffected VexStatus = "NOT_AFFECTED" + VexStatusAffected VexStatus = "AFFECTED" + VexStatusFixed VexStatus = "FIXED" + VexStatusUnderInvestigation VexStatus = "UNDER_INVESTIGATION" + VexStatusResolvedWithPedigree VexStatus = "RESOLVED_WITH_PEDIGREE" + VexStatusFalsePositive VexStatus = "FALSE_POSITIVE" ) var AllVexStatus = []VexStatus{ @@ -1727,11 +1743,13 @@ var AllVexStatus = []VexStatus{ VexStatusAffected, VexStatusFixed, VexStatusUnderInvestigation, + VexStatusResolvedWithPedigree, + VexStatusFalsePositive, } func (e VexStatus) IsValid() bool { switch e { - case VexStatusNotAffected, VexStatusAffected, VexStatusFixed, VexStatusUnderInvestigation: + case VexStatusNotAffected, VexStatusAffected, VexStatusFixed, VexStatusUnderInvestigation, VexStatusResolvedWithPedigree, VexStatusFalsePositive: return true } return false @@ -1762,10 +1780,14 @@ func (e VexStatus) MarshalGQL(w io.Writer) { type VulnerabilityScoreType string const ( - VulnerabilityScoreTypeCVSSv2 VulnerabilityScoreType = "CVSSv2" - VulnerabilityScoreTypeCVSSv3 VulnerabilityScoreType = "CVSSv3" - VulnerabilityScoreTypeEPSSv1 VulnerabilityScoreType = "EPSSv1" - VulnerabilityScoreTypeEPSSv2 VulnerabilityScoreType = "EPSSv2" + VulnerabilityScoreTypeCVSSv2 VulnerabilityScoreType = "CVSSv2" + VulnerabilityScoreTypeCVSSv3 VulnerabilityScoreType = "CVSSv3" + VulnerabilityScoreTypeEPSSv1 VulnerabilityScoreType = "EPSSv1" + VulnerabilityScoreTypeEPSSv2 VulnerabilityScoreType = "EPSSv2" + VulnerabilityScoreTypeCVSSv31 VulnerabilityScoreType = "CVSSv31" + VulnerabilityScoreTypeCVSSv4 VulnerabilityScoreType = "CVSSv4" + VulnerabilityScoreTypeOwasp VulnerabilityScoreType = "OWASP" + VulnerabilityScoreTypeSsvc VulnerabilityScoreType = "SSVC" ) var AllVulnerabilityScoreType = []VulnerabilityScoreType{ @@ -1773,11 +1795,15 @@ var AllVulnerabilityScoreType = []VulnerabilityScoreType{ VulnerabilityScoreTypeCVSSv3, VulnerabilityScoreTypeEPSSv1, VulnerabilityScoreTypeEPSSv2, + VulnerabilityScoreTypeCVSSv31, + VulnerabilityScoreTypeCVSSv4, + VulnerabilityScoreTypeOwasp, + VulnerabilityScoreTypeSsvc, } func (e VulnerabilityScoreType) IsValid() bool { switch e { - case VulnerabilityScoreTypeCVSSv2, VulnerabilityScoreTypeCVSSv3, VulnerabilityScoreTypeEPSSv1, VulnerabilityScoreTypeEPSSv2: + case VulnerabilityScoreTypeCVSSv2, VulnerabilityScoreTypeCVSSv3, VulnerabilityScoreTypeEPSSv1, VulnerabilityScoreTypeEPSSv2, VulnerabilityScoreTypeCVSSv31, VulnerabilityScoreTypeCVSSv4, VulnerabilityScoreTypeOwasp, VulnerabilityScoreTypeSsvc: return true } return false diff --git a/pkg/assembler/graphql/schema/certifyVEXStatement.graphql b/pkg/assembler/graphql/schema/certifyVEXStatement.graphql index 3e34fd9432..f0e734ef71 100644 --- a/pkg/assembler/graphql/schema/certifyVEXStatement.graphql +++ b/pkg/assembler/graphql/schema/certifyVEXStatement.graphql @@ -57,6 +57,8 @@ enum VexStatus { AFFECTED FIXED UNDER_INVESTIGATION + RESOLVED_WITH_PEDIGREE + FALSE_POSITIVE } "Records the justification included in the VEX statement." @@ -67,6 +69,13 @@ enum VexJustification { VULNERABLE_CODE_CANNOT_BE_CONTROLLED_BY_ADVERSARY INLINE_MITIGATIONS_ALREADY_EXIST NOT_PROVIDED + REQUIRES_CONFIGURATION + REQUIRES_DEPENDENCY + REQUIRES_ENVIRONMENT + PROTECTED_BY_COMPILER + PROTECTED_AT_RUNTIME + PROTECTED_AT_PERIMETER + PROTECTED_BY_MITIGATING_CONTROL } """ diff --git a/pkg/assembler/graphql/schema/vulnMetadata.graphql b/pkg/assembler/graphql/schema/vulnMetadata.graphql index 9a659e2c41..05a963a5c4 100644 --- a/pkg/assembler/graphql/schema/vulnMetadata.graphql +++ b/pkg/assembler/graphql/schema/vulnMetadata.graphql @@ -23,6 +23,10 @@ enum VulnerabilityScoreType { CVSSv3 EPSSv1 EPSSv2 + CVSSv31 + CVSSv4 + OWASP + SSVC } "The Comparator is used by the vulnerability score filter on ranges" diff --git a/pkg/handler/processor/cdx_vex/cdx_vex.go b/pkg/handler/processor/cdx_vex/cdx_vex.go new file mode 100644 index 0000000000..6d68a7091a --- /dev/null +++ b/pkg/handler/processor/cdx_vex/cdx_vex.go @@ -0,0 +1,40 @@ +package cdx_vex + +import ( + "encoding/json" + "fmt" + + cdx "github.com/CycloneDX/cyclonedx-go" + + "github.com/guacsec/guac/pkg/handler/processor" +) + +type CdxVexProcessor struct{} + +func (p *CdxVexProcessor) ValidateSchema(d *processor.Document) error { + if d.Type != processor.DocumentCdxVex { + return fmt.Errorf("expected document type: %v, actual document type: %v", processor.DocumentCdxVex, d.Type) + } + + switch d.Format { + case processor.FormatJSON: + var decoded cdx.BOM + err := json.Unmarshal(d.Blob, &decoded) + if err == nil && decoded.Vulnerabilities != nil { + return nil + } + return err + } + + return fmt.Errorf("unable to support parsing of CSAF document format: %v", d.Format) + + return nil +} + +func (p *CdxVexProcessor) Unpack(d *processor.Document) ([]*processor.Document, error) { + if d.Type != processor.DocumentCdxVex { + return nil, fmt.Errorf("expected document type: %v, actual document type: %v", processor.DocumentCsaf, d.Type) + } + + return []*processor.Document{}, nil +} diff --git a/pkg/handler/processor/guesser/type_cdx_vex.go b/pkg/handler/processor/guesser/type_cdx_vex.go new file mode 100644 index 0000000000..977ee0802c --- /dev/null +++ b/pkg/handler/processor/guesser/type_cdx_vex.go @@ -0,0 +1,23 @@ +package guesser + +import ( + "encoding/json" + + cdx "github.com/CycloneDX/cyclonedx-go" + "github.com/guacsec/guac/pkg/handler/processor" +) + +type cdxVexTypeGuesser struct{} + +func (_ *cdxVexTypeGuesser) GuessDocumentType(blob []byte, format processor.FormatType) processor.DocumentType { + switch format { + case processor.FormatJSON: + // Decode the BOM + var decoded cdx.BOM + err := json.Unmarshal(blob, &decoded) + if err == nil && decoded.Vulnerabilities != nil { + return processor.DocumentCdxVex + } + } + return processor.DocumentUnknown +} diff --git a/pkg/handler/processor/guesser/type_cyclonedx.go b/pkg/handler/processor/guesser/type_cyclonedx.go index 9c1dd94e35..f50b65f4dc 100644 --- a/pkg/handler/processor/guesser/type_cyclonedx.go +++ b/pkg/handler/processor/guesser/type_cyclonedx.go @@ -37,6 +37,9 @@ func (_ *cycloneDXTypeGuesser) GuessDocumentType(blob []byte, format processor.F bom := new(cdx.BOM) decoder := cdx.NewBOMDecoder(reader, cdx.BOMFileFormatJSON) err := decoder.Decode(bom) + if err == nil && bom.Vulnerabilities != nil { + return processor.DocumentUnknown + } if err == nil && bom.BOMFormat == cycloneDXFormat { return processor.DocumentCycloneDX } diff --git a/pkg/handler/processor/guesser/type_guesser.go b/pkg/handler/processor/guesser/type_guesser.go index 8988df372a..8cb09ac66b 100644 --- a/pkg/handler/processor/guesser/type_guesser.go +++ b/pkg/handler/processor/guesser/type_guesser.go @@ -29,6 +29,7 @@ func init() { _ = RegisterDocumentTypeGuesser(&cycloneDXTypeGuesser{}, "cyclonedx") _ = RegisterDocumentTypeGuesser(&depsDevTypeGuesser{}, "deps.dev") _ = RegisterDocumentTypeGuesser(&csafTypeGuesser{}, "csaf") + _ = RegisterDocumentTypeGuesser(&cdxVexTypeGuesser{}, "cdx-vex") } // DocumentTypeGuesser guesses the document type based on the blob and format given diff --git a/pkg/handler/processor/process/process.go b/pkg/handler/processor/process/process.go index d8fd17fb3a..6cee6d5076 100644 --- a/pkg/handler/processor/process/process.go +++ b/pkg/handler/processor/process/process.go @@ -24,6 +24,7 @@ import ( uuid "github.com/gofrs/uuid" "github.com/guacsec/guac/pkg/emitter" "github.com/guacsec/guac/pkg/handler/processor" + "github.com/guacsec/guac/pkg/handler/processor/cdx_vex" "github.com/guacsec/guac/pkg/handler/processor/csaf" "github.com/guacsec/guac/pkg/handler/processor/cyclonedx" "github.com/guacsec/guac/pkg/handler/processor/deps_dev" @@ -49,6 +50,7 @@ func init() { _ = RegisterDocumentProcessor(&scorecard.ScorecardProcessor{}, processor.DocumentScorecard) _ = RegisterDocumentProcessor(&cyclonedx.CycloneDXProcessor{}, processor.DocumentCycloneDX) _ = RegisterDocumentProcessor(&deps_dev.DepsDev{}, processor.DocumentDepsDev) + _ = RegisterDocumentProcessor(&cdx_vex.CdxVexProcessor{}, processor.DocumentCdxVex) } func RegisterDocumentProcessor(p processor.DocumentProcessor, d processor.DocumentType) error { diff --git a/pkg/handler/processor/processor.go b/pkg/handler/processor/processor.go index af8c205a42..07f237c31a 100644 --- a/pkg/handler/processor/processor.go +++ b/pkg/handler/processor/processor.go @@ -62,6 +62,7 @@ const ( DocumentCycloneDX DocumentType = "CycloneDX" DocumentDepsDev DocumentType = "DEPS_DEV" DocumentCsaf DocumentType = "CSAF" + DocumentCdxVex DocumentType = "CDX_VEX" DocumentIngestPredicates DocumentType = "INGEST_PREDICATES" DocumentUnknown DocumentType = "UNKNOWN" ) diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go index 2aea28b818..5fc5950e5d 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go @@ -22,6 +22,7 @@ import ( "time" cdx "github.com/CycloneDX/cyclonedx-go" + "github.com/guacsec/guac/pkg/assembler" "github.com/guacsec/guac/pkg/assembler/clients/generated" "github.com/guacsec/guac/pkg/assembler/helpers" @@ -32,15 +33,24 @@ import ( ) var vexStatusMap = map[cdx.ImpactAnalysisState]generated.VexStatus{ - "resolved": generated.VexStatusFixed, - "exploitable": generated.VexStatusAffected, - "in_triage": generated.VexStatusUnderInvestigation, - "not_affected": generated.VexStatusNotAffected, + "resolved": generated.VexStatusFixed, + "exploitable": generated.VexStatusAffected, + "in_triage": generated.VexStatusUnderInvestigation, + "not_affected": generated.VexStatusNotAffected, + "resolved_with_pedigree": generated.VexStatusResolvedWithPedigree, + "false_positive": generated.VexStatusFalsePositive, } var justificationsMap = map[cdx.ImpactAnalysisJustification]generated.VexJustification{ - "code_not_present": generated.VexJustificationVulnerableCodeNotPresent, - "code_not_reachable": generated.VexJustificationVulnerableCodeNotInExecutePath, + "code_not_present": generated.VexJustificationVulnerableCodeNotPresent, + "code_not_reachable": generated.VexJustificationVulnerableCodeNotInExecutePath, + "requires_configuration": generated.VexJustificationRequiresConfiguration, + "requires_dependency": generated.VexJustificationRequiresDependency, + "requires_environment": generated.VexJustificationRequiresEnvironment, + "protected_by_compiler": generated.VexJustificationProtectedByCompiler, + "protected_at_runtime": generated.VexJustificationProtectedAtRuntime, + "protected_at_perimeter": generated.VexJustificationProtectedAtPerimeter, + "protected_by_mitigating_control": generated.VexJustificationProtectedByMitigatingControl, } type cdxVexParser struct { @@ -75,10 +85,6 @@ func (c *cdxVexParser) GetIdentifiers(ctx context.Context) (*common.IdentifierSt return nil, fmt.Errorf("not yet implemented") } -func generateVexIngest(ctx context.Context) *assembler.VexIngest { - return nil -} - // Get package name and range versions to create package input spec for the affected packages. func getAffectedPackages(ctx context.Context, vulnInput *generated.VulnerabilityInputSpec, vexData generated.VexStatementInputSpec, affectsObj cdx.Affects) *[]assembler.VexIngest { logger := logging.FromContext(ctx) @@ -146,6 +152,7 @@ func (c *cdxVexParser) GetPredicates(ctx context.Context) *assembler.IngestPredi pred := &assembler.IngestPredicates{} var vex []assembler.VexIngest + var vulnMetadata []assembler.VulnMetadataIngest var certifyVuln []assembler.CertifyVulnIngest var status generated.VexStatus var justification generated.VexJustification @@ -171,8 +178,6 @@ func (c *cdxVexParser) GetPredicates(ctx context.Context) *assembler.IngestPredi } vd := generated.VexStatementInputSpec{ - // is origin the same as vulnerability.ID? - Origin: vulnerability.ID, Status: status, VexJustification: justification, KnownSince: publishedTime, @@ -199,9 +204,22 @@ func (c *cdxVexParser) GetPredicates(ctx context.Context) *assembler.IngestPredi } } } + + for _, vulnRating := range *vulnerability.Ratings { + vm := assembler.VulnMetadataIngest{ + Vulnerability: vuln, + VulnMetadata: &generated.VulnerabilityMetadataInputSpec{ + ScoreType: generated.VulnerabilityScoreType(vulnRating.Method), + ScoreValue: *vulnRating.Score, + Timestamp: publishedTime, + }, + } + vulnMetadata = append(vulnMetadata, vm) + } } pred.Vex = vex pred.CertifyVuln = certifyVuln + pred.VulnMetadata = vulnMetadata return pred } diff --git a/pkg/ingestor/parser/common/graph_builder.go b/pkg/ingestor/parser/common/graph_builder.go index ef6d725ee2..3d59599218 100644 --- a/pkg/ingestor/parser/common/graph_builder.go +++ b/pkg/ingestor/parser/common/graph_builder.go @@ -97,4 +97,14 @@ func addMetadata(predicates *assembler.IngestPredicates, foundIdentities []Trust v.HasSourceAt.Collector = srcInfo.Collector v.HasSourceAt.Origin = srcInfo.Source } + + for _, v := range predicates.VulnMetadata { + v.VulnMetadata.Collector = srcInfo.Collector + v.VulnMetadata.Origin = srcInfo.Source + } + + for _, v := range predicates.Vex { + v.VexData.Collector = srcInfo.Collector + v.VexData.Origin = srcInfo.Source + } } diff --git a/pkg/ingestor/parser/parser.go b/pkg/ingestor/parser/parser.go index 5f3c2c743e..1798107669 100644 --- a/pkg/ingestor/parser/parser.go +++ b/pkg/ingestor/parser/parser.go @@ -47,7 +47,7 @@ func init() { _ = RegisterDocumentParser(scorecard.NewScorecardParser, processor.DocumentScorecard) _ = RegisterDocumentParser(deps_dev.NewDepsDevParser, processor.DocumentDepsDev) _ = RegisterDocumentParser(csaf.NewCsafParser, processor.DocumentCsaf) - _ = RegisterDocumentParser(cdxVex.NewCdxVexParser, processor.DocumentCycloneDX) + _ = RegisterDocumentParser(cdxVex.NewCdxVexParser, processor.DocumentCdxVex) } var ( From 9dce0e01915cb0d091571917ffeb9346ad97da84 Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Fri, 25 Aug 2023 12:45:25 -0700 Subject: [PATCH 03/11] adds license info and removes unreachable code Signed-off-by: stevemenezes --- pkg/handler/processor/cdx_vex/cdx_vex.go | 19 ++++++++++++++++--- pkg/handler/processor/guesser/type_cdx_vex.go | 15 +++++++++++++++ pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go | 2 +- .../parser/cdx_vex/parser_cdx_vex_test.go | 15 +++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/pkg/handler/processor/cdx_vex/cdx_vex.go b/pkg/handler/processor/cdx_vex/cdx_vex.go index 6d68a7091a..252fd02960 100644 --- a/pkg/handler/processor/cdx_vex/cdx_vex.go +++ b/pkg/handler/processor/cdx_vex/cdx_vex.go @@ -1,3 +1,18 @@ +// +// Copyright 2023 The GUAC Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package cdx_vex import ( @@ -26,9 +41,7 @@ func (p *CdxVexProcessor) ValidateSchema(d *processor.Document) error { return err } - return fmt.Errorf("unable to support parsing of CSAF document format: %v", d.Format) - - return nil + return fmt.Errorf("unable to support parsing of cdx-vex document format: %v", d.Format) } func (p *CdxVexProcessor) Unpack(d *processor.Document) ([]*processor.Document, error) { diff --git a/pkg/handler/processor/guesser/type_cdx_vex.go b/pkg/handler/processor/guesser/type_cdx_vex.go index 977ee0802c..c093cfa951 100644 --- a/pkg/handler/processor/guesser/type_cdx_vex.go +++ b/pkg/handler/processor/guesser/type_cdx_vex.go @@ -1,3 +1,18 @@ +// +// Copyright 2023 The GUAC Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package guesser import ( diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go index 5fc5950e5d..26a42df2bb 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go @@ -1,5 +1,5 @@ // -// Copyright 2022 The GUAC Authors. +// Copyright 2023 The GUAC Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go index b637ef685e..f2cb28a0ea 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go @@ -1 +1,16 @@ +// +// Copyright 2023 The GUAC Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package cdx_vex From f63da56511a2d590122aa2a4c746f0222cc18503 Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Fri, 25 Aug 2023 12:51:58 -0700 Subject: [PATCH 04/11] fix linting issues Signed-off-by: stevemenezes --- pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go index 26a42df2bb..179ea25d23 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go @@ -19,6 +19,7 @@ import ( "context" "encoding/json" "fmt" + "strings" "time" cdx "github.com/CycloneDX/cyclonedx-go" @@ -29,7 +30,6 @@ import ( "github.com/guacsec/guac/pkg/handler/processor" "github.com/guacsec/guac/pkg/ingestor/parser/common" "github.com/guacsec/guac/pkg/logging" - "strings" ) var vexStatusMap = map[cdx.ImpactAnalysisState]generated.VexStatus{ From 88e5df36e024d031b0b2871c28a4dccfb7f75105 Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Fri, 25 Aug 2023 16:37:28 -0700 Subject: [PATCH 05/11] addresses comments around enums and adds a test for cdx-vex guesser Signed-off-by: stevemenezes --- .../exampledata/sample-cyclonedx-vex.json | 96 +++++++++++++++++++ internal/testing/testdata/testdata.go | 3 + pkg/assembler/clients/generated/operations.go | 17 +--- .../graphql/generated/root_.generated.go | 9 -- pkg/assembler/graphql/model/nodes.go | 30 ++---- .../schema/certifyVEXStatement.graphql | 9 -- .../processor/guesser/test_cyclonedx_test.go | 88 +++++++++-------- pkg/handler/processor/guesser/type_cdx_vex.go | 38 -------- .../processor/guesser/type_cyclonedx.go | 6 +- pkg/handler/processor/guesser/type_guesser.go | 1 - pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go | 22 ++--- 11 files changed, 169 insertions(+), 150 deletions(-) create mode 100644 internal/testing/testdata/exampledata/sample-cyclonedx-vex.json delete mode 100644 pkg/handler/processor/guesser/type_cdx_vex.go diff --git a/internal/testing/testdata/exampledata/sample-cyclonedx-vex.json b/internal/testing/testdata/exampledata/sample-cyclonedx-vex.json new file mode 100644 index 0000000000..14c5067b42 --- /dev/null +++ b/internal/testing/testdata/exampledata/sample-cyclonedx-vex.json @@ -0,0 +1,96 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "vulnerabilities": [ + { + "id": "CVE-2020-25649", + "source": { + "name": "NVD", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-25649" + }, + "references": [ + { + "id": "SNYK-JAVA-COMFASTERXMLJACKSONCORE-1048302", + "source": { + "name": "SNYK", + "url": "https://security.snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-1048302" + } + } + ], + "ratings": [ + { + "source": { + "name": "NVD", + "url": "https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N&version=3.1" + }, + "score": 7.5, + "severity": "high", + "method": "CVSSv31", + "vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N" + }, + { + "source": { + "name": "SNYK", + "url": "https://security.snyk.io/vuln/SNYK-JAVA-COMFASTERXMLJACKSONCORE-1048302" + }, + "score": 8.2, + "severity": "high", + "method": "CVSSv31", + "vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N" + }, + { + "source": { + "name": "Acme Inc", + "url": "https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:N/MI:N/MA:N&version=3.1" + }, + "score": 0.0, + "severity": "none", + "method": "CVSSv31", + "vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N/CR:X/IR:X/AR:X/MAV:X/MAC:X/MPR:X/MUI:X/MS:X/MC:N/MI:N/MA:N" + } + ], + "cwes": [ + 611 + ], + "description": "com.fasterxml.jackson.core:jackson-databind is a library which contains the general-purpose data-binding functionality and tree-model for Jackson Data Processor.\n\nAffected versions of this package are vulnerable to XML External Entity (XXE) Injection. A flaw was found in FasterXML Jackson Databind, where it does not have entity expansion secured properly in the DOMDeserializer class. The highest threat from this vulnerability is data integrity.", + "detail": "XXE Injection is a type of attack against an application that parses XML input. XML is a markup language that defines a set of rules for encoding documents in a format that is both human-readable and machine-readable. By default, many XML processors allow specification of an external entity, a URI that is dereferenced and evaluated during XML processing. When an XML document is being parsed, the parser can make a request and include the content at the specified URI inside of the XML document.\n\nAttacks can include disclosing local files, which may contain sensitive data such as passwords or private user data, using file: schemes or relative paths in the system identifier.", + "recommendation": "Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.6.7.4, 2.9.10.7, 2.10.5.1 or higher.", + "advisories": [ + { + "title": "GitHub Commit", + "url": "https://github.com/FasterXML/jackson-databind/commit/612f971b78c60202e9cd75a299050c8f2d724a59" + }, + { + "title": "GitHub Issue", + "url": "https://github.com/FasterXML/jackson-databind/issues/2589" + }, + { + "title": "RedHat Bugzilla Bug", + "url": "https://bugzilla.redhat.com/show_bug.cgi?id=1887664" + } + ], + "created": "2020-12-03T00:00:00.000Z", + "published": "2020-12-03T00:00:00.000Z", + "updated": "2021-10-26T00:00:00.000Z", + "credits": { + "individuals": [ + { + "name": "Bartosz Baranowski" + } + ] + }, + "analysis": { + "state": "not_affected", + "justification": "code_not_reachable", + "response": ["will_not_fix", "update"], + "detail": "Automated dataflow analysis and manual code review indicates that the vulnerable code is not reachable, either directly or indirectly." + }, + "affects": [ + { + "ref": "urn:cdx:3e671687-395b-41f5-a30f-a58921a69b79/1#pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.10.0?type=jar" + } + ] + } + ] +} \ No newline at end of file diff --git a/internal/testing/testdata/testdata.go b/internal/testing/testdata/testdata.go index 7fe8883787..102f162b32 100644 --- a/internal/testing/testdata/testdata.go +++ b/internal/testing/testdata/testdata.go @@ -98,6 +98,9 @@ var ( //go:embed exampledata/cyclonedx-no-top-level.json CycloneDXExampleNoTopLevelComp []byte + //go:embed exampledata/sample-cyclonedx-vex.json + CycloneDXExampleVEX []byte + //go:embed exampledata/crev-review.json ITE6CREVExample []byte diff --git a/pkg/assembler/clients/generated/operations.go b/pkg/assembler/clients/generated/operations.go index 5d247c0e7e..f2e9ab735b 100644 --- a/pkg/assembler/clients/generated/operations.go +++ b/pkg/assembler/clients/generated/operations.go @@ -22845,13 +22845,6 @@ const ( VexJustificationVulnerableCodeCannotBeControlledByAdversary VexJustification = "VULNERABLE_CODE_CANNOT_BE_CONTROLLED_BY_ADVERSARY" VexJustificationInlineMitigationsAlreadyExist VexJustification = "INLINE_MITIGATIONS_ALREADY_EXIST" VexJustificationNotProvided VexJustification = "NOT_PROVIDED" - VexJustificationRequiresConfiguration VexJustification = "REQUIRES_CONFIGURATION" - VexJustificationRequiresDependency VexJustification = "REQUIRES_DEPENDENCY" - VexJustificationRequiresEnvironment VexJustification = "REQUIRES_ENVIRONMENT" - VexJustificationProtectedByCompiler VexJustification = "PROTECTED_BY_COMPILER" - VexJustificationProtectedAtRuntime VexJustification = "PROTECTED_AT_RUNTIME" - VexJustificationProtectedAtPerimeter VexJustification = "PROTECTED_AT_PERIMETER" - VexJustificationProtectedByMitigatingControl VexJustification = "PROTECTED_BY_MITIGATING_CONTROL" ) // VexStatementInputSpec represents the input to ingest VEX statements. @@ -22890,12 +22883,10 @@ func (v *VexStatementInputSpec) GetCollector() string { return v.Collector } type VexStatus string const ( - VexStatusNotAffected VexStatus = "NOT_AFFECTED" - VexStatusAffected VexStatus = "AFFECTED" - VexStatusFixed VexStatus = "FIXED" - VexStatusUnderInvestigation VexStatus = "UNDER_INVESTIGATION" - VexStatusResolvedWithPedigree VexStatus = "RESOLVED_WITH_PEDIGREE" - VexStatusFalsePositive VexStatus = "FALSE_POSITIVE" + VexStatusNotAffected VexStatus = "NOT_AFFECTED" + VexStatusAffected VexStatus = "AFFECTED" + VexStatusFixed VexStatus = "FIXED" + VexStatusUnderInvestigation VexStatus = "UNDER_INVESTIGATION" ) // VulnEqualIngestVulnEqual includes the requested fields of the GraphQL type VulnEqual. diff --git a/pkg/assembler/graphql/generated/root_.generated.go b/pkg/assembler/graphql/generated/root_.generated.go index c0af2c8a2e..c66d4c8908 100644 --- a/pkg/assembler/graphql/generated/root_.generated.go +++ b/pkg/assembler/graphql/generated/root_.generated.go @@ -2926,8 +2926,6 @@ enum VexStatus { AFFECTED FIXED UNDER_INVESTIGATION - RESOLVED_WITH_PEDIGREE - FALSE_POSITIVE } "Records the justification included in the VEX statement." @@ -2938,13 +2936,6 @@ enum VexJustification { VULNERABLE_CODE_CANNOT_BE_CONTROLLED_BY_ADVERSARY INLINE_MITIGATIONS_ALREADY_EXIST NOT_PROVIDED - REQUIRES_CONFIGURATION - REQUIRES_DEPENDENCY - REQUIRES_ENVIRONMENT - PROTECTED_BY_COMPILER - PROTECTED_AT_RUNTIME - PROTECTED_AT_PERIMETER - PROTECTED_BY_MITIGATING_CONTROL } """ diff --git a/pkg/assembler/graphql/model/nodes.go b/pkg/assembler/graphql/model/nodes.go index abe57f0698..6ca6dfc737 100644 --- a/pkg/assembler/graphql/model/nodes.go +++ b/pkg/assembler/graphql/model/nodes.go @@ -1672,13 +1672,6 @@ const ( VexJustificationVulnerableCodeCannotBeControlledByAdversary VexJustification = "VULNERABLE_CODE_CANNOT_BE_CONTROLLED_BY_ADVERSARY" VexJustificationInlineMitigationsAlreadyExist VexJustification = "INLINE_MITIGATIONS_ALREADY_EXIST" VexJustificationNotProvided VexJustification = "NOT_PROVIDED" - VexJustificationRequiresConfiguration VexJustification = "REQUIRES_CONFIGURATION" - VexJustificationRequiresDependency VexJustification = "REQUIRES_DEPENDENCY" - VexJustificationRequiresEnvironment VexJustification = "REQUIRES_ENVIRONMENT" - VexJustificationProtectedByCompiler VexJustification = "PROTECTED_BY_COMPILER" - VexJustificationProtectedAtRuntime VexJustification = "PROTECTED_AT_RUNTIME" - VexJustificationProtectedAtPerimeter VexJustification = "PROTECTED_AT_PERIMETER" - VexJustificationProtectedByMitigatingControl VexJustification = "PROTECTED_BY_MITIGATING_CONTROL" ) var AllVexJustification = []VexJustification{ @@ -1688,18 +1681,11 @@ var AllVexJustification = []VexJustification{ VexJustificationVulnerableCodeCannotBeControlledByAdversary, VexJustificationInlineMitigationsAlreadyExist, VexJustificationNotProvided, - VexJustificationRequiresConfiguration, - VexJustificationRequiresDependency, - VexJustificationRequiresEnvironment, - VexJustificationProtectedByCompiler, - VexJustificationProtectedAtRuntime, - VexJustificationProtectedAtPerimeter, - VexJustificationProtectedByMitigatingControl, } func (e VexJustification) IsValid() bool { switch e { - case VexJustificationComponentNotPresent, VexJustificationVulnerableCodeNotPresent, VexJustificationVulnerableCodeNotInExecutePath, VexJustificationVulnerableCodeCannotBeControlledByAdversary, VexJustificationInlineMitigationsAlreadyExist, VexJustificationNotProvided, VexJustificationRequiresConfiguration, VexJustificationRequiresDependency, VexJustificationRequiresEnvironment, VexJustificationProtectedByCompiler, VexJustificationProtectedAtRuntime, VexJustificationProtectedAtPerimeter, VexJustificationProtectedByMitigatingControl: + case VexJustificationComponentNotPresent, VexJustificationVulnerableCodeNotPresent, VexJustificationVulnerableCodeNotInExecutePath, VexJustificationVulnerableCodeCannotBeControlledByAdversary, VexJustificationInlineMitigationsAlreadyExist, VexJustificationNotProvided: return true } return false @@ -1730,12 +1716,10 @@ func (e VexJustification) MarshalGQL(w io.Writer) { type VexStatus string const ( - VexStatusNotAffected VexStatus = "NOT_AFFECTED" - VexStatusAffected VexStatus = "AFFECTED" - VexStatusFixed VexStatus = "FIXED" - VexStatusUnderInvestigation VexStatus = "UNDER_INVESTIGATION" - VexStatusResolvedWithPedigree VexStatus = "RESOLVED_WITH_PEDIGREE" - VexStatusFalsePositive VexStatus = "FALSE_POSITIVE" + VexStatusNotAffected VexStatus = "NOT_AFFECTED" + VexStatusAffected VexStatus = "AFFECTED" + VexStatusFixed VexStatus = "FIXED" + VexStatusUnderInvestigation VexStatus = "UNDER_INVESTIGATION" ) var AllVexStatus = []VexStatus{ @@ -1743,13 +1727,11 @@ var AllVexStatus = []VexStatus{ VexStatusAffected, VexStatusFixed, VexStatusUnderInvestigation, - VexStatusResolvedWithPedigree, - VexStatusFalsePositive, } func (e VexStatus) IsValid() bool { switch e { - case VexStatusNotAffected, VexStatusAffected, VexStatusFixed, VexStatusUnderInvestigation, VexStatusResolvedWithPedigree, VexStatusFalsePositive: + case VexStatusNotAffected, VexStatusAffected, VexStatusFixed, VexStatusUnderInvestigation: return true } return false diff --git a/pkg/assembler/graphql/schema/certifyVEXStatement.graphql b/pkg/assembler/graphql/schema/certifyVEXStatement.graphql index f0e734ef71..3e34fd9432 100644 --- a/pkg/assembler/graphql/schema/certifyVEXStatement.graphql +++ b/pkg/assembler/graphql/schema/certifyVEXStatement.graphql @@ -57,8 +57,6 @@ enum VexStatus { AFFECTED FIXED UNDER_INVESTIGATION - RESOLVED_WITH_PEDIGREE - FALSE_POSITIVE } "Records the justification included in the VEX statement." @@ -69,13 +67,6 @@ enum VexJustification { VULNERABLE_CODE_CANNOT_BE_CONTROLLED_BY_ADVERSARY INLINE_MITIGATIONS_ALREADY_EXIST NOT_PROVIDED - REQUIRES_CONFIGURATION - REQUIRES_DEPENDENCY - REQUIRES_ENVIRONMENT - PROTECTED_BY_COMPILER - PROTECTED_AT_RUNTIME - PROTECTED_AT_PERIMETER - PROTECTED_BY_MITIGATING_CONTROL } """ diff --git a/pkg/handler/processor/guesser/test_cyclonedx_test.go b/pkg/handler/processor/guesser/test_cyclonedx_test.go index 0ff5b1fcf4..cfa644d338 100644 --- a/pkg/handler/processor/guesser/test_cyclonedx_test.go +++ b/pkg/handler/processor/guesser/test_cyclonedx_test.go @@ -28,44 +28,56 @@ func Test_cyclonedxTypeGuesser_GuessDocumentType(t *testing.T) { blob []byte format processor.FormatType expected processor.DocumentType - }{{ - name: "invalid cyclonedx Document", - blob: []byte(`{ - "abc": "def" - }`), - format: processor.FormatJSON, - expected: processor.DocumentUnknown, - }, { - name: "invalid cyclonedx Document", - blob: testdata.CycloneDXInvalidExample, - format: processor.FormatJSON, - expected: processor.DocumentUnknown, - }, { - name: "invalid xml cyclonedx Document", - blob: testdata.CycloneDXInvalidExampleXML, - format: processor.FormatXML, - expected: processor.DocumentUnknown, - }, { - name: "valid small cyclonedx Document", - blob: testdata.CycloneDXBusyboxExample, - format: processor.FormatJSON, - expected: processor.DocumentCycloneDX, - }, { - name: "valid distroless cyclonedx Document", - blob: testdata.CycloneDXDistrolessExample, - format: processor.FormatJSON, - expected: processor.DocumentCycloneDX, - }, { - name: "valid alpine cyclonedx Document", - blob: testdata.CycloneDXExampleAlpine, - format: processor.FormatJSON, - expected: processor.DocumentCycloneDX, - }, { - name: "valid xml cyclonedx Document", - blob: testdata.CycloneDXExampleLaravelXML, - format: processor.FormatXML, - expected: processor.DocumentCycloneDX, - }} + }{ + { + name: "invalid cyclonedx Document", + blob: []byte(`{"abc": "def"}`), + format: processor.FormatJSON, + expected: processor.DocumentUnknown, + }, + { + name: "invalid cyclonedx Document", + blob: testdata.CycloneDXInvalidExample, + format: processor.FormatJSON, + expected: processor.DocumentUnknown, + }, + { + name: "invalid xml cyclonedx Document", + blob: testdata.CycloneDXInvalidExampleXML, + format: processor.FormatXML, + expected: processor.DocumentUnknown, + }, + { + name: "valid small cyclonedx Document", + blob: testdata.CycloneDXBusyboxExample, + format: processor.FormatJSON, + expected: processor.DocumentCycloneDX, + }, + { + name: "valid distroless cyclonedx Document", + blob: testdata.CycloneDXDistrolessExample, + format: processor.FormatJSON, + expected: processor.DocumentCycloneDX, + }, + { + name: "valid alpine cyclonedx Document", + blob: testdata.CycloneDXExampleAlpine, + format: processor.FormatJSON, + expected: processor.DocumentCycloneDX, + }, + { + name: "valid xml cyclonedx Document", + blob: testdata.CycloneDXExampleLaravelXML, + format: processor.FormatXML, + expected: processor.DocumentCycloneDX, + }, + { + name: "valid cyclonedx vex json Document", + blob: testdata.CycloneDXExampleVEX, + format: processor.FormatJSON, + expected: processor.DocumentCdxVex, + }, + } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { guesser := &cycloneDXTypeGuesser{} diff --git a/pkg/handler/processor/guesser/type_cdx_vex.go b/pkg/handler/processor/guesser/type_cdx_vex.go deleted file mode 100644 index c093cfa951..0000000000 --- a/pkg/handler/processor/guesser/type_cdx_vex.go +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright 2023 The GUAC Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package guesser - -import ( - "encoding/json" - - cdx "github.com/CycloneDX/cyclonedx-go" - "github.com/guacsec/guac/pkg/handler/processor" -) - -type cdxVexTypeGuesser struct{} - -func (_ *cdxVexTypeGuesser) GuessDocumentType(blob []byte, format processor.FormatType) processor.DocumentType { - switch format { - case processor.FormatJSON: - // Decode the BOM - var decoded cdx.BOM - err := json.Unmarshal(blob, &decoded) - if err == nil && decoded.Vulnerabilities != nil { - return processor.DocumentCdxVex - } - } - return processor.DocumentUnknown -} diff --git a/pkg/handler/processor/guesser/type_cyclonedx.go b/pkg/handler/processor/guesser/type_cyclonedx.go index f50b65f4dc..3131b0ca34 100644 --- a/pkg/handler/processor/guesser/type_cyclonedx.go +++ b/pkg/handler/processor/guesser/type_cyclonedx.go @@ -37,10 +37,10 @@ func (_ *cycloneDXTypeGuesser) GuessDocumentType(blob []byte, format processor.F bom := new(cdx.BOM) decoder := cdx.NewBOMDecoder(reader, cdx.BOMFileFormatJSON) err := decoder.Decode(bom) - if err == nil && bom.Vulnerabilities != nil { - return processor.DocumentUnknown - } if err == nil && bom.BOMFormat == cycloneDXFormat { + if bom.Vulnerabilities != nil { + return processor.DocumentCdxVex + } return processor.DocumentCycloneDX } case processor.FormatXML: diff --git a/pkg/handler/processor/guesser/type_guesser.go b/pkg/handler/processor/guesser/type_guesser.go index 8cb09ac66b..8988df372a 100644 --- a/pkg/handler/processor/guesser/type_guesser.go +++ b/pkg/handler/processor/guesser/type_guesser.go @@ -29,7 +29,6 @@ func init() { _ = RegisterDocumentTypeGuesser(&cycloneDXTypeGuesser{}, "cyclonedx") _ = RegisterDocumentTypeGuesser(&depsDevTypeGuesser{}, "deps.dev") _ = RegisterDocumentTypeGuesser(&csafTypeGuesser{}, "csaf") - _ = RegisterDocumentTypeGuesser(&cdxVexTypeGuesser{}, "cdx-vex") } // DocumentTypeGuesser guesses the document type based on the blob and format given diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go index 179ea25d23..fe685af66e 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go @@ -33,24 +33,15 @@ import ( ) var vexStatusMap = map[cdx.ImpactAnalysisState]generated.VexStatus{ - "resolved": generated.VexStatusFixed, - "exploitable": generated.VexStatusAffected, - "in_triage": generated.VexStatusUnderInvestigation, - "not_affected": generated.VexStatusNotAffected, - "resolved_with_pedigree": generated.VexStatusResolvedWithPedigree, - "false_positive": generated.VexStatusFalsePositive, + "resolved": generated.VexStatusFixed, + "exploitable": generated.VexStatusAffected, + "in_triage": generated.VexStatusUnderInvestigation, + "not_affected": generated.VexStatusNotAffected, } var justificationsMap = map[cdx.ImpactAnalysisJustification]generated.VexJustification{ - "code_not_present": generated.VexJustificationVulnerableCodeNotPresent, - "code_not_reachable": generated.VexJustificationVulnerableCodeNotInExecutePath, - "requires_configuration": generated.VexJustificationRequiresConfiguration, - "requires_dependency": generated.VexJustificationRequiresDependency, - "requires_environment": generated.VexJustificationRequiresEnvironment, - "protected_by_compiler": generated.VexJustificationProtectedByCompiler, - "protected_at_runtime": generated.VexJustificationProtectedAtRuntime, - "protected_at_perimeter": generated.VexJustificationProtectedAtPerimeter, - "protected_by_mitigating_control": generated.VexJustificationProtectedByMitigatingControl, + "code_not_present": generated.VexJustificationVulnerableCodeNotPresent, + "code_not_reachable": generated.VexJustificationVulnerableCodeNotInExecutePath, } type cdxVexParser struct { @@ -182,6 +173,7 @@ func (c *cdxVexParser) GetPredicates(ctx context.Context) *assembler.IngestPredi VexJustification: justification, KnownSince: publishedTime, Statement: vulnerability.Analysis.Detail, + StatusNotes: fmt.Sprintf("%s:%s", string(vulnerability.Analysis.State), string(vulnerability.Analysis.Justification)), } for _, affect := range *vulnerability.Affects { From 91c7dec43fdceb9ca9fe68b4f6200561da57c6ca Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Wed, 30 Aug 2023 00:52:12 -0700 Subject: [PATCH 06/11] adds unit tests for cdx-vex parser Signed-off-by: stevemenezes --- ...vex.json => cyclonedx-unaffected-vex.json} | 0 .../exampledata/cyclonedx-vex-affected.json | 54 +++++++ internal/testing/testdata/testdata.go | 136 +++++++++++++++--- pkg/handler/processor/cdx_vex/cdx_vex.go | 2 +- pkg/handler/processor/cdx_vex/cdx_vex_test.go | 109 ++++++++++++++ ...clonedx_test.go => type_cyclonedx_test.go} | 2 +- .../parser/cdx_vex/parser_cdx_vex_test.go | 59 ++++++++ 7 files changed, 344 insertions(+), 18 deletions(-) rename internal/testing/testdata/exampledata/{sample-cyclonedx-vex.json => cyclonedx-unaffected-vex.json} (100%) create mode 100644 internal/testing/testdata/exampledata/cyclonedx-vex-affected.json create mode 100644 pkg/handler/processor/cdx_vex/cdx_vex_test.go rename pkg/handler/processor/guesser/{test_cyclonedx_test.go => type_cyclonedx_test.go} (98%) diff --git a/internal/testing/testdata/exampledata/sample-cyclonedx-vex.json b/internal/testing/testdata/exampledata/cyclonedx-unaffected-vex.json similarity index 100% rename from internal/testing/testdata/exampledata/sample-cyclonedx-vex.json rename to internal/testing/testdata/exampledata/cyclonedx-unaffected-vex.json diff --git a/internal/testing/testdata/exampledata/cyclonedx-vex-affected.json b/internal/testing/testdata/exampledata/cyclonedx-vex-affected.json new file mode 100644 index 0000000000..59f3f1fc99 --- /dev/null +++ b/internal/testing/testdata/exampledata/cyclonedx-vex-affected.json @@ -0,0 +1,54 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "version": 1, + "metadata" : { + "timestamp" : "2022-03-03T00:00:00Z", + "component" : { + "name" : "ABC", + "type" : "application", + "bom-ref" : "product-ABC" + } + }, + "vulnerabilities": [ + { + "id": "CVE-2021-44228", + "source": { + "name": "NVD", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228" + }, + "ratings": [ + { + "source": { + "name": "NVD", + "url": "https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H&version=3.1" + }, + "score": 10.0, + "severity": "critical", + "method": "CVSSv31", + "vector": "AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H" + } + ], + "analysis": { + "state": "exploitable", + "response": ["will_not_fix", "update"], + "detail": "Versions of Product ABC are affected by the vulnerability. Customers are advised to upgrade to the latest release." + }, + "affects": [ + { + "ref": "urn:cdx:3e671687-395b-41f5-a30f-a58921a69b79/1#pkg:maven/com.fasterxml.jackson.core/jackson-databind@", + "versions": [ + { + "version": "2.4", + "status": "affected" + }, + { + "version": "2.6", + "status": "affected" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/internal/testing/testdata/testdata.go b/internal/testing/testdata/testdata.go index 102f162b32..904124b5bb 100644 --- a/internal/testing/testdata/testdata.go +++ b/internal/testing/testdata/testdata.go @@ -98,8 +98,11 @@ var ( //go:embed exampledata/cyclonedx-no-top-level.json CycloneDXExampleNoTopLevelComp []byte - //go:embed exampledata/sample-cyclonedx-vex.json - CycloneDXExampleVEX []byte + //go:embed exampledata/cyclonedx-unaffected-vex.json + CycloneDXVEXUnAffected []byte + + //go:embed exampledata/cyclonedx-vex-affected.json + CycloneDXVEXAffected []byte //go:embed exampledata/crev-review.json ITE6CREVExample []byte @@ -131,6 +134,99 @@ var ( //go:embed exampledata/ingest_predicates.json IngestPredicatesExample []byte + // CycloneDX VEX testdata unaffected + pkg, _ = asmhelpers.PurlToPkg("pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.10.0?type=jar") + vulnSpec = &generated.VulnerabilityInputSpec{ + Type: "cve", + VulnerabilityID: "cve-2020-25649", + } + CycloneDXUnAffectedVexIngest = []assembler.VexIngest{ + { + Pkg: pkg, + Vulnerability: vulnSpec, + VexData: &generated.VexStatementInputSpec{ + Status: "NOT_AFFECTED", + VexJustification: "VULNERABLE_CODE_NOT_IN_EXECUTE_PATH", + Statement: "Automated dataflow analysis and manual code review indicates that the vulnerable code is not reachable, either directly or indirectly.", + StatusNotes: "not_affected:code_not_reachable", + KnownSince: parseUTCTime("2020-12-03T00:00:00.000Z"), + }, + }, + } + CycloneDXUnAffectedVulnMetadata = []assembler.VulnMetadataIngest{ + { + Vulnerability: vulnSpec, + VulnMetadata: &generated.VulnerabilityMetadataInputSpec{ + ScoreType: "CVSSv31", + ScoreValue: 7.5, + Timestamp: parseUTCTime("2020-12-03T00:00:00.000Z"), + }, + }, + { + Vulnerability: vulnSpec, + VulnMetadata: &generated.VulnerabilityMetadataInputSpec{ + ScoreType: "CVSSv31", + ScoreValue: 8.2, + Timestamp: parseUTCTime("2020-12-03T00:00:00.000Z"), + }, + }, + { + Vulnerability: vulnSpec, + VulnMetadata: &generated.VulnerabilityMetadataInputSpec{ + ScoreType: "CVSSv31", + ScoreValue: 0.0, + Timestamp: parseUTCTime("2020-12-03T00:00:00.000Z"), + }, + }, + } + + // CycloneDX VEX testdata in triage + pkg1, _ = asmhelpers.PurlToPkg("pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.4") + pkg2, _ = asmhelpers.PurlToPkg("pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.6") + + vulnSpecAffected = &generated.VulnerabilityInputSpec{ + Type: "cve", + VulnerabilityID: "cve-2021-44228", + } + vexDataAffected = &generated.VexStatementInputSpec{ + Status: "AFFECTED", + Statement: "Versions of Product ABC are affected by the vulnerability. Customers are advised to upgrade to the latest release.", + StatusNotes: "exploitable:", + } + CycloneDXAffectedVexIngest = []assembler.VexIngest{ + { + Pkg: pkg1, + Vulnerability: vulnSpecAffected, + VexData: vexDataAffected, + }, + { + Pkg: pkg2, + Vulnerability: vulnSpecAffected, + VexData: vexDataAffected, + }, + } + CycloneDXAffectedVulnMetadata = []assembler.VulnMetadataIngest{ + { + Vulnerability: vulnSpecAffected, + VulnMetadata: &generated.VulnerabilityMetadataInputSpec{ + ScoreType: "CVSSv31", + ScoreValue: 10, + }, + }, + } + CycloneDXAffectedCertifyVuln = []assembler.CertifyVulnIngest{ + { + Pkg: pkg1, + Vulnerability: vulnSpecAffected, + VulnData: &generated.ScanMetadataInput{}, + }, + { + Pkg: pkg2, + Vulnerability: vulnSpecAffected, + VulnData: &generated.ScanMetadataInput{}, + }, + } + // DSSE/SLSA Testdata // Taken from: https://slsa.dev/provenance/v0.2#example @@ -144,7 +240,7 @@ var ( "buildType": "https://github.com/Attestations/GitHubActionsWorkflow@v1", "invocation": { "configSource": { - "uri": "git+https://github.com/curl/curl-docker@master", + "uri": "githttps://github.com/curl/curl-docker@master", "digest": { "sha1": "d6525c840a62b398424a78d792f457477135d0cf" }, "entryPoint": "build.yaml:maketgz" } @@ -157,7 +253,7 @@ var ( }, "materials": [ { - "uri": "git+https://github.com/curl/curl-docker@master", + "uri": "githttps://github.com/curl/curl-docker@master", "digest": { "sha1": "24279c5185ddc042896e3748f47fa89b48c1c14e" } }, { "uri": "github_hosted_vm:ubuntu-18.04:20210123.1", @@ -197,7 +293,7 @@ var ( }, "resolvedDependencies": [ { - "uri": "git+https://github.com/octocat/hello-world@refs/heads/main", + "uri": "githttps://github.com/octocat/hello-world@refs/heads/main", "digest": { "gitCommit": "c27d339ee6075c1f744c5d4b200f7901aad2c369" } @@ -277,7 +373,7 @@ var ( Digest: "24279c5185ddc042896e3748f47fa89b48c1c14e", } - mat1Src, _ = asmhelpers.VcsToSrc("git+https://github.com/curl/curl-docker@master") + mat1Src, _ = asmhelpers.VcsToSrc("githttps://github.com/curl/curl-docker@master") mat2 = model.ArtifactInputSpec{ Algorithm: "sha1", @@ -330,9 +426,9 @@ var ( {Key: "slsa.metadata.completeness.materials", Value: "false"}, {Key: "slsa.buildType", Value: "https://github.com/Attestations/GitHubActionsWorkflow@v1"}, {Key: "slsa.invocation.configSource.entryPoint", Value: "build.yaml:maketgz"}, - {Key: "slsa.invocation.configSource.uri", Value: "git+https://github.com/curl/curl-docker@master"}, + {Key: "slsa.invocation.configSource.uri", Value: "githttps://github.com/curl/curl-docker@master"}, {Key: "slsa.metadata.reproducible", Value: "false"}, - {Key: "slsa.materials.0.uri", Value: "git+https://github.com/curl/curl-docker@master"}, + {Key: "slsa.materials.0.uri", Value: "githttps://github.com/curl/curl-docker@master"}, {Key: "slsa.builder.id", Value: "https://github.com/Attestations/GitHubHostedActions@v1"}, {Key: "slsa.invocation.configSource.digest.sha1", Value: "d6525c840a62b398424a78d792f457477135d0cf"}, {Key: "slsa.metadata.completeness.parameters", Value: "false"}, @@ -397,7 +493,7 @@ var ( StartedOn: &slsa1time, SlsaPredicate: []model.SLSAPredicateInputSpec{ {Key: "slsa.buildDefinition.buildType", Value: "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1"}, - {Key: "slsa.buildDefinition.externalParameters.inputs.build_id", Value: "1.23456768e+08"}, + {Key: "slsa.buildDefinition.externalParameters.inputs.build_id", Value: "1.23456768e08"}, {Key: "slsa.buildDefinition.externalParameters.inputs.deploy_target", Value: "deployment_sys_1a"}, {Key: "slsa.buildDefinition.externalParameters.inputs.perform_deploy", Value: "true"}, {Key: "slsa.buildDefinition.externalParameters.vars.MASCOT", Value: "Mona"}, @@ -407,7 +503,7 @@ var ( {Key: "slsa.buildDefinition.internalParameters.github.actor_id", Value: "1234567"}, {Key: "slsa.buildDefinition.internalParameters.github.event_name", Value: "workflow_dispatch"}, {Key: "slsa.buildDefinition.resolvedDependencies.0.digest.gitCommit", Value: "c27d339ee6075c1f744c5d4b200f7901aad2c369"}, - {Key: "slsa.buildDefinition.resolvedDependencies.0.uri", Value: "git+https://github.com/octocat/hello-world@refs/heads/main"}, + {Key: "slsa.buildDefinition.resolvedDependencies.0.uri", Value: "githttps://github.com/octocat/hello-world@refs/heads/main"}, {Key: "slsa.buildDefinition.resolvedDependencies.1.uri", Value: "https://github.com/actions/virtual-environments/releases/tag/ubuntu20/20220515.1"}, {Key: "slsa.runDetails.builder.id", Value: "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v0.0.1"}, {Key: "slsa.runDetails.metadata.invocationID", Value: "https://github.com/octocat/hello-world/actions/runs/1536140711/attempts/1"}, @@ -644,11 +740,11 @@ var ( // CycloneDX Testdata cdxTopLevelPack, _ = asmhelpers.PurlToPkg("pkg:guac/cdx/gcr.io/distroless/static@sha256:6ad5b696af3ca05a048bd29bf0f623040462638cb0b29c8d702cbb2805687388?tag=nonroot") - cdxTzdataPack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/tzdata@2021a-1+deb11u6?arch=all&distro=debian-11") + cdxTzdataPack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/tzdata@2021a-1deb11u6?arch=all&distro=debian-11") cdxNetbasePack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/netbase@6.3?arch=all&distro=debian-11") - cdxBasefilesPack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/base-files@11.1+deb11u5?arch=amd64&distro=debian-11") + cdxBasefilesPack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/base-files@11.1deb11u5?arch=amd64&distro=debian-11") CdxDeps = []assembler.IsDependencyIngest{ { @@ -657,7 +753,7 @@ var ( DepPkgMatchFlag: model.MatchFlags{Pkg: model.PkgMatchTypeSpecificVersion}, IsDependency: &model.IsDependencyInputSpec{ DependencyType: model.DependencyTypeUnknown, - VersionRange: "11.1+deb11u5", + VersionRange: "11.1deb11u5", Justification: isDepJustifyTopPkgJustification, }, }, @@ -677,7 +773,7 @@ var ( DepPkgMatchFlag: model.MatchFlags{Pkg: model.PkgMatchTypeSpecificVersion}, IsDependency: &model.IsDependencyInputSpec{ DependencyType: model.DependencyTypeUnknown, - VersionRange: "2021a-1+deb11u6", + VersionRange: "2021a-1deb11u6", Justification: isDepJustifyTopPkgJustification, }, }, @@ -2057,7 +2153,7 @@ For the update to take effect, all services linked to the OpenSSL library must b StartedOn: &slsaStartTime, SlsaPredicate: []generated.SLSAPredicateInputSpec{ {Key: "slsa.buildDefinition.buildType", Value: "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1"}, - {Key: "slsa.buildDefinition.externalParameters.inputs.build_id", Value: "1.23456768e+08"}, + {Key: "slsa.buildDefinition.externalParameters.inputs.build_id", Value: "1.23456768e08"}, {Key: "slsa.buildDefinition.externalParameters.inputs.deploy_target", Value: "deployment_sys_1a"}, {Key: "slsa.buildDefinition.externalParameters.inputs.perform_deploy", Value: "true"}, {Key: "slsa.buildDefinition.externalParameters.vars.MASCOT", Value: "Mona"}, @@ -2067,7 +2163,7 @@ For the update to take effect, all services linked to the OpenSSL library must b {Key: "slsa.buildDefinition.internalParameters.github.actor_id", Value: "1234567"}, {Key: "slsa.buildDefinition.internalParameters.github.event_name", Value: "workflow_dispatch"}, {Key: "slsa.buildDefinition.resolvedDependencies.0.digest.gitCommit", Value: "c27d339ee6075c1f744c5d4b200f7901aad2c369"}, - {Key: "slsa.buildDefinition.resolvedDependencies.0.uri", Value: "git+https://github.com/octocat/hello-world@refs/heads/main"}, + {Key: "slsa.buildDefinition.resolvedDependencies.0.uri", Value: "githttps://github.com/octocat/hello-world@refs/heads/main"}, {Key: "slsa.buildDefinition.resolvedDependencies.1.uri", Value: "https://github.com/actions/virtual-environments/releases/tag/ubuntu20/20220515.1"}, {Key: "slsa.runDetails.builder.id", Value: "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v0.0.1"}, {Key: "slsa.runDetails.metadata.invocationID", Value: "https://github.com/octocat/hello-world/actions/runs/1536140711/attempts/1"}, @@ -2503,3 +2599,11 @@ func toTime(s string) time.Time { } return timeScanned } + +func parseUTCTime(s string) time.Time { + timeScanned, err := time.Parse("2006-01-02T15:04:05Z", s) + if err != nil { + panic(err) + } + return timeScanned +} diff --git a/pkg/handler/processor/cdx_vex/cdx_vex.go b/pkg/handler/processor/cdx_vex/cdx_vex.go index 252fd02960..43aa115ec3 100644 --- a/pkg/handler/processor/cdx_vex/cdx_vex.go +++ b/pkg/handler/processor/cdx_vex/cdx_vex.go @@ -46,7 +46,7 @@ func (p *CdxVexProcessor) ValidateSchema(d *processor.Document) error { func (p *CdxVexProcessor) Unpack(d *processor.Document) ([]*processor.Document, error) { if d.Type != processor.DocumentCdxVex { - return nil, fmt.Errorf("expected document type: %v, actual document type: %v", processor.DocumentCsaf, d.Type) + return nil, fmt.Errorf("expected document type: %v, actual document type: %v", processor.DocumentCdxVex, d.Type) } return []*processor.Document{}, nil diff --git a/pkg/handler/processor/cdx_vex/cdx_vex_test.go b/pkg/handler/processor/cdx_vex/cdx_vex_test.go new file mode 100644 index 0000000000..d0879ceb43 --- /dev/null +++ b/pkg/handler/processor/cdx_vex/cdx_vex_test.go @@ -0,0 +1,109 @@ +// +// Copyright 2023 The GUAC Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cdx_vex + +import ( + "fmt" + "reflect" + "testing" + + "github.com/guacsec/guac/internal/testing/testdata" + "github.com/guacsec/guac/pkg/handler/processor" +) + +func Test_ValidateSchema(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + doc processor.Document + expectedErr error + }{ + { + name: "Incorrect document type", + doc: processor.Document{ + Type: processor.DocumentCsaf, + }, + expectedErr: fmt.Errorf("expected document type: %v, actual document type: %v", processor.DocumentCdxVex, processor.DocumentCsaf), + }, + { + name: "Successful validation of cdx-vex document", + doc: processor.Document{ + Type: processor.DocumentCdxVex, + Format: processor.FormatJSON, + Blob: testdata.CycloneDXExampleVEX, + }, + }, + { + name: "Invalid format for cdx-vex document", + doc: processor.Document{ + Type: processor.DocumentCdxVex, + Format: processor.FormatXML, + Blob: testdata.CycloneDXExampleVEX, + }, + expectedErr: fmt.Errorf("unable to support parsing of cdx-vex document format: %v", processor.FormatXML), + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + c := CdxVexProcessor{} + err := c.ValidateSchema(&tt.doc) + if err != nil && err.Error() != tt.expectedErr.Error() { + t.Errorf("ValidateSchema() actual error = %v, expected error %v", err, tt.expectedErr) + } + }) + } +} + +func Test_Unpack(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + doc processor.Document + expectedRes []*processor.Document + expectedErr error + }{ + { + name: "Invalid document type", + doc: processor.Document{ + Type: processor.DocumentCycloneDX, + }, + expectedRes: nil, + expectedErr: fmt.Errorf("expected document type: %v, actual document type: %v", processor.DocumentCdxVex, processor.DocumentCycloneDX), + }, + { + name: "Successful unpacked cdx-vex document", + doc: processor.Document{ + Type: processor.DocumentCdxVex, + }, + expectedRes: []*processor.Document{}, + expectedErr: nil, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + c := CdxVexProcessor{} + res, err := c.Unpack(&tt.doc) + if err != nil && err.Error() != tt.expectedErr.Error() { + t.Errorf("Unpack() actual error = %v, expected error %v", err, tt.expectedErr) + } + if !reflect.DeepEqual(res, tt.expectedRes) { + t.Errorf("Unpack() actual result = %v, expected result %v", res, tt.expectedRes) + } + }) + } +} diff --git a/pkg/handler/processor/guesser/test_cyclonedx_test.go b/pkg/handler/processor/guesser/type_cyclonedx_test.go similarity index 98% rename from pkg/handler/processor/guesser/test_cyclonedx_test.go rename to pkg/handler/processor/guesser/type_cyclonedx_test.go index cfa644d338..552a51d186 100644 --- a/pkg/handler/processor/guesser/test_cyclonedx_test.go +++ b/pkg/handler/processor/guesser/type_cyclonedx_test.go @@ -73,7 +73,7 @@ func Test_cyclonedxTypeGuesser_GuessDocumentType(t *testing.T) { }, { name: "valid cyclonedx vex json Document", - blob: testdata.CycloneDXExampleVEX, + blob: testdata.CycloneDXVEXUnAffected, format: processor.FormatJSON, expected: processor.DocumentCdxVex, }, diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go index f2cb28a0ea..ac7ce564e0 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go @@ -14,3 +14,62 @@ // limitations under the License. package cdx_vex + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/guacsec/guac/internal/testing/testdata" + "github.com/guacsec/guac/pkg/assembler" + "github.com/guacsec/guac/pkg/handler/processor" + "github.com/guacsec/guac/pkg/logging" +) + +// Test and assert predicates +func Test_CdxVexParser(t *testing.T) { + t.Parallel() + ctx := logging.WithLogger(context.Background()) + tests := []struct { + name string + doc *processor.Document + wantPredicates *assembler.IngestPredicates + }{ + { + name: "successfully parsed a cdx_vex document - unaffected package", + doc: &processor.Document{ + Blob: testdata.CycloneDXVEXUnAffected, + }, + wantPredicates: &assembler.IngestPredicates{ + Vex: testdata.CycloneDXUnAffectedVexIngest, + VulnMetadata: testdata.CycloneDXUnAffectedVulnMetadata, + }, + }, + { + name: "successfully parsed a cdx_vex document - affected package", + doc: &processor.Document{ + Blob: testdata.CycloneDXVEXAffected, + }, + wantPredicates: &assembler.IngestPredicates{ + Vex: testdata.CycloneDXAffectedVexIngest, + VulnMetadata: testdata.CycloneDXAffectedVulnMetadata, + CertifyVuln: testdata.CycloneDXAffectedCertifyVuln, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := NewCdxVexParser() + if err := c.Parse(ctx, tt.doc); err != nil { + t.Errorf("CdxVexParser.Parse() error = %v", err) + return + } + + preds := c.GetPredicates(ctx) + if d := cmp.Diff(tt.wantPredicates, preds, testdata.IngestPredicatesCmpOpts...); len(d) != 0 { + t.Errorf("csaf.GetPredicate mismatch values (+got, -expected): %s", d) + } + }) + } +} From 7d73cbc553a40450a7d3e3ecb68242972e2844eb Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Wed, 30 Aug 2023 00:58:24 -0700 Subject: [PATCH 07/11] fix linting issues Signed-off-by: stevemenezes --- pkg/handler/processor/cdx_vex/cdx_vex_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/handler/processor/cdx_vex/cdx_vex_test.go b/pkg/handler/processor/cdx_vex/cdx_vex_test.go index d0879ceb43..10165da50c 100644 --- a/pkg/handler/processor/cdx_vex/cdx_vex_test.go +++ b/pkg/handler/processor/cdx_vex/cdx_vex_test.go @@ -43,7 +43,7 @@ func Test_ValidateSchema(t *testing.T) { doc: processor.Document{ Type: processor.DocumentCdxVex, Format: processor.FormatJSON, - Blob: testdata.CycloneDXExampleVEX, + Blob: testdata.CycloneDXVEXUnAffected, }, }, { @@ -51,7 +51,7 @@ func Test_ValidateSchema(t *testing.T) { doc: processor.Document{ Type: processor.DocumentCdxVex, Format: processor.FormatXML, - Blob: testdata.CycloneDXExampleVEX, + Blob: testdata.CycloneDXVEXUnAffected, }, expectedErr: fmt.Errorf("unable to support parsing of cdx-vex document format: %v", processor.FormatXML), }, From a63c835e133226e1994cef0ae999a4d0ed560b1b Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Wed, 30 Aug 2023 09:50:05 -0700 Subject: [PATCH 08/11] fix unit tests Signed-off-by: stevemenezes --- internal/testing/testdata/testdata.go | 28 +++++++++---------- .../processor/guesser/type_cyclonedx_test.go | 1 + .../parser/cdx_vex/parser_cdx_vex_test.go | 4 +-- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/internal/testing/testdata/testdata.go b/internal/testing/testdata/testdata.go index 904124b5bb..0cff19ba14 100644 --- a/internal/testing/testdata/testdata.go +++ b/internal/testing/testdata/testdata.go @@ -240,7 +240,7 @@ var ( "buildType": "https://github.com/Attestations/GitHubActionsWorkflow@v1", "invocation": { "configSource": { - "uri": "githttps://github.com/curl/curl-docker@master", + "uri": "git+https://github.com/curl/curl-docker@master", "digest": { "sha1": "d6525c840a62b398424a78d792f457477135d0cf" }, "entryPoint": "build.yaml:maketgz" } @@ -253,7 +253,7 @@ var ( }, "materials": [ { - "uri": "githttps://github.com/curl/curl-docker@master", + "uri": "git+https://github.com/curl/curl-docker@master", "digest": { "sha1": "24279c5185ddc042896e3748f47fa89b48c1c14e" } }, { "uri": "github_hosted_vm:ubuntu-18.04:20210123.1", @@ -293,7 +293,7 @@ var ( }, "resolvedDependencies": [ { - "uri": "githttps://github.com/octocat/hello-world@refs/heads/main", + "uri": "git+https://github.com/octocat/hello-world@refs/heads/main", "digest": { "gitCommit": "c27d339ee6075c1f744c5d4b200f7901aad2c369" } @@ -373,7 +373,7 @@ var ( Digest: "24279c5185ddc042896e3748f47fa89b48c1c14e", } - mat1Src, _ = asmhelpers.VcsToSrc("githttps://github.com/curl/curl-docker@master") + mat1Src, _ = asmhelpers.VcsToSrc("git+https://github.com/curl/curl-docker@master") mat2 = model.ArtifactInputSpec{ Algorithm: "sha1", @@ -426,9 +426,9 @@ var ( {Key: "slsa.metadata.completeness.materials", Value: "false"}, {Key: "slsa.buildType", Value: "https://github.com/Attestations/GitHubActionsWorkflow@v1"}, {Key: "slsa.invocation.configSource.entryPoint", Value: "build.yaml:maketgz"}, - {Key: "slsa.invocation.configSource.uri", Value: "githttps://github.com/curl/curl-docker@master"}, + {Key: "slsa.invocation.configSource.uri", Value: "git+https://github.com/curl/curl-docker@master"}, {Key: "slsa.metadata.reproducible", Value: "false"}, - {Key: "slsa.materials.0.uri", Value: "githttps://github.com/curl/curl-docker@master"}, + {Key: "slsa.materials.0.uri", Value: "git+https://github.com/curl/curl-docker@master"}, {Key: "slsa.builder.id", Value: "https://github.com/Attestations/GitHubHostedActions@v1"}, {Key: "slsa.invocation.configSource.digest.sha1", Value: "d6525c840a62b398424a78d792f457477135d0cf"}, {Key: "slsa.metadata.completeness.parameters", Value: "false"}, @@ -493,7 +493,7 @@ var ( StartedOn: &slsa1time, SlsaPredicate: []model.SLSAPredicateInputSpec{ {Key: "slsa.buildDefinition.buildType", Value: "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1"}, - {Key: "slsa.buildDefinition.externalParameters.inputs.build_id", Value: "1.23456768e08"}, + {Key: "slsa.buildDefinition.externalParameters.inputs.build_id", Value: "1.23456768e+08"}, {Key: "slsa.buildDefinition.externalParameters.inputs.deploy_target", Value: "deployment_sys_1a"}, {Key: "slsa.buildDefinition.externalParameters.inputs.perform_deploy", Value: "true"}, {Key: "slsa.buildDefinition.externalParameters.vars.MASCOT", Value: "Mona"}, @@ -503,7 +503,7 @@ var ( {Key: "slsa.buildDefinition.internalParameters.github.actor_id", Value: "1234567"}, {Key: "slsa.buildDefinition.internalParameters.github.event_name", Value: "workflow_dispatch"}, {Key: "slsa.buildDefinition.resolvedDependencies.0.digest.gitCommit", Value: "c27d339ee6075c1f744c5d4b200f7901aad2c369"}, - {Key: "slsa.buildDefinition.resolvedDependencies.0.uri", Value: "githttps://github.com/octocat/hello-world@refs/heads/main"}, + {Key: "slsa.buildDefinition.resolvedDependencies.0.uri", Value: "git+https://github.com/octocat/hello-world@refs/heads/main"}, {Key: "slsa.buildDefinition.resolvedDependencies.1.uri", Value: "https://github.com/actions/virtual-environments/releases/tag/ubuntu20/20220515.1"}, {Key: "slsa.runDetails.builder.id", Value: "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v0.0.1"}, {Key: "slsa.runDetails.metadata.invocationID", Value: "https://github.com/octocat/hello-world/actions/runs/1536140711/attempts/1"}, @@ -740,11 +740,11 @@ var ( // CycloneDX Testdata cdxTopLevelPack, _ = asmhelpers.PurlToPkg("pkg:guac/cdx/gcr.io/distroless/static@sha256:6ad5b696af3ca05a048bd29bf0f623040462638cb0b29c8d702cbb2805687388?tag=nonroot") - cdxTzdataPack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/tzdata@2021a-1deb11u6?arch=all&distro=debian-11") + cdxTzdataPack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/tzdata@2021a-1+deb11u6?arch=all&distro=debian-11") cdxNetbasePack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/netbase@6.3?arch=all&distro=debian-11") - cdxBasefilesPack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/base-files@11.1deb11u5?arch=amd64&distro=debian-11") + cdxBasefilesPack, _ = asmhelpers.PurlToPkg("pkg:deb/debian/base-files@11.1+deb11u5?arch=amd64&distro=debian-11") CdxDeps = []assembler.IsDependencyIngest{ { @@ -753,7 +753,7 @@ var ( DepPkgMatchFlag: model.MatchFlags{Pkg: model.PkgMatchTypeSpecificVersion}, IsDependency: &model.IsDependencyInputSpec{ DependencyType: model.DependencyTypeUnknown, - VersionRange: "11.1deb11u5", + VersionRange: "11.1+deb11u5", Justification: isDepJustifyTopPkgJustification, }, }, @@ -773,7 +773,7 @@ var ( DepPkgMatchFlag: model.MatchFlags{Pkg: model.PkgMatchTypeSpecificVersion}, IsDependency: &model.IsDependencyInputSpec{ DependencyType: model.DependencyTypeUnknown, - VersionRange: "2021a-1deb11u6", + VersionRange: "2021a-1+deb11u6", Justification: isDepJustifyTopPkgJustification, }, }, @@ -2153,7 +2153,7 @@ For the update to take effect, all services linked to the OpenSSL library must b StartedOn: &slsaStartTime, SlsaPredicate: []generated.SLSAPredicateInputSpec{ {Key: "slsa.buildDefinition.buildType", Value: "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1"}, - {Key: "slsa.buildDefinition.externalParameters.inputs.build_id", Value: "1.23456768e08"}, + {Key: "slsa.buildDefinition.externalParameters.inputs.build_id", Value: "1.23456768e+08"}, {Key: "slsa.buildDefinition.externalParameters.inputs.deploy_target", Value: "deployment_sys_1a"}, {Key: "slsa.buildDefinition.externalParameters.inputs.perform_deploy", Value: "true"}, {Key: "slsa.buildDefinition.externalParameters.vars.MASCOT", Value: "Mona"}, @@ -2163,7 +2163,7 @@ For the update to take effect, all services linked to the OpenSSL library must b {Key: "slsa.buildDefinition.internalParameters.github.actor_id", Value: "1234567"}, {Key: "slsa.buildDefinition.internalParameters.github.event_name", Value: "workflow_dispatch"}, {Key: "slsa.buildDefinition.resolvedDependencies.0.digest.gitCommit", Value: "c27d339ee6075c1f744c5d4b200f7901aad2c369"}, - {Key: "slsa.buildDefinition.resolvedDependencies.0.uri", Value: "githttps://github.com/octocat/hello-world@refs/heads/main"}, + {Key: "slsa.buildDefinition.resolvedDependencies.0.uri", Value: "git+https://github.com/octocat/hello-world@refs/heads/main"}, {Key: "slsa.buildDefinition.resolvedDependencies.1.uri", Value: "https://github.com/actions/virtual-environments/releases/tag/ubuntu20/20220515.1"}, {Key: "slsa.runDetails.builder.id", Value: "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v0.0.1"}, {Key: "slsa.runDetails.metadata.invocationID", Value: "https://github.com/octocat/hello-world/actions/runs/1536140711/attempts/1"}, diff --git a/pkg/handler/processor/guesser/type_cyclonedx_test.go b/pkg/handler/processor/guesser/type_cyclonedx_test.go index 552a51d186..63aef46c5d 100644 --- a/pkg/handler/processor/guesser/type_cyclonedx_test.go +++ b/pkg/handler/processor/guesser/type_cyclonedx_test.go @@ -23,6 +23,7 @@ import ( ) func Test_cyclonedxTypeGuesser_GuessDocumentType(t *testing.T) { + t.Parallel() testCases := []struct { name string blob []byte diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go index ac7ce564e0..36d4375976 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go @@ -37,7 +37,7 @@ func Test_CdxVexParser(t *testing.T) { wantPredicates *assembler.IngestPredicates }{ { - name: "successfully parsed a cdx_vex document - unaffected package", + name: "successfully parsed a cdx_vex document containing unaffected package", doc: &processor.Document{ Blob: testdata.CycloneDXVEXUnAffected, }, @@ -47,7 +47,7 @@ func Test_CdxVexParser(t *testing.T) { }, }, { - name: "successfully parsed a cdx_vex document - affected package", + name: "successfully parsed a cdx_vex document containing affected package", doc: &processor.Document{ Blob: testdata.CycloneDXVEXAffected, }, From db18cc2a908e8fabc8d14e8eb182d151e4e84534 Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Wed, 30 Aug 2023 10:02:32 -0700 Subject: [PATCH 09/11] nit typo Signed-off-by: stevemenezes --- pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go index 36d4375976..8856538f90 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go @@ -68,7 +68,7 @@ func Test_CdxVexParser(t *testing.T) { preds := c.GetPredicates(ctx) if d := cmp.Diff(tt.wantPredicates, preds, testdata.IngestPredicatesCmpOpts...); len(d) != 0 { - t.Errorf("csaf.GetPredicate mismatch values (+got, -expected): %s", d) + t.Errorf("cdxVex.GetPredicate mismatch values (+got, -expected): %s", d) } }) } From ae32d499297ea720860b208283d3f7331c0568a8 Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Wed, 30 Aug 2023 22:35:03 -0700 Subject: [PATCH 10/11] address nits, adds cdx-vex xml and relevant tests Signed-off-by: stevemenezes --- .../exampledata/cyclonedx-unaffected-vex.json | 2 +- .../exampledata/cyclonedx-vex-affected.json | 2 +- .../testdata/exampledata/cyclonedx-vex.xml | 57 +++++++++++++++++++ internal/testing/testdata/testdata.go | 21 ++++--- pkg/handler/processor/cdx_vex/cdx_vex.go | 6 ++ pkg/handler/processor/cdx_vex/cdx_vex_test.go | 10 +++- pkg/handler/processor/guesser/guesser_test.go | 20 +++++++ .../processor/guesser/type_cyclonedx.go | 3 + .../processor/guesser/type_cyclonedx_test.go | 6 ++ pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go | 16 +++--- .../parser/cdx_vex/parser_cdx_vex_test.go | 6 +- .../parser/cyclonedx/parser_cyclonedx.go | 4 +- 12 files changed, 130 insertions(+), 23 deletions(-) create mode 100644 internal/testing/testdata/exampledata/cyclonedx-vex.xml diff --git a/internal/testing/testdata/exampledata/cyclonedx-unaffected-vex.json b/internal/testing/testdata/exampledata/cyclonedx-unaffected-vex.json index 14c5067b42..aca23e9549 100644 --- a/internal/testing/testdata/exampledata/cyclonedx-unaffected-vex.json +++ b/internal/testing/testdata/exampledata/cyclonedx-unaffected-vex.json @@ -93,4 +93,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/internal/testing/testdata/exampledata/cyclonedx-vex-affected.json b/internal/testing/testdata/exampledata/cyclonedx-vex-affected.json index 59f3f1fc99..c27d8527c5 100644 --- a/internal/testing/testdata/exampledata/cyclonedx-vex-affected.json +++ b/internal/testing/testdata/exampledata/cyclonedx-vex-affected.json @@ -51,4 +51,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/internal/testing/testdata/exampledata/cyclonedx-vex.xml b/internal/testing/testdata/exampledata/cyclonedx-vex.xml new file mode 100644 index 0000000000..3ff3b8c897 --- /dev/null +++ b/internal/testing/testdata/exampledata/cyclonedx-vex.xml @@ -0,0 +1,57 @@ + + + + + CVE-2018-7489 + + NVD + https://nvd.nist.gov/vuln/detail/CVE-2019-9997 + + + + + NVD + https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H&version=3.0 + + 9.8 + critical + CVSSv3 + AN/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H + + + + 184 + 502 + + FasterXML jackson-databind before 2.7.9.3, 2.8.x before 2.8.11.1 and 2.9.x before 2.9.5 allows unauthenticated remote code execution because of an incomplete fix for the CVE-2017-7525 deserialization flaw. This is exploitable by sending maliciously crafted JSON input to the readValue method of the ObjectMapper, bypassing a blacklist that is ineffective if the c3p0 libraries are available in the classpath. + Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.6.7.5, 2.8.11.1, 2.9.5 or higher. + + + GitHub Commit + https://github.com/FasterXML/jackson-databind/commit/6799f8f10cc78e9af6d443ed6982d00a13f2e7d2 + + + GitHub Issue + https://github.com/FasterXML/jackson-databind/issues/1931 + + + 2021-01-01T00:00:00.000Z + 2021-01-01T00:00:00.000Z + 2021-01-01T00:00:00.000Z + + not_affected + code_not_reachable + + will_not_fix + update + + An optional explanation of why the application is not affected by the vulnerable component. + + + + urn:cdx:3e671687-395b-41f5-a30f-a58921a69b79/1#jackson-databind-2.8.0 + + + + + diff --git a/internal/testing/testdata/testdata.go b/internal/testing/testdata/testdata.go index 0cff19ba14..5bb896c107 100644 --- a/internal/testing/testdata/testdata.go +++ b/internal/testing/testdata/testdata.go @@ -104,6 +104,9 @@ var ( //go:embed exampledata/cyclonedx-vex-affected.json CycloneDXVEXAffected []byte + //go:embed exampledata/cyclonedx-vex.xml + CyloneDXVEXExampleXML []byte + //go:embed exampledata/crev-review.json ITE6CREVExample []byte @@ -145,8 +148,8 @@ var ( Pkg: pkg, Vulnerability: vulnSpec, VexData: &generated.VexStatementInputSpec{ - Status: "NOT_AFFECTED", - VexJustification: "VULNERABLE_CODE_NOT_IN_EXECUTE_PATH", + Status: generated.VexStatusNotAffected, + VexJustification: generated.VexJustificationVulnerableCodeNotInExecutePath, Statement: "Automated dataflow analysis and manual code review indicates that the vulnerable code is not reachable, either directly or indirectly.", StatusNotes: "not_affected:code_not_reachable", KnownSince: parseUTCTime("2020-12-03T00:00:00.000Z"), @@ -157,7 +160,7 @@ var ( { Vulnerability: vulnSpec, VulnMetadata: &generated.VulnerabilityMetadataInputSpec{ - ScoreType: "CVSSv31", + ScoreType: generated.VulnerabilityScoreTypeCvssv31, ScoreValue: 7.5, Timestamp: parseUTCTime("2020-12-03T00:00:00.000Z"), }, @@ -165,7 +168,7 @@ var ( { Vulnerability: vulnSpec, VulnMetadata: &generated.VulnerabilityMetadataInputSpec{ - ScoreType: "CVSSv31", + ScoreType: generated.VulnerabilityScoreTypeCvssv31, ScoreValue: 8.2, Timestamp: parseUTCTime("2020-12-03T00:00:00.000Z"), }, @@ -173,7 +176,7 @@ var ( { Vulnerability: vulnSpec, VulnMetadata: &generated.VulnerabilityMetadataInputSpec{ - ScoreType: "CVSSv31", + ScoreType: generated.VulnerabilityScoreTypeCvssv31, ScoreValue: 0.0, Timestamp: parseUTCTime("2020-12-03T00:00:00.000Z"), }, @@ -189,7 +192,7 @@ var ( VulnerabilityID: "cve-2021-44228", } vexDataAffected = &generated.VexStatementInputSpec{ - Status: "AFFECTED", + Status: generated.VexStatusAffected, Statement: "Versions of Product ABC are affected by the vulnerability. Customers are advised to upgrade to the latest release.", StatusNotes: "exploitable:", } @@ -209,7 +212,7 @@ var ( { Vulnerability: vulnSpecAffected, VulnMetadata: &generated.VulnerabilityMetadataInputSpec{ - ScoreType: "CVSSv31", + ScoreType: generated.VulnerabilityScoreTypeCvssv31, ScoreValue: 10, }, }, @@ -2024,8 +2027,8 @@ var ( }, Vulnerability: &model.VulnerabilityInputSpec{Type: "cve", VulnerabilityID: "cve-2023-0286"}, VexData: &model.VexStatementInputSpec{ - Status: "AFFECTED", - VexJustification: "NOT_PROVIDED", + Status: generated.VexStatusAffected, + VexJustification: generated.VexJustificationNotProvided, Statement: `For details on how to apply this update, which includes the changes described in this advisory, refer to: https://access.redhat.com/articles/11258 diff --git a/pkg/handler/processor/cdx_vex/cdx_vex.go b/pkg/handler/processor/cdx_vex/cdx_vex.go index 43aa115ec3..7654d6acbe 100644 --- a/pkg/handler/processor/cdx_vex/cdx_vex.go +++ b/pkg/handler/processor/cdx_vex/cdx_vex.go @@ -16,6 +16,7 @@ package cdx_vex import ( + "bytes" "encoding/json" "fmt" @@ -39,6 +40,11 @@ func (p *CdxVexProcessor) ValidateSchema(d *processor.Document) error { return nil } return err + case processor.FormatXML: + reader := bytes.NewReader(d.Blob) + bom := new(cdx.BOM) + decoder := cdx.NewBOMDecoder(reader, cdx.BOMFileFormatXML) + return decoder.Decode(bom) } return fmt.Errorf("unable to support parsing of cdx-vex document format: %v", d.Format) diff --git a/pkg/handler/processor/cdx_vex/cdx_vex_test.go b/pkg/handler/processor/cdx_vex/cdx_vex_test.go index 10165da50c..e7259391f9 100644 --- a/pkg/handler/processor/cdx_vex/cdx_vex_test.go +++ b/pkg/handler/processor/cdx_vex/cdx_vex_test.go @@ -39,13 +39,21 @@ func Test_ValidateSchema(t *testing.T) { expectedErr: fmt.Errorf("expected document type: %v, actual document type: %v", processor.DocumentCdxVex, processor.DocumentCsaf), }, { - name: "Successful validation of cdx-vex document", + name: "Successful validation of cdx-vex json document", doc: processor.Document{ Type: processor.DocumentCdxVex, Format: processor.FormatJSON, Blob: testdata.CycloneDXVEXUnAffected, }, }, + { + name: "Successful validation of cdx-vex xml document", + doc: processor.Document{ + Type: processor.DocumentCdxVex, + Format: processor.FormatXML, + Blob: testdata.CyloneDXVEXExampleXML, + }, + }, { name: "Invalid format for cdx-vex document", doc: processor.Document{ diff --git a/pkg/handler/processor/guesser/guesser_test.go b/pkg/handler/processor/guesser/guesser_test.go index edacfaa923..b0cdb4e6e2 100644 --- a/pkg/handler/processor/guesser/guesser_test.go +++ b/pkg/handler/processor/guesser/guesser_test.go @@ -209,6 +209,26 @@ func Test_GuessDocument(t *testing.T) { }, expectedType: processor.DocumentCsaf, expectedFormat: processor.FormatJSON, + }, { + name: "valid cdx vex json Document", + document: &processor.Document{ + Blob: testdata.CycloneDXVEXUnAffected, + Type: processor.DocumentUnknown, + Format: processor.FormatUnknown, + SourceInformation: processor.SourceInformation{}, + }, + expectedType: processor.DocumentCdxVex, + expectedFormat: processor.FormatJSON, + }, { + name: "valid cdx vex xml Document", + document: &processor.Document{ + Blob: testdata.CyloneDXVEXExampleXML, + Type: processor.DocumentUnknown, + Format: processor.FormatUnknown, + SourceInformation: processor.SourceInformation{}, + }, + expectedType: processor.DocumentCdxVex, + expectedFormat: processor.FormatXML, }} for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/handler/processor/guesser/type_cyclonedx.go b/pkg/handler/processor/guesser/type_cyclonedx.go index 3131b0ca34..9b6586b76f 100644 --- a/pkg/handler/processor/guesser/type_cyclonedx.go +++ b/pkg/handler/processor/guesser/type_cyclonedx.go @@ -48,6 +48,9 @@ func (_ *cycloneDXTypeGuesser) GuessDocumentType(blob []byte, format processor.F decoder := cdx.NewBOMDecoder(reader, cdx.BOMFileFormatXML) err := decoder.Decode(bom) if err == nil && strings.HasPrefix(bom.XMLNS, "http://cyclonedx.org/schema/bom/") { + if bom.Vulnerabilities != nil { + return processor.DocumentCdxVex + } return processor.DocumentCycloneDX } } diff --git a/pkg/handler/processor/guesser/type_cyclonedx_test.go b/pkg/handler/processor/guesser/type_cyclonedx_test.go index 63aef46c5d..9cfefb55ce 100644 --- a/pkg/handler/processor/guesser/type_cyclonedx_test.go +++ b/pkg/handler/processor/guesser/type_cyclonedx_test.go @@ -78,6 +78,12 @@ func Test_cyclonedxTypeGuesser_GuessDocumentType(t *testing.T) { format: processor.FormatJSON, expected: processor.DocumentCdxVex, }, + { + name: "valid cyclonedx vex xml Document", + blob: testdata.CyloneDXVEXExampleXML, + format: processor.FormatXML, + expected: processor.DocumentCdxVex, + }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go index fe685af66e..84272fac80 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex.go @@ -17,7 +17,6 @@ package cdx_vex import ( "context" - "encoding/json" "fmt" "strings" "time" @@ -29,6 +28,7 @@ import ( "github.com/guacsec/guac/pkg/assembler/helpers" "github.com/guacsec/guac/pkg/handler/processor" "github.com/guacsec/guac/pkg/ingestor/parser/common" + "github.com/guacsec/guac/pkg/ingestor/parser/cyclonedx" "github.com/guacsec/guac/pkg/logging" ) @@ -59,11 +59,11 @@ func NewCdxVexParser() common.DocumentParser { // Parse breaks out the document into the graph components func (c *cdxVexParser) Parse(ctx context.Context, doc *processor.Document) error { c.doc = doc - err := json.Unmarshal(doc.Blob, &c.cdxBom) + bom, err := cyclonedx.ParseCycloneDXBOM(doc) if err != nil { - return fmt.Errorf("unable to unmarshal CDX VEX document: %w", err) + return fmt.Errorf("unable to parse cdx-vex document: %w", err) } - + c.cdxBom = bom return nil } @@ -73,11 +73,11 @@ func (c *cdxVexParser) GetIdentities(ctx context.Context) []common.TrustInformat } func (c *cdxVexParser) GetIdentifiers(ctx context.Context) (*common.IdentifierStrings, error) { - return nil, fmt.Errorf("not yet implemented") + return c.identifierStrings, nil } // Get package name and range versions to create package input spec for the affected packages. -func getAffectedPackages(ctx context.Context, vulnInput *generated.VulnerabilityInputSpec, vexData generated.VexStatementInputSpec, affectsObj cdx.Affects) *[]assembler.VexIngest { +func (c *cdxVexParser) getAffectedPackages(ctx context.Context, vulnInput *generated.VulnerabilityInputSpec, vexData generated.VexStatementInputSpec, affectsObj cdx.Affects) *[]assembler.VexIngest { logger := logging.FromContext(ctx) var pkgRef string // TODO: retrieve purl from metadata if present - https://github.com/guacsec/guac/blob/main/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go#L76 @@ -104,6 +104,7 @@ func getAffectedPackages(ctx context.Context, vulnInput *generated.Vulnerability return nil } + c.identifierStrings.PurlStrings = append(c.identifierStrings.PurlStrings, pkgURL) return &[]assembler.VexIngest{{VexData: &vexData, Vulnerability: vulnInput, Pkg: pkg}} } @@ -133,6 +134,7 @@ func getAffectedPackages(ctx context.Context, vulnInput *generated.Vulnerability } vi.Pkg = pkg viList = append(viList, *vi) + c.identifierStrings.PurlStrings = append(c.identifierStrings.PurlStrings, pkgURL) } return &viList @@ -177,7 +179,7 @@ func (c *cdxVexParser) GetPredicates(ctx context.Context) *assembler.IngestPredi } for _, affect := range *vulnerability.Affects { - vi := getAffectedPackages(ctx, vuln, vd, affect) + vi := c.getAffectedPackages(ctx, vuln, vd, affect) if vi == nil { continue } diff --git a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go index 8856538f90..af5cc88ab7 100644 --- a/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go +++ b/pkg/ingestor/parser/cdx_vex/parser_cdx_vex_test.go @@ -39,7 +39,8 @@ func Test_CdxVexParser(t *testing.T) { { name: "successfully parsed a cdx_vex document containing unaffected package", doc: &processor.Document{ - Blob: testdata.CycloneDXVEXUnAffected, + Blob: testdata.CycloneDXVEXUnAffected, + Format: processor.FormatJSON, }, wantPredicates: &assembler.IngestPredicates{ Vex: testdata.CycloneDXUnAffectedVexIngest, @@ -49,7 +50,8 @@ func Test_CdxVexParser(t *testing.T) { { name: "successfully parsed a cdx_vex document containing affected package", doc: &processor.Document{ - Blob: testdata.CycloneDXVEXAffected, + Blob: testdata.CycloneDXVEXAffected, + Format: processor.FormatJSON, }, wantPredicates: &assembler.IngestPredicates{ Vex: testdata.CycloneDXAffectedVexIngest, diff --git a/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go b/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go index f025454f61..9bab80de0b 100644 --- a/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go +++ b/pkg/ingestor/parser/cyclonedx/parser_cyclonedx.go @@ -53,7 +53,7 @@ func NewCycloneDXParser() common.DocumentParser { // Parse breaks out the document into the graph components func (c *cyclonedxParser) Parse(ctx context.Context, doc *processor.Document) error { c.doc = doc - cdxBom, err := parseCycloneDXBOM(doc) + cdxBom, err := ParseCycloneDXBOM(doc) if err != nil { return fmt.Errorf("failed to parse cyclonedx BOM: %w", err) } @@ -180,7 +180,7 @@ func (c *cyclonedxParser) getPackages(cdxBom *cdx.BOM) error { return nil } -func parseCycloneDXBOM(doc *processor.Document) (*cdx.BOM, error) { +func ParseCycloneDXBOM(doc *processor.Document) (*cdx.BOM, error) { bom := cdx.BOM{} switch doc.Format { case processor.FormatJSON: From 7dc8f50777e5fea9b3c22f8acaf12446a6378124 Mon Sep 17 00:00:00 2001 From: stevemenezes Date: Wed, 30 Aug 2023 23:06:17 -0700 Subject: [PATCH 11/11] fix tests Signed-off-by: stevemenezes --- pkg/handler/processor/cdx_vex/cdx_vex_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/handler/processor/cdx_vex/cdx_vex_test.go b/pkg/handler/processor/cdx_vex/cdx_vex_test.go index e7259391f9..34ae3646aa 100644 --- a/pkg/handler/processor/cdx_vex/cdx_vex_test.go +++ b/pkg/handler/processor/cdx_vex/cdx_vex_test.go @@ -58,10 +58,10 @@ func Test_ValidateSchema(t *testing.T) { name: "Invalid format for cdx-vex document", doc: processor.Document{ Type: processor.DocumentCdxVex, - Format: processor.FormatXML, + Format: processor.FormatUnknown, Blob: testdata.CycloneDXVEXUnAffected, }, - expectedErr: fmt.Errorf("unable to support parsing of cdx-vex document format: %v", processor.FormatXML), + expectedErr: fmt.Errorf("unable to support parsing of cdx-vex document format: %v", processor.FormatUnknown), }, }