Skip to content

Patch when closed: migration, types, and FMA manifest "is app open" query #49415

Description

@cdcme

Related user story

#39962

Task

Lay the data foundation: a migration adding patch_when_closed to policies and a managed pre-install-query column to software_installers, the Go types, and the FMA-manifest pipeline that authors an "is app open?" query per app and hydrates it into the managed column. Ships the managed query end-to-end into the installer so the config-API and runtime sub-issues can build on it.

Migration

  • Add patch_when_closed tinyint(1) NOT NULL DEFAULT 0 to policies (near continuous_automations_enabled, schema.sql:2580).
  • Add a managed pre-install-query column to software_installers, mirroring patch_query text NOT NULL (schema.sql:3129) — e.g. app_open_query text NOT NULL DEFAULT ''. It holds the manifest "is app open?" query; user pre_install_query (:3111) is untouched.
  • Follow .claude/rules/fleet-database.md: make migration name=PatchWhenClosed, Up + no-op Down, matching _test.go.

Go types

  • server/fleet/policies.go: add PatchWhenClosed to PolicyPayload (:67 area), NewTeamPolicyPayload (:125), ModifyPolicyPayload (:348, *bool), and PolicyData (db:"patch_when_closed", :442 area).
  • server/fleet/software_installer.go: add the managed-query field to SoftwareInstaller (:97 area) and UploadSoftwareInstallerPayload.
  • server/fleet/maintained_apps.go: add the new query field to MaintainedApp (db:"app_open_query", beside AutomaticInstallQuery/PatchQuery, :18-21).

FMA manifest pipeline

  • FMAQueries (ee/maintained-apps/maintained_apps.go:19-22): add the open field; update IsEmpty() (:66).
  • Author the query in ee/maintained-apps/ingesters/homebrew/ingester.go (~:149/:208, alongside Exists/Patched) and ingesters/winget/ingester.go. macOS: a query that returns a row when the app process is not running (install proceeds only if closed); Windows equivalent. Reuse the dogfood queries from Update apps when closed #48662 (it-and-security/lib/**/pre-install-queries/is-<app>-running.yml) as the source of truth for per-app process names.
  • Emit queries.open in ee/maintained-apps/outputs/<app>/*.json (regenerate).
  • Hydrate in server/mdm/maintainedapps/sync.go:257-260 and persist via UpsertMaintainedApp (server/datastore/mysql/maintained_apps.go:23).
  • Write it to the managed column in AddFleetMaintainedApp (ee/server/service/maintained_apps.go:166-190).

Why author per platform, not one generic query: process names differ by OS and app; the manifest already carries per-platform exists/patched, so open follows the same pattern. Why reuse #48662's queries: they're already validated in Fleet's own dogfood.

Condition of satisfaction

Migration (MYSQL_TEST=1 go test ./server/datastore/mysql/...):

  • applyUpToPrevapplyNext adds both columns with correct types/defaults; existing rows get patch_when_closed=0 and empty managed query.

Manifest pipeline (go test ./ee/maintained-apps/...):

  • Ingesters emit queries.open for macOS and Windows apps; FMAQueries.IsEmpty() accounts for the new field.
  • Hydrate maps queries.open into the new MaintainedApp field; UpsertMaintainedApp round-trips it.
  • Adding an FMA writes the managed query into the installer column.

Negative: an FMA with no open query hydrates to an empty managed query and behaves exactly as today.

  • Run make generate-mock if the datastore interface changes; go test ./server/service/ after.

Metadata

Metadata

Assignees

Labels

#g-auto-patchingProduct group focused on auto patching software~backendBackend-related issue.~sub-taskA technical sub-task that is part of a story. (Not QA'd. Not estimated.)

Type

Projects

Status
✅ Ready for release

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions