Mutate Windows Python versions to match what's in NVD (#25813)

Also includes a CPE translation fix to avoid missing Python prereleases
on Windows, though we have further work to do to generate a CPE that
matches the one NVD uses.

For #24611.

# 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] Added/updated automated tests
- [x] A detailed QA plan exists on the associated ticket (if it isn't
there, work with the product group's QA engineer to add it)
- [x] Manual QA for all new/changed functionality
This commit is contained in:
Ian Littman 2025-02-03 12:22:48 -06:00 committed by GitHub
parent 44af7155db
commit 8bb9acbc7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 120 additions and 2 deletions

View file

@ -1770,6 +1770,35 @@ var (
s.Version = fmt.Sprintf("%d.%d.%s.%s", yearBasedMajorVersion, yearBasedMinorVersion, "99", eapMinorAndPatchVersion)
},
},
{
// Python versions on Windows encode ABI and release information in a way that's incompatible with NVD lookups
checkSoftware: func(h *fleet.Host, s *fleet.Software) bool {
return s.Source == "programs" && strings.HasPrefix(s.Name, "Python 3.")
},
mutateSoftware: func(s *fleet.Software, logger log.Logger) {
versionComponents := strings.Split(s.Version, ".")
patchVersion := versionComponents[2][0 : len(versionComponents[2])-3]
releaseLevel := versionComponents[2][len(versionComponents[2])-3 : len(versionComponents[2])-1]
releaseSerial := versionComponents[2][len(versionComponents[2])-1 : len(versionComponents[2])]
candidateSuffix := ""
switch releaseLevel { // see https://github.com/python/cpython/issues/100829#issuecomment-1374656643
case "10":
candidateSuffix = "-alpha" + releaseSerial
case "11":
candidateSuffix = "-beta" + releaseSerial
case "12":
candidateSuffix = "-rc" + releaseSerial
} // default
if patchVersion == "" { // dot-zero patch releases have a 3-digit patch + build number
patchVersion = "0"
}
versionComponents[2] = patchVersion + candidateSuffix
s.Version = strings.Join(versionComponents[0:3], ".")
},
},
}
)

View file

@ -1975,6 +1975,76 @@ func TestSanitizeSoftware(t *testing.T) {
BundleIdentifier: "com.jetbrains.intellij-EAP",
},
},
{
name: "Python for Windows GA dot-zero",
h: &fleet.Host{},
s: &fleet.Software{
Name: "Python 3.12 (64-bit)",
Version: "3.12.150.1013",
Source: "programs",
},
sanitized: &fleet.Software{
Name: "Python 3.12 (64-bit)",
Version: "3.12.0",
Source: "programs",
},
},
{
name: "Python for Windows GA patch release",
h: &fleet.Host{},
s: &fleet.Software{
Name: "Python 3.12.8 (64-bit)",
Version: "3.12.8150.0",
Source: "programs",
},
sanitized: &fleet.Software{
Name: "Python 3.12.8 (64-bit)",
Version: "3.12.8",
Source: "programs",
},
},
{
name: "Python for Windows alpha",
h: &fleet.Host{},
s: &fleet.Software{
Name: "Python 3.14.0a4 (64-bit)",
Version: "3.14.104.1013",
Source: "programs",
},
sanitized: &fleet.Software{
Name: "Python 3.14.0a4 (64-bit)",
Version: "3.14.0-alpha4",
Source: "programs",
},
},
{
name: "Python for Windows beta",
h: &fleet.Host{},
s: &fleet.Software{
Name: "Python 3.14.0b3 (64-bit)",
Version: "3.14.113.1013",
Source: "programs",
},
sanitized: &fleet.Software{
Name: "Python 3.14.0b3 (64-bit)",
Version: "3.14.0-beta3",
Source: "programs",
},
},
{
name: "Python for Windows RC",
h: &fleet.Host{},
s: &fleet.Software{
Name: "Python 3.14.0rc2 (64-bit)",
Version: "3.14.122.1013",
Source: "programs",
},
sanitized: &fleet.Software{
Name: "Python 3.14.0rc2 (64-bit)",
Version: "3.14.0-rc2",
Source: "programs",
},
},
} {
t.Run(tc.name, func(t *testing.T) {
sanitizeSoftware(tc.h, tc.s, log.NewNopLogger())

View file

@ -894,10 +894,19 @@ func TestCPEFromSoftwareIntegration(t *testing.T) {
software: fleet.Software{
Name: "Python 3.10.6 (64-bit)",
Source: "programs",
Version: "3.10.6150.0",
Version: "3.10.6",
Vendor: "Python Software Foundation",
BundleIdentifier: "",
}, cpe: "cpe:2.3:a:python:python:3.10.6150.0:*:*:*:*:windows:*:*",
}, cpe: "cpe:2.3:a:python:python:3.10.6:*:*:*:*:windows:*:*",
},
{
software: fleet.Software{
Name: "Python 3.14.0a1 (64-bit)",
Source: "programs",
Version: "3.14.0-alpha1",
Vendor: "Python Software Foundation",
// should be "cpe:2.3:a:python:python:3.14.0:alpha1:*:*:*:windows:*:*"; see #24810
}, cpe: "cpe:2.3:a:python:python:3.14.0-alpha1:*:*:*:*:windows:*:*",
},
{
software: fleet.Software{

View file

@ -70,6 +70,16 @@
"vendor": ["7-zip"]
}
},
{
"software": {
"name": ["/^Python 3\\.\\d{1,2}/"],
"source": ["programs"]
},
"filter": {
"product": ["python"],
"vendor": ["python"]
}
},
{
"software": {
"name": ["Docs"],