Merge pull request #33 from Quentin-M/insertvulns
database: Improve InsertVulnerabilities.
This commit is contained in:
commit
46fffdfc81
@ -96,7 +96,6 @@ func (av *AbstractVulnerability) ToVulnerability(fixedInNodes []string) *Vulnera
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InsertVulnerabilities inserts or updates several vulnerabilities in the database in one transaction
|
// InsertVulnerabilities inserts or updates several vulnerabilities in the database in one transaction
|
||||||
// It ensures that a vulnerability can't be fixed by two packages belonging the same Branch.
|
|
||||||
// During an update, if the vulnerability was previously fixed by a version in a branch and a new package of that branch is specified, the previous one is deleted
|
// During an update, if the vulnerability was previously fixed by a version in a branch and a new package of that branch is specified, the previous one is deleted
|
||||||
// Otherwise, it simply adds the defined packages, there is currently no way to delete affected packages.
|
// Otherwise, it simply adds the defined packages, there is currently no way to delete affected packages.
|
||||||
//
|
//
|
||||||
@ -110,13 +109,15 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
var err error
|
var err error
|
||||||
t := cayley.NewTransaction()
|
t := cayley.NewTransaction()
|
||||||
cachedVulnerabilities := make(map[string]*Vulnerability)
|
cachedVulnerabilities := make(map[string]*Vulnerability)
|
||||||
|
|
||||||
|
var notifications []Notification
|
||||||
newVulnerabilityNotifications := make(map[string]*NewVulnerabilityNotification)
|
newVulnerabilityNotifications := make(map[string]*NewVulnerabilityNotification)
|
||||||
vulnerabilityPriorityIncreasedNotifications := make(map[string]*VulnerabilityPriorityIncreasedNotification)
|
vulnerabilityPriorityIncreasedNotifications := make(map[string]*VulnerabilityPriorityIncreasedNotification)
|
||||||
vulnerabilityPackageChangedNotifications := make(map[string]*VulnerabilityPackageChangedNotification)
|
vulnerabilityPackageChangedNotifications := make(map[string]*VulnerabilityPackageChangedNotification)
|
||||||
|
|
||||||
// Iterate over all the vulnerabilities we need to insert/update
|
// Iterate over all the vulnerabilities we need to insert/update
|
||||||
for _, vulnerability := range vulnerabilities {
|
for _, vulnerability := range vulnerabilities {
|
||||||
// Is the vulnerability already existing ?
|
// Check if the vulnerability already exists
|
||||||
existingVulnerability, _ := cachedVulnerabilities[vulnerability.ID]
|
existingVulnerability, _ := cachedVulnerabilities[vulnerability.ID]
|
||||||
if existingVulnerability == nil {
|
if existingVulnerability == nil {
|
||||||
existingVulnerability, err = FindOneVulnerability(vulnerability.ID, FieldVulnerabilityAll)
|
existingVulnerability, err = FindOneVulnerability(vulnerability.ID, FieldVulnerabilityAll)
|
||||||
@ -128,23 +129,6 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow inserting/updating a vulnerability which is fixed in two packages of the same branch
|
|
||||||
if len(vulnerability.FixedInNodes) > 0 {
|
|
||||||
fixedInPackages, err := FindAllPackagesByNodes(vulnerability.FixedInNodes, []string{FieldPackageOS, FieldPackageName})
|
|
||||||
if err != nil {
|
|
||||||
return []Notification{}, err
|
|
||||||
}
|
|
||||||
fixedInBranches := make(map[string]struct{})
|
|
||||||
for _, fixedInPackage := range fixedInPackages {
|
|
||||||
branch := fixedInPackage.Branch()
|
|
||||||
if _, branchExists := fixedInBranches[branch]; branchExists {
|
|
||||||
log.Warningf("could not insert vulnerability %s because it is fixed in two packages of the same branch", vulnerability.ID)
|
|
||||||
return []Notification{}, cerrors.NewBadRequestError("could not insert a vulnerability which is fixed in two packages of the same branch")
|
|
||||||
}
|
|
||||||
fixedInBranches[branch] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert/Update vulnerability
|
// Insert/Update vulnerability
|
||||||
if existingVulnerability == nil {
|
if existingVulnerability == nil {
|
||||||
// The vulnerability does not exist, create it
|
// The vulnerability does not exist, create it
|
||||||
@ -165,7 +149,6 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
|
|
||||||
// Insert it
|
// Insert it
|
||||||
vulnerability.Node = vulnerability.GetNode()
|
vulnerability.Node = vulnerability.GetNode()
|
||||||
cachedVulnerabilities[vulnerability.ID] = vulnerability
|
|
||||||
|
|
||||||
t.AddQuad(cayley.Quad(vulnerability.Node, FieldIs, FieldVulnerabilityIsValue, ""))
|
t.AddQuad(cayley.Quad(vulnerability.Node, FieldIs, FieldVulnerabilityIsValue, ""))
|
||||||
t.AddQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityID, vulnerability.ID, ""))
|
t.AddQuad(cayley.Quad(vulnerability.Node, FieldVulnerabilityID, vulnerability.ID, ""))
|
||||||
@ -177,7 +160,11 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a notification
|
// Add a notification
|
||||||
newVulnerabilityNotifications[vulnerability.ID] = &NewVulnerabilityNotification{VulnerabilityID: vulnerability.ID}
|
notification := &NewVulnerabilityNotification{VulnerabilityID: vulnerability.ID}
|
||||||
|
notifications = append(notifications, notification)
|
||||||
|
newVulnerabilityNotifications[vulnerability.ID] = notification
|
||||||
|
|
||||||
|
cachedVulnerabilities[vulnerability.ID] = vulnerability
|
||||||
} else {
|
} else {
|
||||||
// The vulnerability already exists, update it
|
// The vulnerability already exists, update it
|
||||||
if vulnerability.Link != "" && existingVulnerability.Link != vulnerability.Link {
|
if vulnerability.Link != "" && existingVulnerability.Link != vulnerability.Link {
|
||||||
@ -185,6 +172,7 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityLink, vulnerability.Link, ""))
|
t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityLink, vulnerability.Link, ""))
|
||||||
existingVulnerability.Link = vulnerability.Link
|
existingVulnerability.Link = vulnerability.Link
|
||||||
}
|
}
|
||||||
|
|
||||||
if vulnerability.Priority != "" && vulnerability.Priority != types.Unknown && existingVulnerability.Priority != vulnerability.Priority {
|
if vulnerability.Priority != "" && vulnerability.Priority != types.Unknown && existingVulnerability.Priority != vulnerability.Priority {
|
||||||
if !vulnerability.Priority.IsValid() {
|
if !vulnerability.Priority.IsValid() {
|
||||||
log.Warningf("could not update a vulnerability which has an invalid priority [ID: %s, Link: %s, Priority: %s]. Valid priorities are: %v.", vulnerability.ID, vulnerability.Link, vulnerability.Priority, types.Priorities)
|
log.Warningf("could not update a vulnerability which has an invalid priority [ID: %s, Link: %s, Priority: %s]. Valid priorities are: %v.", vulnerability.ID, vulnerability.Link, vulnerability.Priority, types.Priorities)
|
||||||
@ -197,10 +185,12 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
// Any priorityChangeNotification already ?
|
// Any priorityChangeNotification already ?
|
||||||
if existingPriorityNotification, _ := vulnerabilityPriorityIncreasedNotifications[vulnerability.ID]; existingPriorityNotification != nil {
|
if existingPriorityNotification, _ := vulnerabilityPriorityIncreasedNotifications[vulnerability.ID]; existingPriorityNotification != nil {
|
||||||
// There is a priority change notification, replace it but keep the old priority field
|
// There is a priority change notification, replace it but keep the old priority field
|
||||||
vulnerabilityPriorityIncreasedNotifications[vulnerability.ID] = &VulnerabilityPriorityIncreasedNotification{OldPriority: existingPriorityNotification.OldPriority, NewPriority: vulnerability.Priority, VulnerabilityID: existingVulnerability.ID}
|
existingPriorityNotification.NewPriority = vulnerability.Priority
|
||||||
} else {
|
} else {
|
||||||
// No previous notification, just add a new one
|
// No previous notification, just add a new one
|
||||||
vulnerabilityPriorityIncreasedNotifications[vulnerability.ID] = &VulnerabilityPriorityIncreasedNotification{OldPriority: existingVulnerability.Priority, NewPriority: vulnerability.Priority, VulnerabilityID: existingVulnerability.ID}
|
notification := &VulnerabilityPriorityIncreasedNotification{OldPriority: existingVulnerability.Priority, NewPriority: vulnerability.Priority, VulnerabilityID: existingVulnerability.ID}
|
||||||
|
notifications = append(notifications, notification)
|
||||||
|
vulnerabilityPriorityIncreasedNotifications[vulnerability.ID] = notification
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,12 +199,15 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityPriority, string(vulnerability.Priority), ""))
|
t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityPriority, string(vulnerability.Priority), ""))
|
||||||
existingVulnerability.Priority = vulnerability.Priority
|
existingVulnerability.Priority = vulnerability.Priority
|
||||||
}
|
}
|
||||||
|
|
||||||
if vulnerability.Description != "" && existingVulnerability.Description != vulnerability.Description {
|
if vulnerability.Description != "" && existingVulnerability.Description != vulnerability.Description {
|
||||||
t.RemoveQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityDescription, existingVulnerability.Description, ""))
|
t.RemoveQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityDescription, existingVulnerability.Description, ""))
|
||||||
t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityDescription, vulnerability.Description, ""))
|
t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityDescription, vulnerability.Description, ""))
|
||||||
existingVulnerability.Description = vulnerability.Description
|
existingVulnerability.Description = vulnerability.Description
|
||||||
}
|
}
|
||||||
if len(vulnerability.FixedInNodes) > 0 && len(utils.CompareStringLists(vulnerability.FixedInNodes, existingVulnerability.FixedInNodes)) != 0 {
|
|
||||||
|
newFixedInNodes := utils.CompareStringLists(vulnerability.FixedInNodes, existingVulnerability.FixedInNodes)
|
||||||
|
if len(newFixedInNodes) > 0 {
|
||||||
var removedNodes []string
|
var removedNodes []string
|
||||||
var addedNodes []string
|
var addedNodes []string
|
||||||
|
|
||||||
@ -222,19 +215,14 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return []Notification{}, err
|
return []Notification{}, err
|
||||||
}
|
}
|
||||||
vulnerabilityFixedInPackages, err := FindAllPackagesByNodes(vulnerability.FixedInNodes, []string{FieldPackageOS, FieldPackageName, FieldPackageVersion})
|
newFixedInPackages, err := FindAllPackagesByNodes(newFixedInNodes, []string{FieldPackageOS, FieldPackageName, FieldPackageVersion})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []Notification{}, err
|
return []Notification{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range vulnerabilityFixedInPackages {
|
for _, p := range newFixedInPackages {
|
||||||
// Any already existing link ?
|
|
||||||
fixedInLinkAlreadyExists := false
|
|
||||||
for _, ep := range existingVulnerabilityFixedInPackages {
|
for _, ep := range existingVulnerabilityFixedInPackages {
|
||||||
if *p == *ep {
|
if p.Branch() == ep.Branch() {
|
||||||
// This exact link already exists, we won't insert it again
|
|
||||||
fixedInLinkAlreadyExists = true
|
|
||||||
} else if p.Branch() == ep.Branch() {
|
|
||||||
// A link to this package branch already exist and is not the same version, we will delete it
|
// A link to this package branch already exist and is not the same version, we will delete it
|
||||||
t.RemoveQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityFixedIn, ep.Node, ""))
|
t.RemoveQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityFixedIn, ep.Node, ""))
|
||||||
|
|
||||||
@ -250,15 +238,12 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if fixedInLinkAlreadyExists == false {
|
|
||||||
t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityFixedIn, p.Node, ""))
|
t.AddQuad(cayley.Quad(existingVulnerability.Node, FieldVulnerabilityFixedIn, p.Node, ""))
|
||||||
existingVulnerability.FixedInNodes = append(existingVulnerability.FixedInNodes, p.Node)
|
existingVulnerability.FixedInNodes = append(existingVulnerability.FixedInNodes, p.Node)
|
||||||
addedNodes = append(addedNodes, p.Node)
|
addedNodes = append(addedNodes, p.Node)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Add notification about the FixedIn modification if the vulnerability is not new
|
// Add notification about the FixedIn modification if the vulnerability is not new
|
||||||
if len(removedNodes) > 0 || len(addedNodes) > 0 {
|
|
||||||
if _, newVulnerabilityNotificationExists := newVulnerabilityNotifications[vulnerability.ID]; !newVulnerabilityNotificationExists {
|
if _, newVulnerabilityNotificationExists := newVulnerabilityNotifications[vulnerability.ID]; !newVulnerabilityNotificationExists {
|
||||||
// Any VulnerabilityPackageChangedNotification already ?
|
// Any VulnerabilityPackageChangedNotification already ?
|
||||||
if existingPackageNotification, _ := vulnerabilityPackageChangedNotifications[vulnerability.ID]; existingPackageNotification != nil {
|
if existingPackageNotification, _ := vulnerabilityPackageChangedNotifications[vulnerability.ID]; existingPackageNotification != nil {
|
||||||
@ -267,8 +252,9 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
existingPackageNotification.RemovedFixedInNodes = append(existingPackageNotification.RemovedFixedInNodes, removedNodes...)
|
existingPackageNotification.RemovedFixedInNodes = append(existingPackageNotification.RemovedFixedInNodes, removedNodes...)
|
||||||
} else {
|
} else {
|
||||||
// No previous notification, just add a new one
|
// No previous notification, just add a new one
|
||||||
vulnerabilityPackageChangedNotifications[vulnerability.ID] = &VulnerabilityPackageChangedNotification{VulnerabilityID: vulnerability.ID, AddedFixedInNodes: addedNodes, RemovedFixedInNodes: removedNodes}
|
notification := &VulnerabilityPackageChangedNotification{VulnerabilityID: vulnerability.ID, AddedFixedInNodes: addedNodes, RemovedFixedInNodes: removedNodes}
|
||||||
}
|
notifications = append(notifications, notification)
|
||||||
|
vulnerabilityPackageChangedNotifications[vulnerability.ID] = notification
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,19 +267,7 @@ func InsertVulnerabilities(vulnerabilities []*Vulnerability) ([]Notification, er
|
|||||||
return []Notification{}, ErrTransaction
|
return []Notification{}, ErrTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group all notifications
|
return notifications, nil
|
||||||
var allNotifications []Notification
|
|
||||||
for _, notification := range newVulnerabilityNotifications {
|
|
||||||
allNotifications = append(allNotifications, notification)
|
|
||||||
}
|
|
||||||
for _, notification := range vulnerabilityPriorityIncreasedNotifications {
|
|
||||||
allNotifications = append(allNotifications, notification)
|
|
||||||
}
|
|
||||||
for _, notification := range vulnerabilityPackageChangedNotifications {
|
|
||||||
allNotifications = append(allNotifications, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
return allNotifications, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteVulnerability deletes the vulnerability having the given ID
|
// DeleteVulnerability deletes the vulnerability having the given ID
|
||||||
|
@ -155,9 +155,7 @@ func TestVulnerability(t *testing.T) {
|
|||||||
pkg1 = &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}
|
pkg1 = &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}
|
||||||
pkg1b := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.1")}
|
pkg1b := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.1")}
|
||||||
InsertPackages([]*Package{pkg1, pkg1b})
|
InsertPackages([]*Package{pkg1, pkg1b})
|
||||||
// # A vulnerability can't be inserted if fixed by two packages of the same branch
|
|
||||||
_, err = InsertVulnerabilities([]*Vulnerability{&Vulnerability{ID: "test6", Link: "link6", Priority: types.Medium, Description: "testDescription6", FixedInNodes: []string{pkg1.Node, pkg1b.Node}}})
|
|
||||||
assert.Error(t, err)
|
|
||||||
// # Two updates of the same vulnerability in the same batch with packages of the same branch
|
// # Two updates of the same vulnerability in the same batch with packages of the same branch
|
||||||
pkg0 := &Package{OS: "testOS", Name: "testpkg0", Version: types.NewVersionUnsafe("1.0")}
|
pkg0 := &Package{OS: "testOS", Name: "testpkg0", Version: types.NewVersionUnsafe("1.0")}
|
||||||
InsertPackages([]*Package{pkg0})
|
InsertPackages([]*Package{pkg0})
|
||||||
@ -173,10 +171,6 @@ func TestVulnerability(t *testing.T) {
|
|||||||
assert.NotContains(t, v7.FixedInNodes, pkg1.Node)
|
assert.NotContains(t, v7.FixedInNodes, pkg1.Node)
|
||||||
assert.Contains(t, v7.FixedInNodes, pkg1b.Node)
|
assert.Contains(t, v7.FixedInNodes, pkg1b.Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// # A vulnerability can't be updated if fixed by two packages of the same branch
|
|
||||||
_, err = InsertVulnerabilities([]*Vulnerability{&Vulnerability{ID: "test7", FixedInNodes: []string{pkg1.Node, pkg1b.Node}}})
|
|
||||||
assert.Error(t, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user