Skip to content

Patch policies: Install new version when app is closed #39962

Description

@noahtalerman

Goal

User story
As an IT admin,
I want to install the latest version of a Fleet-maintained app when the app is closed
so that I can patch outdated software w/o bothering my end users.

Changes

Product

Engineering

  • Test plan is finalized
  • Contributor API changes: patch_when_closed on create/update fleet-level policy and update-package ([API] Patch policies: Install new version when app is closed #49021); install_skipped_when_app_open on the installed_software activity ([Activity] Patch policies: Install new version when app is closed #49106).
  • Feature guide changes: Update the patch-management / automatic-install guide to cover "patch only when app is closed."
  • Database schema migrations: Yes. policies.patch_when_closed (bool) and a new managed pre-install-query column on software_installers (mirrors patch_query). One migration.
  • Load testing: Not required. The managed query runs on the host exactly like today's pre-install query, and the policy path already resets retry attempts each run.
  • Pre-QA load test: Not required.
  • Load testing/osquery-perf improvements: None.
  • This is a premium only feature: Yes. Patch policies, continuous automations, and FMA installers are premium; the new field inherits the gate. Both frontend and backend are protected.

ℹ️  Please read this issue carefully and understand it. Pay special attention to UI wireframes, especially "dev notes".

QA

Risk assessment

  • Requires testing in a hosted environment: No. Local dev with macOS and Windows hosts is sufficient.
  • Requires load testing: No.
  • Risk level: Low
  • Regression watch: the retry-cap bypass must key on the managed "app open" query, not on empty pre-install output globally — an ordinary empty pre_install_query result must still fail and count toward the 3-retry limit. The managed query must be ignored for self-service, manual, and setup-experience installs.

Test plan

Make sure to go through the list and consider all events that might be related to this story, so we catch edge cases earlier.

Core flow

Add Fleet-maintained app flow

  • Add FMA → Force install checked → no "End user experience" dropdown shown. Policy that checks if software is installed created, no patch policy, no pre-install query.
  • Add FMA → Patch only checked, Patch only when app is closed selected by default → managed read-only pre-install query added (from manifest), patch policy created, continuous_automations_enabled automatically set true, and can't be changed (disabled).
  • Add FMA → Patch only checked, Force patch selected → patch policy created, no managed pre-install query, app updates even while running.
  • Force install + Patch both selected → "Auto install" pill modal on software title details page shows both policies. Verify Force install policy is unaffected by the app's open/closed state (it only checks if installed and installs as soon as it fails).

Software title details — Deploy options edit

  • Existing app with no automation → enable Patch and Patch only when closed hit save → policy created and pre-install query added after the fact, not just at add-time.
  • Uncheck Patch and save → patch policy and read-only pre-install query are deleted. Other policies referencing the same title untouched.
  • Uncheck Force install and save → only the force-install policy deleted, patch policy left alone.
  • Disable both options (force install and patch) and save → title reverts to plain non-automated software
  • Switch "Patch only when app is closed" → "Force patch" and save → pre-install query removed. Next run installs even while app is open
  • Directly edit the policy and change it to an option other than Patch only when closed enabled, and make sure the continuous automation checkbox is disabled.
  • Attempt to directly set pre_install_query via API on a title with patch_only_when_closed: true → rejected, not silently overwritten
  • Enable Patch only when app is closed on a title that already has a manually-configured pre_install_query (e.g. an OS-version check) → existing query is replaced and read-only.
  • Update package API -> set patch_only_when_closed while patch is false/absent → rejected with the new validation error
  • Make sure that Deploy modal (Software > Actions > Deploy) shows the correct state even when the patch is enabled outside of the UI. e.g user used API to create a patch policy and didn't enable install software automation. In the UI, in the Deploy modal, Patch checkbox will be selected and End user initiated option in End user experience dropdown will be selected.

Policy details / Activities / retry

  • App open when policy runs (automation-triggered) → shown as "Install skipped" (not "Failed") in activity feed (global/host), and policy details -> automation runs. Activity has install_skipped_when_app_open: true.
  • When pre-install query fails, install is NOT retried 2 more times.
  • Regression check: a different, ordinary pre_install_query (not the managed one) still fails normally and still counts toward the 3-retry limit — skip logic must not apply globally to all empty pre-install query results
  • App closes between runs → next continuous-automation run installs successfully; activity has no skip flag
  • App stays open across many consecutive runs → repeated "Install skipped" activities, no crash/log-spam issue, never hits the old 3-attempt cutoff
  • Managed pre-install query is ignored (install proceeds regardless of app state) for: self-service install, manual install from Host details > Software > Library, Setup Experience install — verify all three explicitly
  • Install details modal / host activity feed show the exact "app was open" copy — not the generic pre-install-query-failed copy used elsewhere
  • Delete the patch policy → gating query is cleaned up

GitOps

  • Apply with patch_only_when_closed: true + continuous_automations_enabled: false explicit → rejected
  • Apply with patch_only_when_closed: true, continuous_automations_enabled omitted → auto-set to true; a repeat apply is a no-op
  • Apply with pre_install_query.path set on the FMA entry while a referencing policy has patch_only_when_closed: true → rejected
  • Backward compatibility: an existing patch policy with no patch_only_when_closed key, applied post-upgrade → behavior unchanged, no managed query silently added
  • Remove patch_only_when_closed/patch block from YAML on a later apply → policy/query torn down to match, same as the UI's uncheck-and-save
  • fleetctl generate-gitops on a title with patch_only_when_closed enabled → emits it correctly (round-trip)

Edge cases

  • TODO

Supplemental testing

Testing notes

Confirmation

  1. Engineer: Added comment to user story confirming successful completion of test plan (include any special setup, test data, or configuration used during development/testing if applicable).
  2. QA: Added comment to user story confirming successful completion of test plan.
  3. QA: Determined whether this story needs Playwright automation.
    • Needs automation: Yes / No
    • If yes, filed a follow-up issue in the :help-qa project with status "Needs automation":

Metadata

Metadata

Assignees

Labels

#g-auto-patchingProduct group focused on auto patching softwarestoryA user story defining an entire feature~macos-app-patchingProduct maturity category~product-maturityContributes to Fleet's product maturity goals for the current year

Type

No type

Projects

Status
No status
Status
✔️Awaiting QA

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions