mirror of
https://github.com/fleetdm/fleet
synced 2026-05-23 17:08:53 +00:00
Record activity when the macos minimum version requirement is edited (#9594)
This commit is contained in:
parent
68673cfa6a
commit
c805ea2154
7 changed files with 229 additions and 51 deletions
1
changes/issue-9355-macos-min-version-activity
Normal file
1
changes/issue-9355-macos-min-version-activity
Normal file
|
|
@ -0,0 +1 @@
|
|||
* Added an activity `edited_macos_min_version` when the required minimum macOS version is updated.
|
||||
|
|
@ -43,7 +43,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"pack_id": 123,
|
||||
"pack_id": 123,
|
||||
"pack_name": "foo"
|
||||
}
|
||||
```
|
||||
|
|
@ -60,7 +60,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"pack_id": 123,
|
||||
"pack_id": 123,
|
||||
"pack_name": "foo"
|
||||
}
|
||||
```
|
||||
|
|
@ -98,7 +98,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"policy_id": 123,
|
||||
"policy_id": 123,
|
||||
"policy_name": "foo"
|
||||
}
|
||||
```
|
||||
|
|
@ -115,7 +115,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"policy_id": 123,
|
||||
"policy_id": 123,
|
||||
"policy_name": "foo"
|
||||
}
|
||||
```
|
||||
|
|
@ -132,7 +132,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"policy_id": 123,
|
||||
"policy_id": 123,
|
||||
"policy_name": "foo"
|
||||
}
|
||||
```
|
||||
|
|
@ -188,7 +188,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"query_id": 123,
|
||||
"query_id": 123,
|
||||
"query_name": "foo"
|
||||
}
|
||||
```
|
||||
|
|
@ -205,7 +205,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"query_id": 123,
|
||||
"query_id": 123,
|
||||
"query_name": "foo"
|
||||
}
|
||||
```
|
||||
|
|
@ -275,7 +275,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"team_id": 123,
|
||||
"team_id": 123,
|
||||
"team_name": "foo"
|
||||
}
|
||||
```
|
||||
|
|
@ -292,7 +292,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"team_id": 123,
|
||||
"team_id": 123,
|
||||
"team_name": "foo"
|
||||
}
|
||||
```
|
||||
|
|
@ -311,7 +311,7 @@ This activity contains a field "teams" where each item contains the team details
|
|||
{
|
||||
"teams": [
|
||||
{
|
||||
"id": 123,
|
||||
"id": 123,
|
||||
"name": "foo"
|
||||
}
|
||||
]
|
||||
|
|
@ -331,7 +331,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"team_id": 123,
|
||||
"team_id": 123,
|
||||
"team_name": "foo",
|
||||
"global": false
|
||||
}
|
||||
|
|
@ -350,7 +350,7 @@ This activity contains the following fields:
|
|||
|
||||
```json
|
||||
{
|
||||
"targets_count": 5000,
|
||||
"targets_count": 5000,
|
||||
"query_sql": "SELECT * from osquery_info;",
|
||||
"query_name": "foo"
|
||||
}
|
||||
|
|
@ -530,6 +530,7 @@ Generated when a host is enrolled in Fleet's MDM.
|
|||
|
||||
This activity contains the following fields:
|
||||
- "host_serial": Serial number of the host.
|
||||
- "host_display_name": Display name of the host.
|
||||
- "installed_from_dep": Whether the host was enrolled via DEP.
|
||||
|
||||
#### Example
|
||||
|
|
@ -537,6 +538,7 @@ This activity contains the following fields:
|
|||
```json
|
||||
{
|
||||
"host_serial": "C08VQ2AXHT96",
|
||||
"host_display_name": "MacBookPro16,1 (C08VQ2AXHT96)",
|
||||
"installed_from_dep": true
|
||||
}
|
||||
```
|
||||
|
|
@ -547,6 +549,7 @@ Generated when a host is unenrolled from Fleet's MDM.
|
|||
|
||||
This activity contains the following fields:
|
||||
- "host_serial": Serial number of the host.
|
||||
- "host_display_name": Display name of the host.
|
||||
- "installed_from_dep": Whether the host was enrolled via DEP.
|
||||
|
||||
#### Example
|
||||
|
|
@ -554,10 +557,32 @@ This activity contains the following fields:
|
|||
```json
|
||||
{
|
||||
"host_serial": "C08VQ2AXHT96",
|
||||
"host_display_name": "MacBookPro16,1 (C08VQ2AXHT96)",
|
||||
"installed_from_dep": true
|
||||
}
|
||||
```
|
||||
|
||||
### Type `edited_macos_min_version`
|
||||
|
||||
Generated when the minimum required macOS version is modified.
|
||||
|
||||
This activity contains the following fields:
|
||||
- "team_id": The ID of the team that the minimum macOS version applies to, null if it applies to devices that are not in a team.
|
||||
- "team_name": The name of the team that the minimum macOS version applies to, null if it applies to devices that are not in a team.
|
||||
- "minimum_version": The minimum macOS version required, empty if the requirement was removed.
|
||||
- "deadline": The deadline by which the minimum version requirement must be applied, empty if the requirement was removed.
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"team_id": 3,
|
||||
"team_name": "Workstations",
|
||||
"minimum_version": "13.0.1",
|
||||
"deadline": "2023-06-01"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
<meta name="pageOrderInSection" value="1400">
|
||||
|
|
@ -25,7 +25,7 @@ SELECT 1 FROM disk_encryption WHERE user_uuid IS NOT "" AND filevault_status = '
|
|||
|
||||
## disk_encryption_linux
|
||||
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void, nixos
|
||||
|
||||
- Query:
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ SELECT 1 FROM bitlocker_info WHERE drive_letter = 'C:' AND protection_status = 1
|
|||
|
||||
## disk_space_unix
|
||||
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void, darwin
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void, nixos, darwin
|
||||
|
||||
- Query:
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ select version, errors, warnings from munki_info;
|
|||
|
||||
## network_interface_unix
|
||||
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void, darwin
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void, nixos, darwin
|
||||
|
||||
- Query:
|
||||
|
||||
|
|
@ -230,7 +230,7 @@ SELECT version FROM orbit_info
|
|||
|
||||
## os_unix_like
|
||||
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void, darwin
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void, nixos, darwin
|
||||
|
||||
- Query:
|
||||
|
||||
|
|
@ -328,7 +328,7 @@ SELECT *,
|
|||
|
||||
## software_linux
|
||||
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void
|
||||
- Platforms: linux, ubuntu, debian, rhel, centos, sles, kali, gentoo, amzn, pop, arch, linuxmint, void, nixos
|
||||
|
||||
- Query:
|
||||
|
||||
|
|
|
|||
|
|
@ -103,10 +103,12 @@ func (svc *Service) ModifyTeam(ctx context.Context, teamID uint, payload fleet.T
|
|||
team.Config.WebhookSettings = *payload.WebhookSettings
|
||||
}
|
||||
|
||||
var macOSMinVersionUpdated bool
|
||||
if payload.MDM != nil {
|
||||
if err := payload.MDM.MacOSUpdates.Validate(); err != nil {
|
||||
return nil, fleet.NewInvalidArgumentError("macos_updates", err.Error())
|
||||
}
|
||||
macOSMinVersionUpdated = team.Config.MDM.MacOSUpdates != payload.MDM.MacOSUpdates
|
||||
team.Config.MDM = *payload.MDM
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +146,25 @@ func (svc *Service) ModifyTeam(ctx context.Context, teamID uint, payload fleet.T
|
|||
}
|
||||
}
|
||||
|
||||
return svc.ds.SaveTeam(ctx, team)
|
||||
team, err = svc.ds.SaveTeam(ctx, team)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if macOSMinVersionUpdated {
|
||||
if err := svc.ds.NewActivity(
|
||||
ctx,
|
||||
authz.UserFromContext(ctx),
|
||||
fleet.ActivityTypeEditedMacOSMinVersion{
|
||||
TeamID: &team.ID,
|
||||
TeamName: &team.Name,
|
||||
MinimumVersion: team.Config.MDM.MacOSUpdates.MinimumVersion,
|
||||
Deadline: team.Config.MDM.MacOSUpdates.Deadline,
|
||||
},
|
||||
); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "create activity for team macos min version edited")
|
||||
}
|
||||
}
|
||||
return team, err
|
||||
}
|
||||
|
||||
func (svc *Service) ModifyTeamAgentOptions(ctx context.Context, teamID uint, teamOptions json.RawMessage, applyOptions fleet.ApplySpecOptions) (*fleet.Team, error) {
|
||||
|
|
@ -496,6 +516,9 @@ func (svc *Service) ApplyTeamSpecs(ctx context.Context, specs []*fleet.TeamSpec,
|
|||
}
|
||||
|
||||
if len(details) > 0 {
|
||||
// TODO(mna): we don't create separate activities for e.g. edited agent
|
||||
// options when applying team specs, so I didn't create explicit activities
|
||||
// for min macos version either. Not sure if that's what we want.
|
||||
if err := svc.ds.NewActivity(
|
||||
ctx,
|
||||
authz.UserFromContext(ctx),
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ var ActivityDetailsList = []ActivityDetails{
|
|||
|
||||
ActivityTypeMDMEnrolled{},
|
||||
ActivityTypeMDMUnenrolled{},
|
||||
|
||||
ActivityTypeEditedMacOSMinVersion{},
|
||||
}
|
||||
|
||||
type ActivityDetails interface {
|
||||
|
|
@ -68,7 +70,7 @@ func (a ActivityTypeCreatedPack) Documentation() (activity string, details strin
|
|||
`This activity contains the following fields:
|
||||
- "pack_id": the id of the created pack.
|
||||
- "pack_name": the name of the created pack.`, `{
|
||||
"pack_id": 123,
|
||||
"pack_id": 123,
|
||||
"pack_name": "foo"
|
||||
}`
|
||||
}
|
||||
|
|
@ -87,7 +89,7 @@ func (a ActivityTypeEditedPack) Documentation() (activity string, details string
|
|||
`This activity contains the following fields:
|
||||
- "pack_id": the id of the edited pack.
|
||||
- "pack_name": the name of the edited pack.`, `{
|
||||
"pack_id": 123,
|
||||
"pack_id": 123,
|
||||
"pack_name": "foo"
|
||||
}`
|
||||
}
|
||||
|
|
@ -133,7 +135,7 @@ func (a ActivityTypeCreatedPolicy) Documentation() (activity string, details str
|
|||
`This activity contains the following fields:
|
||||
- "policy_id": the ID of the created policy.
|
||||
- "policy_name": the name of the created policy.`, `{
|
||||
"policy_id": 123,
|
||||
"policy_id": 123,
|
||||
"policy_name": "foo"
|
||||
}`
|
||||
}
|
||||
|
|
@ -152,7 +154,7 @@ func (a ActivityTypeEditedPolicy) Documentation() (activity string, details stri
|
|||
`This activity contains the following fields:
|
||||
- "policy_id": the ID of the edited policy.
|
||||
- "policy_name": the name of the edited policy.`, `{
|
||||
"policy_id": 123,
|
||||
"policy_id": 123,
|
||||
"policy_name": "foo"
|
||||
}`
|
||||
}
|
||||
|
|
@ -171,7 +173,7 @@ func (a ActivityTypeDeletedPolicy) Documentation() (activity string, details str
|
|||
`This activity contains the following fields:
|
||||
- "policy_id": the ID of the deleted policy.
|
||||
- "policy_name": the name of the deleted policy.`, `{
|
||||
"policy_id": 123,
|
||||
"policy_id": 123,
|
||||
"policy_name": "foo"
|
||||
}`
|
||||
}
|
||||
|
|
@ -230,7 +232,7 @@ func (a ActivityTypeCreatedSavedQuery) Documentation() (activity string, details
|
|||
`This activity contains the following fields:
|
||||
- "query_id": the ID of the created query.
|
||||
- "query_name": the name of the created query.`, `{
|
||||
"query_id": 123,
|
||||
"query_id": 123,
|
||||
"query_name": "foo"
|
||||
}`
|
||||
}
|
||||
|
|
@ -249,7 +251,7 @@ func (a ActivityTypeEditedSavedQuery) Documentation() (activity string, details
|
|||
`This activity contains the following fields:
|
||||
- "query_id": the ID of the query being edited.
|
||||
- "query_name": the name of the query being edited.`, `{
|
||||
"query_id": 123,
|
||||
"query_id": 123,
|
||||
"query_name": "foo"
|
||||
}`
|
||||
}
|
||||
|
|
@ -324,7 +326,7 @@ func (a ActivityTypeCreatedTeam) Documentation() (activity string, details strin
|
|||
`This activity contains the following fields:
|
||||
- "team_id": unique ID of the created team.
|
||||
- "team_name": the name of the created team.`, `{
|
||||
"team_id": 123,
|
||||
"team_id": 123,
|
||||
"team_name": "foo"
|
||||
}`
|
||||
}
|
||||
|
|
@ -343,7 +345,7 @@ func (a ActivityTypeDeletedTeam) Documentation() (activity string, details strin
|
|||
`This activity contains the following fields:
|
||||
- "team_id": unique ID of the deleted team.
|
||||
- "team_name": the name of the deleted team.`, `{
|
||||
"team_id": 123,
|
||||
"team_id": 123,
|
||||
"team_name": "foo"
|
||||
}`
|
||||
}
|
||||
|
|
@ -368,7 +370,7 @@ func (a ActivityTypeAppliedSpecTeam) Documentation() (activity string, details s
|
|||
- "name": Name of the team.`, `{
|
||||
"teams": [
|
||||
{
|
||||
"id": 123,
|
||||
"id": 123,
|
||||
"name": "foo"
|
||||
}
|
||||
]
|
||||
|
|
@ -391,7 +393,7 @@ func (a ActivityTypeEditedAgentOptions) Documentation() (activity string, detail
|
|||
- "global": "true" if the user updated the global agent options, "false" if the agent options of a team were updated.
|
||||
- "team_id": unique ID of the team for which the agent options were updated (null if global is true).
|
||||
- "team_name": the name of the team for which the agent options were updated (null if global is true).`, `{
|
||||
"team_id": 123,
|
||||
"team_id": 123,
|
||||
"team_name": "foo",
|
||||
"global": false
|
||||
}`
|
||||
|
|
@ -413,7 +415,7 @@ func (a ActivityTypeLiveQuery) Documentation() (activity string, details string,
|
|||
- "targets_count": Number of hosts where the live query was targeted to run.
|
||||
- "query_sql": The SQL query to run on hosts.
|
||||
- "query_name": Name of the query (this field is not set if this was not a saved query).`, `{
|
||||
"targets_count": 5000,
|
||||
"targets_count": 5000,
|
||||
"query_sql": "SELECT * from osquery_info;",
|
||||
"query_name": "foo"
|
||||
}`
|
||||
|
|
@ -442,6 +444,11 @@ type Activity struct {
|
|||
Streamed *bool `json:"-" db:"streamed"`
|
||||
}
|
||||
|
||||
// AuthzType implement AuthzTyper to be able to verify access to activities
|
||||
func (*Activity) AuthzType() string {
|
||||
return "activity"
|
||||
}
|
||||
|
||||
type ActivityTypeUserLoggedIn struct {
|
||||
PublicIP string `json:"public_ip"`
|
||||
}
|
||||
|
|
@ -677,7 +684,27 @@ func (a ActivityTypeMDMUnenrolled) Documentation() (activity string, details str
|
|||
}`
|
||||
}
|
||||
|
||||
// AuthzType implement AuthzTyper to be able to verify access to activities
|
||||
func (*Activity) AuthzType() string {
|
||||
return "activity"
|
||||
type ActivityTypeEditedMacOSMinVersion struct {
|
||||
TeamID *uint `json:"team_id"`
|
||||
TeamName *string `json:"team_name"`
|
||||
MinimumVersion string `json:"minimum_version"`
|
||||
Deadline string `json:"deadline"`
|
||||
}
|
||||
|
||||
func (a ActivityTypeEditedMacOSMinVersion) ActivityName() string {
|
||||
return "edited_macos_min_version"
|
||||
}
|
||||
|
||||
func (a ActivityTypeEditedMacOSMinVersion) Documentation() (activity string, details string, detailsExample string) {
|
||||
return `Generated when the minimum required macOS version is modified.`,
|
||||
`This activity contains the following fields:
|
||||
- "team_id": The ID of the team that the minimum macOS version applies to, null if it applies to devices that are not in a team.
|
||||
- "team_name": The name of the team that the minimum macOS version applies to, null if it applies to devices that are not in a team.
|
||||
- "minimum_version": The minimum macOS version required, empty if the requirement was removed.
|
||||
- "deadline": The deadline by which the minimum version requirement must be applied, empty if the requirement was removed.`, `{
|
||||
"team_id": 3,
|
||||
"team_name": "Workstations",
|
||||
"minimum_version": "13.0.1",
|
||||
"deadline": "2023-06-01"
|
||||
}`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -429,7 +429,22 @@ func (svc *Service) ModifyAppConfig(ctx context.Context, p []byte, applyOpts fle
|
|||
Global: true,
|
||||
},
|
||||
); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "create activity for app config modification")
|
||||
return nil, ctxerr.Wrap(ctx, err, "create activity for app config agent options modification")
|
||||
}
|
||||
}
|
||||
|
||||
// if the macOS minimum version requirement changed, create the corresponding
|
||||
// activity
|
||||
if oldAppConfig.MDM.MacOSUpdates != appConfig.MDM.MacOSUpdates {
|
||||
if err := svc.ds.NewActivity(
|
||||
ctx,
|
||||
authz.UserFromContext(ctx),
|
||||
fleet.ActivityTypeEditedMacOSMinVersion{
|
||||
MinimumVersion: appConfig.MDM.MacOSUpdates.MinimumVersion,
|
||||
Deadline: appConfig.MDM.MacOSUpdates.Deadline,
|
||||
},
|
||||
); err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "create activity for app config macos min version modification")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,12 +115,7 @@ func (s *integrationEnterpriseTestSuite) TestTeamSpecs() {
|
|||
require.Equal(t, mdm, team.Config.MDM)
|
||||
|
||||
// an activity was created for team spec applied
|
||||
var listActivities listActivitiesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/activities", nil, http.StatusOK, &listActivities, "order_key", "id", "order_direction", "desc")
|
||||
require.True(t, len(listActivities.Activities) > 0)
|
||||
assert.Equal(t, fleet.ActivityTypeAppliedSpecTeam{}.ActivityName(), listActivities.Activities[0].Type)
|
||||
require.NotNil(t, listActivities.Activities[0].Details)
|
||||
assert.JSONEq(t, fmt.Sprintf(`{"teams": [{"id": %d, "name": %q}]}`, team.ID, team.Name), string(*listActivities.Activities[0].Details))
|
||||
s.lastActivityMatches(fleet.ActivityTypeAppliedSpecTeam{}.ActivityName(), fmt.Sprintf(`{"teams": [{"id": %d, "name": %q}]}`, team.ID, team.Name), 0)
|
||||
|
||||
// dry-run with invalid agent options
|
||||
agentOpts = json.RawMessage(`{"config": {"nope": 1}}`)
|
||||
|
|
@ -231,11 +226,7 @@ func (s *integrationEnterpriseTestSuite) TestTeamSpecs() {
|
|||
require.Equal(t, appConfig.Features, team.Config.Features)
|
||||
|
||||
// an activity was created for the newly created team via the applied spec
|
||||
s.DoJSON("GET", "/api/latest/fleet/activities", nil, http.StatusOK, &listActivities, "order_key", "id", "order_direction", "desc")
|
||||
require.True(t, len(listActivities.Activities) > 0)
|
||||
assert.Equal(t, fleet.ActivityTypeAppliedSpecTeam{}.ActivityName(), listActivities.Activities[0].Type)
|
||||
require.NotNil(t, listActivities.Activities[0].Details)
|
||||
assert.JSONEq(t, fmt.Sprintf(`{"teams": [{"id": %d, "name": %q}]}`, team.ID, team.Name), string(*listActivities.Activities[0].Details))
|
||||
s.lastActivityMatches(fleet.ActivityTypeAppliedSpecTeam{}.ActivityName(), fmt.Sprintf(`{"teams": [{"id": %d, "name": %q}]}`, team.ID, team.Name), 0)
|
||||
|
||||
// updates
|
||||
teamSpecs = applyTeamSpecsRequest{Specs: []*fleet.TeamSpec{{
|
||||
|
|
@ -680,12 +671,7 @@ func (s *integrationEnterpriseTestSuite) TestTeamEndpoints() {
|
|||
require.Contains(t, string(*tmResp.Team.Config.AgentOptions), `"aws_debug": true`) // left unchanged
|
||||
|
||||
// list activities, it should have created one for edited_agent_options
|
||||
var listActivities listActivitiesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/activities", nil, http.StatusOK, &listActivities, "order_key", "id", "order_direction", "desc")
|
||||
require.True(t, len(listActivities.Activities) > 0)
|
||||
assert.Equal(t, fleet.ActivityTypeEditedAgentOptions{}.ActivityName(), listActivities.Activities[0].Type)
|
||||
require.NotNil(t, listActivities.Activities[0].Details)
|
||||
assert.JSONEq(t, fmt.Sprintf(`{"global": false, "team_id": %d, "team_name": %q}`, tm1ID, team.Name), string(*listActivities.Activities[0].Details))
|
||||
s.lastActivityMatches(fleet.ActivityTypeEditedAgentOptions{}.ActivityName(), fmt.Sprintf(`{"global": false, "team_id": %d, "team_name": %q}`, tm1ID, team.Name), 0)
|
||||
|
||||
// modify team agent options - unknown team
|
||||
tmResp.Team = nil
|
||||
|
|
@ -1262,6 +1248,7 @@ func (s *integrationEnterpriseTestSuite) TestMacOSUpdatesConfig() {
|
|||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion)
|
||||
require.Equal(t, "2021-01-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline)
|
||||
s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "minimum_version": "10.15.0", "deadline": "2021-01-01"}`, team.ID, team.Name), 0)
|
||||
|
||||
// only update the deadline
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), fleet.TeamPayload{
|
||||
|
|
@ -1274,16 +1261,20 @@ func (s *integrationEnterpriseTestSuite) TestMacOSUpdatesConfig() {
|
|||
}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion)
|
||||
require.Equal(t, "2025-10-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline)
|
||||
lastActivity := s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "minimum_version": "10.15.0", "deadline": "2025-10-01"}`, team.ID, team.Name), 0)
|
||||
|
||||
// sending a nil MacOSUpdate config doesn't modify anything
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), fleet.TeamPayload{MDM: nil}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, "10.15.0", tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion)
|
||||
require.Equal(t, "2025-10-01", tmResp.Team.Config.MDM.MacOSUpdates.Deadline)
|
||||
// no new activity is created
|
||||
s.lastActivityMatches("", "", lastActivity)
|
||||
|
||||
// sending an empty MacOSUpdate empties both fields
|
||||
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/teams/%d", team.ID), fleet.TeamPayload{MDM: &fleet.TeamMDM{MacOSUpdates: fleet.MacOSUpdates{}}}, http.StatusOK, &tmResp)
|
||||
require.Empty(t, tmResp.Team.Config.MDM.MacOSUpdates.MinimumVersion)
|
||||
require.Empty(t, tmResp.Team.Config.MDM.MacOSUpdates.Deadline)
|
||||
s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), fmt.Sprintf(`{"team_id": %d, "team_name": %q, "minimum_version": "", "deadline": ""}`, team.ID, team.Name), 0)
|
||||
|
||||
// error checks:
|
||||
|
||||
|
|
@ -1527,6 +1518,14 @@ func (s *integrationEnterpriseTestSuite) TestDefaultAppleBMTeam() {
|
|||
func (s *integrationEnterpriseTestSuite) TestMDMMacOSUpdates() {
|
||||
t := s.T()
|
||||
|
||||
// keep the last activity, to detect newly created ones
|
||||
var activitiesResp listActivitiesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/activities", nil, http.StatusOK, &activitiesResp, "order_key", "a.id", "order_direction", "desc")
|
||||
var lastActivity uint
|
||||
if len(activitiesResp.Activities) > 0 {
|
||||
lastActivity = activitiesResp.Activities[0].ID
|
||||
}
|
||||
|
||||
checkInvalidConfig := func(config string) {
|
||||
// try to set an invalid config
|
||||
acResp := appConfigResponse{}
|
||||
|
|
@ -1536,6 +1535,14 @@ func (s *integrationEnterpriseTestSuite) TestMDMMacOSUpdates() {
|
|||
acResp = appConfigResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/config", nil, http.StatusOK, &acResp)
|
||||
require.Equal(t, fleet.MacOSUpdates{}, acResp.MDM.MacOSUpdates)
|
||||
|
||||
// no activity got created
|
||||
activitiesResp = listActivitiesResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/activities", nil, http.StatusOK, &activitiesResp, "order_key", "a.id", "order_direction", "desc")
|
||||
require.Condition(t, func() bool {
|
||||
return (lastActivity == 0 && len(activitiesResp.Activities) == 0) ||
|
||||
(len(activitiesResp.Activities) > 0 && activitiesResp.Activities[0].ID == lastActivity)
|
||||
})
|
||||
}
|
||||
|
||||
// missing minimum_version
|
||||
|
|
@ -1589,11 +1596,69 @@ func (s *integrationEnterpriseTestSuite) TestMDMMacOSUpdates() {
|
|||
require.Equal(t, "12.3.1", acResp.MDM.MacOSUpdates.MinimumVersion)
|
||||
require.Equal(t, "2022-01-01", acResp.MDM.MacOSUpdates.Deadline)
|
||||
|
||||
// edited macos min version activity got created
|
||||
s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"2022-01-01", "minimum_version":"12.3.1", "team_id": null, "team_name": null}`, 0)
|
||||
|
||||
// get the appconfig
|
||||
acResp = appConfigResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/config", nil, http.StatusOK, &acResp)
|
||||
require.Equal(t, "12.3.1", acResp.MDM.MacOSUpdates.MinimumVersion)
|
||||
require.Equal(t, "2022-01-01", acResp.MDM.MacOSUpdates.Deadline)
|
||||
|
||||
// update the deadline
|
||||
acResp = appConfigResponse{}
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{
|
||||
"mdm": {
|
||||
"macos_updates": {
|
||||
"minimum_version": "12.3.1",
|
||||
"deadline": "2024-01-01"
|
||||
}
|
||||
}
|
||||
}`), http.StatusOK, &acResp)
|
||||
require.Equal(t, "12.3.1", acResp.MDM.MacOSUpdates.MinimumVersion)
|
||||
require.Equal(t, "2024-01-01", acResp.MDM.MacOSUpdates.Deadline)
|
||||
|
||||
// another edited macos min version activity got created
|
||||
lastActivity = s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"2024-01-01", "minimum_version":"12.3.1", "team_id": null, "team_name": null}`, 0)
|
||||
|
||||
// update something unrelated - the transparency url
|
||||
acResp = appConfigResponse{}
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{"fleet_desktop":{"transparency_url": "customURL"}}`), http.StatusOK, &acResp)
|
||||
|
||||
// no activity got created
|
||||
s.lastActivityMatches("", ``, lastActivity)
|
||||
|
||||
// clear the macos requirement
|
||||
acResp = appConfigResponse{}
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{
|
||||
"mdm": {
|
||||
"macos_updates": {
|
||||
"minimum_version": "",
|
||||
"deadline": ""
|
||||
}
|
||||
}
|
||||
}`), http.StatusOK, &acResp)
|
||||
require.Empty(t, acResp.MDM.MacOSUpdates.MinimumVersion)
|
||||
require.Empty(t, acResp.MDM.MacOSUpdates.Deadline)
|
||||
|
||||
// edited macos min version activity got created with empty requirement
|
||||
lastActivity = s.lastActivityMatches(fleet.ActivityTypeEditedMacOSMinVersion{}.ActivityName(), `{"deadline":"", "minimum_version":"", "team_id": null, "team_name": null}`, 0)
|
||||
|
||||
// update again with empty macos requirement
|
||||
acResp = appConfigResponse{}
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{
|
||||
"mdm": {
|
||||
"macos_updates": {
|
||||
"minimum_version": "",
|
||||
"deadline": ""
|
||||
}
|
||||
}
|
||||
}`), http.StatusOK, &acResp)
|
||||
require.Empty(t, acResp.MDM.MacOSUpdates.MinimumVersion)
|
||||
require.Empty(t, acResp.MDM.MacOSUpdates.Deadline)
|
||||
|
||||
// no activity got created
|
||||
s.lastActivityMatches("", ``, lastActivity)
|
||||
}
|
||||
|
||||
func (s *integrationEnterpriseTestSuite) TestSSOJITProvisioning() {
|
||||
|
|
@ -2192,6 +2257,28 @@ func (s *integrationEnterpriseTestSuite) TestOrbitConfigNudgeSettings() {
|
|||
require.Equal(t, wantCfg.OSVersionRequirements[0].RequiredInstallationDate.String(), "2022-01-04 04:00:00 +0000 UTC")
|
||||
}
|
||||
|
||||
// gets the latest activity and checks that it matches any provided properties.
|
||||
// empty string or 0 id means do not check that property. It returns the ID of that
|
||||
// latest activity.
|
||||
func (s *integrationEnterpriseTestSuite) lastActivityMatches(name, details string, id uint) uint {
|
||||
var listActivities listActivitiesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/activities", nil, http.StatusOK, &listActivities, "order_key", "a.id", "order_direction", "desc", "per_page", "1")
|
||||
require.True(s.T(), len(listActivities.Activities) > 0)
|
||||
|
||||
act := listActivities.Activities[0]
|
||||
if name != "" {
|
||||
assert.Equal(s.T(), name, act.Type)
|
||||
}
|
||||
if details != "" {
|
||||
require.NotNil(s.T(), act.Details)
|
||||
assert.JSONEq(s.T(), details, string(*act.Details))
|
||||
}
|
||||
if id > 0 {
|
||||
assert.Equal(s.T(), id, act.ID)
|
||||
}
|
||||
return act.ID
|
||||
}
|
||||
|
||||
// allEqual compares all fields of a struct.
|
||||
// If a field is a pointer on one side but not on the other, then it follows that pointer. This is useful for optional
|
||||
// arguments.
|
||||
|
|
|
|||
Loading…
Reference in a new issue