Capture Windows FMA process names for the "app open" query - #50827
Closed
allenhouchins wants to merge 1 commit into
Closed
Capture Windows FMA process names for the "app open" query#50827allenhouchins wants to merge 1 commit into
allenhouchins wants to merge 1 commit into
Conversation
The Windows "app open" pre-install query (FMAQueries.Open) that gates patching a running app had no per-app source of truth for the process name. It came from a hard-coded windowsOpenQueryOverrides map keyed by catalog name (51 of 434 winget inputs), falling back to guessing "<lowercased name>.exe" for everything else. A wrong process name fails green: NOT EXISTS over a predicate that never matches is always true, so the app always reads as "closed" and Fleet patches over a running app with no error anywhere. Add a process_names array to the winget input JSON, so the names can be captured from the installer at authoring time alongside the other identity fields, instead of requiring an edit to a shared map in another package. Entries are validated at ingest (must be a bare file name ending in .exe, or in "*" for a prefix match) rather than best-effort corrected, since a malformed name is invisible at runtime. Multiple exact names collapse to IN (...); a prefix entry becomes LIKE; mixing the two yields a parenthesized OR. Precedence is process_names, then the override map, then the guess. This also folds in #50825, which touches the same function: a multi-word catalog name with no process_names and no override now emits no open query at all rather than an unmatchable guess, and Open is omitempty. That PR is superseded by this one. The two compose so that process_names is what gives a multi-word app a working gate. macOS needs none of this and passes nil: its open query joins apps.path to processes.path, so the bundle identifier already resolves the running process. Windows has no equivalent because programs.install_location is unreliable, especially for MSI installers. 7-zip is included as a worked example, with the two process names read out of its MSI File table. It regenerates byte-identically to its previous curated map entry. The new-fma skill and the contributor README document how to read process names out of each installer type (msiinfo for MSI, AppxManifest for MSIX, 7zz for NSIS), which tools fail and where (innoextract only supports through Inno 6.0.5), and to fall back to the validator log rather than guessing.
allenhouchins
temporarily deployed
to
Docker Hub
August 8, 2026 03:35 — with
GitHub Actions
Inactive
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #50827 +/- ##
=======================================
Coverage 68.53% 68.54%
=======================================
Files 3977 3977
Lines 256168 256216 +48
Branches 13818 13818
=======================================
+ Hits 175566 175623 +57
+ Misses 64982 64978 -4
+ Partials 15620 15615 -5
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Member
Author
|
Closing in favor of a combined branch: these changes are being kept together with the Windows open-query audit (which will populate process_names across the catalog), so one PR carries the mechanism and the data. The commit is preserved as-is on the new branch. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checklist for submitter
Changes file added for user-visible changes in
changes/,orbit/changes/oree/fleetd-chrome/changes.See Changes files for more information.
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.Testing
Details
Important
This supersedes #50825 — that PR touched the same function, so it was folded in here rather than merged separately. Please close #50825 rather than merging both.
The problem
The Windows "app open" pre-install query (
FMAQueries.Open) is the gate that holds a patch back until the user closes the app. It had no per-app source of truth for the process name: it came from the hard-codedwindowsOpenQueryOverridesmap inpkg/patch_policy/patch_policy.go, keyed by catalogname, which covers 51 of 434 winget inputs. Everything else fell back to guessing<lowercased name>.exe.A wrong process name fails green.
NOT EXISTSover a predicate that never matches is always true, so the app always reads as "closed" and Fleet patches over a running app — no error, anywhere. 183 of the uncovered apps have a space in the name ("AWS Client VPN"→aws client vpn.exe), where the guess cannot be right.Editing a shared map in
pkg/patch_policyis also the wrong place for it: the key is the catalogname, which macOS and Windows FMAs deliberately share to group in the library.The change
A
process_namesarray on the winget input JSON, so the names are captured from the installer at authoring time next to the other identity fields:{ "name": "7-zip", "unique_identifier": "7-Zip", "process_names": ["7zFM.exe", "7zG.exe"] }patch_policy.ValidateProcessNames— each entry must be a bare file name ending in.exe, or in*for a prefix match. Malformed entries hard-error rather than being best-effort corrected, because the runtime symptom is invisible.= 'x.exe', several collapse toIN (...), a trailing*becomesLIKE 'x%'(for apps that run many differently-named helpers, e.g.1password*), and mixing the two yields a parenthesized OR.process_names→windowsOpenQueryOverrides→<name>.exeguess. Apps can migrate off the map without touching it.Folded in from #50825: a multi-word catalog name with no
process_namesand no override now emits no open query at all rather than an unmatchable guess, andQueries.Openisomitempty. The two changes compose —process_namesis what gives a multi-word app a working gate in the first place.macOS is unaffected and passes
nil. Its open query joinsapps.pathtoprocesses.path, so the bundle identifier already resolves the running process. Windows has no equivalent becauseprograms.install_locationis unreliable, especially for MSI installers.Documentation
The
new-fmaskill and the contributor README now document how to read process names out of each installer type, verified against real installers rather than assumed:msiinfo export … Shortcut/FileShortcut.Target([#_7zFM.exe]) is the user-facing exeunzip -p app.msix AppxManifest.xmlExecutable="app\Slack.exe"7zz l app.exenotepad++.exe,updater/GUP.exeinnoextract -l -m7zzcan't read Inno eitherWhen the installer won't open, the guidance is to ship without
process_namesand read the exe off the validator log — it installs on a real Windows host, where ARPDisplayIconandInstallLocationare visible — rather than guessing.Testing
Unit tests cover the predicate shapes, escaping, dedupe/trim, precedence over the map, the multi-word drop, and the interaction between the two:
"XnSoft XnConvert"gets a working query withprocess_namesand nothing without it.Manually verified by regenerating one app on each side of the new branch point:
process_names) →IN ('7zfm.exe','7zg.exe'), byte-identical to the curated map entry it replacesopenkey, zero-line diff viaomitemptygo testpasses forpkg/patch_policy, both ingesters, andserver/mdm/maintainedapps(which consumesQueries.Openand is unaffected by the empty value).gofmt,go vet, fullgo build ./..., andGOOS=windows go build ./cmd/maintained-apps/validate/are clean.Note
make lint-go-incrementalcould not be run locally — building the custom golangci-lint binary requires cloning from GitHub, which the sandbox blocks. Relying on CI for the lint pass.Notes for reviewers
GenerateOpenQuerygained a fourth parameter; both call sites and the tests are updated.openkey, so the rest pick these up on the next scheduled ingest.process_namesis a reasonable follow-up but would regenerate 51 outputs, so it is deliberately not in this PR.