mirror of
https://github.com/fleetdm/fleet
synced 2026-05-22 16:39:01 +00:00
Add activity item for resend configuration profile (#18271)
This commit is contained in:
parent
1e6839c004
commit
ecdcb7c2fb
5 changed files with 72 additions and 4 deletions
|
|
@ -1108,6 +1108,25 @@ This activity contains the following fields:
|
|||
}
|
||||
```
|
||||
|
||||
## resent_configuration_profile
|
||||
|
||||
Generated when a user resends an MDM configuration profile to a host.
|
||||
|
||||
This activity contains the following fields:
|
||||
- "host_id": The ID of the host.
|
||||
- "host_display_name": The display name of the host.
|
||||
- "profile_name": The name of the configuration profile.
|
||||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
{
|
||||
"host_id": 1,
|
||||
"host_display_name": "Anna's MacBook Pro",
|
||||
"profile_name": "Passcode requirements"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
<meta name="title" value="Audit logs">
|
||||
<meta name="pageOrderInSection" value="1400">
|
||||
|
|
|
|||
|
|
@ -88,6 +88,8 @@ var ActivityDetailsList = []ActivityDetails{
|
|||
ActivityTypeCreatedDeclarationProfile{},
|
||||
ActivityTypeDeletedDeclarationProfile{},
|
||||
ActivityTypeEditedDeclarationProfile{},
|
||||
|
||||
ActivityTypeResentConfigurationProfile{},
|
||||
}
|
||||
|
||||
type ActivityDetails interface {
|
||||
|
|
@ -1390,6 +1392,28 @@ func (a ActivityTypeEditedDeclarationProfile) Documentation() (activity string,
|
|||
}`
|
||||
}
|
||||
|
||||
type ActivityTypeResentConfigurationProfile struct {
|
||||
HostID *uint `json:"host_id"`
|
||||
HostDisplayName *string `json:"host_display_name"`
|
||||
ProfileName string `json:"profile_name"`
|
||||
}
|
||||
|
||||
func (a ActivityTypeResentConfigurationProfile) ActivityName() string {
|
||||
return "resent_configuration_profile"
|
||||
}
|
||||
|
||||
func (a ActivityTypeResentConfigurationProfile) Documentation() (activity string, details string, detailsExample string) {
|
||||
return `Generated when a user resends an MDM configuration profile to a host.`,
|
||||
`This activity contains the following fields:
|
||||
- "host_id": The ID of the host.
|
||||
- "host_display_name": The display name of the host.
|
||||
- "profile_name": The name of the configuration profile.`, `{
|
||||
"host_id": 1,
|
||||
"host_display_name": "Anna's MacBook Pro",
|
||||
"profile_name": "Passcode requirements"
|
||||
}`
|
||||
}
|
||||
|
||||
// LogRoleChangeActivities logs activities for each role change, globally and one for each change in teams.
|
||||
func LogRoleChangeActivities(ctx context.Context, ds Datastore, adminUser *User, oldGlobalRole *string, oldTeamRoles []UserTeam, user *User) error {
|
||||
if user.GlobalRole != nil && (oldGlobalRole == nil || *oldGlobalRole != *user.GlobalRole) {
|
||||
|
|
|
|||
|
|
@ -791,14 +791,18 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
|||
require.Equal(t, prof, installs[0])
|
||||
require.Empty(t, removes)
|
||||
s.checkMDMProfilesSummaries(t, &tm.ID, fleet.MDMProfilesSummary{Verifying: 1}, nil)
|
||||
s.lastActivityMatches(
|
||||
fleet.ActivityTypeResentConfigurationProfile{}.ActivityName(),
|
||||
fmt.Sprintf(`{"host_id": %d, "host_display_name": %q, "profile_name": %q}`, host.ID, host.DisplayName(), "name-"+mcUUID),
|
||||
0)
|
||||
|
||||
// add a declaration to the team
|
||||
declIdent := "decl-ident-" + t.Name()
|
||||
declIdent := "decl-ident-" + uuid.NewString()
|
||||
fields := map[string][]string{
|
||||
"team_id": {fmt.Sprintf("%d", tm.ID)},
|
||||
}
|
||||
body, headers := generateNewProfileMultipartRequest(
|
||||
t, declIdent+".json", declarationForTest(declIdent), s.token, fields,
|
||||
t, "some-declaration.json", declarationForTest(declIdent), s.token, fields,
|
||||
)
|
||||
res = s.DoRawWithHeaders("POST", "/api/latest/fleet/configuration_profiles", body.Bytes(), http.StatusOK, headers)
|
||||
var resp newMDMConfigProfileResponse
|
||||
|
|
@ -837,6 +841,10 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
|||
_ = s.DoRaw("POST", fmt.Sprintf("/api/latest/fleet/hosts/%d/configuration_profiles/resend/%s", host.ID, declUUID), nil, http.StatusAccepted)
|
||||
checkDDMSync(mdmDevice)
|
||||
s.checkMDMProfilesSummaries(t, &tm.ID, fleet.MDMProfilesSummary{Verifying: 1}, nil)
|
||||
s.lastActivityMatches(
|
||||
fleet.ActivityTypeResentConfigurationProfile{}.ActivityName(),
|
||||
fmt.Sprintf(`{"host_id": %d, "host_display_name": %q, "profile_name": "some-declaration"}`, host.ID, host.DisplayName()),
|
||||
0)
|
||||
|
||||
// transfer the host to the global team
|
||||
err = s.ds.AddHostsToTeam(ctx, nil, []uint{host.ID})
|
||||
|
|
@ -11007,7 +11015,11 @@ func (s *integrationMDMTestSuite) TestWindowsProfileManagement() {
|
|||
// can resend a profile after it has failed
|
||||
res = s.DoRaw("POST", fmt.Sprintf("/api/latest/fleet/hosts/%d/configuration_profiles/resend/%s", host.ID, teamProfiles[0]), nil, http.StatusAccepted)
|
||||
verifyProfiles(mdmDevice, 1, false) // trigger a profile sync, device gets the profile resent
|
||||
checkHostProfileStatus(t, host.UUID, teamProfiles[0], fleet.MDMDeliveryVerifying) // profile was resent, so it back to verifying
|
||||
checkHostProfileStatus(t, host.UUID, teamProfiles[0], fleet.MDMDeliveryVerifying) // profile was resent, so back to verifying
|
||||
s.lastActivityMatches(
|
||||
fleet.ActivityTypeResentConfigurationProfile{}.ActivityName(),
|
||||
fmt.Sprintf(`{"host_id": %d, "host_display_name": %q, "profile_name": %q}`, host.ID, host.DisplayName(), "name-"+teamProfiles[0]),
|
||||
0)
|
||||
|
||||
// add a macOS profile to the team
|
||||
mcUUID := "a" + uuid.NewString()
|
||||
|
|
|
|||
|
|
@ -2025,6 +2025,7 @@ func (svc *Service) ResendHostMDMProfile(ctx context.Context, hostID uint, profi
|
|||
}
|
||||
|
||||
var profileTeamID *uint
|
||||
var profileName string
|
||||
switch {
|
||||
case strings.HasPrefix(profileUUID, fleet.MDMAppleProfileUUIDPrefix):
|
||||
if err := svc.VerifyMDMAppleConfigured(ctx); err != nil {
|
||||
|
|
@ -2038,6 +2039,7 @@ func (svc *Service) ResendHostMDMProfile(ctx context.Context, hostID uint, profi
|
|||
return ctxerr.Wrap(ctx, err, "getting apple config profile")
|
||||
}
|
||||
profileTeamID = prof.TeamID
|
||||
profileName = prof.Name
|
||||
|
||||
case strings.HasPrefix(profileUUID, fleet.MDMAppleDeclarationUUIDPrefix):
|
||||
if err := svc.VerifyMDMAppleConfigured(ctx); err != nil {
|
||||
|
|
@ -2051,6 +2053,7 @@ func (svc *Service) ResendHostMDMProfile(ctx context.Context, hostID uint, profi
|
|||
return ctxerr.Wrap(ctx, err, "getting apple declaration")
|
||||
}
|
||||
profileTeamID = decl.TeamID
|
||||
profileName = decl.Name
|
||||
|
||||
case strings.HasPrefix(profileUUID, fleet.MDMWindowsProfileUUIDPrefix):
|
||||
if err := svc.VerifyMDMWindowsConfigured(ctx); err != nil {
|
||||
|
|
@ -2064,6 +2067,7 @@ func (svc *Service) ResendHostMDMProfile(ctx context.Context, hostID uint, profi
|
|||
return ctxerr.Wrap(ctx, err, "getting windows config profile")
|
||||
}
|
||||
profileTeamID = prof.TeamID
|
||||
profileName = prof.Name
|
||||
|
||||
default:
|
||||
return ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("HostMDMProfile", "Invalid profile UUID prefix.").WithStatus(http.StatusNotFound), "check profile UUID prefix")
|
||||
|
|
@ -2093,7 +2097,13 @@ func (svc *Service) ResendHostMDMProfile(ctx context.Context, hostID uint, profi
|
|||
return ctxerr.Wrap(ctx, err, "resending host mdm profile")
|
||||
}
|
||||
|
||||
// TODO: log activity?
|
||||
if err := svc.ds.NewActivity(ctx, authz.UserFromContext(ctx), &fleet.ActivityTypeResentConfigurationProfile{
|
||||
HostID: &host.ID,
|
||||
HostDisplayName: ptr.String(host.DisplayName()),
|
||||
ProfileName: profileName,
|
||||
}); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "logging activity for resend config profile")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1708,6 +1708,9 @@ func TestMDMResendConfigProfileAuthz(t *testing.T) {
|
|||
ds.ResendHostMDMProfileFunc = func(ctx context.Context, hostUUID, profUUID string) error {
|
||||
return nil
|
||||
}
|
||||
ds.NewActivityFunc = func(context.Context, *fleet.User, fleet.ActivityDetails) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
checkShouldFail := func(t *testing.T, err error, shouldFail bool) {
|
||||
if !shouldFail {
|
||||
|
|
|
|||
Loading…
Reference in a new issue