Skip to content

Commit

Permalink
fix: activity details, response
Browse files Browse the repository at this point in the history
  • Loading branch information
jahzielv committed Jan 29, 2025
1 parent a66a7cd commit 837e0fd
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 26 deletions.
39 changes: 39 additions & 0 deletions docs/Contributing/Audit-logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,45 @@ This activity contains the following fields:
}
```

## updated_app_store_app

Generated when an App Store app is updated in Fleet.

This activity contains the following fields:
- "software_title": Name of the App Store app.
- "software_title_id": ID of the updated app's software title.
- "app_store_id": ID of the app on the Apple App Store.
- "platform": Platform of the app (`darwin`, `ios`, or `ipados`).
- "self_service": App installation can be initiated by device owner.
- "team_name": Name of the team on which this App Store app was updated, or `null` if it was updated on no team.
- "team_id": ID of the team on which this App Store app was updated, or `null`if it was updated on no team.
- "labels_include_any": Target hosts that have any label in the array.
- "labels_exclude_any": Target hosts that don't have any label in the array.

#### Example

```json
{
"software_title": "Logic Pro",
"software_title_id": 123,
"app_store_id": "1234567",
"platform": "darwin",
"self_service": true,
"team_name": "Workstations",
"team_id": 1,
"labels_include_any": [
{
"name": "Engineering",
"id": 12
},
{
"name": "Product",
"id": 17
}
]
}
```

## added_ndes_scep_proxy

Generated when NDES SCEP proxy is configured in Fleet.
Expand Down
27 changes: 17 additions & 10 deletions ee/server/service/vpp.go
Original file line number Diff line number Diff line change
Expand Up @@ -451,36 +451,36 @@ func getVPPAppsMetadata(ctx context.Context, ids []fleet.VPPAppTeam) ([]*fleet.V
return apps, nil
}

func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny []string) error {
func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny []string) (*fleet.VPPAppStoreApp, error) {
if err := svc.authz.Authorize(ctx, &fleet.VPPApp{TeamID: teamID}, fleet.ActionWrite); err != nil {
return err
return nil, err
}

var teamName string
if teamID != nil && *teamID != 0 {
tm, err := svc.ds.Team(ctx, *teamID)
if fleet.IsNotFound(err) {
return fleet.NewInvalidArgumentError("team_id", fmt.Sprintf("team %d does not exist", *teamID)).
return nil, fleet.NewInvalidArgumentError("team_id", fmt.Sprintf("team %d does not exist", *teamID)).
WithStatus(http.StatusNotFound)
} else if err != nil {
return ctxerr.Wrap(ctx, err, "checking if team exists")
return nil, ctxerr.Wrap(ctx, err, "UpdateAppStoreApp: checking if team exists")
}

teamName = tm.Name
}

validatedLabels, err := ValidateSoftwareLabels(ctx, svc, labelsIncludeAny, labelsExcludeAny)
if err != nil {
return ctxerr.Wrap(ctx, err, "UpdateAppStoreApp: validating software labels")
return nil, ctxerr.Wrap(ctx, err, "UpdateAppStoreApp: validating software labels")
}

meta, err := svc.ds.GetVPPAppMetadataByTeamAndTitleID(ctx, teamID, titleID)
if err != nil {
return ctxerr.Wrap(ctx, err, "UpdateAppStoreApp: getting vpp app metadata")
return nil, ctxerr.Wrap(ctx, err, "UpdateAppStoreApp: getting vpp app metadata")
}

if selfService && meta.Platform != fleet.MacOSPlatform {
return fleet.NewUserMessageError(errors.New("Currently, self-service only supports macOS"), http.StatusBadRequest)
return nil, fleet.NewUserMessageError(errors.New("Currently, self-service only supports macOS"), http.StatusBadRequest)
}

appToWrite := &fleet.VPPApp{
Expand All @@ -503,7 +503,7 @@ func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID

_, err = svc.ds.InsertVPPAppWithTeam(ctx, appToWrite, teamID)
if err != nil {
return ctxerr.Wrap(ctx, err, "UpdateAppStoreApp: write app to db")
return nil, ctxerr.Wrap(ctx, err, "UpdateAppStoreApp: write app to db")
}

actLabelsIncl, actLabelsExcl := activitySoftwareLabelsFromValidatedLabels(validatedLabels)
Expand All @@ -520,10 +520,17 @@ func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID
LabelsExcludeAny: actLabelsExcl,
}
if err := svc.NewActivity(ctx, authz.UserFromContext(ctx), act); err != nil {
return ctxerr.Wrap(ctx, err, "create activity for update app store app")
return nil, ctxerr.Wrap(ctx, err, "create activity for update app store app")
}

return nil
updatedAppMeta, err := svc.ds.GetVPPAppMetadataByTeamAndTitleID(ctx, teamID, titleID)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "UpdateAppStoreApp: getting updated app metadata")
}

updatedAppMeta.Platform = ""

return updatedAppMeta, nil
}

func (svc *Service) UploadVPPToken(ctx context.Context, token io.ReadSeeker) (*fleet.VPPTokenDB, error) {
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,6 @@
"browserslist": [
"defaults"
],
"license": "SEE LICENSE IN ./LICENSE"
"license": "SEE LICENSE IN ./LICENSE",
"packageManager": "[email protected]+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
}
5 changes: 3 additions & 2 deletions server/fleet/activities.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ var ActivityDetailsList = []ActivityDetails{
ActivityAddedAppStoreApp{},
ActivityDeletedAppStoreApp{},
ActivityInstalledAppStoreApp{},
ActivityUpdatedAppStoreApp{},

ActivityAddedNDESSCEPProxy{},
ActivityDeletedNDESSCEPProxy{},
Expand Down Expand Up @@ -2077,14 +2078,14 @@ func (a ActivityUpdatedAppStoreApp) ActivityName() string {
func (a ActivityUpdatedAppStoreApp) Documentation() (activity string, details string, detailsExample string) {
return "Generated when an App Store app is updated in Fleet.", `This activity contains the following fields:
- "software_title": Name of the App Store app.
- "software_title_id": ID of the updated software title.
- "software_title_id": ID of the updated app's software title.
- "app_store_id": ID of the app on the Apple App Store.
- "platform": Platform of the app (` + "`darwin`, `ios`, or `ipados`" + `).
- "self_service": App installation can be initiated by device owner.
- "team_name": Name of the team on which this App Store app was updated, or ` + "`null`" + ` if it was updated on no team.
- "team_id": ID of the team on which this App Store app was updated, or ` + "`null`" + `if it was updated on no team.
- "labels_include_any": Target hosts that have any label in the array.
- "labels_exclude_any": Target hosts that don't have any label in the array`, `{
- "labels_exclude_any": Target hosts that don't have any label in the array.`, `{
"software_title": "Logic Pro",
"software_title_id": 123,
"app_store_id": "1234567",
Expand Down
2 changes: 1 addition & 1 deletion server/fleet/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ type Service interface {
GetAppStoreApps(ctx context.Context, teamID *uint) ([]*VPPApp, error)

AddAppStoreApp(ctx context.Context, teamID *uint, appTeam VPPAppTeam) error
UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny []string) error
UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny []string) (*VPPAppStoreApp, error)

// MDMAppleProcessOTAEnrollment handles OTA enrollment requests.
//
Expand Down
6 changes: 3 additions & 3 deletions server/fleet/vpp.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ type VPPApp struct {
TeamID *uint `db:"-" json:"team_id,omitempty"`
TitleID uint `db:"title_id" json:"-"`

CreatedAt time.Time `db:"created_at" json:"-"`
UpdatedAt time.Time `db:"updated_at" json:"-"`
ValidatedLabels *LabelIdentsWithScope
CreatedAt time.Time `db:"created_at" json:"-"`
UpdatedAt time.Time `db:"updated_at" json:"-"`
ValidatedLabels *LabelIdentsWithScope `json:"-"`
}

// AuthzType implements authz.AuthzTyper.
Expand Down
28 changes: 24 additions & 4 deletions server/service/integration_mdm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11095,23 +11095,43 @@ func (s *integrationMDMTestSuite) TestVPPApps() {
require.Len(t, resp.SoftwareTitles, 1)
nonVPPTitleID := resp.SoftwareTitles[0].ID

updateAppReq := &updateAppStoreAppRequest{TeamID: &team.ID, SelfService: false, LabelsIncludeAny: []string{l2.Name}}
updateAppReq := &updateAppStoreAppRequest{TeamID: &team.ID, SelfService: false}

// Attempt to update the non-VPP software using the VPP path. Should fail.
s.Do("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/app_store_app", nonVPPTitleID), updateAppReq, http.StatusNotFound)

// Attempt tp update a non-existent app. Should fail.
s.Do("PATCH", "/api/latest/fleet/software/titles/9999/app_store_app", updateAppReq, http.StatusNotFound)

// Update App2. Unset self service,
s.Do("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/app_store_app", titleID), updateAppReq, http.StatusOK)
// Attempt to update with both types of labels. Should fail.
updateAppReq.LabelsIncludeAny = []string{l1.Name}
updateAppReq.LabelsExcludeAny = []string{l1.Name}
res = s.Do("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/app_store_app", titleID), updateAppReq, http.StatusBadRequest)
require.Contains(t, extractServerErrorText(res.Body), `Only one of "labels_include_any" or "labels_exclude_any" can be included.`)

// Attempt to update with a non-existent label. Should fail.
updateAppReq.LabelsExcludeAny = []string{}
updateAppReq.LabelsIncludeAny = []string{"404_notfound"}
res = s.Do("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/app_store_app", titleID), updateAppReq, http.StatusBadRequest)
require.Contains(t, extractServerErrorText(res.Body), "some or all the labels provided don't exist")

// Update App2. Unset self service and update the labels
updateAppReq.LabelsIncludeAny = []string{l2.Name}
var updateAppResp updateAppStoreAppResponse
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/app_store_app", titleID), updateAppReq, http.StatusOK, &updateAppResp)

require.NotNil(t, updateAppResp.AppStoreApp)
require.Equal(t, updateAppResp.AppStoreApp.AdamID, excludeAnyApp.AdamID)
require.Equal(t, updateAppResp.AppStoreApp.LabelsIncludeAny, []fleet.SoftwareScopeLabel{{LabelName: l2.Name, LabelID: l2.ID}})
require.Empty(t, updateAppResp.AppStoreApp.LabelsExcludeAny)
require.False(t, updateAppResp.AppStoreApp.SelfService)

activityData = `{"team_name": "%s", "software_title": "%s", "app_store_id": "%s", "team_id": %d, "software_title_id": %d, "platform": "%s", "self_service": false, "labels_include_any": [{"id": %d, "name": %q}]}`
s.lastActivityMatches(fleet.ActivityUpdatedAppStoreApp{}.ActivityName(),
fmt.Sprintf(activityData, team.Name,
excludeAnyApp.Name, excludeAnyApp.AdamID, team.ID, titleID, excludeAnyApp.Platform, l2.ID, l2.Name), 0)

// check that our updates worked
// double check that our updates worked
getSWTitle = getSoftwareTitleResponse{}
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d", titleID), nil, http.StatusOK, &getSWTitle, "team_id", fmt.Sprint(team.ID))
require.NotNil(t, getSWTitle.SoftwareTitle.AppStoreApp)
Expand Down
12 changes: 7 additions & 5 deletions server/service/vpp.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,27 +99,29 @@ type updateAppStoreAppRequest struct {
}

type updateAppStoreAppResponse struct {
Err error `json:"error,omitempty"`
AppStoreApp *fleet.VPPAppStoreApp `json:"app_store_app,omitempty"`
Err error `json:"error,omitempty"`
}

func (r updateAppStoreAppResponse) error() error { return r.Err }

func updateAppStoreAppEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (errorer, error) {
req := request.(*updateAppStoreAppRequest)

if err := svc.UpdateAppStoreApp(ctx, req.TitleID, req.TeamID, req.SelfService, req.LabelsIncludeAny, req.LabelsExcludeAny); err != nil {
updatedApp, err := svc.UpdateAppStoreApp(ctx, req.TitleID, req.TeamID, req.SelfService, req.LabelsIncludeAny, req.LabelsExcludeAny)
if err != nil {
return updateAppStoreAppResponse{Err: err}, nil
}

return updateAppStoreAppResponse{}, nil
return updateAppStoreAppResponse{AppStoreApp: updatedApp}, nil
}

func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny []string) error {
func (svc *Service) UpdateAppStoreApp(ctx context.Context, titleID uint, teamID *uint, selfService bool, labelsIncludeAny, labelsExcludeAny []string) (*fleet.VPPAppStoreApp, error) {
// skipauth: No authorization check needed due to implementation returning
// only license error.
svc.authz.SkipAuthorization(ctx)

return fleet.ErrMissingLicense
return nil, fleet.ErrMissingLicense
}

////////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 837e0fd

Please sign in to comment.