diff --git a/.github/ISSUE_TEMPLATE/digital-experience-request.md b/.github/ISSUE_TEMPLATE/digital-experience-request.md
deleted file mode 100644
index 97b697ec8037..000000000000
--- a/.github/ISSUE_TEMPLATE/digital-experience-request.md
+++ /dev/null
@@ -1,28 +0,0 @@
----
-name: 🌐 Digital Experience request [FKA Website request]
-about: Propose a new feature or enhancement to fleetdm.com.
-title: 'TODO: '
-labels: '#g-digital-experience'
-assignees: ''
-
----
-
-## Goal
-
-| User story |
-|:---------------------------------------------------------------------------|
-| As a _________________________________________,
-| I want to _________________________________________
-| so that I can _________________________________________.
-
->For help creating a user story, see ["Writing a good user story"](https://fleetdm.com/handbook/company/development-groups#writing-a-good-user-story) in the website handbook.
-
-
-## How?
-
-- [ ] TODO
-
-### Context
-
-
-
diff --git a/.github/workflows/test-db-changes.yml b/.github/workflows/test-db-changes.yml
index 2bd89ab82b1e..10d1ec4ddea2 100644
--- a/.github/workflows/test-db-changes.yml
+++ b/.github/workflows/test-db-changes.yml
@@ -40,33 +40,6 @@ jobs:
with:
fetch-depth: 0
- - name: Install Go
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
- with:
- go-version-file: 'go.mod'
-
- - name: Start Infra Dependencies
- # Use & to background this
- run: docker compose up -d mysql_test &
-
- - name: Wait for mysql
- run: |
- echo "waiting for mysql..."
- until docker compose exec -T mysql_test sh -c "mysql -uroot -p\"\${MYSQL_ROOT_PASSWORD}\" -e \"SELECT 1=1\" fleet" &> /dev/null; do
- echo "."
- sleep 1
- done
- echo "mysql is ready"
-
- - name: Verify test schema changes
- run: |
- make dump-test-schema
- if [[ $(git diff server/datastore/mysql/schema.sql) ]]; then
- echo "❌ fail: uncommited changes in schema.sql"
- echo "please run `make dump-test-schema` and commit the changes"
- exit 1
- fi
-
# TODO: This doesn't cover all scenarios since other PRs might
# be merged into `main` after this check has passed.
#
@@ -84,8 +57,8 @@ jobs:
base_ref=$(git tag --list "fleet-v*" --sort=-creatordate | head -n 1)
fi
- all_migrations=($(ls server/datastore/mysql/migrations/tables/20*_*.go | sort -r))
- new_migrations=($(git diff --find-renames --name-only --diff-filter=A $base_ref -- server/datastore/mysql/migrations/tables/20\*_\*.go | sort -r))
+ all_migrations=($(ls server/datastore/mysql/migrations/tables/20*_*.go | sort -r | grep -v '_test.go'))
+ new_migrations=($(git diff --find-renames --name-only --diff-filter=A $base_ref -- server/datastore/mysql/migrations/tables/20\*_\*.go ':(exclude,glob)server/datastore/mysql/migrations/tables/20*_*_test.go' | sort -r))
index=0
for migration in "${new_migrations[@]}"; do
@@ -110,3 +83,31 @@ jobs:
echo "Ref: https://github.com/fleetdm/fleet/blob/main/handbook/engineering/scaling-fleet.md#foreign-keys-and-locking"
exit 1
fi
+
+
+ - name: Install Go
+ uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
+ with:
+ go-version-file: 'go.mod'
+
+ - name: Start Infra Dependencies
+ # Use & to background this
+ run: docker compose up -d mysql_test &
+
+ - name: Wait for mysql
+ run: |
+ echo "waiting for mysql..."
+ until docker compose exec -T mysql_test sh -c "mysql -uroot -p\"\${MYSQL_ROOT_PASSWORD}\" -e \"SELECT 1=1\" fleet" &> /dev/null; do
+ echo "."
+ sleep 1
+ done
+ echo "mysql is ready"
+
+ - name: Verify test schema changes
+ run: |
+ make dump-test-schema
+ if [[ $(git diff server/datastore/mysql/schema.sql) ]]; then
+ echo "❌ fail: uncommited changes in schema.sql"
+ echo "please run `make dump-test-schema` and commit the changes"
+ exit 1
+ fi
\ No newline at end of file
diff --git a/CODEOWNERS b/CODEOWNERS
index 153161e7ee82..ab336be41f69 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -41,7 +41,7 @@ go.mod @fleetdm/go
/cmd/ @fleetdm/go
/server/ @fleetdm/go
/ee/server/ @fleetdm/go
-/orbit/ @lucasmrod @roperzh @lukeheath @georgekarrv @sharon-fdm
+/orbit/ @fleetdm/go
##############################################################################################
# 🚀 React files and other files related to the core product frontend.
diff --git a/articles/automatic-software-install-in-fleet.md b/articles/automatic-software-install-in-fleet.md
new file mode 100644
index 000000000000..2dd0c5db0e6c
--- /dev/null
+++ b/articles/automatic-software-install-in-fleet.md
@@ -0,0 +1,79 @@
+# Automatic policy-based installation of software on hosts
+
+![Top Image](../website/assets/images/articles/automatic-software-install-top-image.png)
+
+Fleet [v4.57.0](https://github.com/fleetdm/fleet/releases/tag/fleet-v4.57.0) introduces the ability to automatically and remotely install software on hosts based on predefined policy failures. This guide will walk you through the process of configuring fleet for automatic installation of software on hosts using uploaded installation images and based on programmed policies. You'll learn how to configure and use this feature, as well as understand how the underlying mechanism works.
+
+Fleet allows its users to upload trusted software installation files to be installed and used on hosts. This installation could be conditioned on a failure of a specific Fleet Policy.
+
+## Prerequisites
+
+* Fleet premium with Admin permissions.
+* Fleet [v4.57.0](https://github.com/fleetdm/fleet/releases/tag/fleet-v4.57.0) or greater.
+
+## Step-by-step instructions
+
+1. **Adding software**: Add any software to be available for installation. Follow the [deploying software](https://fleetdm.com/guides/deploy-security-agents) document with instructions how to do it. Note that all installation steps (pre-install query, install script, and post-install script) will be executed as configured, regardless of the policy that triggers the installation.
+
+
+![Add software](../website/assets/images/articles/automatic-software-install-add-software.png)
+
+Current supported software deployment formats:
+- macOS: .pkg
+- Windows: .msi, .exe
+- Linux: .deb
+
+Coming soon:
+- VPP for iOS and iPadOS
+
+2. **Add a policy**: In Fleet, add a policy that failure to pass will trigger the required installation. Go to Policies tab --> Press the top right "Add policy" button. --> Click "create your own policy" --> Enter your policy SQL --> Save --> Fill in details in the Save modal and Save.
+
+```
+SELECT 1 FROM apps WHERE name = 'Adobe Acrobat Reader.app' AND version_compare(bundle_short_version, '23.001.20687') >= 0;
+```
+
+Note: In order to know the exact application name to put in the query (e.g. "Adobe Acrobat Reader.app" in the query above) you can manually install it on a canary/test host and then query SELECT * from apps;
+
+
+3. **Manage automation**: Open Manage Automations: Policies Tab --> top right "Manage automations" --> "Install software".
+
+![Manage policies](../website/assets/images/articles/automatic-software-install-policies-manage.png)
+
+4. **Select policy**: Select (click the check box of) your newly created policy. To the right of it select from the
+ drop-down list the software you would like to be installed upon failure of this policy.
+
+![Install software modal](../website/assets/images/articles/automatic-software-install-install-software.png)
+
+Upon failure of the selected policy, the selected software installation will be triggered.
+
+## How does it work?
+
+* After configuring Fleet to auto-install a specific software the rest will be done automatically.
+* The policy check mechanism runs on a typical 1 hour cadence on all online hosts.
+* Fleet will send install requests to the hosts on the first policy failure (first "No" result for the host) or if a policy goes from "Yes" to "No". On this iteration it will not send a install request if a policy is already failing and continues to fail ("No" -> "No"). See the following flowchart for details.
+
+![Flowchart](../website/assets/images/articles/automatic-software-install-workflow.png)
+*Detailed flowchart*
+
+## Using the REST API for self-service software packages
+
+Fleet provides a REST API for managing software packages, including self-service software packages. Learn more about Fleet's [REST API](https://fleetdm.com/docs/rest-api/rest-api#add-team-policy).
+
+## Managing self-service software packages with GitOps
+
+To manage self-service software packages using Fleet's best practice GitOps, check out the `software` key in the [GitOps reference documentation](https://fleetdm.com/docs/configuration/yaml-files#policies).
+
+## Conclusion
+
+Software deployment can be time-consuming and risky. This guide presents Fleet's ability to mass deploy software to your fleet in a simple and safe way. Starting with uploading a trusted installer and ending with deploying it to the proper set of machines answering the exact policy defined by you.
+
+Leveraging Fleet’s ability to install and upgrade software on your hosts, you can streamline the process of controlling your hosts, replacing old versions of software and having the up-to-date info on what's installed on your fleet.
+
+By automating software deployment, you can gain greater control over what's installed on your machines and have better oversight of version upgrades, ensuring old software with known issues is replaced.
+
+
+
+
+
+
+
diff --git a/articles/deploy-software-packages.md b/articles/deploy-software-packages.md
index 92aa0901ccf1..41a26632f101 100644
--- a/articles/deploy-software-packages.md
+++ b/articles/deploy-software-packages.md
@@ -14,7 +14,7 @@ Fleet [v4.50.0](https://github.com/fleetdm/fleet/releases/tag/fleet-v4.50.0) int
* An S3 bucket [configured](https://fleetdm.com/docs/configuration/fleet-server-configuration#s-3-software-installers-bucket) to store the installers.
-* Increase any load balancer timeouts to at least 5 minutes for the [Add software](https://fleetdm.com/docs/rest-api/rest-api#add-software) endpoint.
+* Increase any load balancer timeouts to at least 5 minutes for the [Add package](https://fleetdm.com/docs/rest-api/rest-api#add-package) and [Modify package](https://fleetdm.com/docs/rest-api/rest-api#modify-package) endpoints.
## Step-by-step instructions
diff --git a/articles/enroll-hosts.md b/articles/enroll-hosts.md
index 0635855596ab..f15f44236b29 100644
--- a/articles/enroll-hosts.md
+++ b/articles/enroll-hosts.md
@@ -320,7 +320,7 @@ Fleetd will send stdout/stderr logs to the following directories:
- macOS: `/private/var/log/orbit/orbit.std{out|err}.log`.
- Windows: `C:\Windows\system32\config\systemprofile\AppData\Local\FleetDM\Orbit\Logs\orbit-osquery.log` (the log file is rotated).
- - Linux: Orbit and osqueryd stdout/stderr output is sent to syslog (`/var/log/syslog` on Debian systems and `/var/log/messages` on CentOS).
+ - Linux: Orbit and osqueryd stdout/stderr output is sent to syslog (`/var/log/syslog` on Debian systems, `/var/log/messages` on CentOS, and `journalctl -u orbit` on Fedora).
If the `logger_path` agent configuration is set to `filesystem`, fleetd will send osquery's "result" and "status" logs to the following directories:
- Windows: C:\Program Files\Orbit\osquery_log
diff --git a/articles/exe-install-scripts.md b/articles/exe-install-scripts.md
new file mode 100644
index 000000000000..3ed2f437191b
--- /dev/null
+++ b/articles/exe-install-scripts.md
@@ -0,0 +1,334 @@
+# Windows EXE install scripts
+
+## What are EXE install scripts?
+
+EXE install scripts are a way to install software on Windows. EXE installers, such as `Figma-124.3.2.exe`, are self-contained packages with all the files and instructions needed to install software on a Windows device. EXE installers are fully customizable and do not follow the same installation process as MSI installers.
+
+For EXE installers, there is no unique script or command that will work for all installers. MSI installers are typically preferred over EXE installers because they provide a standardized installation process, easier silent deployment, and better integration with Windows Installer Service. If available, MSI installers offer more predictable results in enterprise environments.
+
+Some EXE installers and uninstallers require additional switches or flags to run silently. Common flags include `/S`, `/q`, `/quiet`, `/silent`, or `--silent`.
+
+## Device-scoped install scripts
+
+The recommended way to install software on Windows devices is to use device-scoped install scripts. These scripts install the software for all users on the device and run the installation process with administrator privileges.
+
+Fleet defaults to a device-scoped install script when you add software using an EXE installer.
+
+## User-scoped install scripts
+
+Some software can only be installed for a specific user. In this case, you can use user-scoped install scripts. The software is installed only for the user currently logged in, and the installation process is run with the user's privileges.
+
+### Example user-scoped install script
+
+The install script creates a scheduled task that will automatically be run as the current (logged-in) user. The EXE installer is copied to a public directory accessible by the user, ensuring that even non-administrator users can run the scheduled task to complete the installation. After the task finishes, the installer and the task are deleted.
+
+The use of scheduled tasks allows the installer to run with user-level permissions, which is especially useful when installing software for non-admin users without requiring administrator credentials at the time of execution.
+
+Since the installation is run by the current user, the script does not output the installer's messages to the console. If you need to see the output, you can modify the script to redirect it to a file and append it to the script output.
+
+```powershell
+# Some installers require a flag to run silently.
+# Each installer might use a different argument (usually it's "/S" or "/s")
+$installArgs = "/S"
+
+$exeFilePath = "${env:INSTALLER_PATH}"
+
+$exitCode = 0
+
+try {
+
+# Copy the installer to a public folder so that all can access it
+# users
+$exeFilename = Split-Path $exeFilePath -leaf
+Copy-Item -Path $exeFilePath -Destination "${env:PUBLIC}" -Force
+$exeFilePath = "${env:PUBLIC}\$exeFilename"
+
+# Task properties. The task will be started by the logged in user
+$action = New-ScheduledTaskAction -Execute "$exeFilePath" `
+ -Argument "$installArgs"
+$trigger = New-ScheduledTaskTrigger -AtLogOn
+$userName = Get-CimInstance -ClassName Win32_ComputerSystem |
+ Select-Object -expand UserName
+$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries
+
+# Create a task object with the properties defined above
+$task = New-ScheduledTask -Action $action -Trigger $trigger `
+ -Settings $settings
+
+# Register the task
+$taskName = "fleet-install-$exeFilename"
+Register-ScheduledTask "$taskName" -InputObject $task -User "$userName"
+
+# keep track of the start time to cancel if taking too long to start
+$startDate = Get-Date
+
+# Start the task now that it is ready
+Start-ScheduledTask -TaskName "$taskName" -TaskPath "\"
+
+# Wait for the task to be running
+$state = (Get-ScheduledTask -TaskName "$taskName").State
+Write-Host "ScheduledTask is '$state'"
+
+while ($state -ne "Running") {
+ Write-Host "ScheduledTask is '$state'. Waiting to run .exe..."
+
+ $endDate = Get-Date
+ $elapsedTime = New-Timespan -Start $startDate -End $endDate
+ if ($elapsedTime.TotalSeconds -gt 120) {
+ Throw "Timed-out waiting for scheduled task state."
+ }
+
+ Start-Sleep -Seconds 1
+ $state = (Get-ScheduledTask -TaskName "$taskName").State
+}
+
+# Wait for the task to be done
+$state = (Get-ScheduledTask -TaskName "$taskName").State
+while ($state -eq "Running") {
+ Write-Host "ScheduledTask is '$state'. Waiting for .exe to complete..."
+
+ $endDate = Get-Date
+ $elapsedTime = New-Timespan -Start $startDate -End $endDate
+ if ($elapsedTime.TotalSeconds -gt 120) {
+ Throw "Timed-out waiting for scheduled task state."
+ }
+
+ Start-Sleep -Seconds 10
+ $state = (Get-ScheduledTask -TaskName "$taskName").State
+}
+
+# Remove task
+Write-Host "Removing ScheduledTask: $taskName."
+Unregister-ScheduledTask -TaskName "$taskName" -Confirm:$false
+
+} catch {
+ Write-Host "Error: $_"
+ $exitCode = 1
+} finally {
+ # Remove installer
+ Remove-Item -Path $exeFilePath -Force
+}
+
+Exit $exitCode
+```
+
+### Example user-scoped uninstall script
+
+The uninstall script creates a scheduled task that will automatically be run as the current (logged-in) user. The uninstaller creates a separate PowerShell script for the user. After the task finishes, the script and the task are deleted.
+
+Since the uninstall script is run by the current user, it does not output its messages to the console. If you need to see the output, you can modify the main script to redirect it to a file and append it to the output.
+
+```powershell
+# Fleet extracts the name from the installer (EXE) and saves it to PACKAGE_ID
+# variable
+$softwareName = $PACKAGE_ID
+
+# Script to uninstall software as the current logged-in user.
+$userScript = @'
+$softwareName = $PACKAGE_ID
+
+# Using the exact software name here is recommended to avoid
+# uninstalling unintended software.
+$softwareNameLike = "*$softwareName*"
+
+# Some uninstallers require additional flags to run silently.
+# Each uninstaller might use a different argument (usually it's "/S" or "/s")
+$uninstallArgs = "/S"
+
+$uninstallCommand = ""
+$exitCode = 0
+
+try {
+
+$userKey = `
+ 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
+[array]$uninstallKeys = Get-ChildItem `
+ -Path @($userKey) `
+ -ErrorAction SilentlyContinue |
+ ForEach-Object { Get-ItemProperty $_.PSPath }
+
+$foundUninstaller = $false
+foreach ($key in $uninstallKeys) {
+ # If needed, add -notlike to the comparison to exclude certain similar
+ # software
+ if ($key.DisplayName -like $softwareNameLike) {
+ $foundUninstaller = $true
+ # Get the uninstall command. Some uninstallers do not include
+ # 'QuietUninstallString' and require a flag to run silently.
+ $uninstallCommand = if ($key.QuietUninstallString) {
+ $key.QuietUninstallString
+ } else {
+ $key.UninstallString
+ }
+
+ # The uninstall command may contain command and args, like:
+ # "C:\Program Files\Software\uninstall.exe" --uninstall --silent
+ # Split the command and args
+ $splitArgs = $uninstallCommand.Split('"')
+ if ($splitArgs.Length -gt 1) {
+ if ($splitArgs.Length -eq 3) {
+ $uninstallArgs = "$( $splitArgs[2] ) $uninstallArgs".Trim()
+ } elseif ($splitArgs.Length -gt 3) {
+ Throw `
+ "Uninstall command contains multiple quoted strings. " +
+ "Please update the uninstall script.`n" +
+ "Uninstall command: $uninstallCommand"
+ }
+ $uninstallCommand = $splitArgs[1]
+ }
+ Write-Host "Uninstall command: $uninstallCommand"
+ Write-Host "Uninstall args: $uninstallArgs"
+
+ $processOptions = @{
+ FilePath = $uninstallCommand
+ PassThru = $true
+ Wait = $true
+ }
+ if ($uninstallArgs -ne '') {
+ $processOptions.ArgumentList = "$uninstallArgs"
+ }
+
+ # Start the process and track the exit code
+ $process = Start-Process @processOptions
+ $exitCode = $process.ExitCode
+
+ # Prints the exit code
+ Write-Host "Uninstall exit code: $exitCode"
+ # Exit the loop once the software is found and uninstalled.
+ break
+ }
+}
+
+if (-not $foundUninstaller) {
+ Write-Host "Uninstaller for '$softwareName' not found."
+ $exitCode = 1
+}
+
+} catch {
+ Write-Host "Error: $_"
+ $exitCode = 1
+}
+
+Exit $exitCode
+'@
+
+$exitCode = 0
+
+# Create a script in a public folder so that it can be accessed by all users.
+$uninstallScriptPath = "${env:PUBLIC}/uninstall-$softwareName.ps1"
+$taskName = "fleet-uninstall-$softwareName"
+try {
+ Set-Content -Path $uninstallScriptPath -Value $userScript -Force
+
+ # Task properties. The task will be started by the logged in user
+ $action = New-ScheduledTaskAction -Execute "PowerShell.exe" `
+ -Argument "$uninstallScriptPath"
+ $trigger = New-ScheduledTaskTrigger -AtLogOn
+ $userName = Get-CimInstance -ClassName Win32_ComputerSystem |
+ Select-Object -expand UserName
+ $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries
+
+ # Create a task object with the properties defined above
+ $task = New-ScheduledTask -Action $action -Trigger $trigger `
+ -Settings $settings
+
+ # Register the task
+ Register-ScheduledTask "$taskName" -InputObject $task -User "$userName"
+
+ # keep track of the start time to cancel if taking too long to start
+ $startDate = Get-Date
+
+ # Start the task now that it is ready
+ Start-ScheduledTask -TaskName "$taskName" -TaskPath "\"
+
+ # Wait for the task to be running
+ $state = (Get-ScheduledTask -TaskName "$taskName").State
+ Write-Host "ScheduledTask is '$state'"
+
+ while ($state -ne "Running") {
+ Write-Host "ScheduledTask is '$state'. Waiting to uninstall..."
+
+ $endDate = Get-Date
+ $elapsedTime = New-Timespan -Start $startDate -End $endDate
+ if ($elapsedTime.TotalSeconds -gt 120) {
+ Throw "Timed-out waiting for scheduled task state."
+ }
+
+ Start-Sleep -Seconds 1
+ $state = (Get-ScheduledTask -TaskName "$taskName").State
+ }
+
+ # Wait for the task to be done
+ $state = (Get-ScheduledTask -TaskName "$taskName").State
+ while ($state -eq "Running") {
+ Write-Host "ScheduledTask is '$state'. Waiting for .exe to complete..."
+
+ $endDate = Get-Date
+ $elapsedTime = New-Timespan -Start $startDate -End $endDate
+ if ($elapsedTime.TotalSeconds -gt 120) {
+ Throw "Timed-out waiting for scheduled task state."
+ }
+
+ Start-Sleep -Seconds 10
+ $state = (Get-ScheduledTask -TaskName "$taskName").State
+ }
+
+} catch {
+ Write-Host "Error: $_"
+ $exitCode = 1
+} finally {
+ # Remove task
+ Write-Host "Removing ScheduledTask: $taskName."
+ Unregister-ScheduledTask -TaskName "$taskName" -Confirm:$false
+
+ # Remove user script
+ Remove-Item -Path $uninstallScriptPath -Force
+}
+
+Exit $exitCode
+```
+
+## Install script for raw executables
+
+Raw executables without installers are less common but may be used in specific scenarios, such as when a vendor provides a standalone binary file for a lightweight application. In these cases, ensuring all necessary dependencies are in place is important. Additionally, consider cleaning up the source executable after installation to avoid leaving unnecessary files on the system. If you have a raw executable that does not come with an installer, you can use the following script to install it. This script copies the executable to Program Files, which are accessible by all users.
+
+```powershell
+$exeFilePath = "${env:INSTALLER_PATH}"
+
+try {
+
+# extract the name of the executable to use as the sub-directory name
+$exeName = [System.IO.Path]::GetFileName($exeFilePath)
+$subDir = [System.IO.Path]::GetFileNameWithoutExtension($exeFilePath)
+
+$destinationPath = Join-Path -Path $env:ProgramFiles -ChildPath $subDir
+
+# check if the directory does not exist, and create it if necessary
+if (-not (Test-Path -Path $destinationPath)) {
+ New-Item -ItemType Directory -Path $destinationPath
+}
+
+# copy the .exe file to the new sub-directory
+$destinationExePath = Join-Path -Path $destinationPath -ChildPath $exeName
+Copy-Item -Path $exeFilePath -Destination $destinationExePath
+Exit $LASTEXITCODE
+
+} catch {
+ Write-Host "Error: $_"
+ Exit 1
+}
+```
+## Conclusion
+
+EXE install scripts provide a flexible solution for installing software on Windows devices when MSI installers are unavailable. By leveraging the power of PowerShell and scheduled tasks, IT administrators can easily automate both device-scoped and user-scoped installations. Whether you're deploying software for all users on a device or targeting a specific logged-in user, the provided scripts offer a robust starting point for handling EXE installations.
+
+Always verify the EXE installer's specific flags for silent installation for smoother operations, ensure proper permissions are in place, and consider implementing logging for troubleshooting. While MSI installers are generally preferred for their standardized behavior, these scripts allow you to manage even the most customized EXE installs in enterprise environments.
+
+Following this guide will enable you to manage software deployments using EXE install scripts, improving efficiency and ensuring a seamless installation experience across your Windows devices.
+
+
+
+
+
+
+
diff --git a/articles/fleet-now-supports-ios-and-ipados-software-deployment-and-automated-patch-management.md b/articles/fleet-now-supports-ios-and-ipados-software-deployment-and-automated-patch-management.md
new file mode 100644
index 000000000000..4280852e116c
--- /dev/null
+++ b/articles/fleet-now-supports-ios-and-ipados-software-deployment-and-automated-patch-management.md
@@ -0,0 +1,71 @@
+# Fleet now supports iOS and iPadOS, software deployment, and automated patch management
+
+Managing security, control, and flexibility across diverse devices can be challenging, especially when proprietary systems hold you back. That’s why we’re thrilled to announce that Fleet now supports iOS and iPadOS devices and enhanced patch management features to give your team more control and scalability than ever.
+
+**What does this mean for you?** Now, your team can manage iPhones, iPads, macOS, Windows, and Linux devices from a single platform. This latest release is designed to simplify mobile device management (MDM) while giving your team the control and flexibility they need to scale effectively.
+
+**Highlights**:
+
+* iPhone/iPad BYOD
+* Self-service VPP apps
+* Multiple ABM and VPP support
+* Automatic installation of software on hosts
+
+### Enrolling BYOD iPad/iOS devices in Fleet
+
+[Enrolling BYOD iPhones and iPads in Fleet](https://fleetdm.com/guides/enroll-byod-ios-ipados-hosts) allows IT admins to manage software installations, enforce settings, and ensure devices comply with company policies—all without compromising user autonomy. This helps secure access to organizational resources while maintaining control over device configurations.
+
+![Fleet enrollment profile on an iPhone](../website/assets/images/articles/fleet-now-supports-ios-and-ipados-software-deployment-and-automated-patch-management-2-2000x1000@2x.png "Fleet enrollment profile on an iPhone.")
+
+*Fleet enrollment profile on an iPhone.*
+
+### Self-service Apple App Store apps
+
+Fleet enables organizations to assign and install Apple App Store apps purchased through the Volume Purchase Program (VPP) directly via Self-Service using Fleet Desktop. This feature lets IT administrators [make VPP-purchased apps available to end users](https://fleetdm.com/guides/install-vpp-apps-on-macos-using-fleet).
+
+By integrating VPP app distribution into the Fleet Desktop Self-Service portal, organizations can streamline the deployment of essential software across their macOS devices. This ensures that users have easy access to the tools they need while maintaining control over software distribution. This update enhances the overall user experience and operational efficiency, empowering end users to install approved applications with minimal IT intervention.
+
+### Multiple Apple Business Manager and VPP support
+
+Alongside initial Volume Purchase Program (VPP) support, now you can add and manage multiple Apple Business Manager (ABM) and VPP tokens within a single Fleet instance. This feature is designed for both Managed Service Providers (MSPs) and large enterprises. Whether an MSP or an enterprise with multiple divisions, admins can set up separate workflows to automatically enroll devices and distribute apps through the App Store. This update simplifies the process of handling macOS, iOS, and iPadOS devices, providing a scalable solution for both MSPs and enterprises looking to centralize control while maintaining flexibility for different user groups.
+
+![Add software modal](../website/assets/images/articles/fleet-now-supports-ios-and-ipados-software-deployment-and-automated-patch-management-1-2000x1000@2x.png "Add software modal.")
+*Add software modal.*
+
+### Automatic installation of software on hosts
+
+Fleet [v4.50.0](https://github.com/fleetdm/fleet/releases/tag/fleet-v4.50.0) introduced software deployment capabilities for your hosts. With the recent [v4.57.0](https://fleetdm.com/releases/fleet-4.57.0) update, admins can automatically install software when a policy fails. This proactive approach helps maintain compliance and security without manual intervention.
+
+This feature is handy when a device is found to have a vulnerable or outdated version of software installed. When a policy detects this, Fleet can automatically install a secure, updated version of the software to remediate the issue and bring the host back into compliance. This automation helps IT teams address vulnerabilities quickly and efficiently.
+
+**Current supported software deployment formats:**
+
+* macOS: .pkg
+* Windows: .msi, .exe
+* Linux: .deb
+
+**Learn more about automatic software installation:** [https://fleetdm.com/guides/automatic-software-install-in-fleet](https://fleetdm.com/guides/automatic-software-install-in-fleet)
+
+
+### A smoother path for MDM migrations
+
+Switching MDM platforms has often been seen as a daunting task. Fleet makes the process of migrating easier and more efficient than ever before. With support for iOS and iPadOS, your team can seamlessly manage all your organization’s devices with a single tool that integrates with your existing GitHub repo and workflow.
+
+By embracing open-source flexibility and cross-platform support, Fleet empowers teams to manage their devices in a way that suits their organization’s unique needs.
+
+For more information on migrating to Fleet, check out: [https://fleetdm.com/guides/mdm-migration](https://fleetdm.com/guides/mdm-migration)
+
+### The future of device management is here
+
+With our newly added support for iOS, iPadOS, and patch management tools, you can finally consolidate your device management across multiple platforms, streamlining your processes and reducing tool bloat.
+
+As Mike McNeil, Fleet’s CEO, says: *“Our vision is to empower teams to manage their devices their way—without being locked into proprietary tools or vendor restrictions.”* With Fleet’s open-source approach, IT teams can take back control and build a future that fits their needs.
+
+To learn more about how Fleet can support your organization, visit [fleetdm.com/mdm](https://fleetdm.com/mdm).
+
+
+
+
+
+
+
diff --git a/articles/fleet-supports-macos-15-sequoia-ios-18-and-ipados-18.md b/articles/fleet-supports-macos-15-sequoia-ios-18-and-ipados-18.md
new file mode 100644
index 000000000000..afde4d97339e
--- /dev/null
+++ b/articles/fleet-supports-macos-15-sequoia-ios-18-and-ipados-18.md
@@ -0,0 +1,29 @@
+# Fleet supports Apple’s latest operating systems: macOS 15 Sequoia, iOS 18, and iPadOS 18
+
+![Fleet supports Apple’s latest operating systems: macOS 15 Sequoia, iOS 18, and iPadOS 18](../website/assets/images/articles/fleet-supports-macos-15-sequoia-ios-18-and-ipados-18-1600x900@2x.jpg)
+
+_Photo by [aditya bhatia](https://www.pexels.com/photo/people-walking-on-a-bridge-between-trees-13809734/)_
+
+Fleet is pleased to announce full support for Apple’s newest operating systems, including macOS 15 Sequoia, iOS 18, and iPadOS 18. With these updates, Fleet ensures seamless management and security capabilities for organizations adopting the latest Apple technology across their device fleet. This release enables IT administrators to confidently manage devices running these new operating systems, leveraging Fleet's robust tools for device monitoring, policy enforcement, and configuration management.
+
+## Noteworthy changes and known issues for macOS 15 Sequoia
+
+macOS 15 Sequoia brings significant changes that may impact device management workflows. Notably, firewall settings are no longer contained in a `.plist` file, resulting in potential reporting issues with osquery. Fleet is working with the osquery community to address this issue and update the `alf` table to correctly report firewall status under Sequoia. For more details on this issue, [follow the progress here](https://github.com/fleetdm/fleet/issues/21802). Additionally, manual installation of unsigned `fleet-osquery.pkg` packages now require extra steps due to changes in Apple's security settings, reflecting a heightened focus on device security.
+
+## Expanding Support for Declarative Device Management (DDM)
+
+As Apple expands the Declarative Device Management (DDM) capabilities with macOS 15 Sequoia, Fleet looks forward to implementing these new functionalities to enhance device management capabilities further. Today, administrators can send DDM JSON payloads directly to hosts, enabling more responsive and granular control over device configurations and settings. Fleet's support for DDM allows organizations to leverage this robust framework to manage devices efficiently without constant communication with the server. For more information on DDM, visit Apple’s [guide to Declarative Device Management](https://support.apple.com/guide/deployment/intro-to-declarative-device-management-depb1bab77f8/1/web/1.0).
+
+## Updates Across macOS, iOS, and iPadOS
+
+Apple has renamed "Profiles" to "Device Management" in all the new operating systems within System Settings. This change affects how administrators and users interact with device management settings on all Apple platforms. For more details on navigating these changes, visit Apple’s [support page](https://it-training.apple.com/tutorials/support/sup530/#Determining-Whether-a-Device-Is-Managed).
+
+Fleet remains committed to supporting Apple's latest advancements, ensuring that your organization can seamlessly integrate and manage devices running macOS 15 Sequoia, iOS 18, and iPadOS 18 with the same reliability and security you expect. Beginning with macOS 16, [Fleet will provide release-day support for major macOS releases](https://fleetdm.com/handbook/engineering#provide-0-day-support-for-major-version-macos-releases), ensuring your fleet is always prepared for the latest updates. Stay tuned for updates as we refine and enhance our support for these new platforms. [Engineering | Fleet handbook](https://fleetdm.com/handbook/engineering#provide-0-day-support-for-major-version-macos-releases)
+
+
+
+
+
+
+
+
diff --git a/articles/fleetctl.md b/articles/fleetctl.md
index caa234f845a8..a7e2a245af27 100644
--- a/articles/fleetctl.md
+++ b/articles/fleetctl.md
@@ -10,15 +10,19 @@ fleetctl also provides a quick way to work with all the data exposed by Fleet wi
## Installing fleetctl
-Install fleetctl with npm or download the binary from [GitHub](https://github.com/fleetdm/fleet/releases).
+Download and install [Node.js](https://nodejs.org/en).
+
+Install fleetctl with npm (included in Node.js).
```sh
-npm install -g fleetctl
+sudo npm install -g fleetctl
```
+To install fleetctl on Windows or Linux, download the fleectl binary here on [GitHub](https://github.com/fleetdm/fleet/releases).
+
### Upgrading fleetctl
-The easiest way to update fleetctl is by running the installation command again.
+The easiest way to update fleetctl is by rerunning the installation command.
```sh
npm install -g fleetctl@latest
@@ -30,7 +34,7 @@ npm install -g fleetctl@latest
### Available commands
-Much of the functionality available in the Fleet UI is also available in `fleetctl`. You can run queries, add and remove users, generate Fleet's agent (fleetd) to add new hosts, get information about existing hosts, and more!
+Much of the functionality available in the Fleet UI is also available in fleetctl. You can run queries, add and remove users, generate Fleet's agent (fleetd) to add new hosts, get information about existing hosts, and more!
> Note: Unless a logging infrastructure is configured on your Fleet server, osquery-related logs will be stored locally on each device. Read more [here](https://fleetdm.com/guides/log-destinations)
@@ -74,7 +78,7 @@ This section walks you through authentication, assuming you already have a runni
### Login
-To log in to your Fleet instance, run following commands:
+To log in to your Fleet instance, run the following commands:
1. Set the Fleet instance address
@@ -93,11 +97,11 @@ Password:
[+] Fleet login successful and context configured!
```
-Once your local context is configured, you can use `fleetctl` normally.
+Once your local context is configured, you can use fleetctl normally.
### Log in with SAML (SSO) authentication
-Users that authenticate to Fleet via SSO should retrieve their API token from the UI and set it manually in their `fleetctl` configuration (instead of logging in via `fleetctl login`).
+Users that authenticate to Fleet via SSO should retrieve their API token from the UI and manually set it in their fleetctl configuration (instead of logging in via `fleetctl login`).
**Fleet UI:**
1. Go to the **My account** page (https://fleet.example.com/profile)
@@ -116,13 +120,13 @@ The token can also be set with `fleetctl config set --token`, but this may leak
## Using fleetctl with an API-only user
-When running automated workflows using the Fleet API, we recommend an API-only user's API key rather than the API key of a regular user. A regular user's API key expires frequently for security purposes, requiring routine updates. Meanwhile, an API-only user's key does not expire.
+When running automated workflows using the Fleet API, we recommend using an API-only user's API key rather than a regular user's API key. A regular user's API key expires frequently for security purposes, requiring routine updates. Meanwhile, an API-only user's key does not expire.
An API-only user does not have access to the Fleet UI. Instead, it's only purpose is to interact with the API programmatically or from fleetctl.
### Create API-only user
-Before creating the API-only user, log in to `fleetctl` as an admin. See [authentication](https://#authentication) above for details.
+Before creating the API-only user, log in to fleetctl as an admin. See [authentication](https://#authentication) above for details.
To create your new API-only user, use `fleetctl user create`:
@@ -154,12 +158,12 @@ fleetctl user create --name "API User" --email api@example.com --password temp@p
#### Changing permissions
-To change roles of a current user, log into the Fleet UI as an admin and navigate to **Settings > Users**.
-> Suggestion: To disable/enable a user's access to the UI (converting a regular user to an API-only user or vice versa), create a new user.
+To change the role of a current user, log into the Fleet UI as an admin and navigate to Settings > Users.
+> Suggestion: Create a new user to disable/enable a user's access to the UI (converting a regular user to an API-only user or vice versa).
### Switching users
-To use `fleetctl` with your regular user account but occasionally use your API-only user for specific cases, you can set up your `fleetctl` config with a new `context` to hold the credentials of your API-only user:
+To use fleetctl with your regular user account but occasionally use your API-only user for specific cases, you can set up your fleetctl config with a new `context` to hold the credentials of your API-only user:
```sh
fleetctl config set --address https://dogfood.fleetdm.com --context api
@@ -181,7 +185,7 @@ Running a command with no context will use the default profile.
## Debugging Fleet
-`fleetctl` provides debugging capabilities about the running Fleet server via the `debug` command. To see a complete list of all the options run:
+fleetctl provides debugging capabilities about the running Fleet server via the `debug` command. To see a complete list of all the options, run:
```sh
fleetctl debug --help
@@ -204,4 +208,4 @@ This will generate a `tar.gz` file with:
-
+
diff --git a/articles/how-to-uninstall-fleetd.md b/articles/how-to-uninstall-fleetd.md
new file mode 100644
index 000000000000..1b7a524cd7d9
--- /dev/null
+++ b/articles/how-to-uninstall-fleetd.md
@@ -0,0 +1,34 @@
+# How to uninstall Fleet's agent (fleetd)
+
+This guide walks you through the steps to remove fleetd from your device. After performing these steps, the device will display as an offline host in the Fleet UI until you manually remove it.
+
+## On macOS:
+Run the [cleanup script](https://github.com/fleetdm/fleet/blob/main/orbit/tools/cleanup/cleanup_macos.sh) found in Fleet's GitHub
+
+---
+
+## On Windows:
+Use the "Add or remove programs" dialog to remove Fleet osquery.
+
+![windows_uninstall](https://github.com/user-attachments/assets/4140e62b-f67a-4df6-85b0-430c2c624881)
+
+---
+
+## On Linux:
+
+Using Debian package manager (Debian, Ubuntu, etc.) :
+
+Run ```sudo apt remove fleet-osquery -y```
+
+Using yum Package Manager (RHEL, CentOS, etc.) :
+
+Run ```sudo rpm -e fleet-osquery-X.Y.Z.x86_64```
+
+Are you having trouble uninstalling Fleetd on macOS, Windows, or Linux? Get help on Slack in the [#fleet channel](https://fleetdm.com/slack).
+
+
+
+
+
+
+
diff --git a/articles/how-to-uninstall-osquery.md b/articles/how-to-uninstall-osquery.md
deleted file mode 100644
index c5c54359ab47..000000000000
--- a/articles/how-to-uninstall-osquery.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# How to uninstall osquery
-
-This article walks you through the steps to remove osquery from your device. Remember that if you enrolled this device in a Fleet instance, it would display as an offline host in the Fleet UI until you manually remove it.
-
-## On macOS:
-Open up your terminal and paste the following commands; note that `sudo` is required, and you’ll need administrator privileges to complete this process.
-
-```
-sudo launchctl unload /Library/LaunchDaemons/io.osquery.agent.plist
-sudo rm /Library/LaunchDaemons/io.osquery.agent.plist
-sudo rm -rf /private/var/log/osquery /private/var/osquery
-sudo rm /usr/local/bin/osquery*
-sudo pkgutil --forget io.osquery.agent
-```
-
-These commands stop the running osquery daemon, remove it from your device, and delete the files created by osquery.
-
-And that’s it; you have now removed osquery from your macOS device.
-
----
-
-## On Windows:
-Removing osquery on Windows 10 is a simple process. To get started, open Windows settings and go to Apps. Then find “osquery” and click Uninstall.
-
-![Uninstall osquery](../website/assets/images/articles/how-to-uninstall-osquery-1-607x188@2x.png)
-
-Click Uninstall again to confirm, and osquery will be removed from your Windows device. You might need to restart your computer to complete the uninstall process fully.
-
----
-
-## On Linux:
-
-1. Open your terminal and paste the following commands to stop the running osquery service, uninstall osquery, and clean up files created by osquery.
-
-2. Note that `sudo` is required, and you’ll need administrative privileges to complete this process.
-
-3. Using Debian package manager (Debian, Ubuntu, etc.) :
-
-```
-sudo systemctl stop osqueryd.service
-sudo apt remove osquery
-rm -rf /var/osquery /var/log/osquery /etc/osquery
-```
-
-Using yum Package Manager (RHEL, CentOS, etc.) :
-
-```
-sudo systemctl stop osqueryd.service
-sudo yum remove osquery
-rm -rf /var/osquery /var/log/osquery /etc/osquery
-```
-
-Are you running into trouble uninstalling osquery on macOS, Windows, or Linux? Get help on Slack in the [#fleet channel](https://fleetdm.com/slack).
-
-
-
-
-
-
-
diff --git a/articles/macos-mdm-setup.md b/articles/macos-mdm-setup.md
index bc91ee6a7206..0f32ccb09033 100644
--- a/articles/macos-mdm-setup.md
+++ b/articles/macos-mdm-setup.md
@@ -25,8 +25,7 @@ To connect Fleet to ABM, you have to add an ABM token to Fleet. To add an ABM to
1. Navigate to the **Settings > Integrations > Mobile device management (MDM)** page.
2. Under "Automatic enrollment", click "Add ABM", and then click "Add ABM" again on the next page. Follow the instructions in the modal and upload an ABM token to Fleet.
-When one of your uploaded ABM tokens has expired or is within 30 days of expiring, you will see a warning
-banner at the top of page reminding you to renew your token.
+When one of your uploaded ABM tokens has expired or is within 30 days of expiring, you will see a warning banner at the top of page reminding you to renew your token.
To renew an ABM token:
@@ -53,7 +52,50 @@ If no default team is set for a host platform (macOS, iOS, or iPadOS), then newl
> A host can be transferred to a new (not default) team before it enrolls. In the Fleet UI, you can do this under **Settings** > **Teams**.
-### Simple Certificate Enrollment Protocol (SCEP)
+## Volume Purchasing Program (VPP)
+
+> Available in Fleet Premium
+
+To connect Fleet to Apple's VPP, head to the guide [here](https://fleetdm.com/guides/install-vpp-apps-on-macos-using-fleet).
+
+## Best practice
+
+Most organizations only need one ABM token and one VPP token to manage their macOS, iOS, and iPadOS hosts.
+
+These organizations may need multiple ABM and VPP tokens:
+
+- Managed Service Providers (MSPs)
+- Enterprises that acquire new businesses and as a result inherit new hosts
+- Umbrella organizations that preside over entities with separated purchasing authority (i.e. a hospital or university)
+
+For **MSPs**, the best practice is to have one ABM and VPP connection per client.
+
+The default teams in Fleet for each client's ABM token in Fleet will look like this:
+- macOS: 💻 Client A - Workstations
+- iOS: 📱🏢 Client A - Company-owned iPhones
+- iPadOS:🔳🏢 Client A - Company-owned iPads
+
+Client A's VPP token will be assigned to the above teams.
+
+For **enterprises that acquire**, the best practice is to add a new ABM and VPP connection for each acquisition.
+
+These will default teams in Fleet:
+
+Enterprise ABM token:
+- macOS: 💻 Enterprise - Workstations
+- iOS: 📱🏢 Enterprise - Company-owned iPhones
+- iPadOS:🔳🏢 Enterprise - Company-owned iPads
+
+The enterprises's VPP token will be assigned to the above teams.
+
+Acquisition ABM token:
+- macOS: 💻 Acquisition - Workstations
+- iOS: 📱🏢 Acquisition - Company-owned iPhones
+- iPadOS:🔳🏢 Acquisition - Company-owned iPads
+
+The acquisitions's VPP token will be assigned to the above teams.
+
+## Simple Certificate Enrollment Protocol (SCEP)
Fleet uses SCEP certificates (1 year expiry) to authenticate the requests hosts make to Fleet. Fleet renews each host's SCEP certificates automatically every 180 days.
diff --git a/articles/role-based-access.md b/articles/role-based-access.md
index 95fc712c5252..d147796cdb58 100644
--- a/articles/role-based-access.md
+++ b/articles/role-based-access.md
@@ -46,9 +46,9 @@ GitOps is an API-only and write-only role that can be used on CI/CD pipelines.
| Transfer hosts between teams\* | | | ✅ | ✅ | ✅ |
| Create, edit, and delete labels | | | ✅ | ✅ | ✅ |
| View all software | ✅ | ✅ | ✅ | ✅ | |
-| Add and delete software | | | ✅ | ✅ | ✅ |
+| Add, edit, and delete software | | | ✅ | ✅ | ✅ |
| Download added software | | | ✅ | ✅ | |
-| Install software on hosts | | | ✅ | ✅ | |
+| Install/uninstall software on hosts | | | ✅ | ✅ | |
| Filter software by [vulnerabilities](https://fleetdm.com/docs/using-fleet/vulnerability-processing#vulnerability-processing) | ✅ | ✅ | ✅ | ✅ | |
| Filter hosts by software | ✅ | ✅ | ✅ | ✅ | |
| Filter software by team\* | ✅ | ✅ | ✅ | ✅ | |
@@ -79,9 +79,10 @@ GitOps is an API-only and write-only role that can be used on CI/CD pipelines.
| Edit agent options for hosts assigned to teams\* | | | | ✅ | ✅ |
| Initiate [file carving](https://fleetdm.com/docs/using-fleet/rest-api#file-carving) | | | ✅ | ✅ | |
| Retrieve contents from file carving | | | | ✅ | |
-| View Apple mobile device management (MDM) certificate information | | | | ✅ | |
-| View Apple business manager (BM) information | | | | ✅ | |
-| Generate Apple mobile device management (MDM) certificate signing request (CSR) | | | | ✅ | |
+| Create Apple Push Certificates service (APNs) certificate signing request (CSR) | | | | ✅ | |
+| View, edit, and delete APNs certificate | | | | ✅ | |
+| View, edit, and delete Apple Business Manager (ABM) connections | | | | ✅ | |
+| View, edit, and delete Volume Purchasing Program (VPP) connections | | | | ✅ | |
| View disk encryption key for macOS and Windows hosts | ✅ | ✅ | ✅ | ✅ | |
| Edit OS updates for macOS, Windows, iOS, and iPadOS hosts | | | ✅ | ✅ | ✅ |
| Create, edit, resend and delete configuration profiles for macOS and Windows hosts | | | ✅ | ✅ | ✅ |
@@ -129,7 +130,7 @@ Users with access to multiple teams can be assigned different roles for each tea
| View software | ✅ | ✅ | ✅ | ✅ | |
| Add and delete software | | | ✅ | ✅ | ✅ |
| Download added software | | | ✅ | ✅ | |
-| Install software on hosts | | | ✅ | ✅ | |
+| Install/uninstall software on hosts | | | ✅ | ✅ | |
| Filter software by [vulnerabilities](https://fleetdm.com/docs/using-fleet/vulnerability-processing#vulnerability-processing) | ✅ | ✅ | ✅ | ✅ | |
| Filter hosts by software | ✅ | ✅ | ✅ | ✅ | |
| Filter software | ✅ | ✅ | ✅ | ✅ | |
diff --git a/articles/sysadmin-diaries-gitops-a-strategic-advantage.md b/articles/sysadmin-diaries-gitops-a-strategic-advantage.md
new file mode 100644
index 000000000000..51d087a410df
--- /dev/null
+++ b/articles/sysadmin-diaries-gitops-a-strategic-advantage.md
@@ -0,0 +1,63 @@
+# Sysadmin diaries: GitOps: A strategic advantage for automation, collaboration, and cost savings
+
+![Sysadmin diaries: GitOps: A strategic advantage for automation, collaboration, and cost savings](../website/assets/images/articles/sysadmin-diaries-1600x900@2x.png)
+
+_This diary entry was originally published on [Allen's LinkedIn](https://www.linkedin.com/pulse/gitops-strategic-advantage-automation-collaboration-cost-houchins-a4luf/)._
+
+![GitHub logo and GitHub Actions logo](../website/assets/images/articles/sysadmin-diaries-gitops-a-strategic-advantage-1-312x207@2x.jpg)
+
+For many IT professionals, the idea of GitOps might seem daunting, if not completely foreign. I can relate to this. I’ve spent over two decades contributing at every level of IT, from individual contributor to executive leadership, and until recently, GitOps was something I had never implemented. It felt like a complex, high-barrier concept that no one adequately explained in terms I could quantify.
+
+As an IT leader, I often prioritized immediate business needs over initiatives that seemed more technical or abstract, especially those I didn’t fully understand. GitOps, at first glance, fell into that category. While the term GitOps might be newer, the principles behind it aren’t. Its roots lie in familiar DevOps and Engineering methodologies. GitOps has helped these groups become efficiency wizards orchestrating complex testing, builds, and deployments through centralized code repositories and automations.
+
+Imagine applying those same principles to your entire IT infrastructure and applications. GitOps is something you can approach gradually, finding small wins to build upon, even with the smallest steps. But before you invest any time, why should you care?
+
+GitOps is no longer just for DevOps teams. IT professionals, Information Security and compliance experts, people leaders, and Executives alike should consider it a cornerstone of our operations. It’s time to start thinking about GitOps capabilities as a critical factor in decision-making, whether you’re evaluating new tools or renewing existing ones.
+
+## Information technology
+
+According to *[Okta’s Businesses at Work 2024 report](https://www.okta.com/resources/whitepaper-businesses-at-work/)*, IT teams manage an average of 93 apps globally—some more, some fewer. That’s potentially 93 different systems to context-switch between, each with its own UI, change management process, and configuration quirks. To complicate matters, these systems aren’t usually managed by a single IT team. For instance, network systems might be handled by one group and productivity applications by another, while IT support often requires access across the board.
+
+GitOps changes that dynamic. By centralizing configuration management, GitOps offers full visibility, allowing every team to access the information they need to be more effective. Better yet, it standardizes how contributors interact with systems by using a common “code language,” empowering them to collaborate on areas they wouldn’t usually have administrator rights over. This is one of the most effective ways to break down silos and foster collaboration across traditionally separate groups.
+
+GitOps enables IT teams to unlock greater value through automation, allowing them to focus on more engaging, creative challenges that require human ingenuity—while leaving the repetitive, mundane tasks to the machines. For example, I want to ensure my end users’ devices are running the latest version of Google Chrome. Without GitOps, I’d need to manually monitor for updates and adjust compliance criteria whenever a new version is released.
+
+With GitOps, however, I can automate both the monitoring of Chrome updates and the adjustment of compliance criteria, creating a true “set it and forget it” workflow. This not only saves time but also ensures that compliance is maintained seamlessly, without manual intervention.
+
+![Screenshot of GitHub Actions workflow progress](../website/assets/images/articles/sysadmin-diaries-gitops-a-strategic-advantage-2-1999x680@2x.png)
+
+## Information security & compliance
+
+The best Information Security and Compliance teams aim to protect the company’s assets and customers’ data without negatively impacting user productivity or privacy. However, achieving this balance can be tricky, as security needs often conflict with user autonomy. These teams are also responsible for accessing corporate systems to verify and audit configurations, which can sometimes create friction.
+
+A GitOps-centric environment can help ease this tension by fostering a culture of trust and transparency. Instead of multiple touchpoints, both security teams and end users can access a centralized repository, a single source of truth, for all configuration data. This level of visibility streamlines audits and builds trust, ensuring that security doesn’t feel like “big brother” hovering over end users. It creates an environment where operational teams and users feel empowered, with clear, mutual access to critical information.
+
+![GitOps workflow diagram](../website/assets/images/articles/sysadmin-diaries-gitops-a-strategic-advantage-3-566x415@2x.png)
+
+Most systems offer little or no change management features. At best, they might say, “An admin made a change to this setting” and display what was updated. At worst, they might just say, “An admin made a change” without further details. Not only that, but information security and compliance teams don’t want to hunt for this data across various systems, which leads to the creation of centralized logging systems. These shortcomings also result in teams creating complex ticketing systems to propose, approve, and track changes, inevitably leading to the dreaded change management meeting—a time-consuming and often uninspiring process. They’re typically boring and take us away from more engaging, skill-appropriate tasks. However, With GitOps, every change across every system is tracked in one centralized location. This allows full visibility into each proposed change and its outcome and space for questions and comments. More importantly, anyone can propose changes or solutions, ensuring that the entire team feels involved and invested in decisions that impact them. GitOps doesn’t just streamline the process; it fosters collaboration and ownership in a way that traditional methods can’t.
+
+## Leadership & executives
+
+Let’s face it: you’re juggling competing priorities with constant pressure to increase efficiency and justify spending. While the pitch for GitOps sounds appealing, you’re a realist and know it will require an investment. It may not be strictly financial, but it will demand time and focus from your team. You’ll need to reprioritize commitments to ensure a meaningful return on the effort spent improving efficiency and meeting business demands. This is why GitOps should be introduced as a core strategy from the top down. It requires a shift in mindset and workflow, which might spark a cultural transformation within your organization.
+
+Beyond the tangible benefits, GitOps offers a host of unrealized gains that could have an even bigger impact on your business. Yes, it may be challenging at first, but you’ll be upskilling your team along the way. Learning something new is rarely easy, but support and investing in training will pay off. As your team implements greater automation, you’ll uncover opportunities to streamline processes and eliminate redundant systems, ultimately driving down costs. While licensing reductions are easy to quantify, it’s just as critical for leaders to communicate the story of time and efficiency savings.
+
+Perhaps most importantly, you’ll see a morale boost. Your teams will engage in more meaningful, stimulating work, and the skills they develop in one system will transfer across many others, multiplying their value to the business. This kind of transformation drives productivity and enables your team to become true force multipliers across the entire organization.
+
+## Where do you go from here?
+
+Some of you may already be well along your GitOps journey. If that’s the case, I encourage you to share your insights through conference presentations or by open-sourcing your solutions. By doing so, you can help others navigate similar challenges and showcase the real-world benefits of GitOps.
+
+For those yet to begin, [Fleet](https://fleetdm.com/) is a great place to start. Not only will you be setting up a system that provides comprehensive visibility and insights into all your devices, Fleet also provides an [easy-to-understand GitOps repository to help you get started](https://github.com/fleetdm/fleet-gitops).
+
+I hope this discussion has piqued your interest and given you the confidence to explore GitOps further. It should be at the top of your decision-making criteria during purchasing and renewal cycles for any software or systems you manage. For IT professionals, imagine becoming the hero of work automation and enhancing the services you provide to your customers. For InfoSec and compliance teams, picture gaining faster and deeper visibility into how devices in your environment are configured, whether on-prem or in the cloud, and having one location to run queries and enforce policies. For executives and leadership, envision a more engaged, motivated, and productive team that consistently helps you meet operational goals while driving down costs.
+
+Good luck on your GitOps journey, and don’t hesitate to [reach out if you have questions or want to learn more](https://fleetdm.com/support)!
+
+
+
+
+
+
+
+
diff --git a/changes/18354-update-success-messages b/changes/18354-update-success-messages
new file mode 100644
index 000000000000..98f582dad033
--- /dev/null
+++ b/changes/18354-update-success-messages
@@ -0,0 +1 @@
+* Update success messages for lock, unlock, and wipe commands in the UI.
diff --git a/changes/19619-win-battery b/changes/19619-win-battery
new file mode 100644
index 000000000000..124e58114048
--- /dev/null
+++ b/changes/19619-win-battery
@@ -0,0 +1 @@
+- Windows host details now include battery status
\ No newline at end of file
diff --git a/changes/21276-select-live-query-targets-improvements b/changes/21276-select-live-query-targets-improvements
new file mode 100644
index 000000000000..75b2086beb03
--- /dev/null
+++ b/changes/21276-select-live-query-targets-improvements
@@ -0,0 +1 @@
+- UI Improvements to selecting live query targets (e.g. styling, closing behavior)
diff --git a/changes/21343-hide-redundant-built-in-label-pills b/changes/21343-hide-redundant-built-in-label-pills
new file mode 100644
index 000000000000..92baea5ba52f
--- /dev/null
+++ b/changes/21343-hide-redundant-built-in-label-pills
@@ -0,0 +1 @@
+- UI: Remove redundant built in label filter pills
diff --git a/changes/21370-bundle-id-quickfix b/changes/21370-bundle-id-quickfix
new file mode 100644
index 000000000000..1f27bedc40af
--- /dev/null
+++ b/changes/21370-bundle-id-quickfix
@@ -0,0 +1 @@
+- Fix "no rows" error when adding a software installer that matches an existing title's name and source but not its bundle ID
diff --git a/changes/21409-fedora-label b/changes/21409-fedora-label
new file mode 100644
index 000000000000..2f0ca7cfd61e
--- /dev/null
+++ b/changes/21409-fedora-label
@@ -0,0 +1 @@
+- added builtin label for Fedora Linux. Warning: migrations will fail if a pre-existing 'Fedora Linux' label exists. To resolve, delete the existing 'Fedora Linux' label.
\ No newline at end of file
diff --git a/changes/21594-host-software-filter-bug b/changes/21594-host-software-filter-bug
new file mode 100644
index 000000000000..fb7ff11dda66
--- /dev/null
+++ b/changes/21594-host-software-filter-bug
@@ -0,0 +1 @@
+- Fleet UI: Fix host software filter bug that resets dropdown filter on table changes (pagination, order by column, etc)
diff --git a/changes/21875-duplicate-label-name b/changes/21875-duplicate-label-name
new file mode 100644
index 000000000000..80ee9d9e6925
--- /dev/null
+++ b/changes/21875-duplicate-label-name
@@ -0,0 +1 @@
+- Fleet UI: Surface duplicate label name error to user
diff --git a/changes/21923-switch-exact-search-focus-bug b/changes/21923-switch-exact-search-focus-bug
new file mode 100644
index 000000000000..0ae8b45da921
--- /dev/null
+++ b/changes/21923-switch-exact-search-focus-bug
@@ -0,0 +1 @@
+- UI fix: Switching vulnerability search types does not cause page re-render
diff --git a/changes/22094-cleanup-queries b/changes/22094-cleanup-queries
new file mode 100644
index 000000000000..af8e9ab77da8
--- /dev/null
+++ b/changes/22094-cleanup-queries
@@ -0,0 +1 @@
+- updated activity cleanup job to remove all expired live queries to improve API performance in environment using large volumes of live queries. To note, the cleanup cron may take longer on the first run after upgrade.
\ No newline at end of file
diff --git a/changes/22094-query-optimization b/changes/22094-query-optimization
new file mode 100644
index 000000000000..bd779b451346
--- /dev/null
+++ b/changes/22094-query-optimization
@@ -0,0 +1 @@
+- Increased performance for Host details and Fleet Desktop, particularly in environments using high volumes of live queries
\ No newline at end of file
diff --git a/changes/22122-mdm-apple-status-queries b/changes/22122-mdm-apple-status-queries
new file mode 100644
index 000000000000..2ea893d31ff5
--- /dev/null
+++ b/changes/22122-mdm-apple-status-queries
@@ -0,0 +1 @@
+- Improved performance of SQL queries used to determine MDM profile status for Apple hosts.
\ No newline at end of file
diff --git a/changes/22159-hide-severity-fleet-free b/changes/22159-hide-severity-fleet-free
new file mode 100644
index 000000000000..ddb47088fa36
--- /dev/null
+++ b/changes/22159-hide-severity-fleet-free
@@ -0,0 +1 @@
+- Hide CVSS severity column from Fleet Free software details > vulnerabilities sections
diff --git a/changes/22197-policy-auto-software-truncation b/changes/22197-policy-auto-software-truncation
new file mode 100644
index 000000000000..4b4740622e6c
--- /dev/null
+++ b/changes/22197-policy-auto-software-truncation
@@ -0,0 +1 @@
+- Fleet UI: Fix policy automation truncation when selecting software to auto-install
\ No newline at end of file
diff --git a/changes/22198-defaults b/changes/22198-defaults
new file mode 100644
index 000000000000..ec243e9a48e4
--- /dev/null
+++ b/changes/22198-defaults
@@ -0,0 +1,2 @@
+- Fixes a bug where removing a VPP or ABM token from a GitOps YAML file would leave the team
+ assignments unchanged.
\ No newline at end of file
diff --git a/changes/22207-close-team-modal b/changes/22207-close-team-modal
new file mode 100644
index 000000000000..cad918366754
--- /dev/null
+++ b/changes/22207-close-team-modal
@@ -0,0 +1 @@
+- Fix UI bug: Edit team name closes modal
diff --git a/changes/22415-fix-vpp-migration b/changes/22415-fix-vpp-migration
new file mode 100644
index 000000000000..eed21b93dc12
--- /dev/null
+++ b/changes/22415-fix-vpp-migration
@@ -0,0 +1 @@
+* Fixed an issue with the migration adding support for multiple VPP tokens that would happen if a token is removed prior to upgrading Fleet.
diff --git a/changes/22492-msrc-fix b/changes/22492-msrc-fix
new file mode 100644
index 000000000000..4bd6035faaed
--- /dev/null
+++ b/changes/22492-msrc-fix
@@ -0,0 +1 @@
+* Fix MSRC feed pulls (for NVD release builds) in environments where GitHub access is authenticated
diff --git a/changes/software-edit-request-deadline b/changes/software-edit-request-deadline
new file mode 100644
index 000000000000..f3576256f5ed
--- /dev/null
+++ b/changes/software-edit-request-deadline
@@ -0,0 +1 @@
+* Ensure request timeouts for software installer edits are just as high as for initial software installer uploads
diff --git a/cmd/fleet/serve.go b/cmd/fleet/serve.go
index eda0660a731d..02353ffe3183 100644
--- a/cmd/fleet/serve.go
+++ b/cmd/fleet/serve.go
@@ -1145,7 +1145,8 @@ the way that the Fleet server works.
}
}
- if req.Method == http.MethodPost && strings.HasSuffix(req.URL.Path, "/fleet/software/package") {
+ if (req.Method == http.MethodPost && strings.HasSuffix(req.URL.Path, "/fleet/software/package")) ||
+ (req.Method == http.MethodPatch && strings.HasSuffix(req.URL.Path, "/package") && strings.Contains(req.URL.Path, "/fleet/software/titles/")) {
// when uploading a software installer, the file might be large so
// the read timeout (to read the full request body) must be extended.
rc := http.NewResponseController(rw)
diff --git a/cmd/fleetctl/apply_test.go b/cmd/fleetctl/apply_test.go
index f35b39dc84f1..bd80bb84347c 100644
--- a/cmd/fleetctl/apply_test.go
+++ b/cmd/fleetctl/apply_test.go
@@ -657,6 +657,18 @@ func TestApplyAppConfig(t *testing.T) {
return []*fleet.TeamSummary{{Name: "team1", ID: 1}}, nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{{OrganizationName: t.Name()}}, nil
+ }
+
name := writeTmpYml(t, `---
apiVersion: v1
kind: config
@@ -782,6 +794,18 @@ func TestApplyAppConfigDryRunIssue(t *testing.T) {
return nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
// first, set the default app config's agent options as set after fleetctl setup
name := writeTmpYml(t, `---
apiVersion: v1
@@ -914,6 +938,18 @@ func TestApplyAppConfigDeprecatedFields(t *testing.T) {
return nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
name := writeTmpYml(t, `---
apiVersion: v1
kind: config
@@ -1316,6 +1352,14 @@ func TestApplyAsGitOps(t *testing.T) {
return []*fleet.ABMToken{{ID: 1}}, nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
// Apply global config.
name := writeTmpYml(t, `---
apiVersion: v1
@@ -1873,6 +1917,18 @@ func TestCanApplyIntervalsInNanoseconds(t *testing.T) {
return nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
name := writeTmpYml(t, `---
apiVersion: v1
kind: config
@@ -1908,6 +1964,18 @@ func TestCanApplyIntervalsUsingDurations(t *testing.T) {
return nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
name := writeTmpYml(t, `---
apiVersion: v1
kind: config
@@ -2091,6 +2159,18 @@ func TestApplyMacosSetup(t *testing.T) {
return []*fleet.ABMToken{{ID: 1}}, nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
return ds
}
@@ -2764,6 +2844,17 @@ func TestApplySpecs(t *testing.T) {
ds.DeleteMDMWindowsConfigProfileByTeamAndNameFunc = func(ctx context.Context, teamID *uint, profileName string) error {
return nil
}
+
+ // VPP/AMB
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
}
cases := []struct {
diff --git a/cmd/fleetctl/gitops_test.go b/cmd/fleetctl/gitops_test.go
index 1a054482f618..5a688b2fd91b 100644
--- a/cmd/fleetctl/gitops_test.go
+++ b/cmd/fleetctl/gitops_test.go
@@ -83,6 +83,18 @@ func TestGitOpsBasicGlobalFree(t *testing.T) {
return nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
tmpFile, err := os.CreateTemp(t.TempDir(), "*.yml")
require.NoError(t, err)
@@ -238,6 +250,18 @@ func TestGitOpsBasicGlobalPremium(t *testing.T) {
return nil, nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
tmpFile, err := os.CreateTemp(t.TempDir(), "*.yml")
require.NoError(t, err)
@@ -591,6 +615,17 @@ func TestGitOpsFullGlobal(t *testing.T) {
return nil
}
+ // Needed for checking tokens
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
const (
fleetServerURL = "https://fleet.example.com"
orgName = "GitOps Test"
@@ -1079,6 +1114,18 @@ func TestGitOpsBasicGlobalAndTeam(t *testing.T) {
return nil, 0, nil, nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
globalFile, err := os.CreateTemp(t.TempDir(), "*.yml")
require.NoError(t, err)
@@ -1345,6 +1392,18 @@ func TestGitOpsBasicGlobalAndNoTeam(t *testing.T) {
return nil, 0, nil, nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
globalFileBasic, err := os.CreateTemp(t.TempDir(), "*.yml")
require.NoError(t, err)
@@ -1604,6 +1663,18 @@ func TestGitOpsFullGlobalAndTeam(t *testing.T) {
return team, nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
+
apnsCert, apnsKey, err := mysql.GenerateTestCertBytes()
require.NoError(t, err)
crt, key, err := apple_mdm.NewSCEPCACertKey()
@@ -2234,6 +2305,15 @@ func setupFullGitOpsPremiumServer(t *testing.T) (*mock.Store, **fleet.AppConfig,
ds.ListSoftwareTitlesFunc = func(ctx context.Context, opt fleet.SoftwareTitleListOptions, tmFilter fleet.TeamFilter) ([]fleet.SoftwareTitleListResult, int, *fleet.PaginationMetadata, error) {
return nil, 0, nil, nil
}
+ ds.SaveABMTokenFunc = func(ctx context.Context, tok *fleet.ABMToken) error {
+ return nil
+ }
+ ds.ListVPPTokensFunc = func(ctx context.Context) ([]*fleet.VPPTokenDB, error) {
+ return []*fleet.VPPTokenDB{}, nil
+ }
+ ds.ListABMTokensFunc = func(ctx context.Context) ([]*fleet.ABMToken, error) {
+ return []*fleet.ABMToken{}, nil
+ }
t.Setenv("FLEET_SERVER_URL", fleetServerURL)
t.Setenv("ORG_NAME", orgName)
diff --git a/cmd/msrc/generate.go b/cmd/msrc/generate.go
index 75909ac4fc27..9af759eb2a72 100644
--- a/cmd/msrc/generate.go
+++ b/cmd/msrc/generate.go
@@ -3,6 +3,7 @@ package main
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"os"
"path/filepath"
@@ -34,13 +35,16 @@ func main() {
panicif(err)
now := time.Now()
- httpC := fleethttp.NewGithubClient()
ctx := context.Background()
- ghAPI := io.NewGitHubClient(httpC, github.NewClient(httpC).Repositories, wd)
- msrcAPI := msrc.NewMSRCClient(httpC, inPath, msrc.MSRCBaseURL)
- fmt.Println("Downloading existing bulletins...")
+ githubHttp := fleethttp.NewGithubClient()
+ ghAPI := io.NewGitHubClient(githubHttp, github.NewClient(githubHttp).Repositories, wd)
+
+ msrcHttp := fleethttp.NewClient() // don't reuse the GitHub client as it has an OAuth token baked in
+ msrcAPI := msrc.NewMSRCClient(msrcHttp, inPath, msrc.MSRCBaseURL)
+
+ fmt.Println("Downloading existing MSRC bulletins...")
eBulletins, err := ghAPI.MSRCBulletins(ctx)
panicif(err)
@@ -61,7 +65,16 @@ func main() {
panicif(err)
}
- fmt.Println("Done.")
+ fmt.Println("Done processing MSRC feed.")
+}
+
+// windowsBulletinGracePeriod returns whether we are within the grace period for a MSRC monthly feed to exist.
+//
+// E.g. September 2024 bulletin was released on the 2nd, thus we add some grace period (5 days)
+// for Microsoft to publish the current month bulletin.
+func windowsBulletinGracePeriod(month time.Month, year int) bool {
+ now := time.Now()
+ return month == now.Month() && year == now.Year() && now.Day() <= 5
}
func update(
@@ -72,15 +85,22 @@ func update(
ghClient io.GitHubAPI,
) ([]*parsed.SecurityBulletin, error) {
fmt.Println("Downloading current feed...")
- f, err := msrcClient.GetFeed(m, y)
+ currentFeed, err := msrcClient.GetFeed(m, y)
if err != nil {
- return nil, err
+ if errors.Is(err, msrc.FeedNotFound) && windowsBulletinGracePeriod(m, y) {
+ fmt.Printf("Current month feed %d-%d was not found, skipping...\n", y, m)
+ } else {
+ return nil, err
+ }
}
- fmt.Println("Parsing current feed...")
- nBulletins, err := msrc.ParseFeed(f)
- if err != nil {
- return nil, err
+ var nBulletins map[string]*parsed.SecurityBulletin
+ if currentFeed != "" {
+ fmt.Println("Parsing current feed...")
+ nBulletins, err = msrc.ParseFeed(currentFeed)
+ if err != nil {
+ return nil, err
+ }
}
var bulletins []*parsed.SecurityBulletin
@@ -118,6 +138,10 @@ func backfill(upToM time.Month, upToY int, client msrc.MSRCAPI) ([]*parsed.Secur
fmt.Printf("Downloading feed for %d-%d...\n", d.Year(), d.Month())
f, err := client.GetFeed(d.Month(), d.Year())
if err != nil {
+ if errors.Is(err, msrc.FeedNotFound) && windowsBulletinGracePeriod(d.Month(), d.Year()) {
+ fmt.Printf("Current month feed %d-%d was not found, skipping...\n", d.Year(), d.Month())
+ continue
+ }
return nil, err
}
diff --git a/docs/Contributing/API-for-contributors.md b/docs/Contributing/API-for-contributors.md
index 2ba361b2c3a7..074c3338b4c2 100644
--- a/docs/Contributing/API-for-contributors.md
+++ b/docs/Contributing/API-for-contributors.md
@@ -885,7 +885,20 @@ Content-Type: application/octet-stream
"location": "https://example.com/mdm/apple/mdm",
"renew_date": "2024-10-20T00:00:00Z",
"terms_expired": false,
- "teams": [1, 2, 3]
+ "teams": [
+ {
+ "team_id": 1,
+ "name": "Team 1"
+ },
+ {
+ "team_id": 2,
+ "name": "Team 2"
+ },
+ {
+ "team_id": 2,
+ "name": "Team 3"
+ },
+ ]
}
```
diff --git a/docs/Contributing/Building-Fleet.md b/docs/Contributing/Building-Fleet.md
index 2ab34243a45a..368b68d23b46 100644
--- a/docs/Contributing/Building-Fleet.md
+++ b/docs/Contributing/Building-Fleet.md
@@ -38,7 +38,7 @@ sudo npm install -g yarn
# Install nvm to manage node versions (apt very out of date) https://github.com/nvm-sh/nvm#install--update-script
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
# refresh your session before continuing
-nvm install v19.7.0
+nvm install v20.11.1
```
#### Windows
@@ -149,7 +149,7 @@ The following assumes that you already installed [Docker](https://docs.docker.c
To set up a canonical development environment via Docker, run the following from the root of the repository:
```sh
-docker-compose up
+docker compose up
```
> Note: you can customize the DB Docker image via the environment variables FLEET_MYSQL_IMAGE and FLEET_MYSQL_PLATFORM. For example:
@@ -161,12 +161,12 @@ docker-compose up
If you'd like to shut down the virtual infrastructure created by Docker, run the following from the root of the repository:
```sh
-docker-compose down
+docker compose down
```
### Setting up the database tables
-Once you `docker-compose up` and are running the databases, you can build the code and run the following command to create the database tables:
+Once you `docker compose up` and are running the databases, you can build the code and run the following command to create the database tables:
```sh
./build/fleet prepare db --dev
diff --git a/docs/Contributing/Understanding-host-vitals.md b/docs/Contributing/Understanding-host-vitals.md
index 3cdabf2fde06..3aa2078574f1 100644
--- a/docs/Contributing/Understanding-host-vitals.md
+++ b/docs/Contributing/Understanding-host-vitals.md
@@ -3,7 +3,7 @@
Following is a summary of the detail queries hardcoded in Fleet used to populate the device details:
-## battery
+## battery_macos
- Platforms: darwin
@@ -12,6 +12,20 @@ Following is a summary of the detail queries hardcoded in Fleet used to populate
SELECT serial_number, cycle_count, health FROM battery;
```
+## battery_windows
+
+- Platforms: windows
+
+- Discovery query:
+```sql
+SELECT 1 FROM osquery_registry WHERE active = true AND registry = 'table' AND name = 'battery'
+```
+
+- Query:
+```sql
+SELECT serial_number, cycle_count, designed_capacity, max_capacity FROM battery
+```
+
## chromeos_profile_user_info
- Platforms: chrome
diff --git a/docs/Get started/tutorials-and-guides.md b/docs/Get started/tutorials-and-guides.md
index f83de79f27db..aff2e5a6087c 100644
--- a/docs/Get started/tutorials-and-guides.md
+++ b/docs/Get started/tutorials-and-guides.md
@@ -6,7 +6,7 @@ A collection of guides to help you with Fleet.
- [How to install osquery and enroll Linux devices into Fleet](https://fleetdm.com/guides/how-to-install-osquery-and-enroll-linux-devices-into-fleet)
- [How to install osquery and enroll Windows devices into Fleet](https://fleetdm.com/guides/how-to-install-osquery-and-enroll-windows-devices-into-fleet)
- [Sysadmin diaries: restoring fleetd](https://fleetdm.com/guides/sysadmin-diaries-restoring-fleetd)
-- [How to uninstall osquery](https://fleetdm.com/guides/how-to-uninstall-osquery)
+- [How to uninstall Fleet's agent (fleetd)](https://fleetdm.com/guides/how-to-uninstall-fleetd)
- [Sysadmin diaries: device enrollment](https://fleetdm.com/guides/sysadmin-diaries-device-enrollment)
- [Sysadmin diaries: passcode profiles](https://fleetdm.com/guides/sysadmin-diaries-passcode-profiles)
- [Sysadmin diaries: lost device](https://fleetdm.com/guides/sysadmin-diaries-lost-device)
diff --git a/docs/Get started/why-fleet.md b/docs/Get started/why-fleet.md
index 0918248ac085..e0db75d68759 100644
--- a/docs/Get started/why-fleet.md
+++ b/docs/Get started/why-fleet.md
@@ -1,70 +1,26 @@
# Why Fleet
-## What's it for?
-
-In an industry that views security and IT as a shopping spree rather than a process, it's little wonder that IT and security teams get stuck with bolt-on solutions, misconfigured tools, and disparate workflows.
-
-Fleet helps organizations like Fastly and Gusto reimagine the "easy button."
-
-By simplifying how they do device health, FIM, HIDS, posture assessment, malware detection, vulnerability management, MDM, and the rest, Fleet's API enables teams with thousands of computers to build an IT and security program that works.
-
-### Explore data
-To see what kind of data you can use Fleet to gather, you can check out the [table reference documentation](https://fleetdm.com/tables).
-
-### Out-of-the-box policies
-Fleet includes out-of-the-box support for all [CIS benchmarks for macOS and Windows](https://fleetdm.com/pricing), as well as many [simpler queries](https://fleetdm.com/queries).
-
-Take as much or as little as you need for your organization.
-
-### Supported platforms
-Here are the platforms Fleet currently supports:
+Fleet is an open-source device management platform for Linux, macOS, Windows, Chromebooks, and iOS devices (BYOD or corporate owned.)
-- Linux (all distros)
-- macOS
-- Windows
-- Chromebooks
-- Amazon Web Services (AWS)
-- Google Cloud (GCP)
-- Azure (Microsoft cloud)
-- Data centers
-- Containers (kube, etc)
-- Linux-based IoT devices
-
-## Lighter than air
-Fleet is lightweight and modular. You can use it for security without using it for MDM, and vice versa. You can turn off features you are not using.
-
-### Open by design
-Fleet is dedicated to flexibility, accessibility, and clarity. We think [everyone can contribute](https://fleetdm.com/handbook/company#openness) and that tools should be as easy as possible for everyone to understand.
-
-### Good neighbors
-Ready-to-use, enterprise-friendly [integrations](https://fleetdm.com/integrations) exist for Snowflake, Splunk, GitHub Actions, Vanta, Elastic Jira, Zendesk, and more.
-
-Fleet plays well with Munki, Chef, Puppet, and Ansible, as well as with security tools like Crowdstrike and SentinelOne. For example, you can use the free version of Fleet to quickly report on what hosts are _actually_ running your EDR agent.
-
-
-### Free as in free
-The free version of Fleet will [always be free](https://fleetdm.com/pricing). Fleet is [independently backed](https://linkedin.com/company/fleetdm) and actively maintained with the help of many amazing [contributors](https://github.com/fleetdm/fleet/graphs/contributors).
+## What's it for?
-### Longevity
-The [company behind Fleet](https://fleetdm.com/handbook/company) is founded (and majority-owned) by [true believers in open source](https://fleetdm.com/handbook/company/why-this-way#why-open-source). The company's business model is influenced by GitLab (NYSE: GTLB), with great investors, happy customers, and the capacity to become profitable at any time.
+Managing computers today is getting harder. You have to juggle a mix of operating systems and devices, with a whole bunch of middleman vendors in between.
-In keeping with Fleet's value of openness, [Fleet Device Management's company handbook](https://fleetdm.com/handbook/company) is public and open source. You can read about the [history of Fleet and osquery](https://fleetdm.com/handbook/company#history) and our commitment to improving the product.
+Fleet makes things easier by giving you a single system to manage and secure all your computing devices. You can do MDM, patch stuff, and verify anything—all from one dashboard. It's like having a universal remote control for all your organization's computers.
-
+Fleet is open source, and free features will always be free.
## Is it any good?
-Fleet is used in production by IT and security teams with thousands of laptops and servers. Many deployments support tens of thousands of hosts, and a few large organizations manage deployments as large as 400,000+ hosts.
-## Chat
-Please join us in [MacAdmins Slack](https://www.macadmins.org/) or [osquery Slack](https://fleetdm.com/slack).
+Fleet is used in production by IT and security teams with thousands of laptops and servers. Many deployments support tens of thousands of hosts, and a few large organizations manage deployments as large as 400,000+ hosts.
-The Fleet community is full of [kind and helpful people](https://fleetdm.com/handbook/company#empathy). Whether or not you are a paying customer, if you need help, just ask.
+- **Get what you need:** Fleet lets you work directly with [data](https://fleetdm.com/integrations) and events from the native operating system. It lets you go all the way down to the bare metal. It’s also modular. (You can turn off features you are not using.)
+- **Out of the box:** Ready-to-use integrations exist for the [most common tools](https://fleetdm.com/integrations). You can also build custom workflows with the REST API, webhook events, and the fleetctl command line tool. Or go all in and manage computers [with GitOps](https://fleetdm.com/handbook/company#history).
+- **Good neighbors:** We think tools should be as easy as possible for everyone to understand. We helped [create osquery](https://fleetdm.com/handbook/company#history), and we are committed to improving it.
+- **Free as in free:** The free version of Fleet will [always be free](https://fleetdm.com/pricing). Fleet is independently backed and actively maintained with the help of many amazing contributors.
-
+## Ready to get started?
-## Questions?
-We have answers to the most [common questions](https://fleetdm.com/docs/get-started/faq).
+Deploying Fleet is easy. [Install it](https://fleetdm.com/docs/deploy/deploy-fleet) on a server, or [we can host it](https://fleetdm.com/register) for you. Enroll your devices, and you're set.
diff --git a/docs/REST API/rest-api.md b/docs/REST API/rest-api.md
index 638728015b9d..0a760c32d5fc 100644
--- a/docs/REST API/rest-api.md
+++ b/docs/REST API/rest-api.md
@@ -8644,6 +8644,7 @@ Deletes the session specified by ID. When the user associated with the session n
- [Get software version](#get-software-version)
- [Get operating system version](#get-operating-system-version)
- [Add package](#add-package)
+- [Modify package](#modify-package)
- [List App Store apps](#list-app-store-apps)
- [Add App Store app](#add-app-store-app)
- [Add Fleet library app](#add-fleet-library-app)
@@ -8677,6 +8678,7 @@ Get a list of all software.
| vulnerable | boolean | query | If true or 1, only list software that has detected vulnerabilities. Default is `false`. |
| available_for_install | boolean | query | If `true` or `1`, only list software that is available for install (added by the user). Default is `false`. |
| self_service | boolean | query | If `true` or `1`, only lists self-service software. Default is `false`. |
+| packages_only | boolean | query | If `true` or `1`, only lists packages available for install (without App Store apps). |
| min_cvss_score | integer | query | _Available in Fleet Premium_. Filters to include only software with vulnerabilities that have a CVSS version 3.x base score higher than the specified value. |
| max_cvss_score | integer | query | _Available in Fleet Premium_. Filters to only include software with vulnerabilities that have a CVSS version 3.x base score lower than what's specified. |
| exploit | boolean | query | _Available in Fleet Premium_. If `true`, filters to only include software with vulnerabilities that have been actively exploited in the wild (`cisa_known_exploit: true`). Default is `false`. |
@@ -9229,6 +9231,8 @@ Content-Type: application/octet-stream
### Modify package
+> **Experimental feature**. This feature is undergoing rapid improvement, which may result in breaking changes to the API or configuration surface. It is not recommended for use in automated workflows.
+
_Available in Fleet Premium._
Update a package to install on macOS, Windows, or Linux (Ubuntu) hosts.
diff --git a/frontend/components/AddHostsModal/PlatformWrapper/PlatformWrapper.tsx b/frontend/components/AddHostsModal/PlatformWrapper/PlatformWrapper.tsx
index a2a8ccb1d1c3..7f520ae6440c 100644
--- a/frontend/components/AddHostsModal/PlatformWrapper/PlatformWrapper.tsx
+++ b/frontend/components/AddHostsModal/PlatformWrapper/PlatformWrapper.tsx
@@ -257,7 +257,7 @@ const PlatformWrapper = ({
Run this command with the{" "}
diff --git a/frontend/components/LiveQuery/SelectTargets.tsx b/frontend/components/LiveQuery/SelectTargets.tsx
index ad46545983c0..5302301a08fd 100644
--- a/frontend/components/LiveQuery/SelectTargets.tsx
+++ b/frontend/components/LiveQuery/SelectTargets.tsx
@@ -430,17 +430,6 @@ const SelectTargets = ({
);
};
- if (isLoadingLabels || (isPremiumTier && isLoadingTeams)) {
- return (
-