From 63ebddfd3662c6a208c5960b64a13ed6e86dd6f6 Mon Sep 17 00:00:00 2001 From: Quentin Machu Date: Thu, 28 Jan 2016 13:35:07 -0500 Subject: [PATCH] database: add vulnerability deletion support --- database/database.go | 2 +- .../migrations/20151222113213_Initial.sql | 2 +- database/pgsql/queries.go | 5 ++++ database/pgsql/vulnerability.go | 28 +++++++++++++------ database/pgsql/vulnerability_test.go | 26 +++++++++++++++-- 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/database/database.go b/database/database.go index 1af4be06..65447dbb 100644 --- a/database/database.go +++ b/database/database.go @@ -44,8 +44,8 @@ type Datastore interface { // Vulnerability InsertVulnerabilities([]Vulnerability) error - // DeleteVulnerability(id string) error FindVulnerability(namespaceName, name string) (Vulnerability, error) + DeleteVulnerability(namespaceName, name string) error // Notifications CountAvailableNotifications() (int, error) diff --git a/database/pgsql/migrations/20151222113213_Initial.sql b/database/pgsql/migrations/20151222113213_Initial.sql index b4135662..a9f4032a 100644 --- a/database/pgsql/migrations/20151222113213_Initial.sql +++ b/database/pgsql/migrations/20151222113213_Initial.sql @@ -113,7 +113,7 @@ CREATE TABLE IF NOT EXISTS Vulnerability_Affects_FeatureVersion ( id SERIAL PRIMARY KEY, vulnerability_id INT NOT NULL REFERENCES Vulnerability ON DELETE CASCADE, featureversion_id INT NOT NULL REFERENCES FeatureVersion, - fixedin_id INT NOT NULL REFERENCES Vulnerability_FixedIn_Feature, + fixedin_id INT NOT NULL REFERENCES Vulnerability_FixedIn_Feature ON DELETE CASCADE, UNIQUE (vulnerability_id, featureversion_id)); diff --git a/database/pgsql/queries.go b/database/pgsql/queries.go index fd7df965..64b90969 100644 --- a/database/pgsql/queries.go +++ b/database/pgsql/queries.go @@ -180,6 +180,11 @@ func init() { queries["f_featureversion_by_feature"] = ` SELECT id, version FROM FeatureVersion WHERE feature_id = $1` + queries["r_vulnerability"] = ` + DELETE FROM Vulnerability + WHERE namespace_id = (SELECT id FROM Namespace WHERE name = $1) + AND name = $2` + // notification.go queries["i_notification"] = `INSERT INTO Notification(name, kind, data) VALUES($1, $2, $3)` diff --git a/database/pgsql/vulnerability.go b/database/pgsql/vulnerability.go index b3bf1e3f..52bbcabe 100644 --- a/database/pgsql/vulnerability.go +++ b/database/pgsql/vulnerability.go @@ -315,19 +315,13 @@ func (pgSQL *pgSQL) updateVulnerabilityFeatureVersions(tx *sql.Tx, vulnerability } 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. + // Drop it from Vulnerability_FixedIn_Feature and let it cascade to + // Vulnerability_Affects_FeatureVersion. err := tx.QueryRow(getQuery("r_vulnerability_fixedin_feature"), vulnerability.ID, fv.Feature.ID).Scan(&fixedInID) if err != nil && err != sql.ErrNoRows { return handleError("r_vulnerability_fixedin_feature", err) } - - if err == nil { - _, err = tx.Exec(getQuery("r_vulnerability_affects_featureversion"), fixedInID) - if err != nil { - return handleError("r_vulnerability_affects_featureversion", err) - } - } } } @@ -375,3 +369,21 @@ func linkVulnerabilityToFeatureVersions(tx *sql.Tx, fixedInID, vulnerabilityID, return nil } + +func (pgSQL *pgSQL) DeleteVulnerability(namespaceName, name string) error { + result, err := pgSQL.Exec(getQuery("r_vulnerability"), namespaceName, name) + if err != nil { + return handleError("r_vulnerability", err) + } + + affected, err := result.RowsAffected() + if err != nil { + return handleError("r_vulnerability.RowsAffected()", err) + } + + if affected <= 0 { + return cerrors.ErrNotFound + } + + return nil +} diff --git a/database/pgsql/vulnerability_test.go b/database/pgsql/vulnerability_test.go index 7ed28b9f..fbb266ff 100644 --- a/database/pgsql/vulnerability_test.go +++ b/database/pgsql/vulnerability_test.go @@ -64,7 +64,7 @@ func TestFindVulnerability(t *testing.T) { Name: "CVE-NOPE", Description: "A vulnerability affecting nothing", Namespace: database.Namespace{Name: "debian:7"}, - Severity: types.Unknown, + Severity: types.Unknown, } v2f, err := datastore.FindVulnerability("debian:7", "CVE-NOPE") @@ -73,6 +73,28 @@ func TestFindVulnerability(t *testing.T) { } } +func TestDeleteVulnerability(t *testing.T) { + datastore, err := OpenForTest("InsertVulnerability", true) + if err != nil { + t.Error(err) + return + } + defer datastore.Close() + + // Delete non-existing Vulnerability. + err = datastore.DeleteVulnerability("TestDeleteVulnerabilityNamespace1", "CVE-OPENSSL-1-DEB7") + assert.Equal(t, cerrors.ErrNotFound, err) + err = datastore.DeleteVulnerability("debian:7", "TestDeleteVulnerabilityVulnerability1") + assert.Equal(t, cerrors.ErrNotFound, err) + + // Delete Vulnerability. + err = datastore.DeleteVulnerability("debian:7", "CVE-OPENSSL-1-DEB7") + if assert.Nil(t, err) { + _, err := datastore.FindVulnerability("debian:7", "CVE-OPENSSL-1-DEB7") + assert.Equal(t, cerrors.ErrNotFound, err) + } +} + func TestInsertVulnerability(t *testing.T) { datastore, err := OpenForTest("InsertVulnerability", false) if err != nil { @@ -241,8 +263,6 @@ func equalsVuln(t *testing.T, expected, actual *database.Vulnerability) { } } -// TODO Test Affects in Feature_Version and here. - // func TestInsertVulnerabilityNotifications(t *testing.T) { // Open(&config.DatabaseConfig{Type: "memstore"}) // defer Close()