Skip to content

Send browser User-Agent when downloading FMA installers - #49123

Closed
allenhouchins wants to merge 2 commits into
mainfrom
fma-installer-browser-ua
Closed

Send browser User-Agent when downloading FMA installers#49123
allenhouchins wants to merge 2 commits into
mainfrom
fma-installer-browser-ua

Conversation

@allenhouchins

@allenhouchins allenhouchins commented Jul 10, 2026

Copy link
Copy Markdown
Member

Related issue: N/A

What changed

DownloadInstaller (server/mdm/maintainedapps/installers.go) now sets a browser-like User-Agent header (a current desktop Chrome string) on the download request instead of letting Go send its default Go-http-client/1.1.

Why

Several legitimate vendor download hosts return HTTP 403 to non-browser User-Agents, which blocked Fleet from downloading their installers and blocked the FMA CI validator (cmd/maintained-apps/validate). Confirmed cases:

  • dl.dell.com — used by Dell Display and Peripheral Manager
  • www.crestron.com — used by Crestron AirMedia / AirMedia Peripherals

Both were dropped from the Windows FMA batches (letter C #48969, letter D #49086) solely for this reason. This change unblocks re-adding them (and Dell products generally) as FMAs in a follow-up.

Reviewer notes

  • Single choke point: all three download paths route through DownloadInstaller — runtime install (ee/server/service/maintained_apps.go), auto-update (ee/server/service/maintained_apps_auto_update.go), and the CI validator (cmd/maintained-apps/validate/main.go). The validator has no separate downloader, so the one change covers every path.
  • Client conventions unchanged: callers still build their client via fleethttp.NewClient() / http.DefaultClient; the header is set per-request.
  • Ingester unaffected: the winget ingester reads InstallerSha256 from the winget manifest rather than downloading the installer, so JSON generation was never blocked — only the download paths were.
  • No impact on existing downloads: hosts that ignore the User-Agent (S3, GitHub releases) behave identically. The pre-existing filename-extraction test (redirects + fallback) still passes.

Checklist for submitter

  • Changes file added for user-visible changes in changes/.

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Added TestInstallerBrowserUserAgent: a server that returns 403 to an empty or Go-http-client User-Agent (mimicking the vendor hosts); the download succeeds only because DownloadInstaller sends a browser-like User-Agent, and the test asserts the sent value matches the browserUserAgent constant. The existing TestInstallerFilenameExtraction still passes, confirming no regression for UA-agnostic hosts.

Some legitimate vendor download hosts (e.g. dl.dell.com, www.crestron.com)
return HTTP 403 to requests using Go's default "Go-http-client/1.1"
User-Agent, which blocked Fleet from downloading their installers and also
blocked the FMA CI validator. DownloadInstaller now sets a browser-like
User-Agent header on the request, covering the runtime install, auto-update,
and validator paths (all route through this function). Hosts that don't
inspect the User-Agent (S3, GitHub releases) are unaffected.

This unblocks re-adding Dell and Crestron products as Windows FMAs.
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.98%. Comparing base (f5531fd) to head (ab39e23).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #49123      +/-   ##
==========================================
- Coverage   67.98%   67.98%   -0.01%     
==========================================
  Files        3744     3744              
  Lines      237627   237628       +1     
  Branches    12525    12525              
==========================================
- Hits       161548   161542       -6     
- Misses      61490    61494       +4     
- Partials    14589    14592       +3     
Flag Coverage Δ
backend 69.54% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

allenhouchins added a commit that referenced this pull request Jul 10, 2026
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** N/A

## What changed

Re-adds two Windows Fleet-maintained apps that were dropped from the
letter C batch (#48969) **solely** because `www.crestron.com` returns
HTTP 403 to Fleet's default Go `User-Agent`:

- **Crestron AirMedia** (`Crestron.AirMedia`)
- **Crestron AirMedia Peripherals** (`Crestron.AirMediaPeripherals`)

Each gets an input JSON, a generated output, an `apps.json` catalog
entry with description, a frontend icon component (+ `index.ts`
registration), and a website icon PNG. Both are machine-scope MSIs (WiX)
with upgrade-code uninstall; restored from their pre-drop state with
outputs regenerated against the current winget manifests (versions
unchanged: `5.11.1.164` / `1.11.1.164`, SHAs match).

## ⚠️ Depends on #49123

The 403 is fixed by #49123 (browser `User-Agent` in
`DownloadInstaller`). Until #49123 merges and this branch is rebased on
it, the FMA validator (`cmd/maintained-apps/validate`) will 403
downloading these installers. Merge #49123 first, then rebase/re-run CI
here.

## Validation

Run on a Windows validator with the #49123 UA fix in place — **both apps
passed**: downloaded (confirming the UA fix unblocks
`www.crestron.com`), installed, found via the exists query, and
uninstalled cleanly. The `no changes in C:\Program Files` line is benign
(they install elsewhere; the exists query still finds them).

## Dell Display and Peripheral Manager — investigated, dropped (not
viable as an FMA)

DDPM was verified and included in early revisions of this PR, then
dropped. Its InstallShield (InstallScript) setup aborts with
`0x80042000` in the validator's session-0 SYSTEM context across
**every** documented silent switch — `/Silent`, `/S`, and `/Silent
/HeadlessMode=true` all failed. Per silentinstallhq, DDPM 2.0+ requires
the Windows Desktop Runtime (.NET) prerequisite installed first
(extracted from the installer's own prerequisites folder), and its
bundled InstallShield prerequisite chaining doesn't cooperate with a
headless SYSTEM install; Dell's own community thread for this exact
scenario (task sequence = SYSTEM) is unresolved. An FMA install script
can't reliably extract-and-chain a runtime that may require a reboot,
and DDPM only benefits hosts with Dell displays — so it's not a viable
FMA. The identity work (verified DisplayName/publisher from the real
installer) is recorded in the commit history if it's ever revisited.

# Checklist for submitter

- [ ] Changes file — N/A (FMA catalog data, consistent with prior letter
batches which add no `changes/` entry).

## Testing

- [x] Ran the ingester for both slugs; outputs + `apps.json` regenerated
and validated as JSON.
- [x] QA'd via the Windows FMA validator — both Crestron apps passed
(with the #49123 UA fix present).
allenhouchins added a commit that referenced this pull request Aug 5, 2026
…lient-OS runner (#50313)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** NA (Windows FMA workstream; follow-up to #49127,
which dropped DDPM)

Re-adds **Dell Display and Peripheral Manager**
(`Dell.DisplayAndPeripheralManager` 2.2.2.8) as a Windows
Fleet-maintained app, and adds a `requires_client_os` routing override
so its CI validation always runs on the `windows-11-arm` runner.

## Why DDPM was dropped before, and why it's viable now

DDPM was dropped from the earlier re-add because its InstallShield setup
aborted with `0x80042000` under every documented silent switch, which
was diagnosed at the time as a .NET-prerequisite/headless-chaining
problem. A new debug run with Dell's own `/CreateDebugLog` switch shows
the real cause: the setup evaluates the OS at `OFUIBefore` and
terminates because the runner reports **Microsoft Windows Server 2025**.
DDPM is a Windows 10/11 client application and refuses to install on
Server SKUs — which is exactly what GitHub's x64 `windows-latest` image
is.

```
OSetUMode() 0 AP:2.2.2.8
OFUIBefore
Os Major10 Minor0
OS - 44444
// End Log File...
```

## `requires_client_os` CI routing

- New optional winget input field `requires_client_os: true` (documented
in `ee/maintained-apps/README.md` and on the Go input struct; ignored by
ingestion).
- `.github/scripts/partition-fma-apps.sh` routes any app with this flag
to `windows-11-arm` — the only GitHub-hosted client-OS Windows runner —
regardless of `installer_arch`. The x64 installer runs there under Prism
emulation; DDPM's gate is the OS SKU, not the architecture.
- Verified locally: partitioning the full 421-app Windows catalog
reroutes only `dell-display-and-peripheral-manager/windows`.

## App identity (verified against the real installer)

- Downloaded `DDPM-Setup_2.2.2.8.exe` from `dl.dell.com` (Chrome UA per
#49123); SHA256 matches the winget manifest.
- Embedded InstallShield `[Application]` block: `Name=Dell Display and
Peripheral Manager`, `Company=Dell Technologies`; ProductCode matches
the manifest GUID. The setup log reports `AP:2.2.2.8` as the registering
version.
- Installs with Dell's documented managed-deployment switches `/Silent
/HeadlessMode=true /TelemetryConsent=false /TurnOffCA` — the final
pre-drop iteration (6d0f2c0), which also declines telemetry and
disables DDPM's self-updater on Fleet-managed hosts. Uninstalls via
`msiexec /x` on the ProductCode looked up in the registry by
DisplayName.

Input/uninstall script/icon are restored from the pre-drop state; the
install script is the final pre-drop iteration with its root-cause
comment corrected (Server-SKU OS gate, not headless-SYSTEM chaining).
Output regenerated (winget still at 2.2.2.8; script refs verified).

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [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] QA'd all new/changed functionality manually (partition script
exercised locally over the full catalog and a mixed PR-style slug list;
ingester regenerated with no output drift; `go test
./ee/maintained-apps/ingesters/winget/` passes)
- [ ] `test-fma-windows-pr-only` validates DDPM on the `windows-11-arm`
runner in this PR's CI


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

* **New Features**
* Added Dell Display and Peripheral Manager to the Windows software
catalog, including installation, uninstallation, detection, metadata,
and an app icon.
* Added support for routing applications that require a Windows client
operating system to the appropriate Windows 11 ARM test environment.

* **Documentation**
* Documented Windows client operating system routing behavior and test
environment architecture details.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant