Example #1
0
func TestInsertVulnerabilityNotifications(t *testing.T) {
	Open("memstore", "")
	defer Close()

	pkg1 := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}
	pkg1b := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.2")}
	pkg2 := &Package{OS: "testOS", Name: "testpkg2", Version: types.NewVersionUnsafe("1.0")}
	InsertPackages([]*Package{pkg1, pkg1b, pkg2})

	// NewVulnerabilityNotification
	vuln1 := &Vulnerability{ID: "test1", Link: "link1", Priority: types.Medium, Description: "testDescription1", FixedInNodes: []string{pkg1.Node}}
	vuln2 := &Vulnerability{ID: "test2", Link: "link2", Priority: types.High, Description: "testDescription2", FixedInNodes: []string{pkg1.Node, pkg2.Node}}
	vuln1b := &Vulnerability{ID: "test1", Priority: types.High, FixedInNodes: []string{"pkg3"}}
	notifications, err := InsertVulnerabilities([]*Vulnerability{vuln1, vuln2, vuln1b})
	if assert.Nil(t, err) {
		// We should only have two NewVulnerabilityNotification notifications: one for test1 and one for test2
		// We should not have a VulnerabilityPriorityIncreasedNotification or a VulnerabilityPackageChangedNotification
		// for test1 because it is in the same batch
		if assert.Len(t, notifications, 2) {
			for _, n := range notifications {
				_, ok := n.(*NewVulnerabilityNotification)
				assert.True(t, ok)
			}
		}
	}

	// VulnerabilityPriorityIncreasedNotification
	vuln1c := &Vulnerability{ID: "test1", Priority: types.Critical}
	notifications, err = InsertVulnerabilities([]*Vulnerability{vuln1c})
	if assert.Nil(t, err) {
		if assert.Len(t, notifications, 1) {
			if nn, ok := notifications[0].(*VulnerabilityPriorityIncreasedNotification); assert.True(t, ok) {
				assert.Equal(t, vuln1b.Priority, nn.OldPriority)
				assert.Equal(t, vuln1c.Priority, nn.NewPriority)
			}
		}
	}

	notifications, err = InsertVulnerabilities([]*Vulnerability{&Vulnerability{ID: "test1", Priority: types.Low}})
	assert.Nil(t, err)
	assert.Len(t, notifications, 0)

	// VulnerabilityPackageChangedNotification
	vuln1e := &Vulnerability{ID: "test1", FixedInNodes: []string{pkg1b.Node}}
	vuln1f := &Vulnerability{ID: "test1", FixedInNodes: []string{pkg2.Node}}
	notifications, err = InsertVulnerabilities([]*Vulnerability{vuln1e, vuln1f})
	if assert.Nil(t, err) {
		if assert.Len(t, notifications, 1) {
			if nn, ok := notifications[0].(*VulnerabilityPackageChangedNotification); assert.True(t, ok) {
				// Here, we say that pkg1b fixes the vulnerability, but as pkg1b is in
				// the same branch as pkg1, pkg1 should be removed and pkg1b added
				// We also add pkg2 as fixed
				assert.Contains(t, nn.AddedFixedInNodes, pkg1b.Node)
				assert.Contains(t, nn.RemovedFixedInNodes, pkg1.Node)

				assert.Contains(t, nn.AddedFixedInNodes, pkg2.Node)
			}
		}
	}
}
Example #2
0
func TestRHELParser(t *testing.T) {
	_, filename, _, _ := runtime.Caller(0)
	path := path.Join(path.Dir(filename))

	// Test parsing testdata/fetcher_rhel_test.1.xml
	testFile, _ := os.Open(path + "/testdata/fetcher_rhel_test.1.xml")
	vulnerabilities, err := parseRHSA(testFile)
	if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 1) {
		assert.Equal(t, "RHSA-2015:1193", vulnerabilities[0].ID)
		assert.Equal(t, "https://rhn.redhat.com/errata/RHSA-2015-1193.html", vulnerabilities[0].Link)
		assert.Equal(t, types.Medium, vulnerabilities[0].Priority)
		assert.Equal(t, `Xerces-C is a validating XML parser written in a portable subset of C++. A flaw was found in the way the Xerces-C XML parser processed certain XML documents. A remote attacker could provide specially crafted XML input that, when parsed by an application using Xerces-C, would cause that application to crash.`, vulnerabilities[0].Description)

		if assert.Len(t, vulnerabilities[0].FixedIn, 3) {
			assert.Contains(t, vulnerabilities[0].FixedIn, &database.Package{
				OS:      "centos:7",
				Name:    "xerces-c",
				Version: types.NewVersionUnsafe("3.1.1-7.el7_1"),
			})
			assert.Contains(t, vulnerabilities[0].FixedIn, &database.Package{
				OS:      "centos:7",
				Name:    "xerces-c-devel",
				Version: types.NewVersionUnsafe("3.1.1-7.el7_1"),
			})
			assert.Contains(t, vulnerabilities[0].FixedIn, &database.Package{
				OS:      "centos:7",
				Name:    "xerces-c-doc",
				Version: types.NewVersionUnsafe("3.1.1-7.el7_1"),
			})
		}
	}

	// Test parsing testdata/fetcher_rhel_test.2.xml
	testFile, _ = os.Open(path + "/testdata/fetcher_rhel_test.2.xml")
	vulnerabilities, err = parseRHSA(testFile)
	if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 1) {
		assert.Equal(t, "RHSA-2015:1207", vulnerabilities[0].ID)
		assert.Equal(t, "https://rhn.redhat.com/errata/RHSA-2015-1207.html", vulnerabilities[0].Link)
		assert.Equal(t, types.Critical, vulnerabilities[0].Priority)
		assert.Equal(t, `Mozilla Firefox is an open source web browser. XULRunner provides the XUL Runtime environment for Mozilla Firefox. Several flaws were found in the processing of malformed web content. A web page containing malicious content could cause Firefox to crash or, potentially, execute arbitrary code with the privileges of the user running Firefox.`, vulnerabilities[0].Description)

		if assert.Len(t, vulnerabilities[0].FixedIn, 2) {
			assert.Contains(t, vulnerabilities[0].FixedIn, &database.Package{
				OS:      "centos:6",
				Name:    "firefox",
				Version: types.NewVersionUnsafe("38.1.0-1.el6_6"),
			})
			assert.Contains(t, vulnerabilities[0].FixedIn, &database.Package{
				OS:      "centos:7",
				Name:    "firefox",
				Version: types.NewVersionUnsafe("38.1.0-1.el7_1"),
			})
		}
	}
}
Example #3
0
func TestDebianParser(t *testing.T) {
	_, filename, _, _ := runtime.Caller(0)

	// Test parsing testdata/fetcher_debian_test.json
	testFile, _ := os.Open(path.Join(path.Dir(filename)) + "/testdata/fetcher_debian_test.json")
	response, err := buildResponse(testFile, "")
	if assert.Nil(t, err) && assert.Len(t, response.Vulnerabilities, 2) {
		for _, vulnerability := range response.Vulnerabilities {
			if vulnerability.ID == "CVE-2015-1323" {
				assert.Equal(t, "https://security-tracker.debian.org/tracker/CVE-2015-1323", vulnerability.Link)
				assert.Equal(t, types.Low, vulnerability.Priority)
				assert.Equal(t, "This vulnerability is not very dangerous.", vulnerability.Description)

				if assert.Len(t, vulnerability.FixedIn, 2) {
					assert.Contains(t, vulnerability.FixedIn, &database.Package{
						OS:      "debian:8",
						Name:    "aptdaemon",
						Version: types.MaxVersion,
					})
					assert.Contains(t, vulnerability.FixedIn, &database.Package{
						OS:      "debian:unstable",
						Name:    "aptdaemon",
						Version: types.NewVersionUnsafe("1.1.1+bzr982-1"),
					})
				}
			} else if vulnerability.ID == "CVE-2003-0779" {
				assert.Equal(t, "https://security-tracker.debian.org/tracker/CVE-2003-0779", vulnerability.Link)
				assert.Equal(t, types.High, vulnerability.Priority)
				assert.Equal(t, "But this one is very dangerous.", vulnerability.Description)

				if assert.Len(t, vulnerability.FixedIn, 3) {
					assert.Contains(t, vulnerability.FixedIn, &database.Package{
						OS:      "debian:8",
						Name:    "aptdaemon",
						Version: types.NewVersionUnsafe("0.7.0"),
					})
					assert.Contains(t, vulnerability.FixedIn, &database.Package{
						OS:      "debian:unstable",
						Name:    "aptdaemon",
						Version: types.NewVersionUnsafe("0.7.0"),
					})
					assert.Contains(t, vulnerability.FixedIn, &database.Package{
						OS:      "debian:8",
						Name:    "asterisk",
						Version: types.NewVersionUnsafe("0.5.56"),
					})
				}
			} else {
				assert.Fail(t, "Wrong vulnerability name: ", vulnerability.ID)
			}
		}
	}
}
Example #4
0
func generateLayersData(sublayersCount, packagesCount, packagesPerBranchesCount int) string {
	var startPackages []string
	var allPackages []*database.Package
	for i := 0; i < packagesCount; i++ {
		for j := 0; j < packagesPerBranchesCount; j++ {
			p := &database.Package{
				OS:      "testOS",
				Name:    "p" + strconv.Itoa(i),
				Version: types.NewVersionUnsafe(strconv.Itoa(j)),
			}
			allPackages = append(allPackages, p)

			if j == 0 {
				startPackages = append(startPackages, p.GetNode())
			}
		}
	}
	err := database.InsertPackages(allPackages)
	if err != nil {
		panic(err)
	}

	var allLayers []*database.Layer
	var packagesCursor int
	for i := 0; i < sublayersCount; i++ {
		parentNode := ""
		if i > 0 {
			parentNode = allLayers[i-1].GetNode()
		}

		var installedPackagesNodes []string
		if i == sublayersCount-1 {
			if packagesCursor <= packagesCount-1 {
				installedPackagesNodes = startPackages[packagesCursor:packagesCount]
			}
		} else if (packagesCount / sublayersCount) > 0 {
			upperPackageCursor := int(math.Min(float64(packagesCursor+(packagesCount/sublayersCount)), float64(packagesCount)))
			installedPackagesNodes = startPackages[packagesCursor:upperPackageCursor]
			packagesCursor = upperPackageCursor
		}

		layer := &database.Layer{
			ID:         "l" + strconv.Itoa(i),
			ParentNode: parentNode,
			Content: database.LayerContent{
				TarSum: "lc" + strconv.Itoa(i),
				OS:     "testOS",
				InstalledPackagesNodes: installedPackagesNodes,
			},
		}
		err := database.InsertLayer(layer)
		if err != nil {
			panic(err)
		}
		allLayers = append(allLayers, layer)
	}

	return allLayers[sublayersCount-1].ID
}
Example #5
0
func TestDistUpgrade(t *testing.T) {
	database.Open("memstore", "")
	defer database.Close()

	_, f, _, _ := runtime.Caller(0)
	path := path.Join(path.Dir(f)) + "/testdata/DistUpgrade/"

	// blank.tar: MAINTAINER Quentin MACHU <quentin.machu.fr>
	// wheezy.tar: FROM debian:wheezy
	// jessie.tar: RUN sed -i "s/precise/trusty/" /etc/apt/sources.list && apt-get update && apt-get -y dist-upgrade
	assert.Nil(t, Process("blank", "", path+"blank.tar.gz"))
	assert.Nil(t, Process("wheezy", "blank", path+"wheezy.tar.gz"))
	assert.Nil(t, Process("jessie", "wheezy", path+"jessie.tar.gz"))

	wheezy, err := database.FindOneLayerByID("wheezy", database.FieldLayerAll)
	if assert.Nil(t, err) {
		assert.Equal(t, "debian:7", wheezy.OS)
		assert.Len(t, wheezy.InstalledPackagesNodes, 52)
		assert.Len(t, wheezy.RemovedPackagesNodes, 0)

		jessie, err := database.FindOneLayerByID("jessie", database.FieldLayerAll)
		if assert.Nil(t, err) {
			assert.Equal(t, "debian:8", jessie.OS)
			assert.Len(t, jessie.InstalledPackagesNodes, 66)
			assert.Len(t, jessie.RemovedPackagesNodes, 44)

			packageNodes, err := jessie.AllPackages()
			if assert.Nil(t, err) {
				// These packages haven't been upgraded
				nonUpgradedPackages := []database.Package{
					database.Package{Name: "libtext-wrapi18n-perl", Version: types.NewVersionUnsafe("0.06-7")},
					database.Package{Name: "libtext-charwidth-perl", Version: types.NewVersionUnsafe("0.04-7")},
					database.Package{Name: "libtext-iconv-perl", Version: types.NewVersionUnsafe("1.7-5")},
					database.Package{Name: "mawk", Version: types.NewVersionUnsafe("1.3.3-17")},
					database.Package{Name: "insserv", Version: types.NewVersionUnsafe("1.14.0-5")},
					database.Package{Name: "db", Version: types.NewVersionUnsafe("5.1.29-5")},
					database.Package{Name: "ustr", Version: types.NewVersionUnsafe("1.0.4-3")},
					database.Package{Name: "xz-utils", Version: types.NewVersionUnsafe("5.1.1alpha+20120614-2")},
				}
				for _, p := range nonUpgradedPackages {
					p.OS = "debian:7"
					assert.Contains(t, packageNodes, p.GetNode(), "Jessie layer doesn't have %s but it should.", p)
				}
				for _, p := range nonUpgradedPackages {
					p.OS = "debian:8"
					assert.NotContains(t, packageNodes, p.GetNode(), "Jessie layer has %s but it shouldn't.", p)
				}
			}
		}
	}
}
Example #6
0
import (
	"testing"

	"github.com/coreos/quay-sec/database"
	"github.com/coreos/quay-sec/utils/types"
)

var rpmPackagesTests = []packagesTest{
	// Test a CentOS 7 RPM database
	// Memo: Use the following command on a RPM-based system to shrink a database: rpm -qa --qf "%{NAME}\n" |tail -n +3| xargs rpm -e --justdb
	packagesTest{
		packages: []*database.Package{
			&database.Package{
				Name:    "centos-release", // Two packages from this source are installed, it should only appear one time
				Version: types.NewVersionUnsafe("7-1.1503.el7.centos.2.8"),
			},
			&database.Package{
				Name:    "filesystem", // Two packages from this source are installed, it should only appear one time
				Version: types.NewVersionUnsafe("3.2-18.el7"),
			},
		},
		data: map[string][]byte{
			"var/lib/rpm/Packages": loadFileForTest("testdata/rpm_Packages"),
		},
	},
}

func TestRpmPackagesDetector(t *testing.T) {
	testPackagesDetector(t, &RpmPackagesDetector{}, rpmPackagesTests)
}
Example #7
0
package packages

import (
	"testing"

	"github.com/coreos/quay-sec/database"
	"github.com/coreos/quay-sec/utils/types"
)

var dpkgPackagesTests = []packagesTest{
	// Test an Ubuntu dpkg status file
	packagesTest{
		packages: []*database.Package{
			&database.Package{
				Name:    "pam", // Two packages from this source are installed, it should only appear one time
				Version: types.NewVersionUnsafe("1.1.8-3.1ubuntu3"),
			},
			&database.Package{
				Name:    "makedev",                                 // The source name and the package name are equals
				Version: types.NewVersionUnsafe("2.3.1-93ubuntu1"), // The version comes from the "Version:" line
			},
			&database.Package{
				Name:    "gcc-5",
				Version: types.NewVersionUnsafe("5.1.1-12ubuntu1"), // The version comes from the "Source:" line
			},
		},
		data: map[string][]byte{
			"var/lib/dpkg/status": loadFileForTest("testdata/dpkg_status"),
		},
	},
}
Example #8
0
func TestPackage(t *testing.T) {
	Open("memstore", "")
	defer Close()

	// Try to insert invalid packages
	for _, invalidPkg := range []*Package{
		&Package{OS: "", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")},
		&Package{OS: "testOS", Name: "", Version: types.NewVersionUnsafe("1.0")},
		&Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("")},
		&Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("bad version")},
		&Package{OS: "", Name: "", Version: types.NewVersionUnsafe("")},
	} {
		err := InsertPackages([]*Package{invalidPkg})
		assert.Error(t, err)
	}

	// Insert a package
	pkg1 := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}
	err := InsertPackages([]*Package{pkg1})
	if assert.Nil(t, err) {
		// Find the inserted package and verify its content
		pkg1b, err := FindOnePackage(pkg1.OS, pkg1.Name, pkg1.Version, FieldPackageAll)
		if assert.Nil(t, err) && assert.NotNil(t, pkg1b) {
			assert.Equal(t, pkg1.Node, pkg1b.Node)
			assert.Equal(t, pkg1.OS, pkg1b.OS)
			assert.Equal(t, pkg1.Name, pkg1b.Name)
			assert.Equal(t, pkg1.Version, pkg1b.Version)
		}

		// Find packages from the inserted branch and verify their content
		// (the first one should be a start package, the second one the inserted one and the third one the end package)
		pkgs1c, err := FindAllPackagesByBranch(pkg1.OS, pkg1.Name, FieldPackageAll)
		if assert.Nil(t, err) && assert.Equal(t, 3, len(pkgs1c)) {
			sort.Sort(ByVersion(pkgs1c))

			assert.Equal(t, pkg1.OS, pkgs1c[0].OS)
			assert.Equal(t, pkg1.Name, pkgs1c[0].Name)
			assert.Equal(t, types.MinVersion, pkgs1c[0].Version)

			assert.Equal(t, pkg1.OS, pkgs1c[1].OS)
			assert.Equal(t, pkg1.Name, pkgs1c[1].Name)
			assert.Equal(t, pkg1.Version, pkgs1c[1].Version)

			assert.Equal(t, pkg1.OS, pkgs1c[2].OS)
			assert.Equal(t, pkg1.Name, pkgs1c[2].Name)
			assert.Equal(t, types.MaxVersion, pkgs1c[2].Version)
		}
	}

	// Insert multiple packages in the same branch, one in another branch, insert local duplicates and database duplicates as well
	pkg2 := []*Package{
		&Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("0.8")},
		&Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("0.9")},
		&Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}, // Already present in the database
		&Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.1")},
		&Package{OS: "testOS", Name: "testpkg2", Version: types.NewVersionUnsafe("1.0")}, // Another branch
		&Package{OS: "testOS", Name: "testpkg2", Version: types.NewVersionUnsafe("1.0")}, // Local duplicates
	}
	nbInSameBranch := 4 + 2 // (start/end packages)

	err = InsertPackages(shuffle(pkg2))
	if assert.Nil(t, err) {
		// Find packages from the inserted branch, verify their order and NextVersion / PreviousVersion
		pkgs2b, err := FindAllPackagesByBranch("testOS", "testpkg1", FieldPackageAll)
		if assert.Nil(t, err) && assert.Equal(t, nbInSameBranch, len(pkgs2b)) {
			sort.Sort(ByVersion(pkgs2b))

			for i := 0; i < nbInSameBranch; i = i + 1 {
				if i == 0 {
					assert.Equal(t, types.MinVersion, pkgs2b[0].Version)
				} else if i < nbInSameBranch-2 {
					assert.Equal(t, pkg2[i].Version, pkgs2b[i+1].Version)

					nv, err := pkgs2b[i+1].NextVersion(FieldPackageAll)
					assert.Nil(t, err)
					assert.Equal(t, pkgs2b[i+2], nv)

					if i > 0 {
						pv, err := pkgs2b[i].PreviousVersion(FieldPackageAll)
						assert.Nil(t, err)
						assert.Equal(t, pkgs2b[i-1], pv)
					} else {
						pv, err := pkgs2b[i].PreviousVersion(FieldPackageAll)
						assert.Nil(t, err)
						assert.Nil(t, pv)
					}
				} else {
					assert.Equal(t, types.MaxVersion, pkgs2b[nbInSameBranch-1].Version)

					nv, err := pkgs2b[nbInSameBranch-1].NextVersion(FieldPackageAll)
					assert.Nil(t, err)
					assert.Nil(t, nv)

					pv, err := pkgs2b[i].PreviousVersion(FieldPackageAll)
					assert.Nil(t, err)
					assert.Equal(t, pkgs2b[i-1], pv)
				}
			}

			// NextVersions
			nv, err := pkgs2b[0].NextVersions(FieldPackageAll)
			if assert.Nil(t, err) && assert.Len(t, nv, nbInSameBranch-1) {
				for i := 0; i < nbInSameBranch-1; i = i + 1 {
					if i < nbInSameBranch-2 {
						assert.Equal(t, pkg2[i].Version, nv[i].Version)
					} else {
						assert.Equal(t, types.MaxVersion, nv[i].Version)
					}
				}
			}

			// PreviousVersions
			pv, err := pkgs2b[nbInSameBranch-1].PreviousVersions(FieldPackageAll)
			if assert.Nil(t, err) && assert.Len(t, pv, nbInSameBranch-1) {
				for i := 0; i < len(pv); i = i + 1 {
					assert.Equal(t, pkgs2b[len(pkgs2b)-i-2], pv[i])
				}
			}
		}

		// Verify that the one we added which was already present in the database has the same node value (meaning that we just fetched it actually)
		assert.Contains(t, pkg2, pkg1)
	}

	// Insert duplicated latest packages directly, ensure only one is actually inserted. Then insert another package in the branch and ensure that its next version is the latest one
	pkg3a := &Package{OS: "testOS", Name: "testpkg3", Version: types.MaxVersion}
	pkg3b := &Package{OS: "testOS", Name: "testpkg3", Version: types.MaxVersion}
	pkg3c := &Package{OS: "testOS", Name: "testpkg3", Version: types.MaxVersion}
	err1 := InsertPackages([]*Package{pkg3a, pkg3b})
	err2 := InsertPackages([]*Package{pkg3c})
	if assert.Nil(t, err1) && assert.Nil(t, err2) {
		assert.Equal(t, pkg3a, pkg3b)
		assert.Equal(t, pkg3b, pkg3c)
	}
	pkg4 := Package{OS: "testOS", Name: "testpkg3", Version: types.NewVersionUnsafe("1.0")}
	InsertPackages([]*Package{&pkg4})
	pkgs34, _ := FindAllPackagesByBranch("testOS", "testpkg3", FieldPackageAll)
	if assert.Len(t, pkgs34, 3) {
		sort.Sort(ByVersion(pkgs34))
		assert.Equal(t, pkg4.Node, pkgs34[1].Node)
		assert.Equal(t, pkg3a.Node, pkgs34[2].Node)
		assert.Equal(t, pkg3a.Node, pkgs34[1].NextVersionNode)
	}

	// Insert two identical packages but with "different" versions
	// The second version should be simplified to the first one
	// Therefore, we should just have three packages (the inserted one and the start/end packages of the branch)
	InsertPackages([]*Package{&Package{OS: "testOS", Name: "testdirtypkg", Version: types.NewVersionUnsafe("0.1")}})
	InsertPackages([]*Package{&Package{OS: "testOS", Name: "testdirtypkg", Version: types.NewVersionUnsafe("0:0.1")}})
	dirtypkgs, err := FindAllPackagesByBranch("testOS", "testdirtypkg", FieldPackageAll)
	assert.Nil(t, err)
	assert.Len(t, dirtypkgs, 3)
}
Example #9
0
func TestVulnerability(t *testing.T) {
	Open("memstore", "")
	defer Close()

	// Insert invalid vulnerabilities
	for _, vulnerability := range []Vulnerability{
		Vulnerability{ID: "", Link: "link1", Priority: types.Medium, FixedInNodes: []string{"pkg1"}},
		Vulnerability{ID: "test1", Link: "", Priority: types.Medium, FixedInNodes: []string{"pkg1"}},
		Vulnerability{ID: "test1", Link: "link1", Priority: "InvalidPriority", FixedInNodes: []string{"pkg1"}},
		Vulnerability{ID: "test1", Link: "link1", Priority: types.Medium, FixedInNodes: []string{}},
	} {
		_, err := InsertVulnerabilities([]*Vulnerability{&vulnerability})
		assert.Error(t, err)
	}

	// Some data
	vuln1 := &Vulnerability{ID: "test1", Link: "link1", Priority: types.Medium, Description: "testDescription1", FixedInNodes: []string{"pkg1"}}
	vuln2 := &Vulnerability{ID: "test2", Link: "link2", Priority: types.High, Description: "testDescription2", FixedInNodes: []string{"pkg1", "pkg2"}}
	vuln3 := &Vulnerability{ID: "test3", Link: "link3", Priority: types.High, FixedInNodes: []string{"pkg3"}} // Empty description

	// Insert some vulnerabilities
	_, err := InsertVulnerabilities([]*Vulnerability{vuln1, vuln2, vuln3})
	if assert.Nil(t, err) {
		// Find one of the vulnerabilities we just inserted and verify its content
		v1, err := FindOneVulnerability(vuln1.ID, FieldVulnerabilityAll)
		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])
			}
		}

		// Ensure that vulnerabilities with empty descriptions work as well
		v3, err := FindOneVulnerability(vuln3.ID, FieldVulnerabilityAll)
		if assert.Nil(t, err) && assert.NotNil(t, v3) {
			assert.Equal(t, vuln3.Description, v3.Description)
		}

		// Find vulnerabilities by fixed packages
		vulnsFixedInPkg1AndPkg3, err := FindAllVulnerabilitiesByFixedIn([]string{"pkg2", "pkg3"}, FieldVulnerabilityAll)
		assert.Nil(t, err)
		assert.Len(t, vulnsFixedInPkg1AndPkg3, 2)

		// Delete vulnerability
		if assert.Nil(t, DeleteVulnerability(vuln1.ID)) {
			v1, err := FindOneVulnerability(vuln1.ID, FieldVulnerabilityAll)
			assert.Equal(t, cerrors.ErrNotFound, err)
			assert.Nil(t, v1)
		}
	}

	// Update a vulnerability and verify its new content
	pkg1 := &Package{OS: "testOS", Name: "testpkg1", Version: types.NewVersionUnsafe("1.0")}
	InsertPackages([]*Package{pkg1})
	vuln5 := &Vulnerability{ID: "test5", Link: "link5", Priority: types.Medium, Description: "testDescription5", FixedInNodes: []string{pkg1.Node}}

	_, err = InsertVulnerabilities([]*Vulnerability{vuln5})
	if assert.Nil(t, err) {
		// Partial updates
		// # Just a field update
		vuln5b := &Vulnerability{ID: "test5", Priority: types.High}
		_, err := InsertVulnerabilities([]*Vulnerability{vuln5b})
		if assert.Nil(t, err) {
			v5b, err := FindOneVulnerability(vuln5b.ID, FieldVulnerabilityAll)
			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 := &Vulnerability{ID: "test5", Link: "http://foo.bar"}
		vuln5b2 := &Vulnerability{ID: "test5", Link: "http://bar.foo"}
		_, err = InsertVulnerabilities([]*Vulnerability{vuln5b1, vuln5b2})
		if assert.Nil(t, err) {
			v5b2, err := FindOneVulnerability(vuln5b2.ID, FieldVulnerabilityAll)
			if assert.Nil(t, err) && assert.NotNil(t, v5b2) {
				assert.Equal(t, vuln5b2.Link, v5b2.Link)
			}
		}

		// # All fields except fixedIn update
		vuln5c := &Vulnerability{ID: "test5", Link: "link5c", Priority: types.Critical, Description: "testDescription5c"}
		_, err = InsertVulnerabilities([]*Vulnerability{vuln5c})
		if assert.Nil(t, err) {
			v5c, err := FindOneVulnerability(vuln5c.ID, FieldVulnerabilityAll)
			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 := &Vulnerability{ID: "test5", Link: "link5d", Priority: types.Low, Description: "testDescription5d", FixedInNodes: []string{pkg2.Node, pkg3.Node}}

		_, err = InsertVulnerabilities([]*Vulnerability{vuln5d})
		if assert.Nil(t, err) {
			v5d, err := FindOneVulnerability(vuln5d.ID, FieldVulnerabilityAll)
			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 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 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})
	// # 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
	pkg0 := &Package{OS: "testOS", Name: "testpkg0", Version: types.NewVersionUnsafe("1.0")}
	InsertPackages([]*Package{pkg0})
	_, err = InsertVulnerabilities([]*Vulnerability{&Vulnerability{ID: "test7", Link: "link7", Priority: types.Medium, Description: "testDescription7", FixedInNodes: []string{pkg0.Node}}})
	if assert.Nil(t, err) {
		vuln7b := &Vulnerability{ID: "test7", FixedInNodes: []string{pkg1.Node}}
		vuln7c := &Vulnerability{ID: "test7", FixedInNodes: []string{pkg1b.Node}}
		_, err = InsertVulnerabilities([]*Vulnerability{vuln7b, vuln7c})
		if assert.Nil(t, err) {
			v7, err := FindOneVulnerability("test7", FieldVulnerabilityAll)
			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)
			}

			// # 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)
		}
	}
}