Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: backend for VPP related global activities #20484

Merged
merged 10 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/19870-vpp-activities-backend
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Adds global activity support for VPP related activities.
8 changes: 7 additions & 1 deletion docs/Using Fleet/Audit-logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,7 @@ Generated when a software installer is deleted from Fleet.
This activity contains the following fields:
- "software_title": Name of the software.
- "software_package": Filename of the installer.
- "team_name": Name of the team to which this software was added. `null if it was added to no team.
- "team_name": Name of the team to which this software was added. `null` if it was added to no team.
- "team_id": The ID of the team to which this software was added. `null` if it was added to no team.
- "self_service": Whether the software was available for installation by the end user.

Expand All @@ -1174,6 +1174,12 @@ This activity contains the following fields:
}
```

## vpp_enabled

Generated when the VPP feature is enabled in Fleet.




<meta name="title" value="Audit logs">
<meta name="pageOrderInSection" value="1400">
Expand Down
10 changes: 10 additions & 0 deletions ee/server/service/vpp.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"net/http"

"github.com/fleetdm/fleet/v4/server/authz"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mdm/apple/itunes"
Expand Down Expand Up @@ -159,5 +160,14 @@ func (svc *Service) AddAppStoreApp(ctx context.Context, teamID *uint, adamID str
return ctxerr.Wrap(ctx, err, "writing VPP app to db")
}

act := fleet.ActivityAddedAppStoreApp{
AppStoreID: app.AdamID,
TeamName: teamName,
SoftwareTitle: app.Name,
}
if err := svc.NewActivity(ctx, authz.UserFromContext(ctx), act); err != nil {
return ctxerr.Wrap(ctx, err, "create activity for add app store app")
}

return nil
}
92 changes: 91 additions & 1 deletion server/fleet/activities.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ var ActivityDetailsList = []ActivityDetails{
ActivityTypeInstalledSoftware{},
ActivityTypeAddedSoftware{},
ActivityTypeDeletedSoftware{},
ActivityEnabledVPP{},
}

type ActivityDetails interface {
Expand Down Expand Up @@ -1507,7 +1508,7 @@ func (a ActivityTypeDeletedSoftware) Documentation() (string, string, string) {
return `Generated when a software installer is deleted from Fleet.`, `This activity contains the following fields:
- "software_title": Name of the software.
- "software_package": Filename of the installer.
- "team_name": Name of the team to which this software was added.` + " `null " + `if it was added to no team.
- "team_name": Name of the team to which this software was added.` + " `null` " + `if it was added to no team.
- "team_id": The ID of the team to which this software was added.` + " `null` " + `if it was added to no team.
- "self_service": Whether the software was available for installation by the end user.`, `{
"software_title": "Falcon.app",
Expand Down Expand Up @@ -1598,3 +1599,92 @@ func LogRoleChangeActivities(
}
return nil
}

type ActivityEnabledVPP struct{}

func (a ActivityEnabledVPP) ActivityName() string {
return "vpp_enabled"
}

func (a ActivityEnabledVPP) Documentation() (activity string, details string, detailsExample string) {
return "Generated when the VPP feature is enabled in Fleet.", "", ""
}

type ActivityDisabledVPP struct{}

func (a ActivityDisabledVPP) ActivityName() string {
return "vpp_disabled"
}

func (a ActivityDisabledVPP) Documentation() (activity string, details string, detailsExample string) {
return "Generated when the VPP feature is disabled in Fleet.", "", ""
}

type ActivityAddedAppStoreApp struct {
SoftwareTitle string `json:"software_title"`
AppStoreID string `json:"app_store_id"`
TeamName string `json:"team_name"`
jahzielv marked this conversation as resolved.
Show resolved Hide resolved
}

func (a ActivityAddedAppStoreApp) ActivityName() string {
return "added_app_store_app"
}

func (a ActivityAddedAppStoreApp) Documentation() (activity string, details string, detailsExample string) {
return "Generated when an App Store app is added to Fleet.", `This activity contains the following fields:
- "software_title": Name of the App Store app.
- "app_store_id": ID of the app on the Apple App Store.
- "team_name": Name of the team to which this App Store app was added.`, `{
"software_title": "Logic Pro",
"app_store_id": "1234567",
"team_name": "Workstations"
}`
}

type ActivityDeletedAppStoreApp struct {
SoftwareTitle string `json:"software_title"`
AppStoreID string `json:"app_store_id"`
TeamName string `json:"team_name"`
}

func (a ActivityDeletedAppStoreApp) ActivityName() string {
return "deleted_app_store_app"
}

func (a ActivityDeletedAppStoreApp) Documentation() (activity string, details string, detailsExample string) {
return "Generated when an App Store app is deleted from Fleet.", `This activity contains the following fields:
- "software_title": Name of the App Store app.
- "app_store_id": ID of the app on the Apple App Store.
- "team_name": Name of the team from which this App Store app was deleted.`, `{
"software_title": "Logic Pro",
"app_store_id": "1234567",
"team_name": "Workstations"
}`
}

type ActivityInstalledAppStoreApp struct {
HostID int `json:"host_id"`
HostDisplayName string `json:"host_display_name"`
SoftwareTitle string `json:"software_title"`
AppStoreID int `json:"app_store_id"`
CommandUUID string `json:"command_uuid"`
}

func (a ActivityInstalledAppStoreApp) ActivityName() string {
return "installed_app_store_app"
}

func (a ActivityInstalledAppStoreApp) Documentation() (string, string, string) {
jahzielv marked this conversation as resolved.
Show resolved Hide resolved
return "Generated when an App Store app is installed on a device.", `This activity contains the following fields:
- host_id: ID of the host on which the app was installed.
- host_display_name: Display name of the host.
- software_title: Name of the App Store app.
- app_store_id: ID of the app on the Apple App Store.
- command_uuid: UUID of the MDM command used to install the app.`, `{
"host_id": 42,
"host_display_name": "Anna's MacBook Pro",
"software_title": "Logic Pro",
"app_store_id": "1234567",
"command_uuid": "98765432-1234-1234-1234-1234567890ab"
}`
}
4 changes: 4 additions & 0 deletions server/service/integration_enterprise_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10706,6 +10706,8 @@ func (s *integrationMDMTestSuite) TestVPPApps() {
t.Setenv("FLEET_DEV_VPP_URL", s.appleVPPConfigSrv.URL)
s.uploadDataViaForm("/api/latest/fleet/mdm/apple/vpp_token", "token", "token.vpptoken", []byte(base64.StdEncoding.EncodeToString([]byte(tokenJSON))), http.StatusAccepted, "")

s.lastActivityMatches(fleet.ActivityEnabledVPP{}.ActivityName(), "", 0)

// Get the token
var resp getMDMAppleVPPTokenResponse
s.DoJSON("GET", "/api/latest/fleet/vpp", &getMDMAppleVPPTokenRequest{}, http.StatusOK, &resp)
Expand Down Expand Up @@ -10759,6 +10761,7 @@ func (s *integrationMDMTestSuite) TestVPPApps() {
// Add an app store app to team 1
var addAppResp addAppStoreAppResponse
s.DoJSON("POST", "/api/latest/fleet/software/app_store_apps", &addAppStoreAppRequest{TeamID: &team.ID, AppStoreID: appResp.AppStoreApps[0].AdamID}, http.StatusOK, &addAppResp)
s.lastActivityMatches(fleet.ActivityAddedAppStoreApp{}.ActivityName(), fmt.Sprintf(`{"team_name": "%s", "software_title": "%s", "app_store_id": "%s"}`, team.Name, appResp.AppStoreApps[0].Name, appResp.AppStoreApps[0].AdamID), 0)

// Add an app store app to non-existent team
s.DoJSON("POST", "/api/latest/fleet/software/app_store_apps", &addAppStoreAppRequest{TeamID: ptr.Uint(9999), AppStoreID: appResp.AppStoreApps[0].AdamID}, http.StatusNotFound, &addAppResp)
Expand All @@ -10781,6 +10784,7 @@ func (s *integrationMDMTestSuite) TestVPPApps() {
// Delete VPP token and check that it's not appearing anymore
s.Do("DELETE", "/api/latest/fleet/mdm/apple/vpp_token", &deleteMDMAppleVPPTokenRequest{}, http.StatusNoContent)
s.DoJSON("GET", "/api/latest/fleet/vpp", &getMDMAppleVPPTokenRequest{}, http.StatusNotFound, &resp)
s.lastActivityMatches(fleet.ActivityDisabledVPP{}.ActivityName(), "", 0)
}

// 1. software title uploaded doesn't match existing title
Expand Down
16 changes: 15 additions & 1 deletion server/service/mdm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2646,6 +2646,11 @@ func (svc *Service) UploadMDMAppleVPPToken(ctx context.Context, token io.ReadSee
return ctxerr.Wrap(ctx, err, "writing VPP token to db")
}

act := fleet.ActivityEnabledVPP{}
if err := svc.NewActivity(ctx, authz.UserFromContext(ctx), act); err != nil {
return ctxerr.Wrap(ctx, err, "create activity for upload VPP token")
}

return nil
}

Expand Down Expand Up @@ -2729,5 +2734,14 @@ func (svc *Service) DeleteMDMAppleVPPToken(ctx context.Context) error {
return err
}

return svc.ds.DeleteMDMConfigAssetsByName(ctx, []fleet.MDMAssetName{fleet.MDMAssetVPPToken})
if err := svc.ds.DeleteMDMConfigAssetsByName(ctx, []fleet.MDMAssetName{fleet.MDMAssetVPPToken}); err != nil {
return ctxerr.Wrap(ctx, err, "delete VPP token")
}

act := fleet.ActivityDisabledVPP{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we decided to not store an user id for add/remove here?

if err := svc.NewActivity(ctx, authz.UserFromContext(ctx), act); err != nil {
return ctxerr.Wrap(ctx, err, "create activity for delete VPP token")
}

return nil
}
4 changes: 4 additions & 0 deletions server/service/mdm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ func TestMDMAppleAuthorization(t *testing.T) {
return nil
}

ds.NewActivityFunc = func(ctx context.Context, user *fleet.User, activity fleet.ActivityDetails, details []byte, createdAt time.Time) error {
return nil
}

ds.DeleteMDMConfigAssetsByNameFunc = func(ctx context.Context, assetNames []fleet.MDMAssetName) error { return nil }

// use a custom implementation of checkAuthErr as the service call will fail
Expand Down
Loading