You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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/...):
applyUpToPrev → applyNext 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.
Related user story
#39962
Task
Lay the data foundation: a migration adding
patch_when_closedtopoliciesand a managed pre-install-query column tosoftware_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
patch_when_closed tinyint(1) NOT NULL DEFAULT 0topolicies(nearcontinuous_automations_enabled,schema.sql:2580).software_installers, mirroringpatch_query text NOT NULL(schema.sql:3129) — e.g.app_open_query text NOT NULL DEFAULT ''. It holds the manifest "is app open?" query; userpre_install_query(:3111) is untouched..claude/rules/fleet-database.md:make migration name=PatchWhenClosed,Up+ no-opDown, matching_test.go.Go types
server/fleet/policies.go: addPatchWhenClosedtoPolicyPayload(:67area),NewTeamPolicyPayload(:125),ModifyPolicyPayload(:348,*bool), andPolicyData(db:"patch_when_closed",:442area).server/fleet/software_installer.go: add the managed-query field toSoftwareInstaller(:97area) andUploadSoftwareInstallerPayload.server/fleet/maintained_apps.go: add the new query field toMaintainedApp(db:"app_open_query", besideAutomaticInstallQuery/PatchQuery,:18-21).FMA manifest pipeline
FMAQueries(ee/maintained-apps/maintained_apps.go:19-22): add theopenfield; updateIsEmpty()(:66).ee/maintained-apps/ingesters/homebrew/ingester.go(~:149/:208, alongsideExists/Patched) andingesters/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.queries.openinee/maintained-apps/outputs/<app>/*.json(regenerate).server/mdm/maintainedapps/sync.go:257-260and persist viaUpsertMaintainedApp(server/datastore/mysql/maintained_apps.go:23).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, soopenfollows 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/...):applyUpToPrev→applyNextadds both columns with correct types/defaults; existing rows getpatch_when_closed=0and empty managed query.Manifest pipeline (
go test ./ee/maintained-apps/...):queries.openfor macOS and Windows apps;FMAQueries.IsEmpty()accounts for the new field.Hydratemapsqueries.openinto the newMaintainedAppfield;UpsertMaintainedAppround-trips it.Negative: an FMA with no
openquery hydrates to an empty managed query and behaves exactly as today.make generate-mockif the datastore interface changes;go test ./server/service/after.