mirror of
https://github.com/fleetdm/fleet
synced 2026-05-22 16:39:01 +00:00
1136 lines
34 KiB
Go
1136 lines
34 KiB
Go
package nvd
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/fleetdm/fleet/v4/pkg/nettest"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
"github.com/fleetdm/fleet/v4/server/mock"
|
|
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/cvefeed"
|
|
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/wfn"
|
|
"github.com/go-kit/log"
|
|
kitlog "github.com/go-kit/log"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// firefox93WindowsVulnerabilities was manually generated by visiting:
|
|
// https://nvd.nist.gov/vuln/search/results?form_type=Advanced&results_type=overview&isCpeNameSearch=true&seach_type=all&query=cpe:2.3:a:mozilla:firefox:93.0:*:*:*:*:*:*:*
|
|
type cve struct {
|
|
ID string
|
|
resolvedInVersion string
|
|
}
|
|
|
|
var firefox93WindowsVulnerabilities = []cve{
|
|
{ID: "CVE-2021-43540", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-38503", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38504", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38506", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38507", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38508", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-38509", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43534", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43532", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43531", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43533", resolvedInVersion: "94.0"},
|
|
{ID: "CVE-2021-43538", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43542", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43543", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-30547"},
|
|
{ID: "CVE-2021-43546", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43537", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43541", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43536", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43545", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2021-43539", resolvedInVersion: "95.0"},
|
|
{ID: "CVE-2022-34480", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-26387", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-22759", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-28281", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-45415", resolvedInVersion: "107.0"},
|
|
{ID: "CVE-2022-42930", resolvedInVersion: "106.0"},
|
|
{ID: "CVE-2022-0511", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-22763", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22737", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22751", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-38478", resolvedInVersion: "104.0"},
|
|
{ID: "CVE-2022-22761", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-34482", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-26486", resolvedInVersion: "97.0.2"},
|
|
{ID: "CVE-2022-22739", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22755", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-22757", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-1097", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-22754", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-22748", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22736", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22745", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-26385", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-26383", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-3266", resolvedInVersion: "105.0"},
|
|
{ID: "CVE-2022-34468", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-34481", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-28289", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-22741", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-28284", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-34484", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-22752", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-26485", resolvedInVersion: "97.0.2"},
|
|
{ID: "CVE-2022-28286", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-28283", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-28285", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-0843", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-29909", resolvedInVersion: "100.0"},
|
|
{ID: "CVE-2022-22749", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-26384", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-28282", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-28287", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-40956", resolvedInVersion: "105.0"},
|
|
{ID: "CVE-2022-22740", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22743", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-22764", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-22738", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-1529", resolvedInVersion: "100.0.2"},
|
|
{ID: "CVE-2022-22760", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-29916", resolvedInVersion: "100.0"},
|
|
{ID: "CVE-2022-29917", resolvedInVersion: "100.0"},
|
|
{ID: "CVE-2022-22747", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-26382", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-22742", resolvedInVersion: "96.0"},
|
|
{ID: "CVE-2022-28288", resolvedInVersion: "99.0"},
|
|
{ID: "CVE-2022-22756", resolvedInVersion: "97.0"},
|
|
{ID: "CVE-2022-26381", resolvedInVersion: "98.0"},
|
|
{ID: "CVE-2022-1802", resolvedInVersion: "100.0.2"},
|
|
{ID: "CVE-2022-34483", resolvedInVersion: "102.0"},
|
|
{ID: "CVE-2022-29915", resolvedInVersion: "100.0"},
|
|
}
|
|
|
|
type threadSafeDSMock struct {
|
|
mu sync.Mutex
|
|
*mock.Store
|
|
}
|
|
|
|
func (d *threadSafeDSMock) ListSoftwareCPEs(ctx context.Context) ([]fleet.SoftwareCPE, error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
return d.Store.ListSoftwareCPEs(ctx)
|
|
}
|
|
|
|
func (d *threadSafeDSMock) InsertSoftwareVulnerability(ctx context.Context, vuln fleet.SoftwareVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
return d.Store.InsertSoftwareVulnerability(ctx, vuln, src)
|
|
}
|
|
|
|
func TestTranslateCPEToCVE(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.Background()
|
|
|
|
// NVD_TEST_VULNDB_DIR can be used to speed up development (sync vulnerability data only once).
|
|
tempDir := os.Getenv("NVD_TEST_VULNDB_DIR")
|
|
if tempDir == "" {
|
|
// download the CVEs once for all sub-tests, and then disable syncing
|
|
tempDir = t.TempDir()
|
|
err := nettest.RunWithNetRetry(t, func() error {
|
|
return DownloadCVEFeed(tempDir, "", false, log.NewNopLogger())
|
|
})
|
|
require.NoError(t, err)
|
|
} else {
|
|
require.DirExists(t, tempDir)
|
|
t.Logf("Using %s as database path", tempDir)
|
|
}
|
|
|
|
cveTests := map[string]struct {
|
|
cpe string
|
|
excludedCVEs []string
|
|
includedCVEs []cve
|
|
// continuesToUpdate indicates if the product/software
|
|
// continues to register new CVE vulnerabilities.
|
|
continuesToUpdate bool
|
|
}{
|
|
"cpe:2.3:a:1password:1password:3.9.9:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2012-6369"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:1password:1password:3.9.9:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2012-6369"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:pypa:pip:9.0.3:*:*:*:*:python:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2019-20916", resolvedInVersion: "19.2"},
|
|
{ID: "CVE-2021-3572", resolvedInVersion: "21.1"},
|
|
{ID: "CVE-2023-5752", resolvedInVersion: "23.3"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:mozilla:firefox:93.0:*:*:*:*:windows:*:*": {
|
|
includedCVEs: firefox93WindowsVulnerabilities,
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:mozilla:firefox:93.0.100:*:*:*:*:windows:*:*": {
|
|
includedCVEs: firefox93WindowsVulnerabilities,
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:icloud:1.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{
|
|
"CVE-2017-13797",
|
|
"CVE-2017-2383",
|
|
"CVE-2017-2366",
|
|
"CVE-2016-4613",
|
|
"CVE-2016-4692",
|
|
"CVE-2016-4743",
|
|
"CVE-2016-7578",
|
|
"CVE-2016-7583",
|
|
"CVE-2016-7586",
|
|
"CVE-2016-7587",
|
|
"CVE-2016-7589",
|
|
"CVE-2016-7592",
|
|
"CVE-2016-7598",
|
|
"CVE-2016-7599",
|
|
"CVE-2016-7610",
|
|
"CVE-2016-7611",
|
|
"CVE-2016-7614",
|
|
"CVE-2016-7632",
|
|
"CVE-2016-7635",
|
|
"CVE-2016-7639",
|
|
"CVE-2016-7640",
|
|
"CVE-2016-7641",
|
|
"CVE-2016-7642",
|
|
"CVE-2016-7645",
|
|
"CVE-2016-7646",
|
|
"CVE-2016-7648",
|
|
"CVE-2016-7649",
|
|
"CVE-2016-7652",
|
|
"CVE-2016-7654",
|
|
"CVE-2016-7656",
|
|
"CVE-2017-2383",
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:clickstudios:passwordstate:9.5.8.4:*:*:*:*:chrome:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2022-4610", resolvedInVersion: ""},
|
|
{ID: "CVE-2022-4611", resolvedInVersion: ""},
|
|
{ID: "CVE-2022-4613", resolvedInVersion: ""},
|
|
{ID: "CVE-2022-4612", resolvedInVersion: ""},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:garageband:10.4.11:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-54559"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:o:apple:macos:15.1.1:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2024-54559", resolvedInVersion: "15.2"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:avira:password_manager:2.18.4.38471:*:*:*:*:firefox:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2022-28795"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:zoom:zoom:5.0.4301.0407:*:*:*:*:chrome:*:*": {
|
|
excludedCVEs: []string{"CVE-2021-28133"}, // CVE-2021-28133 is a vulnerability in the Zoom application, not the extension.
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:bitwarden:bitwarden:1.55.0:*:*:*:*:firefox:*:*": {
|
|
excludedCVEs: []string{"CVE-2023-38840"}, // CVE-2023-38840 is a vulnerability in the Bitwarden application, not the extension.
|
|
continuesToUpdate: true,
|
|
},
|
|
// No Version Start
|
|
"cpe:2.3:a:python:setuptools:64:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2022-40897", resolvedInVersion: "65.5.1"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:mozilla:firefox:93.0.100:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
// CVE matches multiple products
|
|
{ID: "CVE-2022-40956", resolvedInVersion: "105.0"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
// Multiple product matches with different version ranges
|
|
"cpe:2.3:o:apple:macos:14.1:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-42919", resolvedInVersion: "14.2"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:windows_subsystem_for_linux:0.63.10:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2021-43907", resolvedInVersion: "0.63.11"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:github:pull_requests_and_issues:0.66.1:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-36867", resolvedInVersion: "0.66.2"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
/*"cpe:2.3:a:microsoft:python_extension:2020.9.1:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2020-17163", resolvedInVersion: "2020.9.2"},
|
|
{ID: "CVE-2024-49050", resolvedInVersion: "2024.18.2"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},*/
|
|
"cpe:2.3:a:microsoft:jupyter:2023.10.10:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-36018", resolvedInVersion: "2023.10.1100000000"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:microsoft:jupyter:2024.2.0:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{},
|
|
continuesToUpdate: false,
|
|
},
|
|
"cpe:2.3:a:microsoft:eslint:2.0.0:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2020-1481", resolvedInVersion: "2.1.7"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},
|
|
/*"cpe:2.3:a:microsoft:python_extension:2020.4.0:*:*:*:*:visual_studio_code:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2020-1171", resolvedInVersion: "2020.5.0"},
|
|
{ID: "CVE-2020-1192", resolvedInVersion: "2020.5.0"},
|
|
{ID: "CVE-2020-17163", resolvedInVersion: "2020.9.2"},
|
|
{ID: "CVE-2024-49050", resolvedInVersion: "2024.18.2"},
|
|
},
|
|
continuesToUpdate: false,
|
|
},*/
|
|
"cpe:2.3:a:adobe:animate:*:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-44325"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:17.0:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-42852", resolvedInVersion: "17.1"},
|
|
{ID: "CVE-2023-42950", resolvedInVersion: "17.2"},
|
|
{ID: "CVE-2024-23273", resolvedInVersion: "17.4"},
|
|
},
|
|
excludedCVEs: []string{
|
|
"CVE-2023-28205", // This vulnerability is for Safari 16.4.0
|
|
"CVE-2024-23252", // Rejected CVE
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:apple:safari:16.4.0:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-28205", resolvedInVersion: "16.4.1"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:365_apps:16.0.17628.20144:*:*:*:*:windows:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2024-21402"},
|
|
},
|
|
excludedCVEs: []string{"CVE-2011-5049"}, // OS vulnerability
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:citrix:workspace:2309.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-6286"},
|
|
continuesToUpdate: true,
|
|
},
|
|
// FIXME: https://github.com/fleetdm/fleet/issues/31303
|
|
// "cpe:2.3:a:citrix:workspace:2309.0:*:*:*:*:windows:*:*": {
|
|
// includedCVEs: []cve{
|
|
// {ID: "CVE-2024-6286", resolvedInVersion: "2402"},
|
|
// },
|
|
// continuesToUpdate: true,
|
|
// },
|
|
"cpe:2.3:a:python:python:3.9.6:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-4030"},
|
|
continuesToUpdate: true,
|
|
},
|
|
// Skipping test while troubleshooting https://github.com/fleetdm/fleet/issues/24286
|
|
//
|
|
// "cpe:2.3:a:python:python:3.9.6:*:*:*:*:windows:*:*": {
|
|
// includedCVEs: []cve{
|
|
// {ID: "CVE-2024-4030", resolvedInVersion: "3.9.20"},
|
|
// },
|
|
// continuesToUpdate: true,
|
|
// },
|
|
// Tests the expandCPEAliases rule for virtualbox on macOS
|
|
"cpe:2.3:a:oracle:virtualbox:7.0.6:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2023-21989", resolvedInVersion: "7.0.8"},
|
|
{ID: "CVE-2024-21141", resolvedInVersion: "7.0.20"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:mozilla:firefox:*:*:*:*:*:*:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-10004"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:okta:verify:9.27.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-10327"},
|
|
continuesToUpdate: true,
|
|
},
|
|
// CVE-2023-48795 false positive and true positive checks (see #26073)
|
|
"cpe:2.3:a:microsoft:powershell:7.4.3:*:*:*:*:*:*:*": {
|
|
excludedCVEs: []string{"CVE-2023-48795", "CVE-2025-21171"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:openbsd:openssh:9.5:p1:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2023-48795", resolvedInVersion: "9.6"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:openbsd:openssh:9.6:*:*:*:*:*:*": {
|
|
excludedCVEs: []string{"CVE-2023-48795"},
|
|
continuesToUpdate: true,
|
|
},
|
|
// end of CVE-2023-48795 checks
|
|
// CVE-2025-21171 handling
|
|
// https://github.com/fleetdm/fleet/pull/30767
|
|
// NVD lists this CVE for version 7.5 and not 7.5.0
|
|
"cpe:2.3:a:microsoft:powershell:7.5.0:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-21171"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:powershell:7.5.0:*:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-21171"},
|
|
includedCVEs: []cve{{ID: "CVE-2025-30399"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:powershell:7.5.2:*:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-21171", "CVE-2025-30399"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:powershell:7.5:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2025-21171"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:microsoft:powershell:7.5:*:*:*:*:windows:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2025-21171"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
// end of CVE-2025-21171 checks
|
|
"cpe:2.3:a:jetbrains:goland:2022.3.99.123.456:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2024-37051", resolvedInVersion: "2023.1.6"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:jetbrains:goland:2024.3:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-37051"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:iterm2:iterm2:3.5.1:*:*:*:*:*:*:*": {
|
|
includedCVEs: []cve{
|
|
{ID: "CVE-2024-38395", resolvedInVersion: "3.5.2"},
|
|
// NVD is being flakey so may not show this // {ID: "CVE-2024-38396", resolvedInVersion: "3.5.2"},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:simple_password_store_project:simple_password_store:1.7.0:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2018-12356", resolvedInVersion: "1.7.2"}},
|
|
},
|
|
"cpe:2.3:a:python:python:3.12.0:*:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.13.0:*:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha1:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha2:*:*:*:windows:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.12.0:-:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{
|
|
ID: "CVE-2025-1795",
|
|
resolvedInVersion: "3.12.3",
|
|
},
|
|
{
|
|
ID: "CVE-2024-7592",
|
|
resolvedInVersion: "3.12.6",
|
|
},
|
|
{
|
|
ID: "CVE-2024-6923",
|
|
resolvedInVersion: "3.12.5",
|
|
},
|
|
{
|
|
ID: "CVE-2024-0397",
|
|
resolvedInVersion: "3.12.3",
|
|
},
|
|
{
|
|
ID: "CVE-2024-12254",
|
|
resolvedInVersion: "3.12.9",
|
|
},
|
|
{
|
|
ID: "CVE-2024-9287",
|
|
resolvedInVersion: "3.12.8",
|
|
},
|
|
{
|
|
ID: "CVE-2025-0938",
|
|
resolvedInVersion: "3.12.9",
|
|
},
|
|
{
|
|
ID: "CVE-2023-6507",
|
|
// TODO: fix missing version here (according to vulncheck it was fixed in
|
|
// 3.12.1, but the generated feed data doesn't have this value)
|
|
resolvedInVersion: "",
|
|
},
|
|
{
|
|
ID: "CVE-2024-8088",
|
|
resolvedInVersion: "3.12.6",
|
|
},
|
|
{
|
|
ID: "CVE-2024-4032",
|
|
resolvedInVersion: "3.12.4",
|
|
},
|
|
{
|
|
ID: "CVE-2024-3219",
|
|
resolvedInVersion: "3.12.5",
|
|
},
|
|
{
|
|
ID: "CVE-2024-0450",
|
|
resolvedInVersion: "3.12.2",
|
|
},
|
|
{
|
|
ID: "CVE-2023-6597",
|
|
resolvedInVersion: "3.12.1",
|
|
},
|
|
{
|
|
ID: "CVE-2024-3220",
|
|
resolvedInVersion: "3.14.0",
|
|
},
|
|
{
|
|
ID: "CVE-2024-6232",
|
|
resolvedInVersion: "3.12.6",
|
|
},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha1:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{
|
|
ID: "CVE-2024-12254",
|
|
resolvedInVersion: "3.14.0a3",
|
|
},
|
|
{
|
|
ID: "CVE-2024-9287",
|
|
resolvedInVersion: "",
|
|
},
|
|
{
|
|
ID: "CVE-2025-0938",
|
|
resolvedInVersion: "3.14.0a5",
|
|
},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha2:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{
|
|
{
|
|
ID: "CVE-2024-12254",
|
|
resolvedInVersion: "3.14.0a3",
|
|
},
|
|
{
|
|
ID: "CVE-2025-0938",
|
|
resolvedInVersion: "3.14.0a5",
|
|
},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:python:python:3.14.0:alpha3:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2024-12254"},
|
|
includedCVEs: []cve{
|
|
{
|
|
ID: "CVE-2025-0938",
|
|
resolvedInVersion: "3.14.0a5",
|
|
},
|
|
},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:google:chrome:138.0.7204.91:*:*:*:*:linux:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-6554"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:google:chrome:138.0.7204.92:*:*:*:*:macos:*:*": {
|
|
excludedCVEs: []string{"CVE-2025-6554"},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:docker:desktop:4.43.2:*:*:*:*:macos:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2025-9074", resolvedInVersion: "4.44.3"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
"cpe:2.3:a:docker:desktop:4.39.0:*:*:*:*:windows:*:*": {
|
|
includedCVEs: []cve{{ID: "CVE-2025-9074", resolvedInVersion: "4.44.3"}},
|
|
continuesToUpdate: true,
|
|
},
|
|
}
|
|
|
|
cveOSTests := []struct {
|
|
platform string
|
|
version string
|
|
osID uint
|
|
includedCVEs []string
|
|
excludedCVEs []string
|
|
}{
|
|
{
|
|
platform: "darwin",
|
|
version: "14.1.2",
|
|
osID: 1,
|
|
includedCVEs: []string{
|
|
"CVE-2023-45866",
|
|
"CVE-2023-42886",
|
|
"CVE-2023-42891",
|
|
"CVE-2023-42906",
|
|
"CVE-2023-42910",
|
|
"CVE-2023-42924",
|
|
"CVE-2023-42883",
|
|
"CVE-2023-42894",
|
|
"CVE-2023-42926",
|
|
"CVE-2023-42932",
|
|
"CVE-2023-42907",
|
|
"CVE-2023-42922",
|
|
"CVE-2023-42904",
|
|
"CVE-2023-42901",
|
|
"CVE-2023-42898",
|
|
"CVE-2023-42903",
|
|
"CVE-2023-42902",
|
|
"CVE-2023-42909",
|
|
"CVE-2023-42914",
|
|
"CVE-2023-42874",
|
|
"CVE-2023-42882",
|
|
"CVE-2023-42912",
|
|
"CVE-2023-42911",
|
|
"CVE-2023-42890",
|
|
"CVE-2023-42905",
|
|
"CVE-2023-42919",
|
|
"CVE-2023-42900",
|
|
"CVE-2023-42899",
|
|
"CVE-2023-42908",
|
|
"CVE-2023-42884",
|
|
},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "13.6.2",
|
|
osID: 2,
|
|
// This is a subset of vulnerabilities for macOS 13.6.2
|
|
includedCVEs: []string{
|
|
"CVE-2023-32361",
|
|
"CVE-2023-35990",
|
|
"CVE-2023-40541",
|
|
"CVE-2023-40400",
|
|
"CVE-2023-41980",
|
|
"CVE-2023-38615",
|
|
"CVE-2023-39233",
|
|
"CVE-2023-40402",
|
|
"CVE-2023-40450",
|
|
"CVE-2023-42891",
|
|
"CVE-2023-41079",
|
|
"CVE-2023-42932",
|
|
"CVE-2023-38586",
|
|
"CVE-2023-41067",
|
|
"CVE-2023-40407",
|
|
"CVE-2023-42924",
|
|
"CVE-2023-40395",
|
|
"CVE-2023-38596",
|
|
"CVE-2023-32396",
|
|
"CVE-2023-29497",
|
|
},
|
|
},
|
|
{
|
|
platform: "darwin",
|
|
version: "15.3",
|
|
osID: 3,
|
|
// This was resolved in 15.3, so it should be excluded. See https://github.com/fleetdm/fleet/issues/26561.
|
|
excludedCVEs: []string{"CVE-2025-24176"},
|
|
},
|
|
}
|
|
|
|
t.Run("find_vulns_on_cpes", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ds := new(mock.Store)
|
|
|
|
softwareIDToCPEs := make(map[uint]string)
|
|
ds.ListSoftwareCPEsFunc = func(ctx context.Context) ([]fleet.SoftwareCPE, error) {
|
|
var softwareCPEs []fleet.SoftwareCPE
|
|
i := uint(0)
|
|
for cpe := range cveTests {
|
|
softwareCPEs = append(softwareCPEs, fleet.SoftwareCPE{CPE: cpe, SoftwareID: i})
|
|
softwareIDToCPEs[i] = cpe
|
|
i++
|
|
}
|
|
return softwareCPEs, nil
|
|
}
|
|
|
|
var osIDs []uint
|
|
ds.ListOperatingSystemsForPlatformFunc = func(ctx context.Context, p string) ([]fleet.OperatingSystem, error) {
|
|
var oss []fleet.OperatingSystem
|
|
for _, os := range cveOSTests {
|
|
oss = append(oss, fleet.OperatingSystem{
|
|
ID: os.osID,
|
|
Platform: os.platform,
|
|
Version: os.version,
|
|
})
|
|
osIDs = append(osIDs, os.osID)
|
|
}
|
|
return oss, nil
|
|
}
|
|
|
|
cveLock := &sync.Mutex{}
|
|
cvesFound := make(map[string][]cve)
|
|
ds.InsertSoftwareVulnerabilityFunc = func(ctx context.Context, vuln fleet.SoftwareVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
cveLock.Lock()
|
|
defer cveLock.Unlock()
|
|
|
|
cpe, ok := softwareIDToCPEs[vuln.SoftwareID]
|
|
if !ok {
|
|
return false, fmt.Errorf("software id -> cpe not found: %d", vuln.SoftwareID)
|
|
}
|
|
cve := cve{
|
|
ID: vuln.CVE,
|
|
resolvedInVersion: *vuln.ResolvedInVersion,
|
|
}
|
|
cvesFound[cpe] = append(cvesFound[cpe], cve)
|
|
return false, nil
|
|
}
|
|
|
|
osCVELock := &sync.Mutex{}
|
|
osCVEsFound := make(map[uint][]string)
|
|
ds.InsertOSVulnerabilityFunc = func(ctx context.Context, vuln fleet.OSVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
osCVELock.Lock()
|
|
defer osCVELock.Unlock()
|
|
|
|
osCVEsFound[vuln.OSID] = append(osCVEsFound[vuln.OSID], vuln.CVE)
|
|
|
|
return false, nil
|
|
}
|
|
|
|
ds.DeleteOutOfDateVulnerabilitiesFunc = func(ctx context.Context, source fleet.VulnerabilitySource, olderThan time.Time) error {
|
|
return nil
|
|
}
|
|
ds.DeleteOutOfDateOSVulnerabilitiesFunc = func(ctx context.Context, source fleet.VulnerabilitySource, olderThan time.Time) error {
|
|
return nil
|
|
}
|
|
|
|
_, err := TranslateCPEToCVE(ctx, ds, tempDir, kitlog.NewNopLogger(), false, time.Now().UTC().Add(-time.Hour))
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, ds.DeleteOutOfDateVulnerabilitiesFuncInvoked)
|
|
require.True(t, ds.DeleteOutOfDateOSVulnerabilitiesFuncInvoked)
|
|
|
|
for cpe, tc := range cveTests {
|
|
if tc.continuesToUpdate {
|
|
// Given that new vulnerabilities can be found on these
|
|
// packages/products, we check that at least the
|
|
// known ones are found.
|
|
for _, cve := range tc.includedCVEs {
|
|
require.Contains(t, cvesFound[cpe], cve, fmt.Sprintf("%s does not contain CVE %#v", cpe, cve))
|
|
}
|
|
} else {
|
|
// Check for exact match of CVEs found.
|
|
require.ElementsMatch(t, cvesFound[cpe], tc.includedCVEs, cpe)
|
|
}
|
|
|
|
for _, cve := range tc.excludedCVEs {
|
|
for _, cveFound := range cvesFound[cpe] {
|
|
require.NotEqual(t, cve, cveFound.ID, fmt.Sprintf("%s should not contain %s", cpe, cve))
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, tc := range cveOSTests {
|
|
for _, cve := range tc.includedCVEs {
|
|
require.Contains(t, osCVEsFound[tc.osID], cve)
|
|
}
|
|
for _, cve := range tc.excludedCVEs {
|
|
require.NotContains(t, osCVEsFound[tc.osID], cve)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("recent_vulns", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ds := new(mock.Store)
|
|
safeDS := &threadSafeDSMock{Store: ds}
|
|
|
|
softwareCPEs := []fleet.SoftwareCPE{
|
|
{CPE: "cpe:2.3:a:google:chrome:*:*:*:*:*:*:*:*", ID: 1, SoftwareID: 1},
|
|
{CPE: "cpe:2.3:a:mozilla:firefox:*:*:*:*:*:*:*:*", ID: 2, SoftwareID: 2},
|
|
{CPE: "cpe:2.3:a:haxx:curl:*:*:*:*:*:*:*:*", ID: 3, SoftwareID: 3},
|
|
}
|
|
ds.DeleteOutOfDateVulnerabilitiesFunc = func(ctx context.Context, source fleet.VulnerabilitySource, olderThan time.Time) error {
|
|
return nil
|
|
}
|
|
ds.ListSoftwareCPEsFunc = func(ctx context.Context) ([]fleet.SoftwareCPE, error) {
|
|
return softwareCPEs, nil
|
|
}
|
|
ds.InsertSoftwareVulnerabilityFunc = func(ctx context.Context, vuln fleet.SoftwareVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
return true, nil
|
|
}
|
|
ds.ListOperatingSystemsForPlatformFunc = func(ctx context.Context, p string) ([]fleet.OperatingSystem, error) {
|
|
return nil, nil
|
|
}
|
|
ds.DeleteOutOfDateOSVulnerabilitiesFunc = func(ctx context.Context, source fleet.VulnerabilitySource, olderThan time.Time) error {
|
|
return nil
|
|
}
|
|
|
|
recent, err := TranslateCPEToCVE(ctx, safeDS, tempDir, kitlog.NewNopLogger(), true, time.Now().Add(-time.Hour))
|
|
require.NoError(t, err)
|
|
|
|
byCPE := make(map[uint]int)
|
|
for _, cpe := range recent {
|
|
byCPE[cpe.Affected()]++
|
|
}
|
|
|
|
// even if it's somewhat far in the past, I've seen the exact numbers
|
|
// change a bit between runs with different downloads, so allow for a bit
|
|
// of wiggle room.
|
|
assert.Greater(t, byCPE[softwareCPEs[0].SoftwareID], 150, "google chrome CVEs")
|
|
assert.Greater(t, byCPE[softwareCPEs[1].SoftwareID], 280, "mozilla firefox CVEs")
|
|
assert.Greater(t, byCPE[softwareCPEs[2].SoftwareID], 10, "curl CVEs")
|
|
|
|
// call it again but now return false from this call, simulating CVE-CPE pairs
|
|
// that already existed in the DB.
|
|
ds.InsertSoftwareVulnerabilityFunc = func(ctx context.Context, vuln fleet.SoftwareVulnerability, src fleet.VulnerabilitySource) (bool, error) {
|
|
return false, nil
|
|
}
|
|
recent, err = TranslateCPEToCVE(ctx, safeDS, tempDir, kitlog.NewNopLogger(), true, time.Now().UTC().Add(-time.Hour))
|
|
require.NoError(t, err)
|
|
|
|
// no recent vulnerability should be reported
|
|
assert.Len(t, recent, 0)
|
|
})
|
|
}
|
|
|
|
func TestSyncsCVEFromURL(t *testing.T) {
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if strings.HasSuffix(r.RequestURI, ".meta") {
|
|
fmt.Fprint(w, "lastModifiedDate:2021-08-04T11:10:30-04:00\r\n")
|
|
fmt.Fprint(w, "size:20967174\r\n")
|
|
fmt.Fprint(w, "zipSize:1453429\r\n")
|
|
fmt.Fprint(w, "gzSize:1453293\r\n")
|
|
fmt.Fprint(w, "sha256:10D7338A1E2D8DB344C381793110B67FCA7D729ADA21624EF089EBA78CCE7B53\r\n")
|
|
}
|
|
}))
|
|
defer ts.Close()
|
|
|
|
tempDir := t.TempDir()
|
|
cveFeedPrefixURL := ts.URL + "/feeds/json/cve/1.1/"
|
|
err := DownloadCVEFeed(tempDir, cveFeedPrefixURL, false, log.NewNopLogger())
|
|
require.Error(t, err)
|
|
require.Contains(t,
|
|
err.Error(),
|
|
fmt.Sprintf("1 synchronisation error:\n\tunexpected size for \"%s/feeds/json/cve/1.1/nvdcve-1.1-2002.json.gz\" (200 OK): want 1453293, have 0", ts.URL),
|
|
)
|
|
}
|
|
|
|
// This test is using real data from the 2022 NVD feed
|
|
func TestGetMatchingVersionEndExcluding(t *testing.T) {
|
|
ctx := context.Background()
|
|
testDict := loadDict(t, "../testdata/nvdcve-1.1-2022.json.gz")
|
|
|
|
tests := []struct {
|
|
name string
|
|
cve string
|
|
meta *wfn.Attributes
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "happy path with version with no Version Start",
|
|
cve: "CVE-2022-40897",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "python",
|
|
Product: "setuptools",
|
|
Version: "64",
|
|
},
|
|
want: "65.5.1",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "CVE matches multiple products",
|
|
cve: "CVE-2022-40956",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "mozilla",
|
|
Product: "firefox",
|
|
Version: "93.0.100",
|
|
},
|
|
want: "105.0",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Nodes has nested Children",
|
|
cve: "CVE-2022-40961",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "mozilla",
|
|
Product: "firefox",
|
|
Version: "93.0.100",
|
|
},
|
|
want: "105.0",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Multiple product matches with different version ranges",
|
|
cve: "CVE-2022-26697",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "apple",
|
|
Product: "macos",
|
|
Version: "12.0",
|
|
},
|
|
want: "12.4",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "No version end excluding",
|
|
cve: "CVE-2022-26834",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "cybozu",
|
|
Product: "remote_service_manager",
|
|
Version: "3.1.2",
|
|
},
|
|
want: "",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Version exceeds version end excluding",
|
|
cve: "CVE-2022-4610",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "clickstudios",
|
|
Product: "passwordstate",
|
|
Version: "9.5.8.4",
|
|
TargetSW: "chrome",
|
|
},
|
|
want: "",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Can compare 4th version part",
|
|
cve: "CVE-2022-45889",
|
|
meta: &wfn.Attributes{
|
|
Vendor: "planetestream",
|
|
Product: "planet_estream",
|
|
Version: "6.72.10.06",
|
|
},
|
|
want: "6.72.10.07",
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := getMatchingVersionEndExcluding(ctx, tt.cve, tt.meta, testDict, nil)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("getMatchingVersionEndExcluding() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("got %q, want %q", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetMacOSCPEs(t *testing.T) {
|
|
ctx := context.Background()
|
|
ds := new(mock.Store)
|
|
os := fleet.OperatingSystem{
|
|
ID: 1,
|
|
Name: "macOS",
|
|
Version: "11.6.2",
|
|
Arch: "x86_64",
|
|
KernelVersion: "20.6.0",
|
|
Platform: "darwin",
|
|
}
|
|
|
|
ds.ListOperatingSystemsForPlatformFunc = func(ctx context.Context, p string) ([]fleet.OperatingSystem, error) {
|
|
return []fleet.OperatingSystem{os}, nil
|
|
}
|
|
|
|
CVEs, err := GetMacOSCPEs(ctx, ds)
|
|
require.NoError(t, err)
|
|
require.Len(t, CVEs, 2)
|
|
|
|
expected := map[osCPEWithNVDMeta]struct{}{
|
|
{
|
|
OperatingSystem: os,
|
|
meta: &wfn.Attributes{
|
|
Part: "o",
|
|
Vendor: "apple",
|
|
Product: "mac_os_x",
|
|
Version: CVEs[0].Version,
|
|
Update: wfn.Any,
|
|
Edition: wfn.Any,
|
|
SWEdition: wfn.Any,
|
|
TargetSW: wfn.Any,
|
|
TargetHW: wfn.Any,
|
|
Other: wfn.Any,
|
|
Language: wfn.Any,
|
|
},
|
|
}: {},
|
|
{
|
|
OperatingSystem: os,
|
|
meta: &wfn.Attributes{
|
|
Part: "o",
|
|
Vendor: "apple",
|
|
Product: "macos",
|
|
Version: CVEs[0].Version,
|
|
Update: wfn.Any,
|
|
Edition: wfn.Any,
|
|
SWEdition: wfn.Any,
|
|
TargetSW: wfn.Any,
|
|
TargetHW: wfn.Any,
|
|
Other: wfn.Any,
|
|
Language: wfn.Any,
|
|
},
|
|
}: {},
|
|
}
|
|
|
|
for _, cve := range CVEs {
|
|
require.Contains(t, expected, cve)
|
|
}
|
|
}
|
|
|
|
// loadDict loads a cvefeed.Dictionary from a JSON NVD feed file.
|
|
func loadDict(t *testing.T, path string) cvefeed.Dictionary {
|
|
dict, err := cvefeed.LoadJSONDictionary(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return dict
|
|
}
|
|
|
|
func TestExpandCPEAliases(t *testing.T) {
|
|
firefox := &wfn.Attributes{
|
|
Vendor: "mozilla",
|
|
Product: "firefox",
|
|
Version: "93.0.100",
|
|
}
|
|
chromePlugin := &wfn.Attributes{
|
|
Vendor: "google",
|
|
Product: "plugin foobar",
|
|
Version: "93.0.100",
|
|
TargetSW: "chrome",
|
|
}
|
|
|
|
vsCodeExtension := &wfn.Attributes{
|
|
Vendor: "Microsoft",
|
|
Product: "foo.extension",
|
|
Version: "2024.2.1",
|
|
TargetSW: "visual_studio_code",
|
|
}
|
|
vsCodeExtensionAlias := *vsCodeExtension
|
|
vsCodeExtensionAlias.TargetSW = "visual_studio"
|
|
|
|
pythonCodeExtension := &wfn.Attributes{
|
|
Vendor: "microsoft",
|
|
Product: "python_extension",
|
|
Version: "2024.2.1",
|
|
TargetSW: "visual_studio_code",
|
|
}
|
|
pythonCodeExtensionAlias1 := *pythonCodeExtension
|
|
pythonCodeExtensionAlias1.TargetSW = "visual_studio"
|
|
pythonCodeExtensionAlias2 := *pythonCodeExtension
|
|
pythonCodeExtensionAlias2.Product = "visual_studio_code"
|
|
pythonCodeExtensionAlias2.TargetSW = "python"
|
|
|
|
python3140Alpha2 := &wfn.Attributes{
|
|
Vendor: "python",
|
|
Product: "python",
|
|
Version: "3.14.0",
|
|
Update: "alpha2",
|
|
TargetSW: "windows",
|
|
}
|
|
python3140Alpha2Alias1 := *python3140Alpha2
|
|
python3140Alpha2Alias1.Version = "3.14.0a2"
|
|
python3140Alpha2Alias1.Update = ""
|
|
|
|
python3130Beta1 := &wfn.Attributes{
|
|
Vendor: "python",
|
|
Product: "python",
|
|
Version: "3.13.0",
|
|
Update: "beta2",
|
|
TargetSW: "windows",
|
|
}
|
|
python3130Beta1Alias := *python3130Beta1
|
|
python3130Beta1Alias.Version = "3.13.0b2"
|
|
python3130Beta1Alias.Update = ""
|
|
|
|
python3130RC1 := &wfn.Attributes{
|
|
Vendor: "python",
|
|
Product: "python",
|
|
Version: "3.13.0",
|
|
Update: "rc1",
|
|
TargetSW: "windows",
|
|
}
|
|
python3130RC1Alias := *python3130RC1
|
|
python3130RC1Alias.Version = "3.13.0rc1"
|
|
python3130RC1Alias.Update = ""
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
cpeItem *wfn.Attributes
|
|
expectedAliases []*wfn.Attributes
|
|
}{
|
|
{
|
|
name: "no expansion without target_sw",
|
|
cpeItem: firefox,
|
|
expectedAliases: []*wfn.Attributes{firefox},
|
|
},
|
|
{
|
|
name: "no expansion with target_sw",
|
|
cpeItem: chromePlugin,
|
|
expectedAliases: []*wfn.Attributes{chromePlugin},
|
|
},
|
|
{
|
|
name: "visual studio code extension",
|
|
cpeItem: vsCodeExtension,
|
|
expectedAliases: []*wfn.Attributes{vsCodeExtension, &vsCodeExtensionAlias},
|
|
},
|
|
{
|
|
name: "python visual studio code extension",
|
|
cpeItem: pythonCodeExtension,
|
|
expectedAliases: []*wfn.Attributes{pythonCodeExtension, &pythonCodeExtensionAlias1, &pythonCodeExtensionAlias2},
|
|
},
|
|
{
|
|
name: "pre-release python: 3.14.0 alpha2",
|
|
cpeItem: python3140Alpha2,
|
|
expectedAliases: []*wfn.Attributes{python3140Alpha2, &python3140Alpha2Alias1},
|
|
},
|
|
{
|
|
name: "pre-release python: 3.13.0 beta1",
|
|
cpeItem: python3130Beta1,
|
|
expectedAliases: []*wfn.Attributes{python3130Beta1, &python3130Beta1Alias},
|
|
},
|
|
{
|
|
name: "pre-release python: 3.13.0 rc1",
|
|
cpeItem: python3130RC1,
|
|
expectedAliases: []*wfn.Attributes{python3130RC1, &python3130RC1Alias},
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
aliases := expandCPEAliases(tc.cpeItem)
|
|
require.Equal(t, tc.expectedAliases, aliases)
|
|
})
|
|
}
|
|
}
|