45190 patch policy wrong installer (#46087)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves # Adds a missing `is_active=1` check to get the actual active installer for the software automation's installer. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [x] Added/updated automated tests - [ ] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [x] QA'd all new/changed functionality manually - I tested by pinning the version of the app to the older one, then unpinning and back and checked that the policy is associated to the correct installer with the query below. - I did not manually test updating to a new FMA version. It's possible to do that easily by creating a new branch with a newer version and referring FLEET_DEV_MAINTAINED_APPS_BASE_URL to it. ``` SELECT si.id, si.team_id, si.title_id, si.filename, si.version, si.storage_id, si.uploaded_at, si.updated_at, si.url, si.fleet_maintained_app_id, si.install_during_setup, si.is_active, si.patch_query, si.http_etag, p.patch_software_title_id, p.software_installer_id, p.query FROM software_installers si LEFT JOIN policies p on si.id = p.software_installer_id WHERE filename LIKE "%<app name>%" AND platform = "darwin" AND global_or_team_id = <team id>; ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Patch policies using software install automations now correctly prioritize active installers, ensuring deployment uses the latest appropriate version rather than inactive or outdated alternatives. * **Tests** * Added test scenarios to validate policy installer version selection and active status during automation evaluation. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/46087?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- Fixed a bug where patch policies with software install automations used an inactive, older installer and not the latest.
|
||||
@@ -1373,7 +1373,8 @@ func (ds *Datastore) ApplyPolicySpecs(ctx context.Context, authorID uint, specs
|
||||
VPPAppsTeamsID *uint `db:"vat_id"`
|
||||
}
|
||||
err := sqlx.GetContext(ctx, queryerContext, &ids,
|
||||
`SELECT id si_id, NULL vat_id FROM software_installers WHERE global_or_team_id = ? AND title_id = ?
|
||||
`SELECT id si_id, NULL vat_id FROM software_installers
|
||||
WHERE global_or_team_id = ? AND title_id = ? AND is_active = 1
|
||||
UNION
|
||||
SELECT NULL si_id, vat.id vat_id FROM vpp_apps_teams vat
|
||||
JOIN vpp_apps va ON va.adam_id = vat.adam_id AND va.platform = vat.platform
|
||||
|
||||
@@ -27924,6 +27924,24 @@ func (s *integrationEnterpriseTestSuite) TestPatchPolicies() {
|
||||
require.Equal(t, name, policy.Name)
|
||||
}
|
||||
|
||||
checkPolicyInstaller := func(policyID uint, version string) {
|
||||
var row struct {
|
||||
Version string `db:"version"`
|
||||
IsActive bool `db:"is_active"`
|
||||
}
|
||||
mysqltest.ExecAdhocSQL(t, s.ds, func(q sqlx.ExtContext) error {
|
||||
return sqlx.GetContext(ctx, q, &row,
|
||||
`SELECT si.version, si.is_active
|
||||
FROM policies p
|
||||
JOIN software_installers si ON si.id = p.software_installer_id
|
||||
WHERE p.id = ?`,
|
||||
policyID,
|
||||
)
|
||||
})
|
||||
require.Equal(t, version, row.Version)
|
||||
require.True(t, row.IsActive)
|
||||
}
|
||||
|
||||
createHostPolicyResults := func(host *fleet.Host, policy *fleet.Policy) {
|
||||
distributedResp := submitDistributedQueryResultsResponse{}
|
||||
s.DoJSONWithoutAuth("POST", "/api/osquery/distributed/write", genDistributedReqWithPolicyResults(
|
||||
@@ -28247,6 +28265,7 @@ func (s *integrationEnterpriseTestSuite) TestPatchPolicies() {
|
||||
checkPolicy(listPolResp.Policies[0], spec.Name, "1.0", title.ID)
|
||||
// This is only set if the automation is enable
|
||||
require.Equal(t, title.ID, listPolResp.Policies[0].InstallSoftware.SoftwareTitleID)
|
||||
checkPolicyInstaller(listPolResp.Policies[0].ID, "1.0")
|
||||
|
||||
// Now disable the automation
|
||||
spec = &fleet.PolicySpec{
|
||||
@@ -28325,6 +28344,38 @@ func (s *integrationEnterpriseTestSuite) TestPatchPolicies() {
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/fleets/%d/policies", team.ID), fleet.ListTeamPoliciesRequest{}, http.StatusOK, &listPolResp, "page", "0")
|
||||
require.Len(t, listPolResp.Policies, 1)
|
||||
checkPolicy(listPolResp.Policies[0], spec.Name, "1.0", title.ID)
|
||||
|
||||
// Test 4: FMA upgraded again with two versions already cached.
|
||||
spec = &fleet.PolicySpec{
|
||||
Name: "team patch policy",
|
||||
Query: "SELECT 1",
|
||||
Team: team.Name,
|
||||
Type: fleet.PolicyTypePatch,
|
||||
FleetMaintainedAppSlug: "zoom/windows",
|
||||
SoftwareTitleID: new(title.ID),
|
||||
}
|
||||
|
||||
resetFMAState(states["/zoom/windows.json"], "1.3", []byte("ghi"), "")
|
||||
|
||||
s.DoJSON("POST", "/api/latest/fleet/software/batch",
|
||||
batchSetSoftwareInstallersRequest{Software: []*fleet.SoftwareInstallerPayload{{Slug: ptr.String("zoom/windows")}}, TeamName: team.Name},
|
||||
http.StatusAccepted, &resp,
|
||||
"team_name", team.Name, "team_id", fmt.Sprint(team.ID),
|
||||
)
|
||||
waitBatchSetSoftwareInstallersCompleted(t, &s.withServer, team.Name, resp.RequestUUID)
|
||||
|
||||
applyResp = fleet.ApplyPolicySpecsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/spec/policies",
|
||||
fleet.ApplyPolicySpecsRequest{Specs: []*fleet.PolicySpec{spec}},
|
||||
http.StatusOK, &applyResp,
|
||||
)
|
||||
title = getActiveTitleForTeam(team.ID, "zoom")
|
||||
|
||||
listPolResp = fleet.ListTeamPoliciesResponse{}
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/fleets/%d/policies", team.ID), fleet.ListTeamPoliciesRequest{}, http.StatusOK, &listPolResp, "page", "0")
|
||||
require.Len(t, listPolResp.Policies, 1)
|
||||
checkPolicy(listPolResp.Policies[0], spec.Name, "1.3", title.ID)
|
||||
checkPolicyInstaller(listPolResp.Policies[0].ID, "1.3")
|
||||
})
|
||||
|
||||
t.Run("override and empty queries behave the same", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user