fix issue with resetting abm token teams (#26259)

For #24040

Add gitops option for the request to modify the app config.

There was an issue with the abm token teams getting reset to default
anytime the `PATCH /fleet/config` endpoint was called. @jahzielv and I
discussed various options on how to solve this and agreed that the
approach taken in this PR was the quickest but not the best. Ideally,
we'd like the gitops client to send back the data to the endpoint that
its going to update. This will allow the `PATCH /fleet/config` endpoint
to work like a standard `PATCH` request and only update the options
provided instead of updating the app config differently depending on the
client calling the endpoint.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files)
for more information.
- [x] Added/updated automated tests
- [x] Manual QA for all new/changed functionality
This commit is contained in:
Gabriel Hernandez
2025-02-18 20:08:06 +00:00
committed by GitHub
parent e5fd094c68
commit a669f3938b
5 changed files with 49 additions and 10 deletions
@@ -0,0 +1 @@
- fix an issue where the abm token teams were being reset when making updates to the app config.
-1
View File
@@ -1301,7 +1301,6 @@ func (svc *Service) UpdateABMTokenTeams(ctx context.Context, tokenID uint, macOS
}
// validate the team IDs
token.MacOSTeam = fleet.ABMTokenTeam{Name: fleet.TeamNameNoTeam}
token.MacOSDefaultTeamID = nil
token.IOSTeam = fleet.ABMTokenTeam{Name: fleet.TeamNameNoTeam}
+11 -9
View File
@@ -702,7 +702,6 @@ func (svc *Service) ModifyAppConfig(ctx context.Context, p []byte, applyOpts fle
}
}
// Reset teams for ABM tokens that exist in Fleet but aren't present in the config being passed
tokensInCfg := make(map[string]struct{})
for _, t := range newAppConfig.MDM.AppleBusinessManager.Value {
tokensInCfg[t.OrganizationName] = struct{}{}
@@ -712,13 +711,16 @@ func (svc *Service) ModifyAppConfig(ctx context.Context, p []byte, applyOpts fle
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "listing ABM tokens")
}
for _, tok := range toks {
if _, ok := tokensInCfg[tok.OrganizationName]; !ok {
tok.MacOSDefaultTeamID = nil
tok.IOSDefaultTeamID = nil
tok.IPadOSDefaultTeamID = nil
if err := svc.ds.SaveABMToken(ctx, tok); err != nil {
return nil, ctxerr.Wrap(ctx, err, "saving ABM token assignments")
if newAppConfig.MDM.AppleBusinessManager.Set && len(newAppConfig.MDM.AppleBusinessManager.Value) == 0 {
for _, tok := range toks {
if _, ok := tokensInCfg[tok.OrganizationName]; !ok {
tok.MacOSDefaultTeamID = nil
tok.IOSDefaultTeamID = nil
tok.IPadOSDefaultTeamID = nil
if err := svc.ds.SaveABMToken(ctx, tok); err != nil {
return nil, ctxerr.Wrap(ctx, err, "saving ABM token assignments")
}
}
}
}
@@ -1229,7 +1231,7 @@ func (svc *Service) validateABMAssignments(
return []*fleet.ABMToken{tok}, nil
}
if mdm.AppleBusinessManager.Set && mdm.AppleBusinessManager.Valid {
if mdm.AppleBusinessManager.Set && len(mdm.AppleBusinessManager.Value) > 0 {
if !license.IsPremium() {
invalid.Append("mdm.apple_business_manager", ErrMissingLicense.Error())
return nil, nil
+6
View File
@@ -1613,6 +1613,12 @@ func (c *Client) DoGitOps(
return nil, errors.New("org_settings.mdm config is not a map")
}
if _, ok := mdmAppConfig["apple_bm_default_team"]; !ok && appConfig.License.IsPremium() {
if _, ok := mdmAppConfig["apple_business_manager"]; !ok {
mdmAppConfig["apple_business_manager"] = []interface{}{}
}
}
// Put in default value for volume_purchasing_program to clear the configuration if it's not set.
if v, ok := mdmAppConfig["volume_purchasing_program"]; !ok || v == nil {
mdmAppConfig["volume_purchasing_program"] = []interface{}{}
+31
View File
@@ -950,6 +950,37 @@ func (s *integrationMDMTestSuite) getABMTokenByName(orgName string, tokens []*fl
return nil
}
func (s *integrationMDMTestSuite) TestABMTeamPersistsOnConfigChange() {
t := s.T()
s.enableABM(t.Name())
// Same tests, but for teams
team, err := s.ds.NewTeam(context.Background(), &fleet.Team{
Name: "team1",
Description: "desc team1",
})
require.NoError(t, err)
tokensResp := listABMTokensResponse{}
s.DoJSON("GET", "/api/latest/fleet/abm_tokens", nil, http.StatusOK, &tokensResp)
tok := s.getABMTokenByName(t.Name(), tokensResp.Tokens)
s.DoJSON("PATCH", fmt.Sprintf("/api/latest/fleet/abm_tokens/%d/teams", tok.ID), json.RawMessage(fmt.Sprintf(`{
"ios_team_id": %d
}`, team.ID)), http.StatusOK, &updateABMTokenTeamsResponse{})
s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(`{
"org_info": {"org_name": "New name"}
}`), http.StatusOK, &appConfigResponse{})
s.DoJSON("GET", "/api/latest/fleet/abm_tokens", nil, http.StatusOK, &tokensResp)
require.Len(t, tokensResp.Tokens, 1)
assert.Equal(t, team.Name, tokensResp.Tokens[0].IOSTeam.Name)
assert.Equal(t, team.ID, tokensResp.Tokens[0].IOSTeam.ID)
}
func (s *integrationMDMTestSuite) TestABMExpiredToken() {
t := s.T()