fleet/server/vulnerabilities/goval_dictionary/database_test.go
Ian Littman e96c70e4c0
Pull xz'd goval-dictionary sqlite files to evaluate vulnerabilities on Amazon Linux hosts (#21506)
#20934

This is tied to https://github.com/fleetdm/vulnerabilities/pull/14; for
supported OS versions (currently Amazon Linux 1/2/2022/2023) we'll pull
XZ'd sqlite files from the vulnerabilities repo and query them to
determine what's vulnerable. See the associated issue for how I
self-QA'd this.

This replaced OVAL parsing for Amazon Linux 2, as we were using the
wrong data source there (Amazon has backported a bunch of fixes to their
own-named releases, so any RHEL fixes don't match).

Some checklist items are missing here; getting this set up in draft to
get code feedback now, and I'll push updates with e.g. docs changes, as
well ass an addition to the changes file.

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

<!-- Note that API documentation changes are now addressed by the
product design team. -->

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files)
for more information.
- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)
- [x] Added/updated tests
    - [x] Add tests to oval_platform
    - [x] Add sync_test
    - [x] Add database_test
- [x] Manual QA for all new/changed functionality
- [x] Update vulnerability management docs
2024-08-26 14:07:42 -05:00

93 lines
4 KiB
Go

package goval_dictionary
import (
"database/sql"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/oval"
kitlog "github.com/go-kit/log"
"github.com/stretchr/testify/require"
"testing"
)
func TestDatabase(t *testing.T) {
// build minimal slice of goval-dictionary sqlite schema
sqlite, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatal(err)
}
dbSetupQueries := []string{
// create schema
"CREATE TABLE packages (name TEXT NOT NULL, arch TEXT NOT NULL, version TEXT NOT NULL, definition_id INTEGER NOT NULL)",
"CREATE TABLE definitions (id INTEGER NOT NULL PRIMARY KEY)",
"CREATE TABLE advisories (id INTEGER NOT NULL PRIMARY KEY, definition_id INTEGER NOT NULL)",
"CREATE TABLE cves (cve_id TEXT NOT NULL, advisory_id INTEGER NOT NULL)",
// insert records
`INSERT INTO packages (name, arch, version, definition_id) VALUES
('expat', 'aarch64', '0:2.1.0-15.amzn2.0.3', 1), ('krb5-server', 'aarch64', '0:1.15.1-55.amzn2.2.8', 2)`,
"INSERT INTO definitions (id) VALUES (1), (2)",
"INSERT INTO advisories (id, definition_id) VALUES (1, 1), (2, 2)",
`INSERT INTO cves (cve_id, advisory_id) VALUES
('CVE-2022-23990', 1), ('CVE-2022-25313', 1), ('CVE-2024-37370', 2), ('CVE-2024-37371', 2)`,
}
for _, query := range dbSetupQueries {
if _, err := sqlite.Exec(query); err != nil {
t.Fatal(err)
}
}
db := NewDB(sqlite, oval.NewPlatform("amzn", "Amazon Linux 2.0.0"))
logger := kitlog.NewNopLogger()
t.Run("Non-matching architecture", func(t *testing.T) {
require.Len(t, db.Eval([]fleet.Software{{Name: "expat", Version: "2.1.0", Release: "", Arch: "x86_64"}}, logger), 0)
})
t.Run("Non-matching package name", func(t *testing.T) {
require.Len(t, db.Eval([]fleet.Software{{Name: "expath", Version: "2.1.0", Release: "", Arch: "aarch64"}}, logger), 0)
})
t.Run("Fixed version", func(t *testing.T) {
require.Len(t, db.Eval([]fleet.Software{{Name: "expath", Version: "2.1.0", Release: "15.amzn2.0.3", Arch: "aarch64"}}, logger), 0)
})
t.Run("Newer than fixed version", func(t *testing.T) {
require.Len(t, db.Eval([]fleet.Software{{Name: "expath", Version: "2.1.0", Release: "15.amzn2.0.5", Arch: "aarch64"}}, logger), 0)
})
t.Run("Older than fixed version", func(t *testing.T) {
vulns := db.Eval([]fleet.Software{{Name: "expat", Version: "2.1.0", Release: "", Arch: "aarch64", ID: 123}}, logger)
require.Len(t, vulns, 2)
require.Equal(t, "2.1.0-15.amzn2.0.3", *vulns[0].ResolvedInVersion)
require.Equal(t, "2.1.0-15.amzn2.0.3", *vulns[1].ResolvedInVersion)
require.Equal(t, "CVE-2022-23990", vulns[0].CVE)
require.Equal(t, "CVE-2022-25313", vulns[1].CVE)
require.Equal(t, uint(123), vulns[0].SoftwareID)
require.Equal(t, uint(123), vulns[1].SoftwareID)
})
t.Run("Multiple packages, fixed version", func(t *testing.T) {
require.Len(t, db.Eval([]fleet.Software{
{Name: "expat", Version: "2.1.0", Release: "15.amzn2.1.0", Arch: "aarch64"},
{Name: "krb5-server", Version: "1.15.1", Release: "55.amzn2.2.8", Arch: "aarch64"},
}, logger), 0)
})
t.Run("Multiple packages, multiple vulnerabilities", func(t *testing.T) {
vulns := db.Eval([]fleet.Software{
{Name: "expat", Version: "2.1.0", Release: "15.amzn2.0.2", Arch: "aarch64", ID: 234},
{Name: "krb5-server", Version: "1.15.1", Release: "55.amzn2.2.7", Arch: "aarch64", ID: 235},
}, logger)
require.Len(t, vulns, 4)
require.Equal(t, "2.1.0-15.amzn2.0.3", *vulns[0].ResolvedInVersion)
require.Equal(t, "2.1.0-15.amzn2.0.3", *vulns[1].ResolvedInVersion)
require.Equal(t, "1.15.1-55.amzn2.2.8", *vulns[2].ResolvedInVersion)
require.Equal(t, "CVE-2022-23990", vulns[0].CVE)
require.Equal(t, "CVE-2022-25313", vulns[1].CVE)
require.Equal(t, "CVE-2024-37370", vulns[2].CVE)
require.Equal(t, "CVE-2024-37371", vulns[3].CVE)
require.Equal(t, uint(234), vulns[0].SoftwareID)
require.Equal(t, uint(234), vulns[1].SoftwareID)
require.Equal(t, uint(235), vulns[2].SoftwareID)
require.Equal(t, uint(235), vulns[3].SoftwareID)
})
}