fleet/ee/maintained-apps/README.md
Allen Houchins 61bf32838f
Revise PR review instructions for app contributions (#43538)
Updated instructions to mention the Fleet-maintained apps DRI instead of
the Product Designer for PR reviews.
2026-04-14 11:51:07 -05:00

164 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Fleet-maintained apps (FMA)
## Adding a new app (macOS)
1. Find the app's metadata in its [Homebrew formulae](https://formulae.brew.sh/)
2. Create a new manifest file called `$YOUR_APP_NAME.json` in the `inputs/homebrew/` directory. For
example, if you wanted to add Box Drive, create the file `inputs/homebrew/box-drive.json`.
3. Fill out the file according to the [input schema below](#macos-input-file-schema). For our example Box Drive app, it would look like this:
```json
{
"name": "Box Drive",
"slug": "box-drive/darwin",
"unique_identifier": "com.box.desktop",
"token": "box-drive",
"installer_format": "pkg",
"default_categories": ["Productivity"]
}
```
4. Run the following command from the root of the Fleet repo to generate the app's output data:
```bash
go run cmd/maintained-apps/main.go --slug="<slug-name>" --debug
```
5. The contributor is responsible for adding the icon to Fleet (e.g. the TypeScript and website PNG components of [#29175](https://github.com/fleetdm/fleet/pull/29175/files)). These are generated using the [generate-icons](https://github.com/fleetdm/fleet/tree/main/tools/software/icons) script. **The script automatically adds the import statement and map entry to `frontend/pages/SoftwarePage/components/icons/index.ts`**, so you don't need to manually update the index file.
6. Add a description for the app in `outputs/apps.json` file. You can use descriptions from [Homebrew formulae](https://formulae.brew.sh/). For consistency and presentation on the website, the description should follow sentence casing and the following format: `<App Name>` is a(n) (copy description from Homebrew)., making sure to end with a `.`.
7. Open a PR to the `fleet` repository with the above changes. The [#g-software Engineering Manager (EM)](https://fleetdm.com/handbook/company/product-groups#software-group) is automatically added reviewer. Also, @ mention the [Fleet-maintained apps DRI](https://fleetdm.com/handbook/company/communications#:~:text=Fleet%2Dmaintained%20apps).
8. If the app passes automated tests, it is approved and merged. The EM reviews the PR within 3 business days. The app should appear shortly in the Fleet-maintained apps section when adding new software to Fleet. The app icon will not appear in Fleet until the following release.
### macOS input file schema
| Name | Type | Description |
|--------------------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | string | **Required.** User-facing name of the application. |
| `unique_identifier` | string | **Required.** Platform-specific unique identifier (e.g., bundle identifier on macOS). |
| `token` | string | **Required.** Homebrew's unique identifier. It's the `token` field of the Homebrew API response. |
| `installer_format` | string | **Required.** File format of the installer (`zip`, `dmg`, `pkg`). Determine via the file extension in the Homebrew API `url` field or by downloading the installer if the extension isnt present. |
| `slug` | string | **Required.** Identifies the app/platform combination (e.g., `box-drive/darwin`). Used to name manifest files and reference the app in [Fleet's best practice GitOps](https://fleetdm.com/docs/configuration/yaml-files#fleet-maintained-apps). Format: `<app-name>/<platform>`, where app name is filesystem-friendly and platform is `darwin`. |
| `default_categories` | string | **Required.** Default categories for self-service if none are specified. Valid values: `Browsers`, `Communication`, `Developer Tools`, `Productivity`. |
| `pre_uninstall_scripts` | string | Command lines run **before** the generated uninstall script (e.g., for [Box](inputs/homebrew/box-drive.json)). |
| `post_uninstall_scripts` | string | Command lines run **after** the generated uninstall script (e.g., for [Box](inputs/homebrew/box-drive.json)). |
| `install_script_path` | string | Filepath to a custom install script (`.sh`). Overrides the generated install script. Script must be placed in `inputs/homebrew/scripts/`. |
| `uninstall_script_path` | string | Filepath to a custom uninstall script (`.sh`). Overrides the generated uninstall script. Cannot be used together with `pre_uninstall_scripts` or `post_uninstall_scripts`. Script must be placed in `inputs/homebrew/scripts/`. |
## Adding a new app (Windows)
1. Find the Winget `PackageIdentifier` in the relevant [winget-pkgs repo manifest](https://github.com/microsoft/winget-pkgs/tree/master/manifests).
2. Get the unique identifier that Fleet will use for matching the software with software inventory:
- On a test Windows host, install the app manually, then run the following PowerShell script that correlates to the defined `installer_scope`:
- Machine scope: `Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' -ErrorAction SilentlyContinue | Where-Object {$_.DisplayName -like '*<App Name>*'} | Select-Object DisplayName, DisplayVersion, Publisher`
- User scope: `Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' -ErrorAction SilentlyContinue | Where-Object {$_.DisplayName -like '*<App Name>*'} | Select-Object DisplayName, DisplayVersion, Publisher`
If the `unique_identifier` doesn't match the `DisplayName`, then Fleet will incorrectly create two software titles when the Fleet-maintained app is added and later installed. One title for the Fleet-maintained app and a separate title for the inventoried software.
3. Fill out the file according to the [input schema](#windows-input-file-schema). For example, Box Drive looks like this:
```json
{
"name": "Box Drive",
"slug": "box-drive/windows",
"package_identifier": "Box.Box",
"unique_identifier": "Box",
"installer_arch": "x64",
"installer_type": "msi",
"installer_scope": "machine",
"default_categories": ["Productivity"]
}
```
4. Run `go run cmd/maintained-apps/main.go --slug="<app-name>/windows" --debug` from the root of the
Fleet repo to generate the app's output data, replacing `<app-name>` with your app's name, for example:
```bash
go run cmd/maintained-apps/main.go --slug="box-drive/windows" --debug
```
5. The contributor is responsible for adding the icon to Fleet (e.g. the TypeScript and website PNG components of [#29175](https://github.com/fleetdm/fleet/pull/29175/files)). These are generated using the [generate-icons](https://github.com/fleetdm/fleet/tree/main/tools/software/icons) script. **The script automatically adds the import statement and map entry to `frontend/pages/SoftwarePage/components/icons/index.ts`**, so you don't need to manually update the index file.
6. Add a description for the app in outputs/apps.json file. You can use descriptions from the wingest manifest.
7. Open a PR to the fleet repository with the above changes. The [#g-software Engineering Manager (EM)](https://fleetdm.com/handbook/company/product-groups#software-group) is automatically added reviewer. Also, @ mention the #g-software Product Designer (PD) in a comment that points them to the new icon. This way, the icon change gets a second pair of eyes.
8. If the app passes automated tests, it is approved and merged. The EM reviews the PR within 3 business days. The app should appear shortly in the Fleet-maintained apps section when adding new software to Fleet. The app icon will not appear in Fleet until the following release.
### Windows input file schema
| Name | Type | Description |
|--------------------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | string | **Required.** User-facing name of the application. |
| `unique_identifier` | string | **Required.** Platform-specific unique identifier. For Windows, this is the `DisplayName`. |
| `package_identifier` | string | **Required.** The `PackageIdentifier` from winget. Fleet uses this to pull the correct metadata for the app. |
| `slug` | string | **Required.** Identifies the app/platform combination (e.g., `box-drive/windows`). Used to name manifest files and reference the app in [Fleet's best practice GitOps](https://fleetdm.com/docs/configuration/yaml-files#fleet-maintained-apps). Format: `<app-name>/<platform>`, where app name is filesystem-friendly and platform is `darwin`. |
| `installer_arch` | string | **Required.** `x64` or `x86` (most apps use `x64`). |
| `installer_type` | string | **Required.** `exe`, `msi`, or `msix` (file type, not vendor tech like "wix") |
| `installer_scope` | string | **Required.** `machine` or `user` (prefer `machine` for managed installs) |
| `default_categories` | string | **Required.** Default categories for self-service if none are specified. Valid values: `Browsers`, `Communication`, `Developer Tools`, `Productivity`. |
| `install_script_path` | string | Filepath to a custom install script (`.ps1`). Overrides the generated install script. Script must be placed in `inputs/winget/scripts/`. For `.msi` apps, the ingestor automatically generates install scripts. Do not add scripts unless you need to override the generated behavior. For `.exe` apps, you must provide PowerShell scripts that run the installer file directly. Fleet stores the installer and sends it to the host at install time; your script must execute it using the `INSTALLER_PATH` environment variable. |
| `uninstall_script_path` | string | Filepath to a custom uninstall script (`.ps1`). Overrides the generated uninstall script. Script must be placed in `inputs/winget/scripts/`. For `.msi` apps, the ingestor automatically generates uninstall scripts. Do not add scripts unless you need to override the generated behavior. For `.exe` apps, you must provide a script to uninstall the app. Scripts for `.exe` apps are vendor-specific. Use the vendors documented silent uninstall switch or the registered UninstallString (if available), ensuring the script runs silently and returns the installers exit code. |
| `fuzzy_match_name` | boolean | If the `unique_identifier` doesn't match the `DisplayName`, use `fuzzy_match_name` to specify that Fleet uses "fuzzy matching" to match the Fleet-maintained app and the inventoried software. For example, for Pritunl, the `unique_identifier` is "Pritunl" and the inventories software's `DisplayName` is "Pritunl Client". With `fuzzy_match_name` set to true, Pritunl app will be matched to the inventories software. |
#### Windows troubleshooting
- App not found in Fleet UI: ensure `apps.json` was updated by the generator and your override URL is correct
- Install fails silently: confirm your `installer_type`, `installer_arch`, and `installer_scope` match the selected winget installer; run your PowerShell script manually on a test host
- Uninstall doesnt remove the app: prefer explicit uninstall scripts; otherwise, ensure the winget manifest exposes `ProductCode` or `UpgradeCode`
- Hash mismatch errors: if the upstream manifest is in flux, you can set `ignore_hash: true` in the input JSON (use sparingly)
#### Can I do this on macOS?
The instructions below are meant to be run on a Windows host. But, you can run most of this on a macOS host, as well:
- You can author Windows inputs and run the generator on macOS. The ingester is Go code that fetches data from winget/GitHub and works crossplatform.
- To find the PackageName and Publisher, you can look in the locale and installer yaml files in the winget-pkgs repo.
- Validation and testing still require a Windows host (to verify programs.name and to run install/uninstall).
## Updating existing Fleet-maintained apps
Fleet-maintained apps need to be updated as frequently as possible while maintaining reliability. This is currently a balancing act as both scenarios below result in customer workflow blocking bugs:
- App vendor updates to installers can break install/uninstall scripts
- App vendors will deprecate download links for older installers
A Github action periodically creates a PR that updates one or more apps in the catalog by:
- Bumping versions
- Regenerating install/uninstall scripts
Each app updated in the PR must be validated independently. Only merge the PR if all apps changed meet the following criteria:
- [X] App can be downloaded using manifest URL
- [X] App installs successfully on host using manifest install script
- [X] App exists on host
- [X] App uninstalls successfully on host using manifest uninstall script
If an app does not pass test criteria:
- [Freeze the app](#freezing-an-existing-fleet-maintained-app)
- File a bug for tracking
## Freezing an existing Fleet-maintained app
If any app fails validation:
1. Do not merge the PR as-is.
2. Add `"frozen": true"` to the failing app's input file (e.g.,`inputs/homebrew/<app>.json`).
3. Revert its corresponding output manifest file (e.g., `outputs/<slug>.json`) to the version in the `main` branch:
```bash
git checkout origin/main -- ee/maintained-apps/outputs/<slug>.json
```
4. Validate changes in the frozen input file by running the following. This should output no errors and generate no changes.
```bash
go run cmd/maintained-apps/main.go --slug="<slug>" --debug
```
5. Commit both the input change and the output file revert to the same PR.