diff --git a/server/service/integration_mdm_dep_test.go b/server/service/integration_mdm_dep_test.go index f9fe498981..21e34c0ff7 100644 --- a/server/service/integration_mdm_dep_test.go +++ b/server/service/integration_mdm_dep_test.go @@ -221,6 +221,70 @@ func (s *integrationMDMTestSuite) TestDEPEnrollReleaseDeviceTeam() { } } +func (s *integrationMDMTestSuite) TestDEPEnrollReleaseIphoneTeam() { + t := s.T() + ctx := context.Background() + + // Set up a mock DEP Apple API + s.enableABM(t.Name()) + s.mockDEPResponse(t.Name(), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + encoder := json.NewEncoder(w) + switch r.URL.Path { + case "/session": + _, _ = w.Write([]byte(`{"auth_session_token": "session123"}`)) + case "/account": + _, _ = w.Write([]byte(fmt.Sprintf(`{"admin_id": "admin123", "org_name": "%s"}`, "foo"))) + case "/profile": + require.NoError(t, encoder.Encode(godep.ProfileResponse{ProfileUUID: "profile123"})) + } + })) + + teamDevice := godep.Device{SerialNumber: "IOS0_SERIAL", Model: "iPhone 16 Pro", OS: "ios", DeviceFamily: "iPhone", OpType: "added"} + + tm, err := s.ds.NewTeam(ctx, &fleet.Team{Name: "test-team-device-release"}) + require.NoError(t, err) + + enrollSecret := "test-release-dep-device-team" + err = s.ds.ApplyEnrollSecrets(ctx, &tm.ID, []*fleet.EnrollSecret{{Secret: enrollSecret}}) + require.NoError(t, err) + + // add a custom setup assistant and ensure enable_release_device_manually is + // false (the default) + teamProf := `{"y": 2}` + s.Do("POST", "/api/latest/fleet/enrollment_profiles/automatic", createMDMAppleSetupAssistantRequest{ + TeamID: &tm.ID, + Name: "team", + EnrollmentProfile: json.RawMessage(teamProf), + }, http.StatusOK) + payload := map[string]any{ + "enable_release_device_manually": false, + } + s.Do("PATCH", "/api/latest/fleet/setup_experience", json.RawMessage(jsonMustMarshal(t, payload)), http.StatusNoContent) + + var acResp appConfigResponse + s.enableABM("fleet_ade_test") + s.DoJSON("PATCH", "/api/latest/fleet/config", json.RawMessage(fmt.Sprintf(`{ + "mdm": { + "apple_business_manager": [{ + "organization_name": %q, + "macos_team": %q, + "ios_team": %q, + "ipados_team": %q + }] + } + }`, "fleet_ade_test", tm.Name, tm.Name, tm.Name)), http.StatusOK, &acResp) + + // add a team profile + teamProfile := mobileconfigForTest("N2", "I2") + s.Do("POST", "/api/v1/fleet/mdm/apple/profiles/batch", batchSetMDMAppleProfilesRequest{Profiles: [][]byte{teamProfile}}, http.StatusNoContent, "team_id", fmt.Sprint(tm.ID)) + + for _, enableReleaseManually := range []bool{false, true} { + t.Run(fmt.Sprintf("enableReleaseManually=%t", enableReleaseManually), func(t *testing.T) { + s.runDEPEnrollReleaseDeviceTest(t, teamDevice, enableReleaseManually, &tm.ID, "I2", false) + }) + } +} + func (s *integrationMDMTestSuite) runDEPEnrollReleaseDeviceTest(t *testing.T, device godep.Device, enableReleaseManually bool, teamID *uint, customProfileIdent string, useOldFleetdFlow bool) { ctx := context.Background() @@ -297,6 +361,11 @@ func (s *integrationMDMTestSuite) runDEPEnrollReleaseDeviceTest(t *testing.T, de // enroll the host depURLToken := loadEnrollmentProfileDEPToken(t, s.ds) mdmDevice := mdmtest.NewTestMDMClientAppleDEP(s.server.URL, depURLToken) + var isIphone bool + if device.DeviceFamily == "iPhone" { + mdmDevice.Model = "iPhone 14,6" + isIphone = true + } mdmDevice.SerialNumber = device.SerialNumber err := mdmDevice.Enroll() require.NoError(t, err) @@ -333,10 +402,17 @@ func (s *integrationMDMTestSuite) runDEPEnrollReleaseDeviceTest(t *testing.T, de require.NoError(t, err) } - // expected commands: install fleetd, install bootstrap, install CA, install profiles - // (custom one, fleetd configuration, FileVault) (not expected: account - // configuration, since enrollment_reference not set) - require.Len(t, cmds, 6) + if isIphone { + // expected commands: install CA, install profile (only the custom one), + // not expected: account configuration, since enrollment_reference not set + require.Len(t, cmds, 2) + } else { + // expected commands: install fleetd, install bootstrap, install CA, install profiles + // (custom one, fleetd configuration, FileVault) (not expected: account + // configuration, since enrollment_reference not set) + require.Len(t, cmds, 6) + } + var installProfileCount, installEnterpriseCount, otherCount int var profileCustomSeen, profileFleetdSeen, profileFleetCASeen, profileFileVaultSeen bool for _, cmd := range cmds { @@ -361,6 +437,68 @@ func (s *integrationMDMTestSuite) runDEPEnrollReleaseDeviceTest(t *testing.T, de otherCount++ } } + + if isIphone { + require.Equal(t, 2, installProfileCount) + require.Equal(t, 0, installEnterpriseCount) + require.Equal(t, 0, otherCount) + require.True(t, profileCustomSeen) + require.False(t, profileFleetdSeen) + require.True(t, profileFleetCASeen) + require.False(t, profileFileVaultSeen) + + // for iDevices, fleetd is not installed so the rest of this test does not apply. + if enableReleaseManually { + // get the worker's pending job from the future, there should not be any + // because it needs to be released manually + pending, err := s.ds.GetQueuedJobs(ctx, 1, time.Now().UTC().Add(time.Minute)) + require.NoError(t, err) + require.Empty(t, pending) + } else { + // otherwise the device release job should be enqueued + pending, err := s.ds.GetQueuedJobs(ctx, 1, time.Now().UTC().Add(time.Minute)) + require.NoError(t, err) + require.Len(t, pending, 1) + require.Equal(t, "apple_mdm", pending[0].Name) + require.Contains(t, string(*pending[0].Args), worker.AppleMDMPostDEPReleaseDeviceTask) + + // make the pending job ready to run immediately and run the job + mysql.ExecAdhocSQL(t, s.ds, func(q sqlx.ExtContext) error { + _, err := q.ExecContext(ctx, `UPDATE jobs SET not_before = ? WHERE id = ?`, time.Now().Add(-1*time.Minute).UTC(), pending[0].ID) + return err + }) + + s.runWorker() + + // make the device process the commands, it should receive the + // DeviceConfigured one. + cmds = cmds[:0] + cmd, err = mdmDevice.Idle() + require.NoError(t, err) + for cmd != nil { + var fullCmd micromdm.CommandPayload + require.NoError(t, plist.Unmarshal(cmd.Raw, &fullCmd)) + cmds = append(cmds, &fullCmd) + cmd, err = mdmDevice.Acknowledge(cmd.CommandUUID) + require.NoError(t, err) + } + + require.Len(t, cmds, 1) + var deviceConfiguredCount int + for _, cmd := range cmds { + switch cmd.Command.RequestType { + case "DeviceConfigured": + deviceConfiguredCount++ + default: + otherCount++ + } + } + require.Equal(t, 1, deviceConfiguredCount) + require.Equal(t, 0, otherCount) + } + return + } + require.Equal(t, 4, installProfileCount) require.Equal(t, 2, installEnterpriseCount) require.Equal(t, 0, otherCount)