Skip to content

Commit 431946e

Browse files
authored
✨ Detect Microsoft Exchange SU updates (#5874)
The updated CU version will then be used to also update the Exchange package version. Signed-off-by: Christian Zunker <christian@mondoo.com>
1 parent 81b2a47 commit 431946e

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

providers/os/resources/packages/windows_packages.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ var (
7373
}
7474

7575
sqlGDRUpdateRegExp = regexp.MustCompile(`^GDR.\d+.+SQL.Server.\d+.\(KB\d+\)`)
76+
exchangeCURegExp = regexp.MustCompile(`^Microsoft Exchange Server.\d+.+Update.\d+$`)
7677
sqlHotfixRegExp = regexp.MustCompile(`^Hotfix.+SQL.Server`)
7778
// Find the database engine package and use version as a reference for the update
7879
msSqlServiceRegexp = regexp.MustCompile(`^SQL Server \d+ Database Engine Services$`)
@@ -591,6 +592,11 @@ func (w *WinPkgManager) List() ([]Package, error) {
591592
pkgs = updateMsSqlPackages(pkgs, msSqlHotfixes[len(msSqlHotfixes)-1])
592593
}
593594

595+
exchangeCU := findExchangeCU(pkgs)
596+
if exchangeCU != nil {
597+
pkgs = updateExchangePackage(pkgs, *exchangeCU)
598+
}
599+
594600
pkgs = append(pkgs, hotfixAsPkgs...)
595601
return pkgs, nil
596602
}
@@ -742,3 +748,31 @@ func createPackage(name, version, format, arch, publisher, installLocation strin
742748

743749
return pkg
744750
}
751+
752+
// findExchangeCU returns the installed CU Exchange
753+
// When a SU is installed, the CU is updated to the SU version
754+
// But not the actual Exchange Server version
755+
// We need this package to update the Exchange Server version
756+
func findExchangeCU(packages []Package) *Package {
757+
for _, p := range packages {
758+
if exchangeCURegExp.MatchString(p.Name) {
759+
return &p
760+
}
761+
}
762+
763+
return nil
764+
}
765+
766+
// updateExchangePackage updates the version of the Exchange Server packages to the latest hotfix/security version
767+
func updateExchangePackage(pkgs []Package, latestExchangeCU Package) []Package {
768+
// Find other SQL Server packages and update them to the latest hotfix version
769+
for i, pkg := range pkgs {
770+
if pkg.Name == "Microsoft Exchange Server" {
771+
currentVersion := pkgs[i].Version
772+
pkgs[i].Version = latestExchangeCU.Version
773+
log.Debug().Str("package", pkg.Name).Str("version", latestExchangeCU.Version).Msg("Updated Exchange package")
774+
pkgs[i].PUrl = strings.Replace(pkgs[i].PUrl, currentVersion, latestExchangeCU.Version, 1)
775+
}
776+
}
777+
return pkgs
778+
}

providers/os/resources/packages/windows_packages_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,3 +487,69 @@ func TestCreatePackage(t *testing.T) {
487487
assert.Equal(t, "GDR 2042 für SQL Server 2017 (KB5014354) (64-bit)", pkg.Name)
488488
})
489489
}
490+
491+
func TestFindAndUpdateMsExchangeSU_en(t *testing.T) {
492+
// Setup: create a list of packages with Exchange CU and SU
493+
packages := []Package{
494+
// This is the version of the latest CU installed on the machine
495+
{Name: "Microsoft Exchange Server", Version: "15.2.1748.10", PUrl: "pkg:windows/windows/Microsoft%20Exchange%20Server@15.2.1748.10?arch=AMD64"},
496+
// This is a SU for the CU and updates only the CU version, not the main Exchange Server version
497+
{Name: "Security Update for Exchange Server 2019 Cumulative Update 15 (KB5063221)", Version: "1", PUrl: "pkg:windows/windows/Security%20Update%20for%20Exchange%20Server%202019%20Cumulative%20Update%2015%20%28KB5063221%29@1?arch=AMD64"},
498+
// We need this version
499+
{Name: "Microsoft Exchange Server 2019 Cumulative Update 15", Version: "15.2.1748.36", PUrl: "pkg:windows/windows/Microsoft%20Exchange%20Server%202019%20Cumulative%20Update%2015@15.2.1748.36?arch=AMD64"},
500+
{Name: "Not a hotfix", Version: "1.0.0", PUrl: "pkg:windows/windows/Not%20a%20hotfix@1.0.0?arch=x86"},
501+
}
502+
503+
expectedLatestVersion := "15.2.1748.36"
504+
// Step 1: Find SQL Server hotfixes
505+
cu := findExchangeCU(packages)
506+
require.NotNil(t, cu)
507+
508+
// Step 2: Update SQL Server packages with the latest hotfix version
509+
updated := updateExchangePackage(packages, *cu)
510+
511+
// Step 3: Check that the Exchange Server package has the updated version
512+
pkg := findPkgByName(updated, "Microsoft Exchange Server")
513+
require.NotNil(t, pkg)
514+
require.Equal(t, expectedLatestVersion, pkg.Version)
515+
assert.Equal(t, "pkg:windows/windows/Microsoft%20Exchange%20Server@"+expectedLatestVersion+"?arch=AMD64", pkg.PUrl)
516+
517+
// Step 5: Ensure non-SQL Server packages are unchanged
518+
pkg = findPkgByName(updated, "Not a hotfix")
519+
require.NotNil(t, pkg)
520+
require.Equal(t, "1.0.0", pkg.Version)
521+
assert.Equal(t, "pkg:windows/windows/Not%20a%20hotfix@1.0.0?arch=x86", pkg.PUrl)
522+
}
523+
524+
func TestFindAndUpdateMsExchangeSU_de(t *testing.T) {
525+
// Setup: create a list of packages with Exchange CU and SU
526+
packages := []Package{
527+
// This is the version of the latest CU installed on the machine
528+
{Name: "Microsoft Exchange Server", Version: "15.2.1748.10", PUrl: "pkg:windows/windows/Microsoft%20Exchange%20Server@15.2.1748.10?arch=AMD64"},
529+
// This is a SU for the CU and updates only the CU version, not the main Exchange Server version
530+
{Name: "Security Update für Exchange Server 2019 Kumulatives Update 15 (KB5063221)", Version: "1", PUrl: "pkg:windows/windows/Security%20Update%20f%C3%BCr%20Exchange%20Server%202019%20Kumulatives%20Update%2015%20%28KB5063221%29@1?arch=AMD64"},
531+
// We need this version
532+
{Name: "Microsoft Exchange Server 2019 Kumulatives Update 15", Version: "15.2.1748.36", PUrl: "pkg:windows/windows/Microsoft%20Exchange%20Server%202019%20Kumulatives%20Update%2015@15.2.1748.36?arch=AMD64"},
533+
{Name: "Not a hotfix", Version: "1.0.0", PUrl: "pkg:windows/windows/Not%20a%20hotfix@1.0.0?arch=x86"},
534+
}
535+
536+
expectedLatestVersion := "15.2.1748.36"
537+
// Step 1: Find SQL Server hotfixes
538+
cu := findExchangeCU(packages)
539+
require.NotNil(t, cu)
540+
541+
// Step 2: Update SQL Server packages with the latest hotfix version
542+
updated := updateExchangePackage(packages, *cu)
543+
544+
// Step 3: Check that the Exchange Server package has the updated version
545+
pkg := findPkgByName(updated, "Microsoft Exchange Server")
546+
require.NotNil(t, pkg)
547+
require.Equal(t, expectedLatestVersion, pkg.Version)
548+
assert.Equal(t, "pkg:windows/windows/Microsoft%20Exchange%20Server@"+expectedLatestVersion+"?arch=AMD64", pkg.PUrl)
549+
550+
// Step 5: Ensure non-SQL Server packages are unchanged
551+
pkg = findPkgByName(updated, "Not a hotfix")
552+
require.NotNil(t, pkg)
553+
require.Equal(t, "1.0.0", pkg.Version)
554+
assert.Equal(t, "pkg:windows/windows/Not%20a%20hotfix@1.0.0?arch=x86", pkg.PUrl)
555+
}

0 commit comments

Comments
 (0)