database: allow removing fixed packages in vulnerabilities
This commit is contained in:
parent
7c70fc1c20
commit
1b53142e38
@ -167,6 +167,11 @@ func init() {
|
||||
UPDATE Vulnerability_FixedIn_Feature
|
||||
SET version = $3
|
||||
WHERE vulnerability_id = $1 AND feature_id = $2
|
||||
RETURNING id`
|
||||
|
||||
queries["r_vulnerability_fixedin_feature"] = `
|
||||
DELETE FROM Vulnerability_FixedIn_Feature
|
||||
WHERE vulnerability_id = $1 AND feature_id = $2
|
||||
RETURNING id`
|
||||
|
||||
queries["r_vulnerability_affects_featureversion"] = `
|
||||
|
64
database/pgsql/testdata/data.sql
vendored
64
database/pgsql/testdata/data.sql
vendored
@ -1,32 +1,44 @@
|
||||
INSERT INTO namespace (id, name) VALUES (1, 'debian:7');
|
||||
INSERT INTO namespace (id, name) VALUES (2, 'debian:8');
|
||||
INSERT INTO namespace (id, name) VALUES
|
||||
(1, 'debian:7'),
|
||||
(2, 'debian:8');
|
||||
|
||||
INSERT INTO feature (id, namespace_id, name) VALUES (1, 1, 'wechat');
|
||||
INSERT INTO feature (id, namespace_id, name) VALUES (2, 1, 'openssl');
|
||||
INSERT INTO feature (id, namespace_id, name) VALUES (4, 1, 'libssl');
|
||||
INSERT INTO feature (id, namespace_id, name) VALUES (3, 2, 'openssl');
|
||||
INSERT INTO featureversion (id, feature_id, version) VALUES (1, 1, '0.5');
|
||||
INSERT INTO featureversion (id, feature_id, version) VALUES (2, 2, '1.0');
|
||||
INSERT INTO featureversion (id, feature_id, version) VALUES (3, 2, '2.0');
|
||||
INSERT INTO featureversion (id, feature_id, version) VALUES (4, 3, '1.0');
|
||||
INSERT INTO feature (id, namespace_id, name) VALUES
|
||||
(1, 1, 'wechat'),
|
||||
(2, 1, 'openssl'),
|
||||
(4, 1, 'libssl'),
|
||||
(3, 2, 'openssl');
|
||||
|
||||
INSERT INTO layer (id, name, engineversion, parent_id, namespace_id) VALUES (1, 'layer-0', 1, NULL, NULL);
|
||||
INSERT INTO layer (id, name, engineversion, parent_id, namespace_id) VALUES (2, 'layer-1', 1, 1, 1);
|
||||
INSERT INTO layer (id, name, engineversion, parent_id, namespace_id) VALUES (3, 'layer-2', 1, 2, 1);
|
||||
INSERT INTO layer (id, name, engineversion, parent_id, namespace_id) VALUES (4, 'layer-3a', 1, 3, 1);
|
||||
INSERT INTO layer (id, name, engineversion, parent_id, namespace_id) VALUES (5, 'layer-3b', 1, 3, 2);
|
||||
INSERT INTO layer_diff_featureversion (id, layer_id, featureversion_id, modification) VALUES (1, 2, 1, 'add');
|
||||
INSERT INTO layer_diff_featureversion (id, layer_id, featureversion_id, modification) VALUES (2, 2, 2, 'add');
|
||||
INSERT INTO layer_diff_featureversion (id, layer_id, featureversion_id, modification) VALUES (3, 3, 2, 'del'); -- layer-2: Update Debian:7 OpenSSL 1.0 -> 2.0
|
||||
INSERT INTO layer_diff_featureversion (id, layer_id, featureversion_id, modification) VALUES (4, 3, 3, 'add'); -- ^
|
||||
INSERT INTO layer_diff_featureversion (id, layer_id, featureversion_id, modification) VALUES (5, 5, 3, 'del'); -- layer-3b: Delete Debian:7 OpenSSL 2.0
|
||||
INSERT INTO layer_diff_featureversion (id, layer_id, featureversion_id, modification) VALUES (6, 5, 4, 'add'); -- layer-3b: Add Debian:8 OpenSSL 1.0
|
||||
INSERT INTO featureversion (id, feature_id, version) VALUES
|
||||
(1, 1, '0.5'),
|
||||
(2, 2, '1.0'),
|
||||
(3, 2, '2.0'),
|
||||
(4, 3, '1.0');
|
||||
|
||||
INSERT INTO vulnerability (id, namespace_id, name, description, link, severity) VALUES (1, 1, 'CVE-OPENSSL-1-DEB7', 'A vulnerability affecting OpenSSL < 2.0 on Debian 7.0', 'http://google.com/#q=CVE-OPENSSL-1-DEB7', 'High');
|
||||
INSERT INTO vulnerability_fixedin_feature (id, vulnerability_id, feature_id, version) VALUES (1, 1, 2, '2.0');
|
||||
INSERT INTO vulnerability_fixedin_feature (id, vulnerability_id, feature_id, version) VALUES (2, 1, 4, '1.9-abc');
|
||||
INSERT INTO vulnerability_affects_featureversion (id, vulnerability_id, featureversion_id, fixedin_id) VALUES (1, 1, 2, 1); -- CVE-OPENSSL-1-DEB7 affects Debian:7 OpenSSL 1.0
|
||||
INSERT INTO vulnerability (id, namespace_id, name, description, link, severity) VALUES (2, 1, 'CVE-NOPE', 'A vulnerability affecting nothing', '', 'Unknown');
|
||||
INSERT INTO layer (id, name, engineversion, parent_id, namespace_id) VALUES
|
||||
(1, 'layer-0', 1, NULL, NULL),
|
||||
(2, 'layer-1', 1, 1, 1),
|
||||
(3, 'layer-2', 1, 2, 1),
|
||||
(4, 'layer-3a', 1, 3, 1),
|
||||
(5, 'layer-3b', 1, 3, 2);
|
||||
|
||||
INSERT INTO layer_diff_featureversion (id, layer_id, featureversion_id, modification) VALUES
|
||||
(1, 2, 1, 'add'),
|
||||
(2, 2, 2, 'add'),
|
||||
(3, 3, 2, 'del'), -- layer-2: Update Debian:7 OpenSSL 1.0 -> 2.0
|
||||
(4, 3, 3, 'add'), -- ^
|
||||
(5, 5, 3, 'del'), -- layer-3b: Delete Debian:7 OpenSSL 2.0
|
||||
(6, 5, 4, 'add'); -- layer-3b: Add Debian:8 OpenSSL 1.0
|
||||
|
||||
INSERT INTO vulnerability (id, namespace_id, name, description, link, severity) VALUES
|
||||
(1, 1, 'CVE-OPENSSL-1-DEB7', 'A vulnerability affecting OpenSSL < 2.0 on Debian 7.0', 'http://google.com/#q=CVE-OPENSSL-1-DEB7', 'High'),
|
||||
(2, 1, 'CVE-NOPE', 'A vulnerability affecting nothing', '', 'Unknown');
|
||||
|
||||
INSERT INTO vulnerability_fixedin_feature (id, vulnerability_id, feature_id, version) VALUES
|
||||
(1, 1, 2, '2.0'),
|
||||
(2, 1, 4, '1.9-abc');
|
||||
|
||||
INSERT INTO vulnerability_affects_featureversion (id, vulnerability_id, featureversion_id, fixedin_id) VALUES
|
||||
(1, 1, 2, 1); -- CVE-OPENSSL-1-DEB7 affects Debian:7 OpenSSL 1.0
|
||||
|
||||
SELECT pg_catalog.setval(pg_get_serial_sequence('namespace', 'id'), (SELECT MAX(id) FROM namespace)+1);
|
||||
SELECT pg_catalog.setval(pg_get_serial_sequence('feature', 'id'), (SELECT MAX(id) FROM feature)+1);
|
||||
|
@ -64,6 +64,7 @@ func (pgSQL *pgSQL) FindVulnerability(namespaceName, name string) (database.Vuln
|
||||
}
|
||||
|
||||
// FixedIn.Namespace are not necessary, they are overwritten by the vuln.
|
||||
// By setting the fixed version to minVersion, we can say that the vuln does'nt affect anymore.
|
||||
func (pgSQL *pgSQL) InsertVulnerabilities(vulnerabilities []database.Vulnerability) error {
|
||||
for _, vulnerability := range vulnerabilities {
|
||||
err := pgSQL.insertVulnerability(vulnerability)
|
||||
@ -224,10 +225,6 @@ func createFeatureVersionNameMap(features []database.FeatureVersion) (map[string
|
||||
return m, s
|
||||
}
|
||||
|
||||
// TODO(Quentin-M): Add support for removing Vulnerability_FixedIn_Feature when Version = MinVersion.
|
||||
// We should then update the vulnerability fetcher to do it.
|
||||
// Also maybe we would delete a Vulnerability if it hasn't any FixedIn.
|
||||
// --> And affects
|
||||
func (pgSQL *pgSQL) updateVulnerabilityFeatureVersions(tx *sql.Tx, vulnerability, existingVulnerability *database.Vulnerability, newFixedInFeatureVersions, updatedFixedInFeatureVersions []database.FeatureVersion) error {
|
||||
var fixedInID int
|
||||
|
||||
@ -247,6 +244,7 @@ func (pgSQL *pgSQL) updateVulnerabilityFeatureVersions(tx *sql.Tx, vulnerability
|
||||
}
|
||||
|
||||
for _, fv := range updatedFixedInFeatureVersions {
|
||||
if fv.Version != types.MinVersion {
|
||||
// Update Vulnerability_FixedIn_Feature.
|
||||
err := tx.QueryRow(getQuery("u_vulnerability_fixedin_feature"), vulnerability.ID, fv.ID,
|
||||
&fv.Version).Scan(&fixedInID)
|
||||
@ -265,6 +263,21 @@ func (pgSQL *pgSQL) updateVulnerabilityFeatureVersions(tx *sql.Tx, vulnerability
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Updating FixedIn by saying that the fixed version is the lowest possible version, it
|
||||
// basically means that the vulnerability doesn't affect the feature (anymore).
|
||||
// Drop it from Vulnerability_FixedIn_Feature and Vulnerability_Affects_FeatureVersion.
|
||||
err := tx.QueryRow(getQuery("r_vulnerability_fixedin_feature"), vulnerability.ID, fv.ID).
|
||||
Scan(&fixedInID)
|
||||
if err != nil {
|
||||
return handleError("r_vulnerability_fixedin_feature", err)
|
||||
}
|
||||
|
||||
_, err = tx.Exec(getQuery("r_vulnerability_affects_featureversion"), fixedInID)
|
||||
if err != nil {
|
||||
return handleError("r_vulnerability_affects_featureversion", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -27,6 +27,7 @@ func TestFindVulnerability(t *testing.T) {
|
||||
Description: "A vulnerability affecting OpenSSL < 2.0 on Debian 7.0",
|
||||
Link: "http://google.com/#q=CVE-OPENSSL-1-DEB7",
|
||||
Severity: types.High,
|
||||
Namespace: database.Namespace{Name: "debian:7"},
|
||||
FixedIn: []database.FeatureVersion{
|
||||
database.FeatureVersion{
|
||||
Feature: database.Feature{Name: "openssl"},
|
||||
@ -46,8 +47,10 @@ func TestFindVulnerability(t *testing.T) {
|
||||
|
||||
// Find a vulnerability that has no link, no severity and no FixedIn.
|
||||
v2 := database.Vulnerability{
|
||||
Name: "CVE-OPENSSL-1-DEB7",
|
||||
Description: "A vulnerability affecting OpenSSL < 2.0 on Debian 7.0",
|
||||
Name: "CVE-NOPE",
|
||||
Description: "A vulnerability affecting nothing",
|
||||
Namespace: database.Namespace{Name: "debian:7"},
|
||||
Severity: types.Unknown,
|
||||
}
|
||||
|
||||
v2f, err := datastore.FindVulnerability("debian:7", "CVE-NOPE")
|
||||
@ -106,6 +109,18 @@ func TestInsertVulnerability(t *testing.T) {
|
||||
},
|
||||
Version: types.NewVersionUnsafe("0.1"),
|
||||
}
|
||||
f7 := database.FeatureVersion{
|
||||
Feature: database.Feature{
|
||||
Name: "TestInsertVulnerabilityFeatureVersion5",
|
||||
},
|
||||
Version: types.MaxVersion,
|
||||
}
|
||||
f8 := database.FeatureVersion{
|
||||
Feature: database.Feature{
|
||||
Name: "TestInsertVulnerabilityFeatureVersion5",
|
||||
},
|
||||
Version: types.MinVersion,
|
||||
}
|
||||
|
||||
// Insert invalid vulnerabilities.
|
||||
for _, vulnerability := range []database.Vulnerability{
|
||||
@ -147,7 +162,7 @@ func TestInsertVulnerability(t *testing.T) {
|
||||
v1 := database.Vulnerability{
|
||||
Name: "TestInsertVulnerability1",
|
||||
Namespace: n1,
|
||||
FixedIn: []database.FeatureVersion{f1, f3, f6},
|
||||
FixedIn: []database.FeatureVersion{f1, f3, f6, f7},
|
||||
Severity: types.Low,
|
||||
Description: "TestInsertVulnerabilityDescription1",
|
||||
Link: "TestInsertVulnerabilityLink1",
|
||||
@ -164,9 +179,9 @@ func TestInsertVulnerability(t *testing.T) {
|
||||
v1.Description = "TestInsertVulnerabilityLink2"
|
||||
v1.Link = "TestInsertVulnerabilityLink2"
|
||||
v1.Severity = types.High
|
||||
// Update f3 by f4, add fixed by f5, add fixed by f6 which already exists.
|
||||
// TODO(Quentin-M): Remove FixedIn.
|
||||
v1.FixedIn = []database.FeatureVersion{f4, f5, f6}
|
||||
// Update f3 in f4, add fixed in f5, add fixed in f6 which already exists, removes fixed in f7 by
|
||||
// adding f8 which is f7 but with MinVersion.
|
||||
v1.FixedIn = []database.FeatureVersion{f4, f5, f6, f8}
|
||||
|
||||
err = datastore.InsertVulnerabilities([]database.Vulnerability{v1})
|
||||
if assert.Nil(t, err) {
|
||||
@ -175,6 +190,14 @@ func TestInsertVulnerability(t *testing.T) {
|
||||
// We already had f1 before the update.
|
||||
// Add it to the struct for comparison.
|
||||
v1.FixedIn = append(v1.FixedIn, f1)
|
||||
|
||||
// Removes f8 from the struct for comparison as it was just here to cancel f7.
|
||||
for i := 0; i < len(v1.FixedIn); i++ {
|
||||
if v1.FixedIn[i].Feature.Name == f8.Feature.Name {
|
||||
v1.FixedIn = append(v1.FixedIn[:i], v1.FixedIn[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
equalsVuln(t, &v1, &v1f)
|
||||
}
|
||||
}
|
||||
@ -206,126 +229,6 @@ func equalsVuln(t *testing.T, expected, actual *database.Vulnerability) {
|
||||
|
||||
// TODO Test Affects in Feature_Version and here.
|
||||
|
||||
//
|
||||
// // Some data
|
||||
// vuln1 := &database.Vulnerability{ID: "test1", Link: "link1", Priority: types.Medium, Description: "testDescription1", FixedInNodes: []string{"pkg1"}}
|
||||
// vuln2 := &database.Vulnerability{ID: "test2", Link: "link2", Priority: types.High, Description: "testDescription2", FixedInNodes: []string{"pkg1", "pkg2"}}
|
||||
// vuln3 := &database.Vulnerability{ID: "test3", Link: "link3", Priority: types.High, FixedInNodes: []string{"pkg3"}} // Empty description
|
||||
//
|
||||
// // Insert some vulnerabilities
|
||||
// _, err := InsertVulnerabilities([]*database.Vulnerability{vuln1, vuln2, vuln3})
|
||||
// if assert.Nil(t, err) {
|
||||
// // Find one of the vulnerabilities we just inserted and verify its content
|
||||
// v1, err := FindOnedatabase.Vulnerability(vuln1.ID, Fielddatabase.VulnerabilityAll)
|
||||
// if assert.Nil(t, err) && assert.NotNil(t, v1) {
|
||||
// assert.Equal(t, vuln1.ID, v1.ID)
|
||||
// assert.Equal(t, vuln1.Link, v1.Link)
|
||||
// assert.Equal(t, vuln1.Priority, v1.Priority)
|
||||
// assert.Equal(t, vuln1.Description, v1.Description)
|
||||
// if assert.Len(t, v1.FixedInNodes, 1) {
|
||||
// assert.Equal(t, vuln1.FixedInNodes[0], v1.FixedInNodes[0])
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Update a database.Vulnerability and verify its new content
|
||||
// pkg1 := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}
|
||||
// InsertPackages([]*Package{pkg1})
|
||||
// vuln5 := &database.Vulnerability{ID: "test5", Link: "link5", Priority: types.Medium, Description: "testDescription5", FixedInNodes: []string{pkg1.Node}}
|
||||
//
|
||||
// _, err = InsertVulnerabilities([]*database.Vulnerability{vuln5})
|
||||
// if assert.Nil(t, err) {
|
||||
// // Partial updates
|
||||
// // # Just a field update
|
||||
// vuln5b := &database.Vulnerability{ID: "test5", Priority: types.High}
|
||||
// _, err := InsertVulnerabilities([]*database.Vulnerability{vuln5b})
|
||||
// if assert.Nil(t, err) {
|
||||
// v5b, err := FindOnedatabase.Vulnerability(vuln5b.ID, Fielddatabase.VulnerabilityAll)
|
||||
// if assert.Nil(t, err) && assert.NotNil(t, v5b) {
|
||||
// assert.Equal(t, vuln5b.ID, v5b.ID)
|
||||
// assert.Equal(t, vuln5b.Priority, v5b.Priority)
|
||||
//
|
||||
// if assert.Len(t, v5b.FixedInNodes, 1) {
|
||||
// assert.Contains(t, v5b.FixedInNodes, pkg1.Node)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // # Just a field update, twice in the same transaction
|
||||
// vuln5b1 := &database.Vulnerability{ID: "test5", Link: "http://foo.bar"}
|
||||
// vuln5b2 := &database.Vulnerability{ID: "test5", Link: "http://bar.foo"}
|
||||
// _, err = InsertVulnerabilities([]*database.Vulnerability{vuln5b1, vuln5b2})
|
||||
// if assert.Nil(t, err) {
|
||||
// v5b2, err := FindOnedatabase.Vulnerability(vuln5b2.ID, Fielddatabase.VulnerabilityAll)
|
||||
// if assert.Nil(t, err) && assert.NotNil(t, v5b2) {
|
||||
// assert.Equal(t, vuln5b2.Link, v5b2.Link)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // # All fields except fixedIn update
|
||||
// vuln5c := &database.Vulnerability{ID: "test5", Link: "link5c", Priority: types.Critical, Description: "testDescription5c"}
|
||||
// _, err = InsertVulnerabilities([]*database.Vulnerability{vuln5c})
|
||||
// if assert.Nil(t, err) {
|
||||
// v5c, err := FindOnedatabase.Vulnerability(vuln5c.ID, Fielddatabase.VulnerabilityAll)
|
||||
// if assert.Nil(t, err) && assert.NotNil(t, v5c) {
|
||||
// assert.Equal(t, vuln5c.ID, v5c.ID)
|
||||
// assert.Equal(t, vuln5c.Link, v5c.Link)
|
||||
// assert.Equal(t, vuln5c.Priority, v5c.Priority)
|
||||
// assert.Equal(t, vuln5c.Description, v5c.Description)
|
||||
//
|
||||
// if assert.Len(t, v5c.FixedInNodes, 1) {
|
||||
// assert.Contains(t, v5c.FixedInNodes, pkg1.Node)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Complete update
|
||||
// pkg2 := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.1")}
|
||||
// pkg3 := &Package{OS: "testOS", Name: "testpkg2", Version: types.NewVersionUnsafe("1.0")}
|
||||
// InsertPackages([]*Package{pkg2, pkg3})
|
||||
// vuln5d := &database.Vulnerability{ID: "test5", Link: "link5d", Priority: types.Low, Description: "testDescription5d", FixedInNodes: []string{pkg2.Node, pkg3.Node}}
|
||||
//
|
||||
// _, err = InsertVulnerabilities([]*database.Vulnerability{vuln5d})
|
||||
// if assert.Nil(t, err) {
|
||||
// v5d, err := FindOnedatabase.Vulnerability(vuln5d.ID, Fielddatabase.VulnerabilityAll)
|
||||
// if assert.Nil(t, err) && assert.NotNil(t, v5d) {
|
||||
// assert.Equal(t, vuln5d.ID, v5d.ID)
|
||||
// assert.Equal(t, vuln5d.Link, v5d.Link)
|
||||
// assert.Equal(t, vuln5d.Priority, v5d.Priority)
|
||||
// assert.Equal(t, vuln5d.Description, v5d.Description)
|
||||
//
|
||||
// // Here, we ensure that a database.Vulnerability can only be fixed by one package of a given branch at a given time
|
||||
// // And that we can add new fixed packages as well
|
||||
// if assert.Len(t, v5d.FixedInNodes, 2) {
|
||||
// assert.NotContains(t, v5d.FixedInNodes, pkg1.Node)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Create and update a database.Vulnerability's packages (and from the same branch) in the same batch
|
||||
// pkg1 = &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}
|
||||
// pkg1b := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.1")}
|
||||
// InsertPackages([]*Package{pkg1, pkg1b})
|
||||
//
|
||||
// // # Two updates of the same database.Vulnerability in the same batch with packages of the same branch
|
||||
// pkg0 := &Package{OS: "testOS", Name: "testpkg0", Version: types.NewVersionUnsafe("1.0")}
|
||||
// InsertPackages([]*Package{pkg0})
|
||||
// _, err = InsertVulnerabilities([]*database.Vulnerability{&database.Vulnerability{ID: "test7", Link: "link7", Priority: types.Medium, Description: "testDescription7", FixedInNodes: []string{pkg0.Node}}})
|
||||
// if assert.Nil(t, err) {
|
||||
// vuln7b := &database.Vulnerability{ID: "test7", FixedInNodes: []string{pkg1.Node}}
|
||||
// vuln7c := &database.Vulnerability{ID: "test7", FixedInNodes: []string{pkg1b.Node}}
|
||||
// _, err = InsertVulnerabilities([]*database.Vulnerability{vuln7b, vuln7c})
|
||||
// if assert.Nil(t, err) {
|
||||
// v7, err := FindOnedatabase.Vulnerability("test7", Fielddatabase.VulnerabilityAll)
|
||||
// if assert.Nil(t, err) && assert.Len(t, v7.FixedInNodes, 2) {
|
||||
// assert.Contains(t, v7.FixedInNodes, pkg0.Node)
|
||||
// assert.NotContains(t, v7.FixedInNodes, pkg1.Node)
|
||||
// assert.Contains(t, v7.FixedInNodes, pkg1b.Node)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestInsertVulnerabilityNotifications(t *testing.T) {
|
||||
// Open(&config.DatabaseConfig{Type: "memstore"})
|
||||
// defer Close()
|
||||
|
Loading…
Reference in New Issue
Block a user