Files
fleet/website
kitzy f4d7064f9a Add Rtools as a Windows FMA (#50028)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** #50020

# What this does

Adds **Rtools** as a Windows Fleet-maintained app. One of the 11 apps
split out of #48501 that failed the FMA validator; #50016 shipped the 6
that passed.

## Why it was failing

The install script hit the validator's 10-minute `executeScript` cap
exactly:

```
20:41:22  INFO  msg="Executing install script..." app=Rtools
20:51:22  ERROR msg="Error executing install script: exit status 1"   # exactly 10:00 later
20:51:22  WARN  msg="failed to remove rtools45-6768-6492.exe: ... Access is denied."
```

The locked installer in the temp dir shows a process was still alive.
`Start-Process -Wait` waits for the process *and all of its
descendants*, which is the same root cause as the other install-timeout
apps in this batch.

Rtools is also the one app in the batch where a **slow unpack** is a
plausible second cause — the installer is ~460 MB and expands a full
toolchain. So rather than assume, the script now waits on the installer
process alone with a 480s cap (under the caller's 10-minute budget) and
logs elapsed time plus Add/Remove Programs registration state on every
poll. If the cap is reached:

- **registered** → the install finished and only a lingering child
remains, so it stops that process and succeeds;
- **not registered** → the unpack genuinely didn't finish, and it fails
with that stated explicitly.

Either way the CI log now says which one happened instead of just timing
out.

## Notes

- **Identity verified against the installer**, not winget metadata. The
setup stub's PE version resource reads `CompanyName: The R Foundation`,
`ProductName: Rtools`. Inno derives `VersionInfoCompany` from
`AppPublisher`, so the ARP publisher is `The R Foundation` — which is
what the exists query uses.
- **Versioned ARP name.** The registry `DisplayName` is `Rtools 4.5
(6768-6492)`, so the input uses `fuzzy_match_name` and the exists query
is `name LIKE 'Rtools %'`.
- Installs to `C:\rtools45`, not Program Files, so the validator's "no
changes detected in `C:\Program Files`" line is an expected warning, not
a failure.
- Ships a new catalog icon and website asset.

# Checklist for submitter

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops

## Testing

- [x] FMA CI validator (install → detect → uninstall) **passes** on the
SYSTEM-context Windows runner — [run
30384196159](https://github.com/fleetdm/fleet/actions/runs/30384196159)
(`All checks passed`)
- [x] Generated output verified locally: manifest SHA matches the winget
manifest, exists/patched queries checked against the installer's PE
version resource, `apps.json` is valid JSON with a description filled
in.
- [x] QA'd all new/changed functionality manually




<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Added Rtools as a supported Windows application.
* Added installation and uninstallation support with silent setup and
silent removal.
* Added Rtools version metadata, installer verification, and Developer
tools categorization.
  * Added a dedicated Rtools icon for software listings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-28 23:01:31 -05:00
..

fleetdm.com

This is where the code for the public https://fleetdm.com website lives.

Bugs

To report a bug or make a suggestion for the website, create an issue in the fleet GitHub repository.

Testing locally

See https://fleetdm.com/handbook/engineering#test-fleetdm-com-locally

Deploying the website

To deploy changes to the website to production, merge changes to the main branch. If the changes affect the website's code, or touch any files that the website relies on to build content, such as the query library, osquery schema, docs, handbook, articles, etc., then the website will be redeployed.

Wondering how this works? This is implemented in a GitHub action in this repo. Check out the code there to see how it works! For help understanding what sails run and npm run commands in there do, check the scripts in website/package.json and in website/scripts/.

Changing the database schema

To deploy new code to production that relies on changes to the database schema or other external systems (e.g. Stripe), first put the website in "maintenance mode" in Heroku. Then, make your changes in the database schema. Next, if you have a script to fix/migrate existing data, go ahead and run it now. (e.g. sails run fix-or-migrate-existing-data). Then, merge your changes and wait for the deploy to finish. Finally, switch off "maintenance mode" in Heroku.

Note that entering maintenance mode prevents visitors from using the website, so it should be used sparingly, and ideally at low-traffic times of day.

Warning: Doing an especially sensitive schema migration? There is a potential timing issue to consider, thanks to an infrastructure change that eliminated downtime during deploys by using Heroku's built-in support for hot-swapping. Read more in https://github.com/fleetdm/fleet/issues/6568#issuecomment-1211503881

Wiping the production database

I hope you know what you're doing. The "easiest" kind of database schema migration:

sails_datastores__default__url='REAL_DB_URI_HERE' sails run wipe

Then when you see the sailboat, hit CTRL+C to exit. All done!