Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions utils/results/conversion/simplejsonparser/simplejsonparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func (sjc *CmdResultsSimpleJsonConverter) ParseSbomLicenses(sbom *cyclonedx.BOM)
LicenseKey: license.License.ID,
LicenseName: name,
ImpactedDependencyDetails: formats.ImpactedDependencyDetails{
ImpactedDependencyName: strings.ReplaceAll(compName, "/", ":"),
ImpactedDependencyName: normalizeCdxComponentName(compName, compType),
ImpactedDependencyVersion: compVersion,
ImpactedDependencyType: results.FormalTechOrCdxCompType(compType, sjc.pretty),
Components: results.ExtractComponentDirectComponentsInBOM(bomIndex, component, impactPaths),
Expand Down Expand Up @@ -234,7 +234,7 @@ func (sjc *CmdResultsSimpleJsonConverter) createVulnerabilityOrViolationRowFromC
Summary: summary,
ImpactedDependencyDetails: formats.ImpactedDependencyDetails{
SeverityDetails: severityutils.GetAsDetails(severity, applicabilityStatus, sjc.pretty),
ImpactedDependencyName: strings.ReplaceAll(compName, "/", ":"),
ImpactedDependencyName: normalizeCdxComponentName(compName, compType),
ImpactedDependencyVersion: compVersion,
ImpactedDependencyType: results.FormalTechOrCdxCompType(compType, sjc.pretty),
Components: directComponents,
Expand Down Expand Up @@ -272,7 +272,7 @@ func (sjc *CmdResultsSimpleJsonConverter) createLicenseViolationRow(licenseKey,
LicenseName: licenseName,
ImpactedDependencyDetails: formats.ImpactedDependencyDetails{
SeverityDetails: severityutils.GetAsDetails(severity, jasutils.NotScanned, sjc.pretty),
ImpactedDependencyName: strings.ReplaceAll(compName, "/", ":"),
ImpactedDependencyName: normalizeCdxComponentName(compName, compType),
ImpactedDependencyVersion: compVersion,
ImpactedDependencyType: results.FormalTechOrCdxCompType(compType, sjc.pretty),
Components: directComponents,
Expand All @@ -288,7 +288,7 @@ func (sjc *CmdResultsSimpleJsonConverter) createOpRiskViolationRow(opRiskViolati
ViolationContext: convertToViolationContext(opRiskViolation.Violation),
ImpactedDependencyDetails: formats.ImpactedDependencyDetails{
SeverityDetails: severityutils.GetAsDetails(opRiskViolation.Severity, jasutils.NotScanned, sjc.pretty),
ImpactedDependencyName: strings.ReplaceAll(compName, "/", ":"),
ImpactedDependencyName: normalizeCdxComponentName(compName, compType),
ImpactedDependencyVersion: compVersion,
ImpactedDependencyType: results.FormalTechOrCdxCompType(compType, sjc.pretty),
Components: opRiskViolation.DirectComponents,
Expand Down Expand Up @@ -731,3 +731,14 @@ func sortSourceCodeRow(rows []formats.SourceCodeRow) {
return rows[i].File > rows[j].File
})
}

// Converts a PURL-derived component name to Xray-compatible format.
// SplitPackageURL joins namespace and name with "/".
// For Maven/Gradle (package type "maven"), Xray and package updaters expect "groupId:artifactId" with ":" as the separator.
// For all other ecosystems (Go, npm, etc.) the "/" is semantically part of the package identifier and must be preserved.
func normalizeCdxComponentName(compName, compType string) string {
if compType == techutils.Maven.String() {
return strings.Replace(compName, "/", ":", 1)
}
return compName
}
8 changes: 7 additions & 1 deletion utils/xray/remediation/cdxremediation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package remediation

import (
"fmt"
"strings"

"github.com/CycloneDX/cyclonedx-go"

Expand Down Expand Up @@ -58,6 +59,11 @@ func matchVulnerabilityToRemediationOptions(bom *cyclonedx.BOM, vulnerability *c
}
}

// TODO remove this when https://jfrog-int.atlassian.net/browse/XRAY-137306 is done, as fix versions should be already normalized when returning from remediation API.
func normalizeVersion(version string) string {
return strings.TrimPrefix(version, "v")
}

func getAffectComponentCveRemediationStepsByFixedVersion(cve string, component cyclonedx.Component, cveRemediationOptions []utils.Option, strategy utils.FixStrategy) (steps []utils.OptionStep) {
for _, cveRemediationOption := range cveRemediationOptions {
if cveRemediationOption.Type != utils.InLock {
Expand All @@ -78,7 +84,7 @@ func getAffectComponentCveRemediationStepsByFixedVersion(cve string, component c
continue
}
// We only want FixVersion step type
if step.StepType == utils.FixVersion && step.PkgVersion.Name == component.Name && step.PkgVersion.Version == component.Version {
if step.StepType == utils.FixVersion && step.PkgVersion.Name == component.Name && normalizeVersion(step.PkgVersion.Version) == normalizeVersion(component.Version) {
steps = append(steps, step)
}
}
Expand Down
48 changes: 48 additions & 0 deletions utils/xray/remediation/cdxremediation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,54 @@ func TestMatchVulnerabilityToRemediationOptions(t *testing.T) {
expectedAffectedVersions: nil,
description: "Should ignore remediation steps when component name doesn't match",
},
{
name: "Go component with v-prefix version mismatch between API and BOM",
bom: &cyclonedx.BOM{
Components: &[]cyclonedx.Component{
{
BOMRef: "golang-component-ref",
Name: "golang.org/x/crypto",
Version: "0.33.0",
},
},
},
vulnerability: &cyclonedx.Vulnerability{
ID: "CVE-2023-1234",
Affects: &[]cyclonedx.Affects{
{
Ref: "golang-component-ref",
},
},
},
remediationOptions: utils.CveRemediationResponse{
"CVE-2023-1234": []utils.Option{
{
Type: utils.InLock,
Steps: map[utils.FixStrategy][]utils.OptionStep{
utils.QuickestFixStrategy: {
{
StepType: utils.FixVersion,
PkgVersion: utils.PackageVersionKey{
Name: "golang.org/x/crypto",
Version: "v0.33.0",
},
UpgradeTo: utils.PackageVersionKey{
Version: "v0.40.0",
},
},
},
},
},
},
},
expectedAffectedVersions: []cyclonedx.AffectedVersions{
{
Version: "v0.40.0",
Status: cyclonedx.VulnerabilityStatusNotAffected,
},
},
description: "Should match Go component when API returns v-prefixed version but BOM stores without prefix",
},
{
name: "Component version mismatch should be ignored",
bom: &cyclonedx.BOM{
Expand Down
Loading