Skip to content

Commit ed6afd2

Browse files
CalamarBicefalopaulrosca-snyk
authored andcommitted
wip
1 parent 40d59d1 commit ed6afd2

File tree

3 files changed

+315
-215
lines changed

3 files changed

+315
-215
lines changed

internal/remediation/model.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,31 @@ package remediation
22

33
// Input
44

5+
/**
6+
* Finding represents a vulnerability for a given package & version.
7+
*
8+
* If a finding is introduced through multiple paths, a single finding with several `DependencyPath` entries must be constructed.
9+
*/
510
type Finding struct {
6-
Package Package
7-
Severity Severity
8-
Title string
9-
DependencyPath DependencyPath
10-
11-
// Snyk vuln ID
12-
VulnId string
11+
Package Package
12+
Vulnerability Vulnerability
13+
DependencyPaths []DependencyPath
1314

1415
// All versions containing a fix for this problem
1516
InitiallyFixedInVersions []string
1617
Fix Fix
18+
PackageManager PackageManager
1719
}
20+
21+
type PackageManager string
22+
1823
type Fix interface {
1924
Outcome() Outcome
2025
}
2126

2227
type PinFix struct {
2328
outcome Outcome
24-
pinAction PinAction
29+
PinAction PinAction
2530
}
2631

2732
func (pf PinFix) Outcome() Outcome {
@@ -31,7 +36,7 @@ func (pf PinFix) Outcome() Outcome {
3136
func NewPinFix(outcome Outcome, action PinAction) Fix {
3237
return PinFix{
3338
outcome: outcome,
34-
pinAction: action,
39+
PinAction: action,
3540
}
3641
}
3742

@@ -75,7 +80,7 @@ type Upgrade struct {
7580
From Package
7681
To Package
7782

78-
Fixes []*VulnerabilityInPackage
83+
Fixes []VulnerabilityInPackage
7984
}
8085

8186
type VulnerabilityInPackage struct {
@@ -89,6 +94,7 @@ type Package struct {
8994
Name string
9095
Version string
9196
}
97+
9298
type Vulnerability struct {
9399
ID string
94100
Name string
Lines changed: 144 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,164 +1,172 @@
11
package remediation
22

33
import (
4-
"errors"
54
"fmt"
6-
"slices"
75

8-
"github.com/snyk/go-application-framework/pkg/apiclients/testapi"
9-
10-
"github.com/snyk/cli-extension-os-flows/internal/legacy/definitions"
11-
"github.com/snyk/cli-extension-os-flows/internal/semver/shared"
6+
"github.com/snyk/cli-extension-os-flows/internal/semver"
127
)
138

14-
func FixesToRemediationSummary(findings []Finding, semver shared.Runtime) Summary {
15-
calculatePins(findings, semver)
16-
return Summary{}
17-
}
18-
19-
func getDepedencyPathEvidence(finding testapi.FindingData) (*testapi.DependencyPathEvidence, error) {
20-
for _, ev := range finding.Attributes.Evidence {
21-
disc, err := ev.Discriminator()
22-
if err != nil {
23-
return nil, err
24-
}
25-
26-
if disc != string(testapi.DependencyPath) {
27-
continue
28-
}
29-
30-
depPath, err := ev.AsDependencyPathEvidence()
31-
if err != nil {
32-
return nil, err
33-
}
34-
35-
return &depPath, nil
9+
func FixesToRemediationSummary(findings []Finding) (Summary, error) {
10+
pins, err := calculatePins(findings)
11+
if err != nil {
12+
return Summary{}, err
3613
}
37-
return nil, fmt.Errorf("no depedency path evidence was found for finding: %s", finding.Id)
14+
return Summary{Pins: pins}, err
3815
}
3916

40-
func getSnykVuln(finding testapi.FindingData) (*testapi.SnykVulnProblem, error) {
41-
for _, prob := range finding.Attributes.Problems {
42-
disc, err := prob.Discriminator()
43-
if err != nil {
44-
return nil, err
45-
}
17+
type packageKey string
4618

47-
if disc != string(testapi.SnykVuln) {
48-
continue
49-
}
50-
51-
vuln, err := prob.AsSnykVulnProblem()
52-
if err != nil {
53-
return nil, err
54-
}
55-
56-
return &vuln, nil
57-
}
58-
return nil, nil
19+
func NewPackageKey(p Package) packageKey {
20+
return packageKey(fmt.Sprintf("%s@%s", p.Name, p.Version))
5921
}
6022

61-
func calculatePins(findings []Finding, semver shared.Runtime) (map[string]definitions.PinRemediation, error) {
62-
pin := make(map[string]Upgrade)
23+
func calculatePins(findings []Finding) ([]Upgrade, error) {
24+
var output []Upgrade
25+
var pinMap = make(map[packageKey]Upgrade)
6326
for _, finding := range findings {
64-
if len(finding.DependencyPath) < 2 {
65-
continue
66-
}
27+
vulnerablePackage := finding.Package
28+
key := NewPackageKey(vulnerablePackage)
6729

68-
// vuln, err := getSnykVuln(finding)
69-
// if err != nil {
70-
// return nil, err
71-
// }
72-
//
73-
// if vuln == nil {
74-
// continue
75-
// }
76-
77-
key := fmt.Sprintf("%s@%s", finding.Package.Name, finding.Package.Version)
78-
79-
var currentUpgradeToVersion string
80-
vulnPin, pinExistsForPkg := pin[key]
81-
if pinExistsForPkg {
82-
currentUpgradeToVersion = vulnPin.To.Version
83-
}
84-
85-
if len(finding.InitiallyFixedInVersions) == 0 {
86-
continue
87-
}
30+
upgrade, upgradeExists := pinMap[key]
8831

89-
var sortErr error
90-
slices.SortStableFunc(finding.InitiallyFixedInVersions, func(a, b string) int {
91-
comp, err := semver.Compare(a, b)
92-
if err != nil {
93-
sortErr = errors.Join(sortErr, err)
94-
}
95-
return comp
96-
})
97-
if sortErr != nil {
98-
return nil, fmt.Errorf("failed to sort fixedIn values: %w", sortErr)
32+
vulnerabilityInPackage := VulnerabilityInPackage{
33+
VulnerablePackage: vulnerablePackage,
34+
Vulnerability: finding.Vulnerability,
35+
IntroducedThrough: finding.DependencyPaths,
9936
}
10037

101-
var newVersion string
102-
for _, fixVersion := range finding.InitiallyFixedInVersions {
103-
comp, err := semver.Compare(fixVersion, finding.Package.Version)
38+
if upgradeExists {
39+
highestVersion, err := getMaxVersion(finding.PackageManager, upgrade.To.Version, finding.Fix.(PinFix).PinAction.Package.Version)
10440
if err != nil {
10541
return nil, err
10642
}
43+
upgrade.To.Version = highestVersion
44+
upgrade.Fixes = append(upgrade.Fixes, vulnerabilityInPackage)
10745

108-
if comp > 0 {
109-
newVersion = fixVersion
110-
break
111-
}
112-
}
113-
114-
if newVersion == "" {
115-
continue
116-
}
117-
118-
if !pinExistsForPkg {
119-
pin[key] = Upgrade{
120-
From: finding.Package,
121-
To: Package{
122-
Name: finding.Package.Name,
123-
Version: newVersion,
124-
},
125-
Fixes: []*VulnerabilityInPackage{
126-
{
127-
VulnerablePackage: finding.Package,
128-
Vulnerability: Vulnerability{
129-
ID: finding.VulnId,
130-
Name: finding.Title,
131-
Severity: finding.Severity,
132-
},
133-
IntroducedThrough: []DependencyPath{finding.DependencyPath},
134-
},
135-
},
136-
}
46+
pinMap[key] = upgrade
13747
} else {
138-
var fixForVuln *VulnerabilityInPackage
139-
for _, vulnInPkg := range vulnPin.Fixes {
140-
if vulnInPkg.Vulnerability.ID == finding.VulnId {
141-
fixForVuln := vulnInPkg
142-
break
143-
}
144-
}
145-
if fixForVuln {
146-
fixForVuln.IntroducedThrough = append(fixForVuln.IntroducedThrough, fi)
147-
}
148-
vulnPin.Vulns = append(vulnPin.Vulns, vuln.Id)
14948

150-
v, err := semver.Compare(newVersion, currentUpgradeToVersion)
151-
if err != nil {
152-
return nil, err
153-
}
154-
if v > 0 {
155-
vulnPin.UpgradeTo = fmt.Sprintf("%s@%s", vuln.PackageName, newVersion)
49+
pinMap[key] = Upgrade{
50+
From: vulnerablePackage,
51+
To: finding.Fix.(PinFix).PinAction.Package,
52+
Fixes: []VulnerabilityInPackage{vulnerabilityInPackage},
15653
}
157-
158-
// vulnPin is a copy of the value from the map,
159-
// so we need to store it back after modifying it
160-
pin[key] = vulnPin
16154
}
16255
}
163-
return pin, nil
56+
57+
for _, pin := range pinMap {
58+
output = append(output, pin)
59+
}
60+
return output, nil
61+
//pin := make(map[string]Upgrade)
62+
//for _, finding := range findings {
63+
// if len(finding.DependencyPath) < 2 {
64+
// continue
65+
// }
66+
//
67+
// key := fmt.Sprintf("%s@%s", finding.Package.Name, finding.Package.Version)
68+
//
69+
// var currentUpgradeToVersion string
70+
// vulnPin, pinExistsForPkg := pin[key]
71+
// if pinExistsForPkg {
72+
// currentUpgradeToVersion = vulnPin.To.Version
73+
// }
74+
//
75+
// if len(finding.InitiallyFixedInVersions) == 0 {
76+
// continue
77+
// }
78+
//
79+
// var sortErr error
80+
// slices.SortStableFunc(finding.InitiallyFixedInVersions, func(a, b string) int {
81+
// comp, err := semver.Compare(a, b)
82+
// if err != nil {
83+
// sortErr = errors.Join(sortErr, err)
84+
// }
85+
// return comp
86+
// })
87+
// if sortErr != nil {
88+
// return nil, fmt.Errorf("failed to sort fixedIn values: %w", sortErr)
89+
// }
90+
//
91+
// var newVersion string
92+
// for _, fixVersion := range finding.InitiallyFixedInVersions {
93+
// comp, err := semver.Compare(fixVersion, finding.Package.Version)
94+
// if err != nil {
95+
// return nil, err
96+
// }
97+
//
98+
// if comp > 0 {
99+
// newVersion = fixVersion
100+
// break
101+
// }
102+
// }
103+
//
104+
// if newVersion == "" {
105+
// continue
106+
// }
107+
//
108+
// if !pinExistsForPkg {
109+
// pin[key] = Upgrade{
110+
// From: finding.Package,
111+
// To: Package{
112+
// Name: finding.Package.Name,
113+
// Version: newVersion,
114+
// },
115+
// Fixes: []*VulnerabilityInPackage{
116+
// {
117+
// VulnerablePackage: finding.Package,
118+
// Vulnerability: Vulnerability{
119+
// ID: finding.VulnId,
120+
// Name: finding.Title,
121+
// Severity: finding.Severity,
122+
// },
123+
// IntroducedThrough: []DependencyPath{finding.DependencyPath},
124+
// },
125+
// },
126+
// }
127+
// } else {
128+
// var fixForVuln *VulnerabilityInPackage
129+
// for _, vulnInPkg := range vulnPin.Fixes {
130+
// if vulnInPkg.Vulnerability.ID == finding.VulnId {
131+
// fixForVuln := vulnInPkg
132+
// break
133+
// }
134+
// }
135+
// if fixForVuln {
136+
// fixForVuln.IntroducedThrough = append(fixForVuln.IntroducedThrough, fi)
137+
// }
138+
// vulnPin.Vulns = append(vulnPin.Vulns, vuln.Id)
139+
//
140+
// v, err := semver.Compare(newVersion, currentUpgradeToVersion)
141+
// if err != nil {
142+
// return nil, err
143+
// }
144+
// if v > 0 {
145+
// vulnPin.UpgradeTo = fmt.Sprintf("%s@%s", vuln.PackageName, newVersion)
146+
// }
147+
//
148+
// // vulnPin is a copy of the value from the map,
149+
// // so we need to store it back after modifying it
150+
// pin[key] = vulnPin
151+
// }
152+
//}
153+
//return pin, nil
154+
}
155+
156+
func getMaxVersion(packageManager PackageManager, v1 string, v2 string) (string, error) {
157+
semverResolver, err := semver.GetSemver(string(packageManager))
158+
if err != nil {
159+
return "", err
160+
}
161+
var version string
162+
compare, err := semverResolver.Compare(v1, v2)
163+
if err != nil {
164+
return "", err
165+
}
166+
if compare >= 0 {
167+
version = v1
168+
} else {
169+
version = v2
170+
}
171+
return version, nil
164172
}

0 commit comments

Comments
 (0)