Adjust Nudge configuration to match the specification (#9519)

Related to #9013 this adjusts the Nudge configuration to match the spec.
This commit is contained in:
Roberto Dip
2023-01-26 19:52:03 -03:00
committed by GitHub
parent aa513e722c
commit 0c9a79b248
5 changed files with 122 additions and 57 deletions
@@ -1262,7 +1262,9 @@ Requires `mdm.macos_updates.deadline` to be set.
##### mdm.macos_updates.deadline
A deadline in the form `YYYY-MM-DD`. Hosts that belong to no team and are enrolled into Fleet's MDM won't be able to dismiss the Nudge window once this deadline is past.
A deadline in the form `YYYY-MM-DD`. The exact deadline time is at 04:00:00 (UTC-8).
Hosts that belong to no team and are enrolled into Fleet's MDM won't be able to dismiss the Nudge window once this deadline is past.
Requires `mdm.macos_updates.minimum_version` to be set.
+97
View File
@@ -0,0 +1,97 @@
package fleet
import (
"time"
)
// NudgeConfig represents a subset of the [full Nudge configuration][0] that we
// want to override.
//
// [0]: https://github.com/macadmins/nudge/wiki
type NudgeConfig struct {
OSVersionRequirements []nudgeOSVersionRequirements `json:"osVersionRequirements"`
UserInterface nudgeUserInterface `json:"userInterface"`
UserExperience nudgeUserExperience `json:"userExperience"`
UpdateElements []nudgeUpdateElements `json:"updateElements"`
}
type nudgeAboutUpdateURLs struct {
Language string `json:"_language"`
AboutUpdateURL string `json:"aboutUpdateURL"`
}
type nudgeOSVersionRequirements struct {
RequiredInstallationDate time.Time `json:"requiredInstallationDate"`
RequiredMinimumOSVersion string `json:"requiredMinimumOSVersion"`
AboutUpdateURLs []nudgeAboutUpdateURLs `json:"aboutUpdateURLs"`
}
type nudgeUserInterface struct {
SimpleMode bool `json:"simpleMode"`
ShowDeferralCount bool `json:"showDeferralCount"`
}
type nudgeUserExperience struct {
InitialRefreshCycle int `json:"initialRefreshCycle"`
ApproachingRefreshCycle int `json:"approachingRefreshCycle"`
ImminentRefreshCycle int `json:"imminentRefreshCycle"`
ElapsedRefreshCycle int `json:"elapsedRefreshCycle"`
}
type nudgeUpdateElements struct {
Language string `json:"_language"`
ActionButtonText string `json:"actionButtonText"`
MainHeader string `json:"mainHeader"`
}
func NewNudgeConfig(macOSUpdates MacOSUpdates) (*NudgeConfig, error) {
deadline, err := time.Parse("2006-01-02", macOSUpdates.Deadline)
if err != nil {
return nil, err
}
// Per the spec, the exact deadline time is arbitrarily chosen to be
// 04:00:00 (UTC-8) until we allow users to customize it.
//
// See https://github.com/fleetdm/fleet/issues/9013 for more details.
localizedDeadline := time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 4, 0, 0, 0, time.UTC)
return &NudgeConfig{
OSVersionRequirements: []nudgeOSVersionRequirements{{
RequiredInstallationDate: localizedDeadline,
RequiredMinimumOSVersion: macOSUpdates.MinimumVersion,
AboutUpdateURLs: []nudgeAboutUpdateURLs{{
Language: "en",
AboutUpdateURL: "https://fleetdm.com/docs/using-fleet/mobile-device-management#macos-updates",
}},
}},
UserInterface: nudgeUserInterface{
SimpleMode: true,
ShowDeferralCount: false,
},
UserExperience: nudgeUserExperience{
/* Initially, we show Nudge once every 24 hours */
InitialRefreshCycle: 86400,
/*
* Related to approachingWindowTime (72 hours before deadline by default)
* we still want to show the window once every 24 hours.
*/
ApproachingRefreshCycle: 86400,
/*
* Related to imminentWindowTime (24 hours before deadline by default)
* we want to show the window once every 2 hours.
*/
ImminentRefreshCycle: 7200,
/*
* Related to elapsedWindowTime (once the deadline is past)
* we want to show the window once every hour.
*/
ElapsedRefreshCycle: 3600,
},
UpdateElements: []nudgeUpdateElements{{
Language: "en",
ActionButtonText: "Update",
MainHeader: "Your device requires an update",
}},
}, nil
}
+1 -1
View File
@@ -12,6 +12,6 @@ type OrbitConfigNotifications struct {
type OrbitConfig struct {
Flags json.RawMessage `json:"command_line_startup_flags,omitempty"`
Extensions json.RawMessage `json:"extensions,omitempty"`
NudgeConfig json.RawMessage `json:"nudge_config,omitempty"`
NudgeConfig *NudgeConfig `json:"nudge_config,omitempty"`
Notifications OrbitConfigNotifications `json:"notifications,omitempty"`
}
+13 -36
View File
@@ -2141,18 +2141,10 @@ func (s *integrationEnterpriseTestSuite) TestOrbitConfigNudgeSettings() {
resp = orbitGetConfigResponse{}
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp)
require.JSONEq(
t,
`{
"osVersionRequirements": [
{
"requiredInstallationDate": "2022-01-04",
"requiredMinimumOSVersion": "12.1.3"
}
]
}`,
string(resp.NudgeConfig),
)
wantCfg, err := fleet.NewNudgeConfig(fleet.MacOSUpdates{Deadline: "2022-01-04", MinimumVersion: "12.1.3"})
require.NoError(t, err)
require.Equal(t, wantCfg, resp.NudgeConfig)
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "2022-01-04 04:00:00 +0000 UTC")
// create a team with an empty macos_updates config
team, err := s.ds.NewTeam(context.Background(), &fleet.Team{
@@ -2170,6 +2162,7 @@ func (s *integrationEnterpriseTestSuite) TestOrbitConfigNudgeSettings() {
resp = orbitGetConfigResponse{}
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp)
require.Empty(t, resp.NudgeConfig)
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "2022-01-04 04:00:00 +0000 UTC")
// modify the team config, add macos_updates config
var tmResp teamResponse
@@ -2184,35 +2177,19 @@ func (s *integrationEnterpriseTestSuite) TestOrbitConfigNudgeSettings() {
resp = orbitGetConfigResponse{}
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h.OrbitNodeKey)), http.StatusOK, &resp)
require.JSONEq(
t,
`{
"osVersionRequirements": [
{
"requiredInstallationDate": "1992-01-01",
"requiredMinimumOSVersion": "13.1.1"
}
]
}`,
string(resp.NudgeConfig),
)
wantCfg, err = fleet.NewNudgeConfig(fleet.MacOSUpdates{Deadline: "1992-01-01", MinimumVersion: "13.1.1"})
require.NoError(t, err)
require.Equal(t, wantCfg, resp.NudgeConfig)
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "1992-01-01 04:00:00 +0000 UTC")
// create a new host, still receives the global config
h2 := createOrbitEnrolledHost(t, "darwin", "h2", s.ds)
resp = orbitGetConfigResponse{}
s.DoJSON("POST", "/api/fleet/orbit/config", json.RawMessage(fmt.Sprintf(`{"orbit_node_key": %q}`, *h2.OrbitNodeKey)), http.StatusOK, &resp)
require.JSONEq(
t,
`{
"osVersionRequirements": [
{
"requiredInstallationDate": "2022-01-04",
"requiredMinimumOSVersion": "12.1.3"
}
]
}`,
string(resp.NudgeConfig),
)
wantCfg, err = fleet.NewNudgeConfig(fleet.MacOSUpdates{Deadline: "2022-01-04", MinimumVersion: "12.1.3"})
require.NoError(t, err)
require.Equal(t, wantCfg, resp.NudgeConfig)
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "2022-01-04 04:00:00 +0000 UTC")
}
// allEqual compares all fields of a struct.
+8 -19
View File
@@ -1,12 +1,10 @@
package service
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"text/template"
"github.com/fleetdm/fleet/v4/server"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
@@ -167,11 +165,12 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro
return fleet.OrbitConfig{Notifications: notifs}, err
}
var nudgeConfig bytes.Buffer
var nudgeConfig *fleet.NudgeConfig
if mdmConfig != nil &&
mdmConfig.MacOSUpdates.Deadline != "" &&
mdmConfig.MacOSUpdates.MinimumVersion != "" {
if err := nudgeConfigTemplate.Execute(&nudgeConfig, mdmConfig.MacOSUpdates); err != nil {
nudgeConfig, err = fleet.NewNudgeConfig(mdmConfig.MacOSUpdates)
if err != nil {
return fleet.OrbitConfig{Notifications: notifs}, err
}
}
@@ -180,7 +179,7 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro
Flags: opts.CommandLineStartUpFlags,
Extensions: opts.Extensions,
Notifications: notifs,
NudgeConfig: nudgeConfig.Bytes(),
NudgeConfig: nudgeConfig,
}, nil
}
@@ -196,10 +195,11 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro
}
}
var nudgeConfig bytes.Buffer
var nudgeConfig *fleet.NudgeConfig
if config.MDM.MacOSUpdates.Deadline != "" &&
config.MDM.MacOSUpdates.MinimumVersion != "" {
if err := nudgeConfigTemplate.Execute(&nudgeConfig, config.MDM.MacOSUpdates); err != nil {
nudgeConfig, err = fleet.NewNudgeConfig(config.MDM.MacOSUpdates)
if err != nil {
return fleet.OrbitConfig{Notifications: notifs}, err
}
}
@@ -208,21 +208,10 @@ func (svc *Service) GetOrbitConfig(ctx context.Context) (fleet.OrbitConfig, erro
Flags: opts.CommandLineStartUpFlags,
Extensions: opts.Extensions,
Notifications: notifs,
NudgeConfig: nudgeConfig.Bytes(),
NudgeConfig: nudgeConfig,
}, nil
}
var nudgeConfigTemplate = template.Must(template.New("").Option("missingkey=error").Parse(`
{
"osVersionRequirements": [
{
"requiredInstallationDate": "{{ .Deadline }}",
"requiredMinimumOSVersion": "{{ .MinimumVersion }}"
}
]
}
`))
/////////////////////////////////////////////////////////////////////////////////
// Ping orbit endpoint
/////////////////////////////////////////////////////////////////////////////////