Fix macOS "Update new hosts to latest" staying enabled in GitOps after clearing version/deadline (#45984) (#47602)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #45984 Fix is applied on the GitOps side since that's what I figured the customer was using on the [Slack thread](https://fleetdm.slack.com/archives/C061ZA91Y1J/p1779372669701129). # Checklist for submitter - [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 - [x] QA'd all new/changed functionality manually #### Before Reproduced on `main`: - Set `update_new_hosts: true` beforehand. - Ran `gitops` with `update_new_hosts` commented out. It was still kept as `true`. https://github.com/user-attachments/assets/f6b41f0d-38e6-468f-a605-b3e66b7b2dbc #### After Running `gitops` with `update_new_hosts` commented out switched its value to `false`. https://github.com/user-attachments/assets/24756063-b3a9-400b-a2cc-208dd816a556 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Corrected GitOps behavior for the macOS “Update new hosts to latest” setting so it no longer stays enabled after clearing `minimum_version` and `deadline`; it now defaults to disabled unless both are set. * **Tests** * Added GitOps test coverage to verify the defaulting outcomes across YAML variations for the macOS update settings, including explicit and empty field combinations. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* Fixed an issue where the macOS "Update new hosts to latest" OS update setting could stay enabled in GitOps after `minimum_version` and `deadline` were cleared; when `update_new_hosts` isn't explicitly set, it now defaults to enabled only while a minimum version and deadline are configured.
|
||||
@@ -570,6 +570,100 @@ software:
|
||||
// assert.Equal(t, "hydrant2_secret", h2.ClientSecret)
|
||||
}
|
||||
|
||||
func TestGitOpsMacOSUpdateNewHostsDefault(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
currentlyStoredUpdateNewHosts optjson.Bool
|
||||
macOSUpdatesYAML string
|
||||
wantUpdateNewHosts optjson.Bool
|
||||
}{
|
||||
{
|
||||
name: "empty minimum_version and deadline default update_new_hosts to false",
|
||||
currentlyStoredUpdateNewHosts: optjson.SetBool(true),
|
||||
macOSUpdatesYAML: `
|
||||
macos_updates:
|
||||
deadline: ""
|
||||
minimum_version: ""`,
|
||||
wantUpdateNewHosts: optjson.SetBool(false),
|
||||
},
|
||||
{
|
||||
name: "configured minimum_version and deadline default update_new_hosts to true",
|
||||
currentlyStoredUpdateNewHosts: optjson.SetBool(false),
|
||||
macOSUpdatesYAML: `
|
||||
macos_updates:
|
||||
deadline: "2024-03-03"
|
||||
minimum_version: "14.6.1"`,
|
||||
wantUpdateNewHosts: optjson.SetBool(true),
|
||||
},
|
||||
{
|
||||
// "Update all new hosts to latest" with no minimum version is a valid config, so an
|
||||
// explicit update_new_hosts: true must be honored even when version/deadline are empty.
|
||||
name: "explicit update_new_hosts true is honored without minimum_version or deadline",
|
||||
currentlyStoredUpdateNewHosts: optjson.SetBool(false),
|
||||
macOSUpdatesYAML: `
|
||||
macos_updates:
|
||||
deadline: ""
|
||||
minimum_version: ""
|
||||
update_new_hosts: true`,
|
||||
wantUpdateNewHosts: optjson.SetBool(true),
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
license := &fleet.LicenseInfo{Tier: fleet.TierPremium, Expiration: time.Now().Add(24 * time.Hour)}
|
||||
_, ds := testing_utils.RunServerWithMockedDS(t, &service.TestServerOpts{
|
||||
License: license,
|
||||
KeyValueStore: testing_utils.NewMemKeyValueStore(),
|
||||
})
|
||||
|
||||
// Mock Apple GDMF API (required for validating OS update minimum version settings).
|
||||
mdmtest.StartNewAppleGDMFTestServer(t)
|
||||
|
||||
setupEmptyGitOpsMocks(ds)
|
||||
|
||||
storedUpdateNewHosts := c.currentlyStoredUpdateNewHosts
|
||||
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
|
||||
cfg := &fleet.AppConfig{}
|
||||
cfg.MDM.MacOSUpdates.UpdateNewHosts = storedUpdateNewHosts
|
||||
return cfg, nil
|
||||
}
|
||||
savedAppConfig := &fleet.AppConfig{}
|
||||
ds.SaveAppConfigFunc = func(ctx context.Context, config *fleet.AppConfig) error {
|
||||
savedAppConfig = config
|
||||
return nil
|
||||
}
|
||||
ds.HasAppleUpdateConfigProfileConfiguredFunc = func(ctx context.Context, teamID uint) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
t.Setenv("FLEET_SERVER_URL", "https://fleet.example.com")
|
||||
|
||||
tmpFile, err := os.CreateTemp(t.TempDir(), "*.yml")
|
||||
require.NoError(t, err)
|
||||
_, err = tmpFile.WriteString(`
|
||||
controls:` + c.macOSUpdatesYAML + `
|
||||
queries:
|
||||
policies:
|
||||
labels:
|
||||
agent_options:
|
||||
org_settings:
|
||||
server_settings:
|
||||
server_url: $FLEET_SERVER_URL
|
||||
org_info:
|
||||
contact_url: https://example.com/contact
|
||||
org_name: GitOps Test
|
||||
secrets:
|
||||
software:
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
|
||||
_ = runAppForTest(t, []string{"gitops", "-f", tmpFile.Name()})
|
||||
require.Equal(t, c.wantUpdateNewHosts, savedAppConfig.MDM.MacOSUpdates.UpdateNewHosts)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGitOpsWindowsEntraIDs verifies that Windows Entra tenant and application client IDs round-trip through a
|
||||
// `fleetctl gitops` apply (issue #46388). The client IDs include an upper-case GUID and a case-only duplicate of it,
|
||||
// which exercises server-side normalization: client IDs are authorized case-insensitively, so they are stored
|
||||
|
||||
@@ -2388,10 +2388,13 @@ func (c *Client) DoGitOps(
|
||||
macOSUpdates["deadline"] = ""
|
||||
}
|
||||
|
||||
// To keep things backward compatible, if a minimum_version and deadline are both set but the user hasn't set update_new_hosts,
|
||||
// then we default update_new_hosts to true
|
||||
if macOSUpdates["minimum_version"] != "" && macOSUpdates["deadline"] != "" && macOSUpdates["update_new_hosts"] == nil {
|
||||
macOSUpdates["update_new_hosts"] = true
|
||||
// When update_new_hosts isn't explicitly set, derive it from whether OS updates
|
||||
// are configured: default to true when both minimum_version and deadline are set
|
||||
// (kept for backward compatibility) and false otherwise. Defaulting to false when
|
||||
// updates aren't configured prevents a previously stored "true" from sticking
|
||||
// around once minimum_version/deadline are cleared.
|
||||
if macOSUpdates["update_new_hosts"] == nil {
|
||||
macOSUpdates["update_new_hosts"] = macOSUpdates["minimum_version"] != "" && macOSUpdates["deadline"] != ""
|
||||
}
|
||||
|
||||
// Put in default values for ios_updates
|
||||
|
||||
Reference in New Issue
Block a user