diff --git a/articles/consolidate-multiple-tools-with-fleet.md b/articles/consolidate-multiple-tools-with-fleet.md index cfc4da7199..9de6c4cad0 100644 --- a/articles/consolidate-multiple-tools-with-fleet.md +++ b/articles/consolidate-multiple-tools-with-fleet.md @@ -9,8 +9,6 @@ We've been using Fleet for a few years and we couldn't be happier. The fact that ## Challenge -Scaling organizations face a common challenge: managing every device efficiently across varying teams and locations. Here, we take a deeper look at the impact that Fleet has made at a leading financial technology company. - The leading financial company looked to simplify how they manage devices and reduce tool overlap without sacrificing control over their infrastructure. The use of multiple proprietary device management tools was creating operational silos, and it required specialized expertise for different legacy systems, leading to inefficiencies. ## Solution diff --git a/articles/foursquare-quickly-migrates-to-fleet.md b/articles/foursquare-quickly-migrates-to-fleet.md index 697cee4044..0fc128180e 100644 --- a/articles/foursquare-quickly-migrates-to-fleet.md +++ b/articles/foursquare-quickly-migrates-to-fleet.md @@ -2,7 +2,7 @@
-“After several fast-paced weeks of planning, testing, and collaboration, our corporate engineering team at Foursquare has officially completed the migration to Fleet Device Management as our new device management platform. This move represents a big step forward for us.” +After several fast-paced weeks of planning, testing, and collaboration, our corporate engineering team at Foursquare has officially completed the migration to Fleet Device Management as our new device management platform. This move represents a big step forward for us. **— Mike Meyer, Manager, Corporate Engineering at Foursquare**
diff --git a/articles/global-social-media-platform-switches-to-fleet.md b/articles/global-social-media-platform-switches-to-fleet.md new file mode 100644 index 0000000000..6829aa7e53 --- /dev/null +++ b/articles/global-social-media-platform-switches-to-fleet.md @@ -0,0 +1,79 @@ +# Global social media platform switches to Fleet for workstation telemetry + +
+ +Context is king for device data, and Fleet provides a way to surface that information to our other teams and partners. + +**- Systems and Infrastructure Manager** +
+ +## Challenge + +One of the largest social media platforms sought to enhance its telemetry capabilities to maintain strict compliance and security without compromising data accessibility and operational efficiency. Managing thousands of devices across multiple platforms had led to fragmented visibility and reliance on manual data handling processes, which were time-consuming and error-prone. Additionally, the existing solution failed to provide actionable insights without significant customization, hindering proactive operations and complicating compliance with ongoing [ISO27002](https://www.iso.org/standard/75652.html) and [SOC audit](https://en.wikipedia.org/wiki/System_and_Organization_Controls) requirements. + +## Solution + +The social media platform transitioned to Fleet, consolidating under a single, [multi-platform](https://fleetdm.com/orchestration) system that supports macOS, Linux, and Windows. Fleet's compliance features made it easier to meet regulatory standards and protect sensitive data. Leveraging Fleet's real-time reporting and flexible data management capabilities eliminated the need for manual workflows and extensive customizations. Additionally, deploying [osquery](https://osquery.io/) independently from their existing EDR enhanced data accuracy and reliability, providing more accurate measurement against other benchmarks like [CIS](https://www.cisecurity.org/cis-benchmarks), and standardized osquery operations across their entire fleet. + +## Results + +
+ +Verifiable compliance + +Cross-team data accessibility + +Real-time insights + +Standardized processes +
+ +By switching to Fleet, they were able to institute more stringent compliance policies, verify security posture, gather real-time insight into ongoing operations, and standardize these processes across their growing fleet of diverse devices and teams. + + +## Their story + +This social media platform is one of the largest globally, connecting thousands of communities and millions of users. With a vast user base and a significant global presence, effective visibility is essential to maintaining their required performance, security, and compliance standards. + +The decision to switch to Fleet was driven by a few key factors. Strict adherence to compliance standards, balancing proactive and reactive security measures to protect sensitive data, and streamlining device data accessibility. By making data easily accessible and parsable, Fleet eliminated the inefficiencies of manual workflows and addressed communication gaps across teams, enabling better, faster decision-making. + + +With Fleet, they achieved this through: + +- Eliminating tool overlap + +- Definitive data for compliance and real-time reporting + +- Robust API and webhook support + +- A Unified reporting language + +### Eliminate tool overlap + +Fleet’s centralized platform enabled the combination of device operations across macOS, Windows, and Linux with a [unified reporting language](https://fleetdm.com/docs/deploy/reference-architectures#mysql) that provides flexibility and contextualized data. By adhering to standard data shapes and formats, Fleet makes sure that data is easily interpretable and usable across various teams and applications while serving as the central hub for security data. + +### Definitive data for compliance + +Fleet’s live query engine streams easily accessible and parsable [data](https://fleetdm.com/tables/account_policy_data), eliminating the need for manual exports and data consolidation from multiple tools. With accurate visibility and access across teams, remediations based on information directly from each device lead to fewer infrastructure failures and auditing errors. + +### Robust API and webhook support + +Fleet’s API facilitates real-time [compliance](https://fleetdm.com/queries) auditing and reporting, allowing the team to respond promptly to potential issues by combining data from different tools. The [API](https://fleetdm.com/docs/rest-api/rest-api) and webhook features enable automation and integration with existing systems, eliminating the need for extra middleware and reducing reliance on manual configurations. + +### Unified reporting language + +Fleet's straightforward deployment of the osquery agent across their devices as an independent element ensured data accuracy and reliability while standardizing its operations across macOS, Windows, and Linux. This allowed the social media platform to inspect, collect, fix, install, patch, and program just about anything, every minute of the day, on any computer in their infrastructure, with an unnoticeable performance impact + + +## Conclusion + +Transitioning to Fleet provided the platform with a strategic solution that addressed its critical needs for compliance, security, data accessibility, and operational efficiency. Fleet's cross-platform support and open-source transparency set it apart from competitors, providing a single source of truth for all devices. + + + + + + + + + diff --git a/articles/seamless-mdm-migration.md b/articles/seamless-mdm-migration.md index 369c6c1714..4474924325 100644 --- a/articles/seamless-mdm-migration.md +++ b/articles/seamless-mdm-migration.md @@ -1,5 +1,7 @@ # Seamless macOS MDM migration +> NOTE: Please contact Fleet here https://fleetdm.com/contact or reach out to the Fleet Customer Success team if you are a current Fleet customer for consultation when considering this migration path. We'd love to help! + ![Seamless macOS MDM migrations to Fleet](../website/assets/images/articles/seamless-mdm-migration-1600x900@2x.png) Migrating macOS devices between Mobile Device Management (MDM) solutions is often fraught with challenges, including potential gaps in device management, user disruption, and compliance issues. Traditional MDM migrations typically require end-user interaction and leave devices unmanaged for a period, leading to problems like Wi-Fi disconnections due to certificate profile removal and incomplete migrations. These challenges can force organizations to stay with outdated MDM solutions that no longer meet their needs. But there’s a better way. diff --git a/changes/22723-jetbrains-eap-versions b/changes/22723-jetbrains-eap-versions new file mode 100644 index 0000000000..6efe38c674 --- /dev/null +++ b/changes/22723-jetbrains-eap-versions @@ -0,0 +1 @@ +* Aliased EAP versions of JetBrains IDEs to "last release version plus all fixes" (e.g. 2024.3 EAP -> 2024.2.99) to avoid vulnerability false positives \ No newline at end of file diff --git a/changes/23309-mastodon-in-email-templates b/changes/23309-mastodon-in-email-templates new file mode 100644 index 0000000000..6eac06da3e --- /dev/null +++ b/changes/23309-mastodon-in-email-templates @@ -0,0 +1 @@ +* Added Mastodon icon and URL to server email templates. diff --git a/changes/24795-add-helpful-tooltip-setup-experience b/changes/24795-add-helpful-tooltip-setup-experience new file mode 100644 index 0000000000..4c108c2231 --- /dev/null +++ b/changes/24795-add-helpful-tooltip-setup-experience @@ -0,0 +1 @@ +- add helpful tooltip for the install software setup experience page diff --git a/cmd/fleet/cron.go b/cmd/fleet/cron.go index 1adc6ade43..36e00ddaaf 100644 --- a/cmd/fleet/cron.go +++ b/cmd/fleet/cron.go @@ -309,7 +309,7 @@ func checkWinVulnerabilities( "found new", len(r)) results = append(results, r...) if err != nil { - errHandler(ctx, logger, "analyzing hosts for Windows vulnerabilities", err) + errHandler(ctx, kitlog.With(logger, "os name", o.Name, "display version", o.DisplayVersion), "analyzing hosts for Windows vulnerabilities", err) } } } diff --git a/docs/Get started/FAQ.md b/docs/Get started/FAQ.md index d5da69c959..10d4afe9f2 100644 --- a/docs/Get started/FAQ.md +++ b/docs/Get started/FAQ.md @@ -94,7 +94,7 @@ If a table is not available for your host, Fleet will generally handle things be Fleet Desktop is supported on Ubuntu and Fedora. -Fedora requires a [gnome extension](https://extensions.gnome.org/extension/615/appindicator-support/) and Google Chrome for Fleet Desktop. +Fedora and some flavors of Ubuntu (e.g. Kubuntu) require a [gnome extension](https://extensions.gnome.org/extension/615/appindicator-support/) and Google Chrome for Fleet Desktop. Fleet's default (un)install scripts use `apt-get` for Debian-based distributions, and `dnf` for Red Hat-based distributions. To install packages on CentOS versions prior to 8, either add `dnf` or edit install and uninstall scripts to use the `yum` or `rpm` command. diff --git a/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/AddInstallSoftware/AddInstallSoftware.tests.tsx b/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/AddInstallSoftware/AddInstallSoftware.tests.tsx index 92081fdc54..6ca5d86d80 100644 --- a/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/AddInstallSoftware/AddInstallSoftware.tests.tsx +++ b/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/AddInstallSoftware/AddInstallSoftware.tests.tsx @@ -60,7 +60,10 @@ describe("AddInstallSoftware", () => { ); expect( - screen.getByText(/2 software will be installed during setup/) + screen.getByText( + (_, element) => + element?.textContent === "2 software will be installed during setup." + ) ).toBeVisible(); expect( screen.getByRole("button", { name: "Show selected software" }) diff --git a/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/AddInstallSoftware/AddInstallSoftware.tsx b/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/AddInstallSoftware/AddInstallSoftware.tsx index 98e772f6ec..1ca1ac38ed 100644 --- a/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/AddInstallSoftware/AddInstallSoftware.tsx +++ b/frontend/pages/ManageControlsPage/SetupExperience/cards/InstallSoftware/components/AddInstallSoftware/AddInstallSoftware.tsx @@ -6,6 +6,7 @@ import Button from "components/buttons/Button"; import CustomLink from "components/CustomLink"; import { ISoftwareTitle } from "interfaces/software"; import LinkWithContext from "components/LinkWithContext"; +import TooltipWrapper from "components/TooltipWrapper"; const baseClass = "add-install-software"; @@ -45,9 +46,17 @@ const AddInstallSoftware = ({ software.app_store_app?.install_during_setup ).length; - return installDuringSetupCount === 0 - ? "No software added." - : `${installDuringSetupCount} software will be installed during setup.`; + return installDuringSetupCount === 0 ? ( + "No software added." + ) : ( + <> + {installDuringSetupCount} software will be{" "} + + installed during setup + + . + + ); }; const getButtonText = () => { diff --git a/infrastructure/loadtesting/terraform/ecs.tf b/infrastructure/loadtesting/terraform/ecs.tf index 2327c2787b..fb1b13205a 100644 --- a/infrastructure/loadtesting/terraform/ecs.tf +++ b/infrastructure/loadtesting/terraform/ecs.tf @@ -132,6 +132,10 @@ resource "aws_ecs_task_definition" "backend" { } ] environment = concat([ + { + name = "FLEET_LOGGING_JSON" + value = "true" + }, { name = "FLEET_MYSQL_USERNAME" value = module.aurora_mysql.cluster_master_username diff --git a/server/mail/templates/change_email_confirmation.html b/server/mail/templates/change_email_confirmation.html index d557c06180..917e45a8a2 100644 --- a/server/mail/templates/change_email_confirmation.html +++ b/server/mail/templates/change_email_confirmation.html @@ -143,6 +143,13 @@ src="{{.AssetURL}}/fleet-mark-color-40x40@2x.png" /> + + Mastodon logo + X logo + + Mastodon logo + X logo + + Mastodon logo + X logo + + Mastodon logo + X logo + + Mastodon logo + X logo 0 { s.Version = fmt.Sprintf("%s.%s.00.%s", matches[1], matches[2], matches[3]) } @@ -1635,7 +1629,7 @@ func sanitizeSoftware(h *fleet.Host, s *fleet.Software, logger log.Logger) { checkSoftware: func(h *fleet.Host, s *fleet.Software) bool { return h.Platform == "windows" && s.Name == "Cloudflare WARP" && s.Source == "programs" }, - mutateSoftware: func(s *fleet.Software) { + mutateSoftware: func(s *fleet.Software, logger log.Logger) { // Perform some sanity check on the version before mutating it. parts := strings.Split(s.Version, ".") if len(parts) <= 1 { @@ -1658,7 +1652,7 @@ func sanitizeSoftware(h *fleet.Host, s *fleet.Software, logger log.Logger) { checkSoftware: func(h *fleet.Host, s *fleet.Software) bool { return citrixName.Match([]byte(s.Name)) || s.Name == "Citrix Workspace.app" }, - mutateSoftware: func(s *fleet.Software) { + mutateSoftware: func(s *fleet.Software, logger log.Logger) { parts := strings.Split(s.Version, ".") if len(parts) <= 1 { level.Debug(logger).Log("msg", "failed to parse software version", "name", s.Name, "version", s.Version) @@ -1694,7 +1688,7 @@ func sanitizeSoftware(h *fleet.Host, s *fleet.Software, logger log.Logger) { checkSoftware: func(h *fleet.Host, s *fleet.Software) bool { return s.Name == "minio" && strings.Contains(s.Version, "RELEASE.") }, - mutateSoftware: func(s *fleet.Software) { + mutateSoftware: func(s *fleet.Software, logger log.Logger) { s.Version = strings.TrimPrefix(s.Version, "RELEASE.") }, }, @@ -1705,7 +1699,7 @@ func sanitizeSoftware(h *fleet.Host, s *fleet.Software, logger log.Logger) { return s.Name == "minio" && regex.MatchString(s.Version) }, - mutateSoftware: func(s *fleet.Software) { + mutateSoftware: func(s *fleet.Software, logger log.Logger) { timestamp, err := time.Parse("20060102150405", s.Version) if err != nil { level.Debug(logger).Log("msg", "failed to parse software version", "name", s.Name, "version", s.Version, "err", err) @@ -1714,11 +1708,54 @@ func sanitizeSoftware(h *fleet.Host, s *fleet.Software, logger log.Logger) { s.Version = timestamp.Format("2006-01-02T15-04-05Z") }, }, - } + { + // JetBrains EAP version numbers aren't what are used in CPEs; this handles the translation for Mac versions. + // See #22723 for background. Bundle identifier for EAPs also ends with "-EAP" but checking version makes it + // a bit easier to add other platforms later. EAP version numbers are e.g. EAP GO-243.21565.42, and checking + // here for the dash ensures that string splitting in the mutator always works without a bounds check. + checkSoftware: func(h *fleet.Host, s *fleet.Software) bool { + return s.BundleIdentifier != "" && strings.HasPrefix(s.BundleIdentifier, "com.jetbrains.") && + strings.HasPrefix(s.Version, "EAP ") && strings.Contains(s.Version, "-") + }, + mutateSoftware: func(s *fleet.Software, logger log.Logger) { + // 243 -> 2024.3 + eapMajorVersion := strings.Split(strings.Split(s.Version, "-")[1], ".")[0] + yearBasedMajorVersion, err := strconv.Atoi("20" + eapMajorVersion[:2]) + if err != nil { + level.Debug(logger).Log("msg", "failed to parse JetBrains EAP major version", "version", s.Version, "err", err) + return + } + yearBasedMinorVersion, err := strconv.Atoi(eapMajorVersion[2:]) + if err != nil { + level.Debug(logger).Log("msg", "failed to parse JetBrains EAP minor version", "version", s.Version, "err", err) + return + } + // EAPs are treated as having all fixes from the previous year-based release, but no fixes from the + // year-based release they're an EAP of. The exception to this would be CVE-2024-37051, which was fixed + // in a second/third EAP depending on product, but at this point all vulnerable EAPs force exit on + // startup due to being expired, so that CVE can't be exploited. + yearBasedMinorVersion -= 1 + if yearBasedMinorVersion <= 0 { // wrap e.g. 2024.1 to 2023.4 (not a real version, but has all 2023.3 fixes) + yearBasedMajorVersion -= 1 + yearBasedMinorVersion = 4 + } + + // pass through minor and patch version for EAP to tell different EAP builds apart + eapMinorAndPatchVersion := strings.Join(strings.Split(strings.Split(s.Version, "-")[1], ".")[1:], ".") + s.Version = fmt.Sprintf("%d.%d.%s.%s", yearBasedMajorVersion, yearBasedMinorVersion, "99", eapMinorAndPatchVersion) + }, + }, + } +) + +// sanitizeSoftware performs any sanitization required to the ingested software fields. +// +// Some fields are reported with known incorrect values and we need to fix them before using them. +func sanitizeSoftware(h *fleet.Host, s *fleet.Software, logger log.Logger) { for _, softwareSanitizer := range softwareSanitizers { if softwareSanitizer.checkSoftware(h, s) { - softwareSanitizer.mutateSoftware(s) + softwareSanitizer.mutateSoftware(s, logger) return } } diff --git a/server/service/osquery_utils/queries_test.go b/server/service/osquery_utils/queries_test.go index bf66be3665..a1c366dfe0 100644 --- a/server/service/osquery_utils/queries_test.go +++ b/server/service/osquery_utils/queries_test.go @@ -1920,6 +1920,48 @@ func TestSanitizeSoftware(t *testing.T) { Version: "2020-03-10T00-00-00Z", }, }, + { + name: "JetBrains non-EAP", + h: &fleet.Host{}, + s: &fleet.Software{ + Name: "GoLand.app", + Version: "2024.3.1", + BundleIdentifier: "com.jetbrains.goland", + }, + sanitized: &fleet.Software{ + Name: "GoLand.app", + Version: "2024.3.1", + BundleIdentifier: "com.jetbrains.goland", + }, + }, + { + name: "JetBrains EAP", + h: &fleet.Host{}, + s: &fleet.Software{ + Name: "GoLand.app", + Version: "EAP GO-243.21565.42", + BundleIdentifier: "com.jetbrains.goland-EAP", + }, + sanitized: &fleet.Software{ + Name: "GoLand.app", + Version: "2024.2.99.21565.42", + BundleIdentifier: "com.jetbrains.goland-EAP", + }, + }, + { + name: "JetBrains year-wrapped EAP", + h: &fleet.Host{}, + s: &fleet.Software{ + Name: "IntelliJ IDEA CE", + Version: "EAP IC-241.12345.67", + BundleIdentifier: "com.jetbrains.intellij-EAP", + }, + sanitized: &fleet.Software{ + Name: "IntelliJ IDEA CE", + Version: "2023.4.99.12345.67", + BundleIdentifier: "com.jetbrains.intellij-EAP", + }, + }, } { t.Run(tc.name, func(t *testing.T) { sanitizeSoftware(tc.h, tc.s, log.NewNopLogger()) diff --git a/server/vulnerabilities/msrc/parsed/product.go b/server/vulnerabilities/msrc/parsed/product.go index 2da20eac86..09b9caea87 100644 --- a/server/vulnerabilities/msrc/parsed/product.go +++ b/server/vulnerabilities/msrc/parsed/product.go @@ -66,7 +66,53 @@ func (p Products) GetMatchForOS(ctx context.Context, os fleet.OperatingSystem) ( } func NewProductFromFullName(fullName string) Product { - return Product(fullName) + // If the full name includes a version, return it as-is. + p := Product(fullName) + if p.HasDisplayVersion() { + return p + } + + // Several Windows products listed in MSRC bulletins don't include the OS version number. + // We need this to match the product with a host's OS, so we'll add them here. + versionString := "" + switch { + case strings.Contains(fullName, "Windows Server 2022"): + versionString = "21H2" + + case strings.Contains(fullName, "Windows Server 2016"): + versionString = "1607" + + case strings.Contains(fullName, "Windows Server 2019"): + versionString = "1809" + + case strings.Contains(fullName, "Windows 8.1"): + versionString = "6.3 / NT 6.3" + + case strings.Contains(fullName, "Windows RT 8.1"): + versionString = "6.3 / NT 6.3" + + case strings.Contains(fullName, "Windows Server 2012 R2"): + versionString = "6.3 / NT 6.3" + + case strings.Contains(fullName, "Windows Server 2012"): + versionString = "6.2 / NT 6.2" + + case strings.Contains(fullName, "Windows Server 2008 R2"): + versionString = "6.1 / NT 6.1" + + case strings.Contains(fullName, "Windows 7"): + versionString = "6.1 / NT 6.1" + + case strings.Contains(fullName, "Windows Server 2008"): + versionString = "6.0 / NT 6.0" + } + + finalName := fullName + if versionString != "" { + finalName += (" Version " + versionString) + } + + return Product(finalName) } func NewProductFromOS(os fleet.OperatingSystem) Product { diff --git a/server/vulnerabilities/msrc/parsed/product_test.go b/server/vulnerabilities/msrc/parsed/product_test.go index 13f7a4db49..4164617b06 100644 --- a/server/vulnerabilities/msrc/parsed/product_test.go +++ b/server/vulnerabilities/msrc/parsed/product_test.go @@ -67,354 +67,424 @@ func TestMatches(t *testing.T) { func TestFullProductName(t *testing.T) { testCases := []struct { - fullName string - arch string - prodName string + fullName string + arch string + prodName string + finalName string }{ { - fullName: "Windows 10 Version 1809 for 32-bit Systems", - arch: "32-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1809 for 32-bit Systems", + arch: "32-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1809 for 32-bit Systems", }, { - fullName: "Windows 10 Version 1809 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1809 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1809 for x64-based Systems", }, { - fullName: "Windows 10 Version 1809 for ARM64-based Systems", - arch: "arm64", - prodName: "Windows 10", + fullName: "Windows 10 Version 1809 for ARM64-based Systems", + arch: "arm64", + prodName: "Windows 10", + finalName: "Windows 10 Version 1809 for ARM64-based Systems", }, { - fullName: "Windows Server 2019", - arch: "all", - prodName: "Windows Server 2019", + fullName: "Windows Server 2019", + arch: "all", + prodName: "Windows Server 2019", + finalName: "Windows Server 2019 Version 1809", }, { - fullName: "Windows Server 2019 (Server Core installation)", - arch: "all", - prodName: "Windows Server 2019", + fullName: "Windows Server 2019 (Server Core installation)", + arch: "all", + prodName: "Windows Server 2019", + finalName: "Windows Server 2019 (Server Core installation) Version 1809", }, { - fullName: "Windows 10 Version 1909 for 32-bit Systems", - arch: "32-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1909 for 32-bit Systems", + arch: "32-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1909 for 32-bit Systems", }, { - fullName: "Windows 10 Version 1909 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1909 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1909 for x64-based Systems", }, { - fullName: "Windows 10 Version 1909 for ARM64-based Systems", - arch: "arm64", - prodName: "Windows 10", + fullName: "Windows 10 Version 1909 for ARM64-based Systems", + arch: "arm64", + prodName: "Windows 10", + finalName: "Windows 10 Version 1909 for ARM64-based Systems", }, { - fullName: "Windows 10 Version 21H1 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 21H1 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 21H1 for x64-based Systems", }, { - fullName: "Windows 10 Version 21H1 for ARM64-based Systems", - arch: "arm64", - prodName: "Windows 10", + fullName: "Windows 10 Version 21H1 for ARM64-based Systems", + arch: "arm64", + prodName: "Windows 10", + finalName: "Windows 10 Version 21H1 for ARM64-based Systems", }, { - fullName: "Windows 10 Version 21H1 for 32-bit Systems", - arch: "32-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 21H1 for 32-bit Systems", + arch: "32-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 21H1 for 32-bit Systems", }, { - fullName: "Windows Server 2022", - arch: "all", - prodName: "Windows Server 2022", + fullName: "Windows Server 2022", + arch: "all", + prodName: "Windows Server 2022", + finalName: "Windows Server 2022 Version 21H2", }, { - fullName: "Windows Server 2022 (Server Core installation)", - arch: "all", - prodName: "Windows Server 2022", + fullName: "Windows Server 2022 (Server Core installation)", + arch: "all", + prodName: "Windows Server 2022", + finalName: "Windows Server 2022 (Server Core installation) Version 21H2", }, { - fullName: "Windows 10 Version 20H2 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 20H2 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 20H2 for x64-based Systems", }, { - fullName: "Windows 10 Version 20H2 for 32-bit Systems", - arch: "32-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 20H2 for 32-bit Systems", + arch: "32-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 20H2 for 32-bit Systems", }, { - fullName: "Windows 10 Version 20H2 for ARM64-based Systems", - arch: "arm64", - prodName: "Windows 10", + fullName: "Windows 10 Version 20H2 for ARM64-based Systems", + arch: "arm64", + prodName: "Windows 10", + finalName: "Windows 10 Version 20H2 for ARM64-based Systems", }, { - fullName: "Windows Server, version 20H2 (Server Core Installation)", - arch: "all", - prodName: "Windows Server", + fullName: "Windows Server, version 20H2 (Server Core Installation)", + arch: "all", + prodName: "Windows Server", + finalName: "Windows Server, version 20H2 (Server Core Installation)", }, { - fullName: "Windows 11 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 11", + fullName: "Windows 11 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 11", + finalName: "Windows 11 for x64-based Systems", }, { - fullName: "Windows 11 for ARM64-based Systems", - arch: "arm64", - prodName: "Windows 11", + fullName: "Windows 11 for ARM64-based Systems", + arch: "arm64", + prodName: "Windows 11", + finalName: "Windows 11 for ARM64-based Systems", }, { - fullName: "Windows 10 Version 21H2 for 32-bit Systems", - arch: "32-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 21H2 for 32-bit Systems", + arch: "32-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 21H2 for 32-bit Systems", }, { - fullName: "Windows 10 Version 21H2 for ARM64-based Systems", - arch: "arm64", - prodName: "Windows 10", + fullName: "Windows 10 Version 21H2 for ARM64-based Systems", + arch: "arm64", + prodName: "Windows 10", + finalName: "Windows 10 Version 21H2 for ARM64-based Systems", }, { - fullName: "Windows 10 Version 21H2 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 21H2 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 21H2 for x64-based Systems", }, { - fullName: "Windows 10 for 32-bit Systems", - arch: "32-bit", - prodName: "Windows 10", + fullName: "Windows 10 for 32-bit Systems", + arch: "32-bit", + prodName: "Windows 10", + finalName: "Windows 10 for 32-bit Systems", }, { - fullName: "Windows 10 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 for x64-based Systems", }, { - fullName: "Windows 10 Version 1607 for 32-bit Systems", - arch: "32-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1607 for 32-bit Systems", + arch: "32-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1607 for 32-bit Systems", }, { - fullName: "Windows 10 Version 1607 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1607 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1607 for x64-based Systems", }, { - fullName: "Windows Server 2016", - arch: "all", - prodName: "Windows Server 2016", + fullName: "Windows Server 2016", + arch: "all", + prodName: "Windows Server 2016", + finalName: "Windows Server 2016 Version 1607", }, { - fullName: "Windows Server 2016 (Server Core installation)", - arch: "all", - prodName: "Windows Server 2016", + fullName: "Windows Server 2016 (Server Core installation)", + arch: "all", + prodName: "Windows Server 2016", + finalName: "Windows Server 2016 (Server Core installation) Version 1607", }, { - fullName: "Windows 8.1 for 32-bit systems", - arch: "32-bit", - prodName: "Windows 8.1", + fullName: "Windows 8.1 for 32-bit systems", + arch: "32-bit", + prodName: "Windows 8.1", + finalName: "Windows 8.1 for 32-bit systems Version 6.3 / NT 6.3", }, { - fullName: "Windows 8.1 for x64-based systems", - arch: "64-bit", - prodName: "Windows 8.1", + fullName: "Windows 8.1 for x64-based systems", + arch: "64-bit", + prodName: "Windows 8.1", + finalName: "Windows 8.1 for x64-based systems Version 6.3 / NT 6.3", }, { - fullName: "Windows RT 8.1", - arch: "all", - prodName: "Windows RT 8.1", + fullName: "Windows RT 8.1", + arch: "all", + prodName: "Windows RT 8.1", + finalName: "Windows RT 8.1 Version 6.3 / NT 6.3", }, { - fullName: "Windows Server 2012", - arch: "all", - prodName: "Windows Server 2012", + fullName: "Windows Server 2012", + arch: "all", + prodName: "Windows Server 2012", + finalName: "Windows Server 2012 Version 6.2 / NT 6.2", }, { - fullName: "Windows Server 2012 (Server Core installation)", - arch: "all", - prodName: "Windows Server 2012", + fullName: "Windows Server 2012 (Server Core installation)", + arch: "all", + prodName: "Windows Server 2012", + finalName: "Windows Server 2012 (Server Core installation) Version 6.2 / NT 6.2", }, { - fullName: "Windows Server 2012 R2", - arch: "all", - prodName: "Windows Server 2012 R2", + fullName: "Windows Server 2012 R2", + arch: "all", + prodName: "Windows Server 2012 R2", + finalName: "Windows Server 2012 R2 Version 6.3 / NT 6.3", }, { - fullName: "Windows Server 2012 R2 (Server Core installation)", - arch: "all", - prodName: "Windows Server 2012 R2", + fullName: "Windows Server 2012 R2 (Server Core installation)", + arch: "all", + prodName: "Windows Server 2012 R2", + finalName: "Windows Server 2012 R2 (Server Core installation) Version 6.3 / NT 6.3", }, { - fullName: "Windows 7 for 32-bit Systems Service Pack 1", - arch: "32-bit", - prodName: "Windows 7", + fullName: "Windows 7 for 32-bit Systems Service Pack 1", + arch: "32-bit", + prodName: "Windows 7", + finalName: "Windows 7 for 32-bit Systems Service Pack 1 Version 6.1 / NT 6.1", }, { - fullName: "Windows 7 for x64-based Systems Service Pack 1", - arch: "64-bit", - prodName: "Windows 7", + fullName: "Windows 7 for x64-based Systems Service Pack 1", + arch: "64-bit", + prodName: "Windows 7", + finalName: "Windows 7 for x64-based Systems Service Pack 1 Version 6.1 / NT 6.1", }, { - fullName: "Windows Server 2008 for 32-bit Systems Service Pack 2", - arch: "32-bit", - prodName: "Windows Server 2008", + fullName: "Windows Server 2008 for 32-bit Systems Service Pack 2", + arch: "32-bit", + prodName: "Windows Server 2008", + finalName: "Windows Server 2008 for 32-bit Systems Service Pack 2 Version 6.0 / NT 6.0", }, { - fullName: "Windows Server 2008 for 32-bit Systems Service Pack 2 (Server Core installation)", - arch: "32-bit", - prodName: "Windows Server 2008", + fullName: "Windows Server 2008 for 32-bit Systems Service Pack 2 (Server Core installation)", + arch: "32-bit", + prodName: "Windows Server 2008", + finalName: "Windows Server 2008 for 32-bit Systems Service Pack 2 (Server Core installation) Version 6.0 / NT 6.0", }, { - fullName: "Windows Server 2008 for x64-based Systems Service Pack 2", - arch: "64-bit", - prodName: "Windows Server 2008", + fullName: "Windows Server 2008 for x64-based Systems Service Pack 2", + arch: "64-bit", + prodName: "Windows Server 2008", + finalName: "Windows Server 2008 for x64-based Systems Service Pack 2 Version 6.0 / NT 6.0", }, { - fullName: "Windows Server 2008 for x64-based Systems Service Pack 2 (Server Core installation)", - arch: "64-bit", - prodName: "Windows Server 2008", + fullName: "Windows Server 2008 for x64-based Systems Service Pack 2 (Server Core installation)", + arch: "64-bit", + prodName: "Windows Server 2008", + finalName: "Windows Server 2008 for x64-based Systems Service Pack 2 (Server Core installation) Version 6.0 / NT 6.0", }, { - fullName: "Windows Server 2008 R2 for x64-based Systems Service Pack 1", - arch: "64-bit", - prodName: "Windows Server 2008 R2", + fullName: "Windows Server 2008 R2 for x64-based Systems Service Pack 1", + arch: "64-bit", + prodName: "Windows Server 2008 R2", + finalName: "Windows Server 2008 R2 for x64-based Systems Service Pack 1 Version 6.1 / NT 6.1", }, { - fullName: "Windows Server 2008 R2 for x64-based Systems Service Pack 1 (Server Core installation)", - arch: "64-bit", - prodName: "Windows Server 2008 R2", + fullName: "Windows Server 2008 R2 for x64-based Systems Service Pack 1 (Server Core installation)", + arch: "64-bit", + prodName: "Windows Server 2008 R2", + finalName: "Windows Server 2008 R2 for x64-based Systems Service Pack 1 (Server Core installation) Version 6.1 / NT 6.1", }, { - fullName: "Windows 10 Version 1803 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1803 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1803 for x64-based Systems", }, { - fullName: "Windows Server, version 1803 (Server Core Installation)", - arch: "all", - prodName: "Windows Server", + fullName: "Windows Server, version 1803 (Server Core Installation)", + arch: "all", + prodName: "Windows Server", + finalName: "Windows Server, version 1803 (Server Core Installation)", }, { - fullName: "Windows 10 Version 1809 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1809 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1809 for x64-based Systems", }, { - fullName: "Windows Server 2019", - arch: "all", - prodName: "Windows Server 2019", + fullName: "Windows Server 2019", + arch: "all", + prodName: "Windows Server 2019", + finalName: "Windows Server 2019 Version 1809", }, { - fullName: "Windows Server 2019 (Server Core installation)", - arch: "all", - prodName: "Windows Server 2019", + fullName: "Windows Server 2019 (Server Core installation)", + arch: "all", + prodName: "Windows Server 2019", + finalName: "Windows Server 2019 (Server Core installation) Version 1809", }, { - fullName: "Windows 10 Version 1709 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1709 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1709 for x64-based Systems", }, { - fullName: "Windows 10 Version 1903 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1903 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1903 for x64-based Systems", }, { - fullName: "Windows Server, version 1903 (Server Core installation)", - arch: "all", - prodName: "Windows Server", + fullName: "Windows Server, version 1903 (Server Core installation)", + arch: "all", + prodName: "Windows Server", + finalName: "Windows Server, version 1903 (Server Core installation)", }, { - fullName: "Windows 10 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 for x64-based Systems", }, { - fullName: "Windows 10 Version 1607 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1607 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1607 for x64-based Systems", }, { - fullName: "Windows Server 2016", - arch: "all", - prodName: "Windows Server 2016", + fullName: "Windows Server 2016", + arch: "all", + prodName: "Windows Server 2016", + finalName: "Windows Server 2016 Version 1607", }, { - fullName: "Windows Server 2016 (Server Core installation)", - arch: "all", - prodName: "Windows Server 2016", + fullName: "Windows Server 2016 (Server Core installation)", + arch: "all", + prodName: "Windows Server 2016", + finalName: "Windows Server 2016 (Server Core installation) Version 1607", }, { - fullName: "Windows 8.1 for x64-based systems", - arch: "64-bit", - prodName: "Windows 8.1", + fullName: "Windows 8.1 for x64-based systems", + arch: "64-bit", + prodName: "Windows 8.1", + finalName: "Windows 8.1 for x64-based systems Version 6.3 / NT 6.3", }, { - fullName: "Windows Server 2012", - arch: "all", - prodName: "Windows Server 2012", + fullName: "Windows Server 2012", + arch: "all", + prodName: "Windows Server 2012", + finalName: "Windows Server 2012 Version 6.2 / NT 6.2", }, { - fullName: "Windows Server 2012 (Server Core installation)", - arch: "all", - prodName: "Windows Server 2012", + fullName: "Windows Server 2012 (Server Core installation)", + arch: "all", + prodName: "Windows Server 2012", + finalName: "Windows Server 2012 (Server Core installation) Version 6.2 / NT 6.2", }, { - fullName: "Windows Server 2012 R2", - arch: "all", - prodName: "Windows Server 2012 R2", + fullName: "Windows Server 2012 R2", + arch: "all", + prodName: "Windows Server 2012 R2", + finalName: "Windows Server 2012 R2 Version 6.3 / NT 6.3", }, { - fullName: "Windows Server 2012 R2 (Server Core installation)", - arch: "all", - prodName: "Windows Server 2012 R2", + fullName: "Windows Server 2012 R2 (Server Core installation)", + arch: "all", + prodName: "Windows Server 2012 R2", + finalName: "Windows Server 2012 R2 (Server Core installation) Version 6.3 / NT 6.3", }, { - fullName: "Windows 10 Version 1909 for x64-based Systems", - arch: "64-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1909 for x64-based Systems", + arch: "64-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1909 for x64-based Systems", }, { - fullName: "Windows Server, version 1909 (Server Core installation)", - arch: "all", - prodName: "Windows Server", + fullName: "Windows Server, version 1909 (Server Core installation)", + arch: "all", + prodName: "Windows Server", + finalName: "Windows Server, version 1909 (Server Core installation)", }, { - fullName: "Windows 10 Version 1803 for 32-bit Systems", - arch: "32-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1803 for 32-bit Systems", + arch: "32-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1803 for 32-bit Systems", }, { - fullName: "Windows 10 Version 1803 for ARM64-based Systems", - arch: "arm64", - prodName: "Windows 10", + fullName: "Windows 10 Version 1803 for ARM64-based Systems", + arch: "arm64", + prodName: "Windows 10", + finalName: "Windows 10 Version 1803 for ARM64-based Systems", }, { - fullName: "Windows 10 Version 1809 for 32-bit Systems", - arch: "32-bit", - prodName: "Windows 10", + fullName: "Windows 10 Version 1809 for 32-bit Systems", + arch: "32-bit", + prodName: "Windows 10", + finalName: "Windows 10 Version 1809 for 32-bit Systems", }, { - fullName: "None Available", - arch: "all", - prodName: "", + fullName: "None Available", + arch: "all", + prodName: "", + finalName: "None Available", }, { - fullName: "Windows Server 2008 for 32-bit Systems Service Pack 2 (Server Core installation)", - arch: "32-bit", - prodName: "Windows Server 2008", + fullName: "Windows Server 2008 for 32-bit Systems Service Pack 2 (Server Core installation)", + arch: "32-bit", + prodName: "Windows Server 2008", + finalName: "Windows Server 2008 for 32-bit Systems Service Pack 2 (Server Core installation) Version 6.0 / NT 6.0", }, { - fullName: "Windows Server 2008 for Itanium-Based Systems Service Pack 2", - arch: "itanium", - prodName: "Windows Server 2008", + fullName: "Windows Server 2008 for Itanium-Based Systems Service Pack 2", + arch: "itanium", + prodName: "Windows Server 2008", + finalName: "Windows Server 2008 for Itanium-Based Systems Service Pack 2 Version 6.0 / NT 6.0", }, { - fullName: "Windows Server 2008 R2 for Itanium-Based Systems Service Pack 1", - arch: "itanium", - prodName: "Windows Server 2008 R2", + fullName: "Windows Server 2008 R2 for Itanium-Based Systems Service Pack 1", + arch: "itanium", + prodName: "Windows Server 2008 R2", + finalName: "Windows Server 2008 R2 for Itanium-Based Systems Service Pack 1 Version 6.1 / NT 6.1", }, } @@ -429,6 +499,7 @@ func TestFullProductName(t *testing.T) { for _, tCase := range testCases { sut := NewProductFromFullName(tCase.fullName) require.Equal(t, tCase.prodName, sut.Name(), tCase) + require.Equal(t, tCase.finalName, string(sut), tCase) } }) } diff --git a/server/vulnerabilities/msrc/parsed/security_bulletin.go b/server/vulnerabilities/msrc/parsed/security_bulletin.go index de90cc7f0f..8a9c4a5271 100644 --- a/server/vulnerabilities/msrc/parsed/security_bulletin.go +++ b/server/vulnerabilities/msrc/parsed/security_bulletin.go @@ -3,9 +3,10 @@ package parsed import ( "encoding/json" "errors" + "os" + "github.com/fleetdm/fleet/v4/server/ptr" "golang.org/x/exp/slices" - "os" ) type SecurityBulletin struct { @@ -45,6 +46,9 @@ func UnmarshalBulletin(fPath string) (*SecurityBulletin, error) { if err != nil { return nil, err } + for pID, name := range bulletin.Products { + bulletin.Products[pID] = NewProductFromFullName(string(name)) + } return &bulletin, nil } diff --git a/server/vulnerabilities/msrc/parser_test.go b/server/vulnerabilities/msrc/parser_test.go index d93dac23fd..598d2c705e 100644 --- a/server/vulnerabilities/msrc/parser_test.go +++ b/server/vulnerabilities/msrc/parser_test.go @@ -39,7 +39,7 @@ func TestParser(t *testing.T) { f.Close() require.NoError(t, err) - // All the products we expect to see, grouped by their product name + // All the products we expect to see after marshaling, grouped by their product name. expectedProducts := map[string]parsed.Products{ "Windows 10": { "11568": parsed.NewProductFromFullName("Windows 10 Version 1809 for 32-bit Systems"), @@ -112,6 +112,79 @@ func TestParser(t *testing.T) { }, } + // All the products we expect to see in the parsed XML file, grouped by product name. + expectedXMLProducts := map[string]parsed.Products{ + "Windows 10": { + "11568": parsed.Product("Windows 10 Version 1809 for 32-bit Systems"), + "11569": parsed.Product("Windows 10 Version 1809 for x64-based Systems"), + "11570": parsed.Product("Windows 10 Version 1809 for ARM64-based Systems"), + "11712": parsed.Product("Windows 10 Version 1909 for 32-bit Systems"), + "11713": parsed.Product("Windows 10 Version 1909 for x64-based Systems"), + "11714": parsed.Product("Windows 10 Version 1909 for ARM64-based Systems"), + "11896": parsed.Product("Windows 10 Version 21H1 for x64-based Systems"), + "11897": parsed.Product("Windows 10 Version 21H1 for ARM64-based Systems"), + "11898": parsed.Product("Windows 10 Version 21H1 for 32-bit Systems"), + "11800": parsed.Product("Windows 10 Version 20H2 for x64-based Systems"), + "11801": parsed.Product("Windows 10 Version 20H2 for 32-bit Systems"), + "11802": parsed.Product("Windows 10 Version 20H2 for ARM64-based Systems"), + "11929": parsed.Product("Windows 10 Version 21H2 for 32-bit Systems"), + "11930": parsed.Product("Windows 10 Version 21H2 for ARM64-based Systems"), + "11931": parsed.Product("Windows 10 Version 21H2 for x64-based Systems"), + "10729": parsed.Product("Windows 10 for 32-bit Systems"), + "10735": parsed.Product("Windows 10 for x64-based Systems"), + "10852": parsed.Product("Windows 10 Version 1607 for 32-bit Systems"), + "10853": parsed.Product("Windows 10 Version 1607 for x64-based Systems"), + }, + "Windows Server 2019": { + "11571": parsed.Product("Windows Server 2019"), + "11572": parsed.Product("Windows Server 2019 (Server Core installation)"), + }, + "Windows Server 2022": { + "11923": parsed.Product("Windows Server 2022"), + "11924": parsed.Product("Windows Server 2022 (Server Core installation)"), + }, + "Windows Server": { + "11803": parsed.Product("Windows Server, version 20H2 (Server Core Installation)"), + }, + "Windows 11": { + "11926": parsed.Product("Windows 11 for x64-based Systems"), + "11927": parsed.Product("Windows 11 for ARM64-based Systems"), + }, + "Windows Server 2016": { + "10816": parsed.Product("Windows Server 2016"), + "10855": parsed.Product("Windows Server 2016 (Server Core installation)"), + }, + "Windows 8.1": { + "10481": parsed.Product("Windows 8.1 for 32-bit systems"), + "10482": parsed.Product("Windows 8.1 for x64-based systems"), + }, + "Windows RT 8.1": { + "10484": parsed.Product("Windows RT 8.1"), + }, + "Windows Server 2012": { + "10378": parsed.Product("Windows Server 2012"), + "10379": parsed.Product("Windows Server 2012 (Server Core installation)"), + }, + "Windows Server 2012 R2": { + "10483": parsed.Product("Windows Server 2012 R2"), + "10543": parsed.Product("Windows Server 2012 R2 (Server Core installation)"), + }, + "Windows 7": { + "10047": parsed.Product("Windows 7 for 32-bit Systems Service Pack 1"), + "10048": parsed.Product("Windows 7 for x64-based Systems Service Pack 1"), + }, + "Windows Server 2008": { + "9312": parsed.Product("Windows Server 2008 for 32-bit Systems Service Pack 2"), + "10287": parsed.Product("Windows Server 2008 for 32-bit Systems Service Pack 2 (Server Core installation)"), + "9318": parsed.Product("Windows Server 2008 for x64-based Systems Service Pack 2"), + "9344": parsed.Product("Windows Server 2008 for x64-based Systems Service Pack 2 (Server Core installation)"), + }, + "Windows Server 2008 R2": { + "10051": parsed.Product("Windows Server 2008 R2 for x64-based Systems Service Pack 1"), + "10049": parsed.Product("Windows Server 2008 R2 for x64-based Systems Service Pack 1 (Server Core installation)"), + }, + } + expectedCVEs := map[string][]string{ "Windows 10": { "CVE-2022-30190", @@ -1213,7 +1286,7 @@ func TestParser(t *testing.T) { t.Run("parseXML", func(t *testing.T) { t.Run("only windows products are included", func(t *testing.T) { var expected []msrcxml.Product - for _, grp := range expectedProducts { + for _, grp := range expectedXMLProducts { for pID, pFn := range grp { expected = append( expected, diff --git a/website/assets/images/permanent/mastodon-logo-50x40@2x.png b/website/assets/images/permanent/mastodon-logo-50x40@2x.png new file mode 100644 index 0000000000..5a0e6124fc Binary files /dev/null and b/website/assets/images/permanent/mastodon-logo-50x40@2x.png differ diff --git a/website/assets/styles/pages/testimonials.less b/website/assets/styles/pages/testimonials.less index 787c64738c..f825fed4ab 100644 --- a/website/assets/styles/pages/testimonials.less +++ b/website/assets/styles/pages/testimonials.less @@ -100,6 +100,34 @@ } } + [purpose='section-headline'] { + padding-top: 64px; + padding-bottom: 64px; + p { + margin-bottom: 0px; + } + } + [purpose='articles'] { + padding-bottom: 64px; + } + [purpose='article-link'] { + padding-top: 24px; + padding-bottom: 24px; + border-bottom: 1px solid var(--Fleet-Black-10, #E2E4EA); + [parasails-component='animated-arrow-button'] { + width: fit-content; + display: flex; + align-items: center; + padding: 0; + text-decoration: none; + font-weight: 700; + [purpose='button-text'] { + width: 100%; + } + } + } + + [purpose='testimonials-container'] { columns: 3; margin-bottom: 32px; @@ -427,6 +455,16 @@ height: 304px; } } + [purpose='section-headline'] { + padding-top: 32px; + padding-bottom: 32px; + p { + margin-bottom: 0px; + } + } + [purpose='articles'] { + padding-bottom: 48px; + } [purpose='statistics'] { [purpose='statistics-column'] { display: flex; diff --git a/website/views/pages/testimonials.ejs b/website/views/pages/testimonials.ejs index 5fd1f40323..d4dd1c7153 100644 --- a/website/views/pages/testimonials.ejs +++ b/website/views/pages/testimonials.ejs @@ -112,6 +112,32 @@
+
+

Case strudies

+

Real-world stories of why the community and customers love Fleet.

+
+
+
+
+ 🥀 Leading financial company consolidates multiple tools with Fleet +
+
+ 🪟 Global edge cloud platform simplifies device management with Fleet +
+
+ 🚪 Worldwide security and authentication platform chooses Fleet for Linux management +
+
+ 🔌 Large gaming company enhances server observability with Fleet +
+
+ 🚪 Vehicle manufacturer transitions to Fleet for endpoint security +
+
+ 🚪 Foursquare quickly migrates to Fleet for Device Management +
+
+
Share your story