Example #1
0
func TestInsertVulnerabilityNotifications(t *testing.T) {
	Open(&config.DatabaseConfig{Type: "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 TestDpkgFeatureDetection(t *testing.T) {
	testData := []feature.TestData{
		// Test an Ubuntu dpkg status file
		{
			FeatureVersions: []database.FeatureVersion{
				// Two packages from this source are installed, it should only appear one time
				{
					Feature: database.Feature{Name: "pam"},
					Version: types.NewVersionUnsafe("1.1.8-3.1ubuntu3"),
				},
				{
					Feature: database.Feature{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
				},
				{
					Feature: database.Feature{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": feature.LoadFileForTest("dpkg/testdata/status"),
			},
		},
	}

	feature.TestDetector(t, &DpkgFeaturesDetector{}, testData)
}
Example #3
0
func TestRpmFeatureDetection(t *testing.T) {
	testData := []feature.TestData{
		// 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
		{
			FeatureVersions: []database.FeatureVersion{
				// Two packages from this source are installed, it should only appear once
				{
					Feature: database.Feature{Name: "centos-release"},
					Version: types.NewVersionUnsafe("7-1.1503.el7.centos.2.8"),
				},
				// Two packages from this source are installed, it should only appear once
				{
					Feature: database.Feature{Name: "filesystem"},
					Version: types.NewVersionUnsafe("3.2-18.el7"),
				},
			},
			Data: map[string][]byte{
				"var/lib/rpm/Packages": feature.LoadFileForTest("rpm/testdata/Packages"),
			},
		},
	}

	feature.TestDetector(t, &RpmFeaturesDetector{}, testData)
}
Example #4
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 #5
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 #6
0
func TestFindVulnerability(t *testing.T) {
	datastore, err := openDatabaseForTest("FindVulnerability", true)
	if err != nil {
		t.Error(err)
		return
	}
	defer datastore.Close()

	// Find a vulnerability that does not exist.
	_, err = datastore.FindVulnerability("", "")
	assert.Equal(t, cerrors.ErrNotFound, err)

	// Find a normal vulnerability.
	v1 := database.Vulnerability{
		Name:        "CVE-OPENSSL-1-DEB7",
		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{
			{
				Feature: database.Feature{Name: "openssl"},
				Version: types.NewVersionUnsafe("2.0"),
			},
			{
				Feature: database.Feature{Name: "libssl"},
				Version: types.NewVersionUnsafe("1.9-abc"),
			},
		},
	}

	v1f, err := datastore.FindVulnerability("debian:7", "CVE-OPENSSL-1-DEB7")
	if assert.Nil(t, err) {
		equalsVuln(t, &v1, &v1f)
	}

	// Find a vulnerability that has no link, no severity and no FixedIn.
	v2 := database.Vulnerability{
		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")
	if assert.Nil(t, err) {
		equalsVuln(t, &v2, &v2f)
	}
}
Example #7
0
func TestDistUpgrade(t *testing.T) {
	database.Open(&config.DatabaseConfig{Type: "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", "Docker"))
	assert.Nil(t, Process("wheezy", "blank", path+"wheezy.tar.gz", "Docker"))
	assert.Nil(t, Process("jessie", "wheezy", path+"jessie.tar.gz", "Docker"))

	err := Process("blank", "", path+"blank.tar.gz", "")
	assert.Error(t, err, "could not process a layer which does not have a specified format")

	err = Process("blank", "", path+"blank.tar.gz", "invalid")
	assert.Error(t, err, "could not process a layer which does not have a supported format")

	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 #8
0
func TestUbuntuParser(t *testing.T) {
	_, filename, _, _ := runtime.Caller(0)
	path := filepath.Join(filepath.Dir(filename))

	// Test parsing testdata/fetcher_
	testData, _ := os.Open(path + "/testdata/fetcher_ubuntu_test.txt")
	defer testData.Close()
	vulnerability, unknownReleases, err := parseUbuntuCVE(testData)
	if assert.Nil(t, err) {
		assert.Equal(t, "CVE-2015-4471", vulnerability.Name)
		assert.Equal(t, types.Medium, vulnerability.Severity)
		assert.Equal(t, "Off-by-one error in the lzxd_decompress function in lzxd.c in libmspack before 0.5 allows remote attackers to cause a denial of service (buffer under-read and application crash) via a crafted CAB archive.", vulnerability.Description)

		// Unknown release (line 28)
		_, hasUnkownRelease := unknownReleases["unknown"]
		assert.True(t, hasUnkownRelease)

		expectedFeatureVersions := []database.FeatureVersion{
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "ubuntu:14.04"},
					Name:      "libmspack",
				},
				Version: types.MaxVersion,
			},
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "ubuntu:15.04"},
					Name:      "libmspack",
				},
				Version: types.NewVersionUnsafe("0.4-3"),
			},
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "ubuntu:15.10"},
					Name:      "libmspack-anotherpkg",
				},
				Version: types.NewVersionUnsafe("0.1"),
			},
		}

		for _, expectedFeatureVersion := range expectedFeatureVersions {
			assert.Contains(t, vulnerability.FixedIn, expectedFeatureVersion)
		}
	}
}
Example #9
0
func TestDoVulnerabilitiesNamespacing(t *testing.T) {
	fv1 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "Namespace1"},
			Name:      "Feature1",
		},
		Version: types.NewVersionUnsafe("0.1"),
	}

	fv2 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "Namespace2"},
			Name:      "Feature1",
		},
		Version: types.NewVersionUnsafe("0.2"),
	}

	fv3 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "Namespace2"},
			Name:      "Feature2",
		},
		Version: types.NewVersionUnsafe("0.3"),
	}

	vulnerability := database.Vulnerability{
		Name:    "DoVulnerabilityNamespacing",
		FixedIn: []database.FeatureVersion{fv1, fv2, fv3},
	}

	vulnerabilities := doVulnerabilitiesNamespacing([]database.Vulnerability{vulnerability})
	for _, vulnerability := range vulnerabilities {
		switch vulnerability.Namespace.Name {
		case fv1.Feature.Namespace.Name:
			assert.Len(t, vulnerability.FixedIn, 1)
			assert.Contains(t, vulnerability.FixedIn, fv1)
		case fv2.Feature.Namespace.Name:
			assert.Len(t, vulnerability.FixedIn, 2)
			assert.Contains(t, vulnerability.FixedIn, fv2)
			assert.Contains(t, vulnerability.FixedIn, fv3)
		default:
			t.Errorf("Should not have a Vulnerability with '%s' as its Namespace.", vulnerability.Namespace.Name)
			fmt.Printf("%#v\n", vulnerability)
		}
	}
}
Example #10
0
func TestSLEParser(t *testing.T) {
	_, filename, _, _ := runtime.Caller(0)
	path := filepath.Join(filepath.Dir(filename))

	// Test parsing testdata/fetcher_sle_test.1.xml
	testFile, _ := os.Open(path + "/testdata/fetcher_sle_test.1.xml")
	ov := &oval.OvalFetcher{OsInfo: &SLEInfo{}}
	vulnerabilities, err := ov.ParseOval(testFile)
	if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 1) {
		assert.Equal(t, "CVE-2012-2150", vulnerabilities[0].Name)
		assert.Equal(t, "http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2150", vulnerabilities[0].Link)
		// Severity is not defined for SLE
		assert.Equal(t, types.Unknown, vulnerabilities[0].Severity)
		assert.Equal(t, `xfs_metadump in xfsprogs before 3.2.4 does not properly obfuscate file data, which allows remote attackers to obtain sensitive information by reading a generated image.`, vulnerabilities[0].Description)

		expectedFeatureVersions := []database.FeatureVersion{
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "sle:12"},
					Name:      "xfsprogs",
				},
				Version: types.NewVersionUnsafe("3.2.1-3.5"),
			},
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "sle:12.1"},
					Name:      "xfsprogs",
				},
				Version: types.NewVersionUnsafe("3.2.1-3.5"),
			},
		}

		for _, expectedFeatureVersion := range expectedFeatureVersions {
			assert.Contains(t, vulnerabilities[0].FixedIn, expectedFeatureVersion)
		}

	}

}
Example #11
0
func testInsertLayerUpdate(t *testing.T, datastore database.Datastore) {
	f7 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"},
			Name:      "TestInsertLayerFeature7",
		},
		Version: types.NewVersionUnsafe("0.01"),
	}

	l3, _ := datastore.FindLayer("TestInsertLayer3", true, false)
	l3u := database.Layer{
		Name:      l3.Name,
		Parent:    l3.Parent,
		Namespace: &database.Namespace{Name: "TestInsertLayerNamespaceUpdated1"},
		Features:  []database.FeatureVersion{f7},
	}

	l4u := database.Layer{
		Name:          "TestInsertLayer4",
		Parent:        &database.Layer{Name: "TestInsertLayer3"},
		Features:      []database.FeatureVersion{f7},
		EngineVersion: 2,
	}

	// Try to re-insert without increasing the EngineVersion.
	err := datastore.InsertLayer(l3u)
	assert.Nil(t, err)

	l3uf, err := datastore.FindLayer(l3u.Name, true, false)
	if assert.Nil(t, err) {
		assert.Equal(t, l3.Namespace.Name, l3uf.Namespace.Name)
		assert.Equal(t, l3.EngineVersion, l3uf.EngineVersion)
		assert.Len(t, l3uf.Features, len(l3.Features))
	}

	// Update layer l3.
	// Verify that the Namespace, EngineVersion and FeatureVersions got updated.
	l3u.EngineVersion = 2
	err = datastore.InsertLayer(l3u)
	assert.Nil(t, err)

	l3uf, err = datastore.FindLayer(l3u.Name, true, false)
	if assert.Nil(t, err) {
		assert.Equal(t, l3u.Namespace.Name, l3uf.Namespace.Name)
		assert.Equal(t, l3u.EngineVersion, l3uf.EngineVersion)
		if assert.Len(t, l3uf.Features, 1) {
			assert.True(t, cmpFV(l3uf.Features[0], f7), "Updated layer should have %#v but actually have %#v", f7, l3uf.Features[0])
		}
	}

	// Update layer l4.
	// Verify that the Namespace got updated from its new Parent's, and also verify the
	// EnginVersion and FeatureVersions.
	l4u.Parent = &l3uf
	err = datastore.InsertLayer(l4u)
	assert.Nil(t, err)

	l4uf, err := datastore.FindLayer(l3u.Name, true, false)
	if assert.Nil(t, err) {
		assert.Equal(t, l3u.Namespace.Name, l4uf.Namespace.Name)
		assert.Equal(t, l4u.EngineVersion, l4uf.EngineVersion)
		if assert.Len(t, l4uf.Features, 1) {
			assert.True(t, cmpFV(l3uf.Features[0], f7), "Updated layer should have %#v but actually have %#v", f7, l4uf.Features[0])
		}
	}
}
Example #12
0
func TestProcessWithDistUpgrade(t *testing.T) {
	// TODO(Quentin-M): This should not be bound to a single database implementation.
	datastore, err := pgsql.OpenForTest("ProcessWithDistUpgrade", false)
	if err != nil {
		t.Error(err)
		return
	}
	defer datastore.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(datastore, "Docker", "blank", "", path+"blank.tar.gz", nil))
	assert.Nil(t, Process(datastore, "Docker", "wheezy", "blank", path+"wheezy.tar.gz", nil))
	assert.Nil(t, Process(datastore, "Docker", "jessie", "wheezy", path+"jessie.tar.gz", nil))

	wheezy, err := datastore.FindLayer("wheezy", true, false)
	if assert.Nil(t, err) {
		assert.Equal(t, "debian:7", wheezy.Namespace.Name)
		assert.Len(t, wheezy.Features, 52)

		jessie, err := datastore.FindLayer("jessie", true, false)
		if assert.Nil(t, err) {
			assert.Equal(t, "debian:8", jessie.Namespace.Name)
			assert.Len(t, jessie.Features, 74)

			// These FeatureVersions haven't been upgraded.
			nonUpgradedFeatureVersions := []database.FeatureVersion{
				{
					Feature: database.Feature{Name: "libtext-wrapi18n-perl"},
					Version: types.NewVersionUnsafe("0.06-7"),
				},
				{
					Feature: database.Feature{Name: "libtext-charwidth-perl"},
					Version: types.NewVersionUnsafe("0.04-7"),
				},
				{
					Feature: database.Feature{Name: "libtext-iconv-perl"},
					Version: types.NewVersionUnsafe("1.7-5"),
				},
				{
					Feature: database.Feature{Name: "mawk"},
					Version: types.NewVersionUnsafe("1.3.3-17"),
				},
				{
					Feature: database.Feature{Name: "insserv"},
					Version: types.NewVersionUnsafe("1.14.0-5"),
				},
				{
					Feature: database.Feature{Name: "db"},
					Version: types.NewVersionUnsafe("5.1.29-5"),
				},
				{
					Feature: database.Feature{Name: "ustr"},
					Version: types.NewVersionUnsafe("1.0.4-3"),
				},
				{
					Feature: database.Feature{Name: "xz-utils"},
					Version: types.NewVersionUnsafe("5.1.1alpha+20120614-2"),
				},
			}

			for _, nufv := range nonUpgradedFeatureVersions {
				nufv.Feature.Namespace.Name = "debian:7"

				found := false
				for _, fv := range jessie.Features {
					if fv.Feature.Name == nufv.Feature.Name &&
						fv.Feature.Namespace.Name == nufv.Feature.Namespace.Name &&
						fv.Version == nufv.Version {
						found = true
						break
					}
				}
				assert.Equal(t, true, found, "Jessie layer doesn't have %#v but it should.", nufv)
			}

			for _, nufv := range nonUpgradedFeatureVersions {
				nufv.Feature.Namespace.Name = "debian:8"

				found := false
				for _, fv := range jessie.Features {
					if fv.Feature.Name == nufv.Feature.Name &&
						fv.Feature.Namespace.Name == nufv.Feature.Namespace.Name &&
						fv.Version == nufv.Version {
						found = true
						break
					}
				}
				assert.Equal(t, false, found, "Jessie layer has %#v but it shouldn't.", nufv)
			}
		}
	}
}
Example #13
0
func TestNotification(t *testing.T) {
	datastore, err := openDatabaseForTest("Notification", false)
	if err != nil {
		t.Error(err)
		return
	}
	defer datastore.Close()

	// Try to get a notification when there is none.
	_, err = datastore.GetAvailableNotification(time.Second)
	assert.Equal(t, cerrors.ErrNotFound, err)

	// Create some data.
	f1 := database.Feature{
		Name:      "TestNotificationFeature1",
		Namespace: database.Namespace{Name: "TestNotificationNamespace1"},
	}

	f2 := database.Feature{
		Name:      "TestNotificationFeature2",
		Namespace: database.Namespace{Name: "TestNotificationNamespace1"},
	}

	l1 := database.Layer{
		Name: "TestNotificationLayer1",
		Features: []database.FeatureVersion{
			{
				Feature: f1,
				Version: types.NewVersionUnsafe("0.1"),
			},
		},
	}

	l2 := database.Layer{
		Name: "TestNotificationLayer2",
		Features: []database.FeatureVersion{
			{
				Feature: f1,
				Version: types.NewVersionUnsafe("0.2"),
			},
		},
	}

	l3 := database.Layer{
		Name: "TestNotificationLayer3",
		Features: []database.FeatureVersion{
			{
				Feature: f1,
				Version: types.NewVersionUnsafe("0.3"),
			},
		},
	}

	l4 := database.Layer{
		Name: "TestNotificationLayer4",
		Features: []database.FeatureVersion{
			{
				Feature: f2,
				Version: types.NewVersionUnsafe("0.1"),
			},
		},
	}

	if !assert.Nil(t, datastore.InsertLayer(l1)) ||
		!assert.Nil(t, datastore.InsertLayer(l2)) ||
		!assert.Nil(t, datastore.InsertLayer(l3)) ||
		!assert.Nil(t, datastore.InsertLayer(l4)) {
		return
	}

	// Insert a new vulnerability that is introduced by three layers.
	v1 := database.Vulnerability{
		Name:        "TestNotificationVulnerability1",
		Namespace:   f1.Namespace,
		Description: "TestNotificationDescription1",
		Link:        "TestNotificationLink1",
		Severity:    "Unknown",
		FixedIn: []database.FeatureVersion{
			{
				Feature: f1,
				Version: types.NewVersionUnsafe("1.0"),
			},
		},
	}
	assert.Nil(t, datastore.insertVulnerability(v1, false, true))

	// Get the notification associated to the previously inserted vulnerability.
	notification, err := datastore.GetAvailableNotification(time.Second)

	if assert.Nil(t, err) && assert.NotEmpty(t, notification.Name) {
		// Verify the renotify behaviour.
		if assert.Nil(t, datastore.SetNotificationNotified(notification.Name)) {
			_, err := datastore.GetAvailableNotification(time.Second)
			assert.Equal(t, cerrors.ErrNotFound, err)

			time.Sleep(50 * time.Millisecond)
			notificationB, err := datastore.GetAvailableNotification(20 * time.Millisecond)
			assert.Nil(t, err)
			assert.Equal(t, notification.Name, notificationB.Name)

			datastore.SetNotificationNotified(notification.Name)
		}

		// Get notification.
		filledNotification, nextPage, err := datastore.GetNotification(notification.Name, 2, database.VulnerabilityNotificationFirstPage)
		if assert.Nil(t, err) {
			assert.NotEqual(t, database.NoVulnerabilityNotificationPage, nextPage)
			assert.Nil(t, filledNotification.OldVulnerability)

			if assert.NotNil(t, filledNotification.NewVulnerability) {
				assert.Equal(t, v1.Name, filledNotification.NewVulnerability.Name)
				assert.Len(t, filledNotification.NewVulnerability.LayersIntroducingVulnerability, 2)
			}
		}

		// Get second page.
		filledNotification, nextPage, err = datastore.GetNotification(notification.Name, 2, nextPage)
		if assert.Nil(t, err) {
			assert.Equal(t, database.NoVulnerabilityNotificationPage, nextPage)
			assert.Nil(t, filledNotification.OldVulnerability)

			if assert.NotNil(t, filledNotification.NewVulnerability) {
				assert.Equal(t, v1.Name, filledNotification.NewVulnerability.Name)
				assert.Len(t, filledNotification.NewVulnerability.LayersIntroducingVulnerability, 1)
			}
		}

		// Delete notification.
		assert.Nil(t, datastore.DeleteNotification(notification.Name))

		_, err = datastore.GetAvailableNotification(time.Millisecond)
		assert.Equal(t, cerrors.ErrNotFound, err)
	}

	// Update a vulnerability and ensure that the old/new vulnerabilities are correct.
	v1b := v1
	v1b.Severity = types.High
	v1b.FixedIn = []database.FeatureVersion{
		{
			Feature: f1,
			Version: types.MinVersion,
		},
		{
			Feature: f2,
			Version: types.MaxVersion,
		},
	}

	if assert.Nil(t, datastore.insertVulnerability(v1b, false, true)) {
		notification, err = datastore.GetAvailableNotification(time.Second)
		assert.Nil(t, err)
		assert.NotEmpty(t, notification.Name)

		if assert.Nil(t, err) && assert.NotEmpty(t, notification.Name) {
			filledNotification, nextPage, err := datastore.GetNotification(notification.Name, 2, database.VulnerabilityNotificationFirstPage)
			if assert.Nil(t, err) {
				if assert.NotNil(t, filledNotification.OldVulnerability) {
					assert.Equal(t, v1.Name, filledNotification.OldVulnerability.Name)
					assert.Equal(t, v1.Severity, filledNotification.OldVulnerability.Severity)
					assert.Len(t, filledNotification.OldVulnerability.LayersIntroducingVulnerability, 2)
				}

				if assert.NotNil(t, filledNotification.NewVulnerability) {
					assert.Equal(t, v1b.Name, filledNotification.NewVulnerability.Name)
					assert.Equal(t, v1b.Severity, filledNotification.NewVulnerability.Severity)
					assert.Len(t, filledNotification.NewVulnerability.LayersIntroducingVulnerability, 1)
				}

				assert.Equal(t, -1, nextPage.NewVulnerability)
			}

			assert.Nil(t, datastore.DeleteNotification(notification.Name))
		}
	}

	// Delete a vulnerability and verify the notification.
	if assert.Nil(t, datastore.DeleteVulnerability(v1b.Namespace.Name, v1b.Name)) {
		notification, err = datastore.GetAvailableNotification(time.Second)
		assert.Nil(t, err)
		assert.NotEmpty(t, notification.Name)

		if assert.Nil(t, err) && assert.NotEmpty(t, notification.Name) {
			filledNotification, _, err := datastore.GetNotification(notification.Name, 2, database.VulnerabilityNotificationFirstPage)
			if assert.Nil(t, err) {
				assert.Nil(t, filledNotification.NewVulnerability)

				if assert.NotNil(t, filledNotification.OldVulnerability) {
					assert.Equal(t, v1b.Name, filledNotification.OldVulnerability.Name)
					assert.Equal(t, v1b.Severity, filledNotification.OldVulnerability.Severity)
					assert.Len(t, filledNotification.OldVulnerability.LayersIntroducingVulnerability, 1)
				}
			}

			assert.Nil(t, datastore.DeleteNotification(notification.Name))
		}
	}
}
Example #14
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 #15
0
func TestInsertFeature(t *testing.T) {
	datastore, err := OpenForTest("InsertFeature", false)
	if err != nil {
		t.Error(err)
		return
	}
	defer datastore.Close()

	// Invalid Feature.
	id0, err := datastore.insertFeature(database.Feature{})
	assert.NotNil(t, err)
	assert.Zero(t, id0)

	id0, err = datastore.insertFeature(database.Feature{
		Namespace: database.Namespace{},
		Name:      "TestInsertFeature0",
	})
	assert.NotNil(t, err)
	assert.Zero(t, id0)

	// Insert Feature and ensure we can find it.
	feature := database.Feature{
		Namespace: database.Namespace{Name: "TestInsertFeatureNamespace1"},
		Name:      "TestInsertFeature1",
	}
	id1, err := datastore.insertFeature(feature)
	assert.Nil(t, err)
	id2, err := datastore.insertFeature(feature)
	assert.Nil(t, err)
	assert.Equal(t, id1, id2)

	// Insert invalid FeatureVersion.
	for _, invalidFeatureVersion := range []database.FeatureVersion{
		{
			Feature: database.Feature{},
			Version: types.NewVersionUnsafe("1.0"),
		},
		{
			Feature: database.Feature{
				Namespace: database.Namespace{},
				Name:      "TestInsertFeature2",
			},
			Version: types.NewVersionUnsafe("1.0"),
		},
		{
			Feature: database.Feature{
				Namespace: database.Namespace{Name: "TestInsertFeatureNamespace2"},
				Name:      "TestInsertFeature2",
			},
			Version: types.NewVersionUnsafe(""),
		},
		{
			Feature: database.Feature{
				Namespace: database.Namespace{Name: "TestInsertFeatureNamespace2"},
				Name:      "TestInsertFeature2",
			},
			Version: types.NewVersionUnsafe("bad version"),
		},
	} {
		id3, err := datastore.insertFeatureVersion(invalidFeatureVersion)
		assert.Error(t, err)
		assert.Zero(t, id3)
	}

	// Insert FeatureVersion and ensure we can find it.
	featureVersion := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "TestInsertFeatureNamespace1"},
			Name:      "TestInsertFeature1",
		},
		Version: types.NewVersionUnsafe("2:3.0-imba"),
	}
	id4, err := datastore.insertFeatureVersion(featureVersion)
	assert.Nil(t, err)
	id5, err := datastore.insertFeatureVersion(featureVersion)
	assert.Nil(t, err)
	assert.Equal(t, id4, id5)
}
Example #16
0
func scanVulnerability(queryer Queryer, queryName string, vulnerabilityRow *sql.Row) (database.Vulnerability, error) {
	var vulnerability database.Vulnerability

	err := vulnerabilityRow.Scan(
		&vulnerability.ID,
		&vulnerability.Name,
		&vulnerability.Namespace.ID,
		&vulnerability.Namespace.Name,
		&vulnerability.Description,
		&vulnerability.Link,
		&vulnerability.Severity,
		&vulnerability.Metadata,
	)

	if err != nil {
		return vulnerability, handleError(queryName+".Scan()", err)
	}

	if vulnerability.ID == 0 {
		return vulnerability, cerrors.ErrNotFound
	}

	// Query the FixedIn FeatureVersion now.
	rows, err := queryer.Query(searchVulnerabilityFixedIn, vulnerability.ID)
	if err != nil {
		return vulnerability, handleError("searchVulnerabilityFixedIn.Scan()", err)
	}
	defer rows.Close()

	for rows.Next() {
		var featureVersionID zero.Int
		var featureVersionVersion zero.String
		var featureVersionFeatureName zero.String

		err := rows.Scan(
			&featureVersionVersion,
			&featureVersionID,
			&featureVersionFeatureName,
		)

		if err != nil {
			return vulnerability, handleError("searchVulnerabilityFixedIn.Scan()", err)
		}

		if !featureVersionID.IsZero() {
			// Note that the ID we fill in featureVersion is actually a Feature ID, and not
			// a FeatureVersion ID.
			featureVersion := database.FeatureVersion{
				Model: database.Model{ID: int(featureVersionID.Int64)},
				Feature: database.Feature{
					Model:     database.Model{ID: int(featureVersionID.Int64)},
					Namespace: vulnerability.Namespace,
					Name:      featureVersionFeatureName.String,
				},
				Version: types.NewVersionUnsafe(featureVersionVersion.String),
			}
			vulnerability.FixedIn = append(vulnerability.FixedIn, featureVersion)
		}
	}

	if err := rows.Err(); err != nil {
		return vulnerability, handleError("searchVulnerabilityFixedIn.Rows()", err)
	}

	return vulnerability, nil
}
Example #17
0
	"testing"

	"github.com/coreos/clair/database"
	"github.com/coreos/clair/utils/types"
	"github.com/coreos/clair/worker/detectors/feature"
)

var rpmPackagesTests = []feature.FeatureVersionTest{
	// 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
	{
		FeatureVersions: []database.FeatureVersion{
			// Two packages from this source are installed, it should only appear once
			{
				Feature: database.Feature{Name: "centos-release"},
				Version: types.NewVersionUnsafe("7-1.1503.el7.centos.2.8"),
			},
			// Two packages from this source are installed, it should only appear once
			{
				Feature: database.Feature{Name: "filesystem"},
				Version: types.NewVersionUnsafe("3.2-18.el7"),
			},
		},
		Data: map[string][]byte{
			"var/lib/rpm/Packages": feature.LoadFileForTest("rpm/testdata/Packages"),
		},
	},
}

func TestRpmFeaturesDetector(t *testing.T) {
	feature.TestFeaturesDetector(t, &RpmFeaturesDetector{}, rpmPackagesTests)
Example #18
0
func TestDebianParser(t *testing.T) {
	_, filename, _, _ := runtime.Caller(0)

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

				expectedFeatureVersions := []database.FeatureVersion{
					{
						Feature: database.Feature{
							Namespace: database.Namespace{Name: "debian:8"},
							Name:      "aptdaemon",
						},
						Version: types.MaxVersion,
					},
					{
						Feature: database.Feature{
							Namespace: database.Namespace{Name: "debian:unstable"},

							Name: "aptdaemon",
						},
						Version: types.NewVersionUnsafe("1.1.1+bzr982-1"),
					},
				}

				for _, expectedFeatureVersion := range expectedFeatureVersions {
					assert.Contains(t, vulnerability.FixedIn, expectedFeatureVersion)
				}
			} else if vulnerability.Name == "CVE-2003-0779" {
				assert.Equal(t, "https://security-tracker.debian.org/tracker/CVE-2003-0779", vulnerability.Link)
				assert.Equal(t, types.High, vulnerability.Severity)
				assert.Equal(t, "But this one is very dangerous.", vulnerability.Description)

				expectedFeatureVersions := []database.FeatureVersion{
					{
						Feature: database.Feature{
							Namespace: database.Namespace{Name: "debian:8"},
							Name:      "aptdaemon",
						},
						Version: types.NewVersionUnsafe("0.7.0"),
					},
					{
						Feature: database.Feature{
							Namespace: database.Namespace{Name: "debian:unstable"},
							Name:      "aptdaemon",
						},
						Version: types.NewVersionUnsafe("0.7.0"),
					},
					{
						Feature: database.Feature{
							Namespace: database.Namespace{Name: "debian:8"},
							Name:      "asterisk",
						},
						Version: types.NewVersionUnsafe("0.5.56"),
					},
				}

				for _, expectedFeatureVersion := range expectedFeatureVersions {
					assert.Contains(t, vulnerability.FixedIn, expectedFeatureVersion)
				}
			} else if vulnerability.Name == "CVE-2013-2685" {
				assert.Equal(t, "https://security-tracker.debian.org/tracker/CVE-2013-2685", vulnerability.Link)
				assert.Equal(t, types.Negligible, vulnerability.Severity)
				assert.Equal(t, "Un-affected packages.", vulnerability.Description)

				expectedFeatureVersions := []database.FeatureVersion{
					{
						Feature: database.Feature{
							Namespace: database.Namespace{Name: "debian:8"},
							Name:      "asterisk",
						},
						Version: types.MinVersion,
					},
				}

				for _, expectedFeatureVersion := range expectedFeatureVersions {
					assert.Contains(t, vulnerability.FixedIn, expectedFeatureVersion)
				}
			} else {
				assert.Fail(t, "Wrong vulnerability name: ", vulnerability.ID)
			}
		}
	}
}
Example #19
0
func TestAPKFeatureDetection(t *testing.T) {
	testData := []feature.TestData{
		{
			FeatureVersions: []database.FeatureVersion{
				{
					Feature: database.Feature{Name: "musl"},
					Version: types.NewVersionUnsafe("1.1.14-r10"),
				},
				{
					Feature: database.Feature{Name: "busybox"},
					Version: types.NewVersionUnsafe("1.24.2-r9"),
				},
				{
					Feature: database.Feature{Name: "alpine-baselayout"},
					Version: types.NewVersionUnsafe("3.0.3-r0"),
				},
				{
					Feature: database.Feature{Name: "alpine-keys"},
					Version: types.NewVersionUnsafe("1.1-r0"),
				},
				{
					Feature: database.Feature{Name: "zlib"},
					Version: types.NewVersionUnsafe("1.2.8-r2"),
				},
				{
					Feature: database.Feature{Name: "libcrypto1.0"},
					Version: types.NewVersionUnsafe("1.0.2h-r1"),
				},
				{
					Feature: database.Feature{Name: "libssl1.0"},
					Version: types.NewVersionUnsafe("1.0.2h-r1"),
				},
				{
					Feature: database.Feature{Name: "apk-tools"},
					Version: types.NewVersionUnsafe("2.6.7-r0"),
				},
				{
					Feature: database.Feature{Name: "scanelf"},
					Version: types.NewVersionUnsafe("1.1.6-r0"),
				},
				{
					Feature: database.Feature{Name: "musl-utils"},
					Version: types.NewVersionUnsafe("1.1.14-r10"),
				},
				{
					Feature: database.Feature{Name: "libc-utils"},
					Version: types.NewVersionUnsafe("0.7-r0"),
				},
			},
			Data: map[string][]byte{
				"lib/apk/db/installed": feature.LoadFileForTest("apk/testdata/installed"),
			},
		},
	}
	feature.TestDetector(t, &detector{}, testData)
}
Example #20
0
func TestVulnerability(t *testing.T) {
	Open(&config.DatabaseConfig{Type: "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})

	// # 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)
			}
		}
	}
}
Example #21
0
func TestOracleParser(t *testing.T) {
	_, filename, _, _ := runtime.Caller(0)
	path := filepath.Join(filepath.Dir(filename))

	// Test parsing testdata/fetcher_oracle_test.1.xml
	testFile, _ := os.Open(path + "/testdata/fetcher_oracle_test.1.xml")
	defer testFile.Close()

	vulnerabilities, err := parseELSA(testFile)
	if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 1) {
		assert.Equal(t, "ELSA-2015-1193", vulnerabilities[0].Name)
		assert.Equal(t, "http://linux.oracle.com/errata/ELSA-2015-1193.html", vulnerabilities[0].Link)
		assert.Equal(t, types.Medium, vulnerabilities[0].Severity)
		assert.Equal(t, ` [3.1.1-7] Resolves: rhbz#1217104 CVE-2015-0252 `, vulnerabilities[0].Description)

		expectedFeatureVersions := []database.FeatureVersion{
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "oracle:7"},
					Name:      "xerces-c",
				},
				Version: types.NewVersionUnsafe("3.1.1-7.el7_1"),
			},
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "oracle:7"},
					Name:      "xerces-c-devel",
				},
				Version: types.NewVersionUnsafe("3.1.1-7.el7_1"),
			},
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "oracle:7"},
					Name:      "xerces-c-doc",
				},
				Version: types.NewVersionUnsafe("3.1.1-7.el7_1"),
			},
		}

		for _, expectedFeatureVersion := range expectedFeatureVersions {
			assert.Contains(t, vulnerabilities[0].FixedIn, expectedFeatureVersion)
		}
	}

	testFile2, _ := os.Open(path + "/testdata/fetcher_oracle_test.2.xml")
	defer testFile2.Close()

	vulnerabilities, err = parseELSA(testFile2)
	if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 1) {
		assert.Equal(t, "ELSA-2015-1207", vulnerabilities[0].Name)
		assert.Equal(t, "http://linux.oracle.com/errata/ELSA-2015-1207.html", vulnerabilities[0].Link)
		assert.Equal(t, types.Critical, vulnerabilities[0].Severity)
		assert.Equal(t, ` [38.1.0-1.0.1.el7_1] - Add firefox-oracle-default-prefs.js and remove the corresponding Red Hat file [38.1.0-1] - Update to 38.1.0 ESR [38.0.1-2] - Fixed rhbz#1222807 by removing preun section `, vulnerabilities[0].Description)
		expectedFeatureVersions := []database.FeatureVersion{
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "oracle:6"},
					Name:      "firefox",
				},
				Version: types.NewVersionUnsafe("38.1.0-1.0.1.el6_6"),
			},
			{
				Feature: database.Feature{
					Namespace: database.Namespace{Name: "oracle:7"},
					Name:      "firefox",
				},
				Version: types.NewVersionUnsafe("38.1.0-1.0.1.el7_1"),
			},
		}

		for _, expectedFeatureVersion := range expectedFeatureVersions {
			assert.Contains(t, vulnerabilities[0].FixedIn, expectedFeatureVersion)
		}
	}
}
Example #22
0
func TestProcessWithDistUpgrade(t *testing.T) {
	_, f, _, _ := runtime.Caller(0)
	testDataPath := filepath.Join(filepath.Dir(f)) + "/testdata/DistUpgrade/"

	// Create a mock datastore.
	datastore := newMockDatastore()
	datastore.FctInsertLayer = func(layer database.Layer) error {
		datastore.layers[layer.Name] = layer
		return nil
	}
	datastore.FctFindLayer = func(name string, withFeatures, withVulnerabilities bool) (database.Layer, error) {
		if layer, exists := datastore.layers[name]; exists {
			return layer, nil
		}
		return database.Layer{}, cerrors.ErrNotFound
	}

	// Create the list of FeatureVersions that should not been upgraded from one layer to another.
	nonUpgradedFeatureVersions := []database.FeatureVersion{
		{Feature: database.Feature{Name: "libtext-wrapi18n-perl"}, Version: types.NewVersionUnsafe("0.06-7")},
		{Feature: database.Feature{Name: "libtext-charwidth-perl"}, Version: types.NewVersionUnsafe("0.04-7")},
		{Feature: database.Feature{Name: "libtext-iconv-perl"}, Version: types.NewVersionUnsafe("1.7-5")},
		{Feature: database.Feature{Name: "mawk"}, Version: types.NewVersionUnsafe("1.3.3-17")},
		{Feature: database.Feature{Name: "insserv"}, Version: types.NewVersionUnsafe("1.14.0-5")},
		{Feature: database.Feature{Name: "db"}, Version: types.NewVersionUnsafe("5.1.29-5")},
		{Feature: database.Feature{Name: "ustr"}, Version: types.NewVersionUnsafe("1.0.4-3")},
		{Feature: database.Feature{Name: "xz-utils"}, Version: types.NewVersionUnsafe("5.1.1alpha+20120614-2")},
	}

	// Process test layers.
	//
	// 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(datastore, "Docker", "blank", "", testDataPath+"blank.tar.gz", nil))
	assert.Nil(t, Process(datastore, "Docker", "wheezy", "blank", testDataPath+"wheezy.tar.gz", nil))
	assert.Nil(t, Process(datastore, "Docker", "jessie", "wheezy", testDataPath+"jessie.tar.gz", nil))

	// Ensure that the 'wheezy' layer has the expected namespace and features.
	wheezy, ok := datastore.layers["wheezy"]
	if assert.True(t, ok, "layer 'wheezy' not processed") {
		assert.Equal(t, "debian:7", wheezy.Namespace.Name)
		assert.Len(t, wheezy.Features, 52)

		for _, nufv := range nonUpgradedFeatureVersions {
			nufv.Feature.Namespace.Name = "debian:7"
			assert.Contains(t, wheezy.Features, nufv)
		}
	}

	// Ensure that the 'wheezy' layer has the expected namespace and non-upgraded features.
	jessie, ok := datastore.layers["jessie"]
	if assert.True(t, ok, "layer 'jessie' not processed") {
		assert.Equal(t, "debian:8", jessie.Namespace.Name)
		assert.Len(t, jessie.Features, 74)

		for _, nufv := range nonUpgradedFeatureVersions {
			nufv.Feature.Namespace.Name = "debian:7"
			assert.Contains(t, jessie.Features, nufv)
		}
		for _, nufv := range nonUpgradedFeatureVersions {
			nufv.Feature.Namespace.Name = "debian:8"
			assert.NotContains(t, jessie.Features, nufv)
		}
	}
}
Example #23
0
func testInsertLayerTree(t *testing.T, datastore database.Datastore) {
	f1 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "TestInsertLayerNamespace2"},
			Name:      "TestInsertLayerFeature1",
		},
		Version: types.NewVersionUnsafe("1.0"),
	}
	f2 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "TestInsertLayerNamespace2"},
			Name:      "TestInsertLayerFeature2",
		},
		Version: types.NewVersionUnsafe("0.34"),
	}
	f3 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "TestInsertLayerNamespace2"},
			Name:      "TestInsertLayerFeature3",
		},
		Version: types.NewVersionUnsafe("0.56"),
	}
	f4 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"},
			Name:      "TestInsertLayerFeature2",
		},
		Version: types.NewVersionUnsafe("0.34"),
	}
	f5 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"},
			Name:      "TestInsertLayerFeature3",
		},
		Version: types.NewVersionUnsafe("0.56"),
	}
	f6 := database.FeatureVersion{
		Feature: database.Feature{
			Namespace: database.Namespace{Name: "TestInsertLayerNamespace3"},
			Name:      "TestInsertLayerFeature4",
		},
		Version: types.NewVersionUnsafe("0.666"),
	}

	layers := []database.Layer{
		{
			Name: "TestInsertLayer1",
		},
		{
			Name:      "TestInsertLayer2",
			Parent:    &database.Layer{Name: "TestInsertLayer1"},
			Namespace: &database.Namespace{Name: "TestInsertLayerNamespace1"},
		},
		// This layer changes the namespace and adds Features.
		{
			Name:      "TestInsertLayer3",
			Parent:    &database.Layer{Name: "TestInsertLayer2"},
			Namespace: &database.Namespace{Name: "TestInsertLayerNamespace2"},
			Features:  []database.FeatureVersion{f1, f2, f3},
		},
		// This layer covers the case where the last layer doesn't provide any new Feature.
		{
			Name:     "TestInsertLayer4a",
			Parent:   &database.Layer{Name: "TestInsertLayer3"},
			Features: []database.FeatureVersion{f1, f2, f3},
		},
		// This layer covers the case where the last layer provides Features.
		// It also modifies the Namespace ("upgrade") but keeps some Features not upgraded, their
		// Namespaces should then remain unchanged.
		{
			Name:      "TestInsertLayer4b",
			Parent:    &database.Layer{Name: "TestInsertLayer3"},
			Namespace: &database.Namespace{Name: "TestInsertLayerNamespace3"},
			Features: []database.FeatureVersion{
				// Deletes TestInsertLayerFeature1.
				// Keep TestInsertLayerFeature2 (old Namespace should be kept):
				f4,
				// Upgrades TestInsertLayerFeature3 (with new Namespace):
				f5,
				// Adds TestInsertLayerFeature4:
				f6,
			},
		},
	}

	var err error
	retrievedLayers := make(map[string]database.Layer)
	for _, layer := range layers {
		if layer.Parent != nil {
			// Retrieve from database its parent and assign.
			parent := retrievedLayers[layer.Parent.Name]
			layer.Parent = &parent
		}

		err = datastore.InsertLayer(layer)
		assert.Nil(t, err)

		retrievedLayers[layer.Name], err = datastore.FindLayer(layer.Name, true, false)
		assert.Nil(t, err)
	}

	l4a := retrievedLayers["TestInsertLayer4a"]
	if assert.NotNil(t, l4a.Namespace) {
		assert.Equal(t, "TestInsertLayerNamespace2", l4a.Namespace.Name)
	}
	assert.Len(t, l4a.Features, 3)
	for _, featureVersion := range l4a.Features {
		if cmpFV(featureVersion, f1) && cmpFV(featureVersion, f2) && cmpFV(featureVersion, f3) {
			assert.Error(t, fmt.Errorf("TestInsertLayer4a contains an unexpected package: %#v. Should contain %#v and %#v and %#v.", featureVersion, f1, f2, f3))
		}
	}

	l4b := retrievedLayers["TestInsertLayer4b"]
	if assert.NotNil(t, l4b.Namespace) {
		assert.Equal(t, "TestInsertLayerNamespace3", l4b.Namespace.Name)
	}
	assert.Len(t, l4b.Features, 3)
	for _, featureVersion := range l4b.Features {
		if cmpFV(featureVersion, f2) && cmpFV(featureVersion, f5) && cmpFV(featureVersion, f6) {
			assert.Error(t, fmt.Errorf("TestInsertLayer4a contains an unexpected package: %#v. Should contain %#v and %#v and %#v.", featureVersion, f2, f4, f6))
		}
	}
}
Example #24
0
package packages

import (
	"testing"

	"github.com/coreos/clair/database"
	"github.com/coreos/clair/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 #25
0
func TestInsertVulnerability(t *testing.T) {
	datastore, err := openDatabaseForTest("InsertVulnerability", false)
	if err != nil {
		t.Error(err)
		return
	}
	defer datastore.Close()

	// Create some data.
	n1 := database.Namespace{Name: "TestInsertVulnerabilityNamespace1"}
	n2 := database.Namespace{Name: "TestInsertVulnerabilityNamespace2"}

	f1 := database.FeatureVersion{
		Feature: database.Feature{
			Name:      "TestInsertVulnerabilityFeatureVersion1",
			Namespace: n1,
		},
		Version: types.NewVersionUnsafe("1.0"),
	}
	f2 := database.FeatureVersion{
		Feature: database.Feature{
			Name:      "TestInsertVulnerabilityFeatureVersion1",
			Namespace: n2,
		},
		Version: types.NewVersionUnsafe("1.0"),
	}
	f3 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion2",
		},
		Version: types.MaxVersion,
	}
	f4 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion2",
		},
		Version: types.NewVersionUnsafe("1.4"),
	}
	f5 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion3",
		},
		Version: types.NewVersionUnsafe("1.5"),
	}
	f6 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion4",
		},
		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{
		{
			Name:      "",
			Namespace: n1,
			FixedIn:   []database.FeatureVersion{f1},
			Severity:  types.Unknown,
		},
		{
			Name:      "TestInsertVulnerability0",
			Namespace: database.Namespace{},
			FixedIn:   []database.FeatureVersion{f1},
			Severity:  types.Unknown,
		},
		{
			Name:      "TestInsertVulnerability0-",
			Namespace: database.Namespace{},
			FixedIn:   []database.FeatureVersion{f1},
		},
		{
			Name:      "TestInsertVulnerability0",
			Namespace: n1,
			FixedIn:   []database.FeatureVersion{f1},
			Severity:  types.Priority(""),
		},
		{
			Name:      "TestInsertVulnerability0",
			Namespace: n1,
			FixedIn:   []database.FeatureVersion{f2},
			Severity:  types.Unknown,
		},
	} {
		err := datastore.InsertVulnerabilities([]database.Vulnerability{vulnerability}, true)
		assert.Error(t, err)
	}

	// Insert a simple vulnerability and find it.
	v1meta := make(map[string]interface{})
	v1meta["TestInsertVulnerabilityMetadata1"] = "TestInsertVulnerabilityMetadataValue1"
	v1meta["TestInsertVulnerabilityMetadata2"] = struct {
		Test string
	}{
		Test: "TestInsertVulnerabilityMetadataValue1",
	}

	v1 := database.Vulnerability{
		Name:        "TestInsertVulnerability1",
		Namespace:   n1,
		FixedIn:     []database.FeatureVersion{f1, f3, f6, f7},
		Severity:    types.Low,
		Description: "TestInsertVulnerabilityDescription1",
		Link:        "TestInsertVulnerabilityLink1",
		Metadata:    v1meta,
	}
	err = datastore.InsertVulnerabilities([]database.Vulnerability{v1}, true)
	if assert.Nil(t, err) {
		v1f, err := datastore.FindVulnerability(n1.Name, v1.Name)
		if assert.Nil(t, err) {
			equalsVuln(t, &v1, &v1f)
		}
	}

	// Update vulnerability.
	v1.Description = "TestInsertVulnerabilityLink2"
	v1.Link = "TestInsertVulnerabilityLink2"
	v1.Severity = types.High
	// 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}, true)
	if assert.Nil(t, err) {
		v1f, err := datastore.FindVulnerability(n1.Name, v1.Name)
		if assert.Nil(t, err) {
			// 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)
		}
	}
}
Example #26
0
func TestFindLayer(t *testing.T) {
	datastore, err := openDatabaseForTest("FindLayer", true)
	if err != nil {
		t.Error(err)
		return
	}
	defer datastore.Close()

	// Layer-0: no parent, no namespace, no feature, no vulnerability
	layer, err := datastore.FindLayer("layer-0", false, false)
	if assert.Nil(t, err) && assert.NotNil(t, layer) {
		assert.Equal(t, "layer-0", layer.Name)
		assert.Nil(t, layer.Namespace)
		assert.Nil(t, layer.Parent)
		assert.Equal(t, 1, layer.EngineVersion)
		assert.Len(t, layer.Features, 0)
	}

	layer, err = datastore.FindLayer("layer-0", true, false)
	if assert.Nil(t, err) && assert.NotNil(t, layer) {
		assert.Len(t, layer.Features, 0)
	}

	// Layer-1: one parent, adds two features, one vulnerability
	layer, err = datastore.FindLayer("layer-1", false, false)
	if assert.Nil(t, err) && assert.NotNil(t, layer) {
		assert.Equal(t, layer.Name, "layer-1")
		assert.Equal(t, "debian:7", layer.Namespace.Name)
		if assert.NotNil(t, layer.Parent) {
			assert.Equal(t, "layer-0", layer.Parent.Name)
		}
		assert.Equal(t, 1, layer.EngineVersion)
		assert.Len(t, layer.Features, 0)
	}

	layer, err = datastore.FindLayer("layer-1", true, false)
	if assert.Nil(t, err) && assert.NotNil(t, layer) && assert.Len(t, layer.Features, 2) {
		for _, featureVersion := range layer.Features {
			assert.Equal(t, "debian:7", featureVersion.Feature.Namespace.Name)

			switch featureVersion.Feature.Name {
			case "wechat":
				assert.Equal(t, types.NewVersionUnsafe("0.5"), featureVersion.Version)
			case "openssl":
				assert.Equal(t, types.NewVersionUnsafe("1.0"), featureVersion.Version)
			default:
				t.Errorf("unexpected package %s for layer-1", featureVersion.Feature.Name)
			}
		}
	}

	layer, err = datastore.FindLayer("layer-1", true, true)
	if assert.Nil(t, err) && assert.NotNil(t, layer) && assert.Len(t, layer.Features, 2) {
		for _, featureVersion := range layer.Features {
			assert.Equal(t, "debian:7", featureVersion.Feature.Namespace.Name)

			switch featureVersion.Feature.Name {
			case "wechat":
				assert.Equal(t, types.NewVersionUnsafe("0.5"), featureVersion.Version)
			case "openssl":
				assert.Equal(t, types.NewVersionUnsafe("1.0"), featureVersion.Version)

				if assert.Len(t, featureVersion.AffectedBy, 1) {
					assert.Equal(t, "debian:7", featureVersion.AffectedBy[0].Namespace.Name)
					assert.Equal(t, "CVE-OPENSSL-1-DEB7", featureVersion.AffectedBy[0].Name)
					assert.Equal(t, types.High, featureVersion.AffectedBy[0].Severity)
					assert.Equal(t, "A vulnerability affecting OpenSSL < 2.0 on Debian 7.0", featureVersion.AffectedBy[0].Description)
					assert.Equal(t, "http://google.com/#q=CVE-OPENSSL-1-DEB7", featureVersion.AffectedBy[0].Link)
					assert.Equal(t, types.NewVersionUnsafe("2.0"), featureVersion.AffectedBy[0].FixedBy)
				}
			default:
				t.Errorf("unexpected package %s for layer-1", featureVersion.Feature.Name)
			}
		}
	}
}
Example #27
0
func TestRaceAffects(t *testing.T) {
	datastore, err := openDatabaseForTest("RaceAffects", false)
	if err != nil {
		t.Error(err)
		return
	}
	defer datastore.Close()

	// Insert the Feature on which we'll work.
	feature := database.Feature{
		Namespace: database.Namespace{Name: "TestRaceAffectsFeatureNamespace1"},
		Name:      "TestRaceAffecturesFeature1",
	}
	_, err = datastore.insertFeature(feature)
	if err != nil {
		t.Error(err)
		return
	}

	// Initialize random generator and enforce max procs.
	rand.Seed(time.Now().UnixNano())
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Generate FeatureVersions.
	featureVersions := make([]database.FeatureVersion, numFeatureVersions)
	for i := 0; i < numFeatureVersions; i++ {
		version := rand.Intn(numFeatureVersions)

		featureVersions[i] = database.FeatureVersion{
			Feature: feature,
			Version: types.NewVersionUnsafe(strconv.Itoa(version)),
		}
	}

	// Generate vulnerabilities.
	// They are mapped by fixed version, which will make verification really easy afterwards.
	vulnerabilities := make(map[int][]database.Vulnerability)
	for i := 0; i < numVulnerabilities; i++ {
		version := rand.Intn(numFeatureVersions) + 1

		// if _, ok := vulnerabilities[version]; !ok {
		//   vulnerabilities[version] = make([]database.Vulnerability)
		// }

		vulnerability := database.Vulnerability{
			Name:      uuid.New(),
			Namespace: feature.Namespace,
			FixedIn: []database.FeatureVersion{
				{
					Feature: feature,
					Version: types.NewVersionUnsafe(strconv.Itoa(version)),
				},
			},
			Severity: types.Unknown,
		}

		vulnerabilities[version] = append(vulnerabilities[version], vulnerability)
	}

	// Insert featureversions and vulnerabilities in parallel.
	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		for _, vulnerabilitiesM := range vulnerabilities {
			for _, vulnerability := range vulnerabilitiesM {
				err = datastore.InsertVulnerabilities([]database.Vulnerability{vulnerability}, true)
				assert.Nil(t, err)
			}
		}
		fmt.Println("finished to insert vulnerabilities")
	}()

	go func() {
		defer wg.Done()
		for i := 0; i < len(featureVersions); i++ {
			featureVersions[i].ID, err = datastore.insertFeatureVersion(featureVersions[i])
			assert.Nil(t, err)
		}
		fmt.Println("finished to insert featureVersions")
	}()

	wg.Wait()

	// Verify consistency now.
	var actualAffectedNames []string
	var expectedAffectedNames []string

	for _, featureVersion := range featureVersions {
		featureVersionVersion, _ := strconv.Atoi(featureVersion.Version.String())

		// Get actual affects.
		rows, err := datastore.Query(searchComplexTestFeatureVersionAffects,
			featureVersion.ID)
		assert.Nil(t, err)
		defer rows.Close()

		var vulnName string
		for rows.Next() {
			err = rows.Scan(&vulnName)
			if !assert.Nil(t, err) {
				continue
			}
			actualAffectedNames = append(actualAffectedNames, vulnName)
		}
		if assert.Nil(t, rows.Err()) {
			rows.Close()
		}

		// Get expected affects.
		for i := numVulnerabilities; i > featureVersionVersion; i-- {
			for _, vulnerability := range vulnerabilities[i] {
				expectedAffectedNames = append(expectedAffectedNames, vulnerability.Name)
			}
		}

		assert.Len(t, utils.CompareStringLists(expectedAffectedNames, actualAffectedNames), 0)
		assert.Len(t, utils.CompareStringLists(actualAffectedNames, expectedAffectedNames), 0)
	}
}