mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
accept 89 error on RemoveProfile as valid (#43172)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #42103 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [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/guides/committing-changes.md#changes-files) for more information. - [x] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. - [x] Timeouts are implemented and retries are limited to avoid infinite loops - [x] If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved profile removal handling: Fleet now successfully removes host OS setting entries even when the removal command encounters a "profile not found" error from the device. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
82b6614b2b
commit
3371b48373
5 changed files with 89 additions and 2 deletions
1
changes/42103-accept-89-on-profile-removal
Normal file
1
changes/42103-accept-89-on-profile-removal
Normal file
|
|
@ -0,0 +1 @@
|
|||
* Fixed an issue, where Fleet would not remove the host OS setting entry if a RemoveProfile command failed with error code 89 (Profile not found on device).
|
||||
|
|
@ -91,6 +91,21 @@ func IsRecoveryLockPasswordMismatchError(chain []mdm.ErrorChain) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// IsProfileNotFoundError checks if the error chain indicates that a profile
|
||||
// was not found on the device. When this error occurs during a RemoveProfile
|
||||
// command, it means the profile is already absent — the desired outcome.
|
||||
//
|
||||
// Known error signature:
|
||||
// - MDMClientError (89): "Profile with identifier '...' not found."
|
||||
func IsProfileNotFoundError(chain []mdm.ErrorChain) bool {
|
||||
for _, e := range chain {
|
||||
if e.ErrorDomain == "MDMClientError" && e.ErrorCode == 89 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FmtDDMError formats a DDM error message
|
||||
func FmtDDMError(reasons []fleet.MDMAppleDDMStatusErrorReason) string {
|
||||
var errMsg strings.Builder
|
||||
|
|
|
|||
|
|
@ -46,6 +46,56 @@ func TestGenerateRandomPin(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIsProfileNotFoundError(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
chain []mdm.ErrorChain
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "empty chain",
|
||||
chain: nil,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "MDMClientError 89 - profile not found",
|
||||
chain: []mdm.ErrorChain{
|
||||
{ErrorCode: 89, ErrorDomain: "MDMClientError", USEnglishDescription: "Profile with identifier 'com.example' not found."},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "different MDMClientError code",
|
||||
chain: []mdm.ErrorChain{
|
||||
{ErrorCode: 90, ErrorDomain: "MDMClientError", USEnglishDescription: "Some other error"},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "different error domain with code 89",
|
||||
chain: []mdm.ErrorChain{
|
||||
{ErrorCode: 89, ErrorDomain: "SomeOtherDomain", USEnglishDescription: "Some error"},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "profile not found in chain with other errors",
|
||||
chain: []mdm.ErrorChain{
|
||||
{ErrorCode: 100, ErrorDomain: "SomeOtherDomain", USEnglishDescription: "First error"},
|
||||
{ErrorCode: 89, ErrorDomain: "MDMClientError", USEnglishDescription: "Profile with identifier 'com.example' not found."},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range cases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := IsProfileNotFoundError(tt.chain)
|
||||
require.Equal(t, tt.expected, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsRecoveryLockPasswordMismatchError(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
|
|
|
|||
|
|
@ -3862,11 +3862,20 @@ func (svc *MDMAppleCheckinAndCommandService) CommandAndReportResults(r *mdm.Requ
|
|||
apple_mdm.FmtErrorChain(cmdResult.ErrorChain),
|
||||
)
|
||||
case "RemoveProfile":
|
||||
status := mdmAppleDeliveryStatusFromCommandStatus(cmdResult.Status)
|
||||
detail := apple_mdm.FmtErrorChain(cmdResult.ErrorChain)
|
||||
// MDMClientError 89 means "Profile not found" — for a removal, this
|
||||
// is the desired outcome, so treat it as successful.
|
||||
if status != nil && *status == fleet.MDMDeliveryFailed &&
|
||||
apple_mdm.IsProfileNotFoundError(cmdResult.ErrorChain) {
|
||||
status = &fleet.MDMDeliveryVerifying
|
||||
detail = ""
|
||||
}
|
||||
return nil, svc.ds.UpdateOrDeleteHostMDMAppleProfile(r.Context, &fleet.HostMDMAppleProfile{
|
||||
CommandUUID: cmdResult.CommandUUID,
|
||||
HostUUID: cmdResult.Identifier(),
|
||||
Status: mdmAppleDeliveryStatusFromCommandStatus(cmdResult.Status),
|
||||
Detail: apple_mdm.FmtErrorChain(cmdResult.ErrorChain),
|
||||
Status: status,
|
||||
Detail: detail,
|
||||
OperationType: fleet.MDMOperationTypeRemove,
|
||||
})
|
||||
case "DeviceLock", "EraseDevice":
|
||||
|
|
|
|||
|
|
@ -2069,6 +2069,18 @@ func TestMDMCommandAndReportResultsProfileHandling(t *testing.T) {
|
|||
OperationType: fleet.MDMOperationTypeRemove,
|
||||
},
|
||||
},
|
||||
{
|
||||
status: "Error",
|
||||
requestType: "RemoveProfile",
|
||||
errors: []mdm.ErrorChain{
|
||||
{ErrorCode: 89, ErrorDomain: "MDMClientError", USEnglishDescription: "Profile with identifier 'com.example' not found."},
|
||||
},
|
||||
want: &fleet.HostMDMAppleProfile{
|
||||
Status: &fleet.MDMDeliveryVerifying,
|
||||
Detail: "",
|
||||
OperationType: fleet.MDMOperationTypeRemove,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
|
|
|
|||
Loading…
Reference in a new issue