Skip to content

Remove unenroll pending and add Android COBO wipe to Free - #46653

Merged
getvictor merged 6 commits into
mainfrom
victor/41683-design-feedback
Jun 2, 2026
Merged

Remove unenroll pending and add Android COBO wipe to Free#46653
getvictor merged 6 commits into
mainfrom
victor/41683-design-feedback

Conversation

@getvictor

@getvictor getvictor commented Jun 2, 2026

Copy link
Copy Markdown
Member

Related issue: Resolves #41683

Unenroll/wipe Android on Fleet Free: https://www.youtube.com/watch?v=JvsD3WBcDgE

Checklist for submitter

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

  • New Features

    • Android Lock, Wipe, and Clear passcode commands supported; Lock and Clear for both personal (BYO) and company-owned (COBO) devices, Wipe for COBO only.
    • Android COBO Wipe exposed in Fleet Free (UI and API).
  • Bug Fixes

    • Personal Android unenroll now removes only the work profile (personal data preserved) and no longer shows a transient “wiping” status in the UI.

@getvictor
getvictor requested a review from Copilot June 2, 2026 17:05
@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@getvictor

Copy link
Copy Markdown
Member Author

/agentic_review

@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 2, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0)

Grey Divider


Action required

1. BYO status always reset ✓ Resolved 🐞 Bug ≡ Correctness
Description
suppressAndroidBYODWipeStatus() unconditionally forces Android hosts with enrollment_status "On
(personal)" to device_status="unlocked" and pending_action="". This masks real pending/active states
for BYO Android Lock and Clear passcode commands, so UI/API will incorrectly show the host as
unlocked with no pending action.
Code

server/service/hosts.go[R437-446]

Evidence
The suppression function overwrites status for every Android BYO host, but Android Lock and Clear
passcode flows have no BYO restriction and rely on these status fields to surface pending/active
state.

server/service/hosts.go[437-447]
server/service/hosts.go[514-524]
server/service/hosts.go[1859-1867]
server/fleet/scripts.go[636-733]
server/mdm/android/service/service.go[933-1046]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`suppressAndroidBYODWipeStatus` currently overwrites `host.MDM.DeviceStatus` and `host.MDM.PendingAction` for **all** Android BYO (personal) hosts, regardless of whether the status came from an unenroll-driven wipe or from legitimate Lock / Clear passcode actions.
### Issue Context
Lock and Clear passcode are supported for Android hosts (including BYO), and their state is surfaced via `HostLockWipeStatus` -> `DeviceStatus()` / `PendingAction()`. The new suppression should only hide the *unenroll-driven* BYO wipe state.
### Fix Focus Areas
- server/service/hosts.go[437-447]
- server/service/hosts.go[514-524]
- server/service/hosts.go[1859-1867]
- server/service/labels.go[457-465]
### What to change
- Narrow `suppressAndroidBYODWipeStatus` to only suppress wipe-related state for BYO Android, e.g.:
- Only suppress when `host.MDM.PendingAction != nil && *host.MDM.PendingAction == string(fleet.PendingActionWipe)` (and optionally also when `DeviceStatus == wiped` if you want to avoid showing “Wiped” for BYO work-profile wipes).
- Do **not** suppress when pending action is `lock` or `clear_passcode`.
- Update/add unit tests to cover:
- Android BYO + pending_action=wipe gets suppressed.
- Android BYO + pending_action=lock (or clear_passcode) does **not** get suppressed.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Invalid test pointer construction 🐞 Bug ≡ Correctness
Description
The new tests call new("On (personal)") / new("On (automatic)") for *string pointers, but Go's
built-in new requires a type, not a value. This will fail compilation of
server/service/hosts_test.go.
Code

server/service/hosts_test.go[R3501-3562]

Evidence
The added tests include enrollment: new("On (personal)") and `EnrollmentStatus: new("On
(personal)"), which cannot compile because new` must be called with a type.

server/service/hosts_test.go[3498-3568]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The tests added in `server/service/hosts_test.go` attempt to build `*string` values using `new("...")`, which is invalid Go syntax and will not compile.
### Issue Context
`EnrollmentStatus` is a `*string`, so tests should use an addressable string variable or a helper like `ptr.String("...")` (preferred in this repo).
### Fix Focus Areas
- server/service/hosts_test.go[3501-3522]
- server/service/hosts_test.go[3559-3563]
### What to change
- Replace `new("On (personal)")` and `new("On (automatic)")` with `ptr.String("On (personal)")` / `ptr.String("On (automatic)")`.
- Ensure the file imports `github.com/fleetdm/fleet/v4/server/ptr` if it doesn't already.
- (Optional for clarity) Also update any other pointer-to-string initializations in those tests to consistently use `ptr.String(...)`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@codecov

codecov Bot commented Jun 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 30.64516% with 43 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.87%. Comparing base (0bd7dbc) to head (c7875a4).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
server/service/scripts.go 14.28% 39 Missing and 3 partials ⚠️
ee/server/service/hosts.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #46653      +/-   ##
==========================================
- Coverage   66.88%   66.87%   -0.01%     
==========================================
  Files        2814     2814              
  Lines      224028   224315     +287     
  Branches    11491    11383     -108     
==========================================
+ Hits       149834   150013     +179     
- Misses      60601    60675      +74     
- Partials    13593    13627      +34     
Flag Coverage Δ
backend 68.59% <27.11%> (-0.02%) ⬇️
frontend 56.54% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread server/service/hosts.go Outdated
Comment thread server/service/hosts_test.go Outdated
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR implements Android device wipe commands for Fleet Free users targeting company-owned hosts exclusively, while suppressing transient wipe states for personally-owned Android enrollments. The backend implements the complete WipeHost service with authorization, Android-only validation, and pending state checks. A new helper function suppresses device status and pending action for Android BYO hosts across all host-loading paths to hide UI artifacts. The frontend simplifies the unenroll modal by removing optimistic status updates, updates wipe dropdown gating to allow Fleet Free access for Android COBO, and removes special-case status display logic now that suppression is handled server-side.

Possibly related issues

  • #46286: Extends Android clear-passcode pending-state mechanism (host_mdm_actions.clear_passcode_ref and mdm pending/device status fields) paralleled to Apple platforms, touching the same data structures and UI/server behavior modified in this PR.

Possibly related PRs

  • fleetdm/fleet#46107: Adds the fleetdm.com proxy endpoint and SDK for issuing underlying Android AMAPI commands that this PR wires into the Fleet server WipeHost flow.
  • fleetdm/fleet#46174: Modifies Android host Lock/Wipe/Clear passcode UI behavior and HostActionsDropdown/HostHeader pending-state handling that this PR's BYO suppression changes.
  • fleetdm/fleet#46031: Introduces core Android commands backend infrastructure that this PR's Android-specific WipeHost implementation relies on.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: removing unenroll pending (badge/status) and enabling Android company-owned device wipe on the free tier.
Description check ✅ Passed The description provides the related issue number (#41683), confirms a changes file was added, documents completed testing (automated tests and manual QA), and includes a demo link, meeting template requirements.
Linked Issues check ✅ Passed Code changes comprehensively implement the #41683 requirements: backend Android lock/wipe/clear-passcode support, Free-tier Android COBO wipe enablement, status suppression for BYO unenroll, UI dropdown logic updates, tests, and activity logging.
Out of Scope Changes check ✅ Passed All changes are directly scoped to #41683: Android MDM command support, Free-tier wipe gating, unenroll status suppression, UI updates, and backend/service layer implementations without unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch victor/41683-design-feedback

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx (1)

1718-1725: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Keep BYO Android unenroll hidden after submit.

Removing the success callback leaves this page with no way to mark BYO Android unenroll as pending. In this PR the host reads are normalized back to device_status="unlocked" / no pending action, while the dropdown still hides Android Unenroll only when hostMdmDeviceStatus !== "unlocked". That means the action stays visible immediately after a successful unenroll and can be fired again until some other field changes. Preserve a local pending flag here, or gate the dropdown on a dedicated server-side unenroll-pending signal instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx` around
lines 1718 - 1725, HostDetailsPage currently loses the "unenroll pending" state
after a successful BYO Android unenroll because the success callback was
removed; add a local state flag (e.g., pendingByoAndroidUnenroll) in
HostDetailsPage and set it true from the UnenrollMdmModal success handler (pass
a prop like onSuccess to UnenrollMdmModal), then use that flag alongside
hostMdmDeviceStatus (and/or host.mdm.device_status) to hide the Android Unenroll
action in the dropdown; clear the flag when the modal closes or when the host is
refreshed/host.mdm.device_status changes away from "unlocked" so the UI stays
consistent until the server-side state changes.
🧹 Nitpick comments (1)
server/service/hosts_test.go (1)

3541-3569: ⚡ Quick win

Add one core-service COBO happy-path test.

These cases only prove the early exits. They never reach the new Android COBO branch in server/service/scripts.go that checks config/connectivity, calls androidSvc.WipeAndroidHost, and records ActivityTypeWipedHost. Because Premium overrides WipeHost, premium integration coverage won’t exercise this core implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/service/hosts_test.go` around lines 3541 - 3569, Add a COBO Android
happy-path subtest to TestWipeHostFreeTierGating that exercises the core-service
android branch: mock ds.HostFunc/HostLiteFunc to return a host with Platform
"android" and MDM.EnrollmentStatus set to a company/COBO value (e.g., "On
(company)"), inject a mocked android service on svc where
androidSvc.WipeAndroidHost returns nil, call svc.WipeHost(ctx, hostID, nil) and
assert no error, and also assert that androidSvc.WipeAndroidHost was invoked and
that an activity of type ActivityTypeWipedHost was recorded (or the DS activity
create/update mock was called accordingly) so the core implementation in
server/service/scripts.go is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/service/scripts.go`:
- Around line 1285-1294: When svc.ds.Host returns an error, don’t immediately
reveal host existence; follow the RunHostScript/GetScriptResult fallback-auth
pattern: if fleet.IsNotFound(err) then call svc.authz.Authorize(ctx, <no-team
wipe target>) (i.e. authorize a wipe action with no TeamID) and only return the
not-found error if that authorization succeeds; for other errors keep the
existing ctxerr.Wrap behavior; otherwise continue to the existing team-scoped
Authorize call (svc.authz.Authorize with fleet.MDMCommandAuthz{TeamID:
host.TeamID}) so team-scoped users cannot distinguish “missing host” from
“exists in another team.”
- Around line 1312-1316: The error branch is checking the wrong sentinel so the
Android-specific error handling never runs; update the errors.Is comparison in
the VerifyMDMAndroidConfigured error path to test for
fleet.ErrAndroidMDMNotConfigured (instead of fleet.ErrMDMNotConfigured) so that
when svc.VerifyMDMAndroidConfigured(ctx) returns that sentinel you construct the
fleet.NewInvalidArgumentError("host_id",
fleet.AndroidMDMNotConfiguredMessage).WithStatus(http.StatusBadRequest) before
returning via ctxerr.Wrap(ctx, err, "check android MDM enabled").

---

Outside diff comments:
In `@frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx`:
- Around line 1718-1725: HostDetailsPage currently loses the "unenroll pending"
state after a successful BYO Android unenroll because the success callback was
removed; add a local state flag (e.g., pendingByoAndroidUnenroll) in
HostDetailsPage and set it true from the UnenrollMdmModal success handler (pass
a prop like onSuccess to UnenrollMdmModal), then use that flag alongside
hostMdmDeviceStatus (and/or host.mdm.device_status) to hide the Android Unenroll
action in the dropdown; clear the flag when the modal closes or when the host is
refreshed/host.mdm.device_status changes away from "unlocked" so the UI stays
consistent until the server-side state changes.

---

Nitpick comments:
In `@server/service/hosts_test.go`:
- Around line 3541-3569: Add a COBO Android happy-path subtest to
TestWipeHostFreeTierGating that exercises the core-service android branch: mock
ds.HostFunc/HostLiteFunc to return a host with Platform "android" and
MDM.EnrollmentStatus set to a company/COBO value (e.g., "On (company)"), inject
a mocked android service on svc where androidSvc.WipeAndroidHost returns nil,
call svc.WipeHost(ctx, hostID, nil) and assert no error, and also assert that
androidSvc.WipeAndroidHost was invoked and that an activity of type
ActivityTypeWipedHost was recorded (or the DS activity create/update mock was
called accordingly) so the core implementation in server/service/scripts.go is
covered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4f6f15bb-1462-4218-83a6-5db774c3a7e1

📥 Commits

Reviewing files that changed from the base of the PR and between 880d751 and 376c41f.

📒 Files selected for processing (11)
  • changes/41683-android-lock-wipe-clear-passcode
  • frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx
  • frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.tsx
  • frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
  • frontend/pages/hosts/details/HostDetailsPage/modals/UnenrollMdmModal/UnenrollMdmModal.tsx
  • frontend/pages/hosts/details/cards/HostHeader/HostHeader.tests.tsx
  • frontend/pages/hosts/details/cards/HostHeader/HostHeader.tsx
  • server/service/hosts.go
  • server/service/hosts_test.go
  • server/service/labels.go
  • server/service/scripts.go
💤 Files with no reviewable changes (1)
  • frontend/pages/hosts/details/HostDetailsPage/modals/UnenrollMdmModal/UnenrollMdmModal.tsx

Comment thread server/service/scripts.go
Comment thread server/service/scripts.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts Android MDM command behavior to (1) stop surfacing a transient “unenroll pending” state for Android BYOD unenroll (which internally triggers a work-profile wipe) and (2) make Android COBO wipe available on Fleet Free (UI + core service implementation), while keeping wipe on other platforms Premium-only.

Changes:

  • Implemented Fleet Free WipeHost behavior for Android (COBO), including authz + validations + activity creation.
  • Added backend suppression of the transient BYOD-unenroll wipe state so UI no longer shows an “Unenroll pending” badge.
  • Updated frontend gating + tests to show Android COBO Wipe on Free and removed the special BYOD “Unenroll pending” UI override.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
server/service/scripts.go Implements core (Fleet Free) Android wipe flow and license gating for other platforms.
server/service/labels.go Applies BYOD wipe-status suppression in label host listings when device status is included.
server/service/hosts.go Adds helper to suppress transient BYOD-unenroll wipe status in host list/detail flows.
server/service/hosts_test.go Adds unit tests for suppression helper and Free-tier wipe gating.
frontend/pages/hosts/details/HostDetailsPage/modals/UnenrollMdmModal/UnenrollMdmModal.tsx Removes now-unneeded onSuccess callback used for optimistic “unenroll pending” UI state.
frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx Removes Android BYOD “set host mdm device state to wiping” optimistic update.
frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx Adds/updates dropdown tests for Free-tier Android COBO wipe and removes BYOD “pending unenroll” case.
frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.tsx Updates wipe eligibility logic to allow Android COBO wipe on Fleet Free.
frontend/pages/hosts/details/cards/HostHeader/HostHeader.tsx Removes special-case “Unenroll pending” label/tooltip override for BYOD Android.
frontend/pages/hosts/details/cards/HostHeader/HostHeader.tests.tsx Updates HostHeader tests to reflect removal of “Unenroll pending” badge behavior.
changes/41683-android-lock-wipe-clear-passcode Documents Free-tier availability of Android COBO wipe while keeping other platforms Premium-only.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/service/hosts.go Outdated
Comment thread server/service/scripts.go
Comment thread server/service/scripts.go
Comment thread server/service/hosts_test.go
@getvictor
getvictor marked this pull request as ready for review June 2, 2026 19:21
@getvictor
getvictor requested review from a team as code owners June 2, 2026 19:21

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
ee/server/service/hosts.go (1)

123-128: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Same sentinel mismatch exists in LockHost for Android.

VerifyMDMAndroidConfigured returns fleet.ErrAndroidMDMNotConfigured, but line 124 checks against fleet.ErrMDMNotConfigured. This branch never fires, so the intended Android-specific bad-request message is skipped when Android MDM is disabled—identical to the bug fixed in WipeHost at line 333.

Suggested fix
 	case "android":
 		// Lock is supported for BYO and COBO. The Android Service.LockAndroidHost call enforces
 		// that the host is enrolled (svc.ds.AndroidHostLiteByHostUUID -> NotFound otherwise).
 		if err := svc.VerifyMDMAndroidConfigured(ctx); err != nil {
-			if errors.Is(err, fleet.ErrMDMNotConfigured) {
+			if errors.Is(err, fleet.ErrAndroidMDMNotConfigured) {
 				err = fleet.NewInvalidArgumentError("host_id", fleet.AndroidMDMNotConfiguredMessage).WithStatus(http.StatusBadRequest)
 			}
 			return "", ctxerr.Wrap(ctx, err, "check android MDM enabled")
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ee/server/service/hosts.go` around lines 123 - 128, The Android sentinel
mismatch in LockHost means the branch never fires; update the error check in the
LockHost handling of svc.VerifyMDMAndroidConfigured(ctx) to compare against
fleet.ErrAndroidMDMNotConfigured (not fleet.ErrMDMNotConfigured) and, when
matched, build the bad-request using fleet.NewInvalidArgumentError("host_id",
fleet.AndroidMDMNotConfiguredMessage). Keep the existing ctxerr.Wrap(ctx, err,
"check android MDM enabled") behavior otherwise.
server/service/hosts.go (1)

307-307: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Remove debug print statements.

These fmt.Println statements appear to be debugging artifacts that were left in the code. They should be removed before merging to production as they will pollute logs and provide no value.

🐛 Proposed fix
 		st, err := svc.SoftwareTitleByID(ctx, titleID, req.Opts.TeamFilter)
 		switch {
 		case err == nil:
-			fmt.Println("regular")
 			softwareTitle = st
 
 		case fleet.IsNotFound(err):
 			// Not found: only ID + Name as string from helper.
 			name, displayName, errName := svc.SoftwareTitleNameForHostFilter(ctx, titleID)
 			if errName != nil && !fleet.IsNotFound(errName) {
 				return listHostsResponse{Err: errName}, nil
 			}
 			if errName == nil {
-				fmt.Println("here")
 				softwareTitle = &fleet.SoftwareTitle{
 					ID: titleID,
 				}

Also applies to: 317-317

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/service/hosts.go` at line 307, Remove the stray debug print statements
by deleting the fmt.Println("regular") calls (and any other plain fmt.Println
usages) left in hosts.go; if you need to surface runtime info keep or replace
them with the project's logger (e.g., processLogger or the existing logging
helper) at the appropriate level, and ensure no plain fmt.Println calls remain
(specifically remove the occurrences of fmt.Println("regular") around the
previously noted lines).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/service/integration_core_test.go`:
- Around line 8356-8360: Add a positive test that creates an Android COBO host
and asserts the wipe endpoint returns 200 OK: use s.createHosts(t, "android")
(or the appropriate helper variant that produces an Android COBO host) to obtain
wipeHost, then call s.Do("POST", fmt.Sprintf("/api/v1/fleet/hosts/%d/wipe",
wipeHost.ID), nil, http.StatusOK). Place this alongside the existing Darwin
checks so the test verifies Android COBO wipe succeeds on Fleet Free while
Darwin still returns StatusPaymentRequired.

---

Outside diff comments:
In `@ee/server/service/hosts.go`:
- Around line 123-128: The Android sentinel mismatch in LockHost means the
branch never fires; update the error check in the LockHost handling of
svc.VerifyMDMAndroidConfigured(ctx) to compare against
fleet.ErrAndroidMDMNotConfigured (not fleet.ErrMDMNotConfigured) and, when
matched, build the bad-request using fleet.NewInvalidArgumentError("host_id",
fleet.AndroidMDMNotConfiguredMessage). Keep the existing ctxerr.Wrap(ctx, err,
"check android MDM enabled") behavior otherwise.

In `@server/service/hosts.go`:
- Line 307: Remove the stray debug print statements by deleting the
fmt.Println("regular") calls (and any other plain fmt.Println usages) left in
hosts.go; if you need to surface runtime info keep or replace them with the
project's logger (e.g., processLogger or the existing logging helper) at the
appropriate level, and ensure no plain fmt.Println calls remain (specifically
remove the occurrences of fmt.Println("regular") around the previously noted
lines).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: babd1067-0821-4def-90d0-6461d30c7e14

📥 Commits

Reviewing files that changed from the base of the PR and between 376c41f and c7875a4.

📒 Files selected for processing (11)
  • ee/server/service/hosts.go
  • frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx
  • frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.tsx
  • frontend/pages/hosts/details/cards/HostHeader/HostHeader.tests.tsx
  • server/fleet/datastore.go
  • server/mdm/android/service/service.go
  • server/service/hosts.go
  • server/service/hosts_test.go
  • server/service/integration_core_test.go
  • server/service/integration_mdm_test.go
  • server/service/scripts.go
💤 Files with no reviewable changes (2)
  • frontend/pages/hosts/details/cards/HostHeader/HostHeader.tests.tsx
  • frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx
✅ Files skipped from review due to trivial changes (1)
  • server/mdm/android/service/service.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • server/service/hosts_test.go
  • frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.tsx

Comment thread server/service/integration_core_test.go
Comment thread server/service/scripts.go
// NOTE: keep this Android wipe flow in sync with the Premium implementation in ee/server/service/hosts.go
// (WipeHost + enqueueWipeHostRequest). Wipe is COBO-only for Android; BYO unenroll already runs an AMAPI WIPE
// under the hood (see UnenrollAndroidHost), so routing BYO hosts through Wipe would be redundant + misleading.
if host.MDM.EnrollmentStatus != nil && *host.MDM.EnrollmentStatus == "On (personal)" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Non-blocking. But I like how the front end does this
https://github.com/fleetdm/fleet/blob/main/frontend/interfaces/mdm.ts#L55-L61
makes these feel more like constants vs random strings littered in the code. Could we do the same in go?

  const (
      MDMEnrollmentStatusPersonal  = "On (personal)"
      MDMEnrollmentStatusAutomatic = "On (automatic)"
      MDMEnrollmentStatusManual    = "On (manual)"
      MDMEnrollmentStatusPending   = "Pending"
      MDMEnrollmentStatusOff       = "Off"
  )

Perhaps in server/fleet/hosts.go.

Then these become *host.MDM.EnrollmentStatus == fleet.MDMEnrollmentStatusPersonal which make it feel a bit cleaner.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I agree, but that would have been a bunch more lines of changes, so I didn't do this fix at this time.

Comment thread server/service/scripts.go
return fleet.ErrMissingLicense
}

// NOTE: keep this Android wipe flow in sync with the Premium implementation in ee/server/service/hosts.go

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Non-blocking. But seems like a better way to do this would be to extract a validateAndroidWipeRequest(ctx, host, ds) error helper that both call.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I can do a follow up PR for this.

@getvictor
getvictor merged commit fa7d928 into main Jun 2, 2026
45 checks passed
@getvictor
getvictor deleted the victor/41683-design-feedback branch June 2, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android commands: Lock, wipe, & clear passcode

3 participants