Skip to content

Conversation

@MagnusHJensen
Copy link
Member

@MagnusHJensen MagnusHJensen commented Oct 3, 2025

Related issue: Resolves #33416

It's been decided to ship the feature and in the guide mention the apple bug, that we are currently tracking.
Slack 🧵

Checklist for submitter

If some of the following don't apply, delete the relevant line.

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

Testing

  • Added/updated automated tests

  • QA'd all new/changed functionality manually

Summary by CodeRabbit

  • New Features
    • Added Lost Mode support to lock iOS and iPadOS devices.
    • Added ability to disable Lost Mode to unlock iOS/iPadOS devices.
  • Improvements
    • More consistent lock/unlock experience across macOS, iOS/iPadOS, Windows, and Linux, with clearer status and activity updates.
    • iOS/iPadOS now shows pending unlock status while Lost Mode disable is in progress.
  • Tests
    • Added comprehensive end-to-end tests covering lock/unlock/wipe across Apple, Windows, and Linux devices.

@codecov
Copy link

codecov bot commented Oct 3, 2025

Codecov Report

❌ Patch coverage is 71.75141% with 50 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.23%. Comparing base (e19879e) to head (fedc695).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
server/mdm/apple/commander.go 59.61% 14 Missing and 7 partials ⚠️
ee/server/service/hosts.go 73.97% 13 Missing and 6 partials ⚠️
server/datastore/mysql/nanomdm_storage.go 71.42% 4 Missing and 2 partials ⚠️
server/datastore/mysql/scripts.go 82.35% 2 Missing and 1 partial ⚠️
server/service/apple_mdm.go 50.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #33805      +/-   ##
==========================================
+ Coverage   63.81%   64.23%   +0.42%     
==========================================
  Files        1876     2058     +182     
  Lines      185549   207072   +21523     
  Branches     6810     6810              
==========================================
+ Hits       118399   133012   +14613     
- Misses      57484    63617    +6133     
- Partials     9666    10443     +777     
Flag Coverage Δ
backend 65.34% <71.75%> (+0.33%) ⬆️

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.

@MagnusHJensen
Copy link
Member Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

Walkthrough

Implements Lost Mode-based lock/unlock for iOS/iPadOS alongside existing macOS, updates datastore and interfaces, adds command issuer methods, adjusts status handling, and expands tests. Renames cleanup method to Apple-generic form, introduces device unlock enqueueing, and integrates per-platform lock/unlock control flow in services.

Changes

Cohort / File(s) Summary
Service: per-platform lock/unlock flow
ee/server/service/hosts.go, server/service/apple_mdm.go
Adds iOS/iPadOS Lost Mode enable/disable in lock/unlock flows; introduces viewPIN param to enqueue lock; refactors activity creation; updates cleanup call to CleanAppleMDMLock; extends result handling for Enable/DisableLostMode.
Datastore (MySQL): Apple MDM cleanup and status
server/datastore/mysql/apple_mdm.go, server/datastore/mysql/scripts.go
Renames CleanMacOSMDMLockCleanAppleMDMLock; broadens cleanup WHERE to iOS/iPadOS; updates lock/wipe status to treat UnlockRef as cmd UUID for iOS/iPadOS and timestamp for macOS; stores refs for Enable/DisableLostMode.
Datastore (MySQL): NanoMDM storage
server/datastore/mysql/nanomdm_storage.go, server/datastore/mysql/nanomdm_storage_test.go
Adds EnqueueDeviceUnlockCommand; adjusts GetAllMDMConfigAssetsByName signature; new tests for unlock enqueue path.
Fleet interfaces and structs
server/fleet/datastore.go, server/fleet/apple_mdm.go, server/fleet/scripts.go
Datastore: rename cleanup method; MDMAppleStore: add EnqueueDeviceUnlockCommand; CommandIssuer: add EnableLostMode/DisableLostMode; HostLockWipeStatus gains UnlockMDMCommand/Result and pending-unlock logic for iOS/iPadOS.
MDM Apple commander
server/mdm/apple/commander.go, server/mdm/apple/commander_test.go
Implements Enable/DisableLostMode command creation, enqueue, and push; tests validate payloads, org name inclusion, and invocation paths.
Mocks
server/mock/datastore_mock.go, server/mock/mdm/datastore_mdm_mock.go
Rename cleanup mock to Apple variant; add Android-related mock hooks; add EnqueueDeviceUnlockCommand mock for Apple MDM store.
Unit tests: Apple MDM datastore
server/datastore/mysql/apple_mdm_test.go
Replaces cleanup method usage; adds iPhone lock/unlock/wipe lifecycle test (Lost Mode enable/disable).
Integration tests
server/service/integration_mdm_commands_test.go, server/service/integration_mdm_test.go
Adds end-to-end tests for macOS, iOS/iPadOS (Lost Mode), Windows/Linux; significantly expands MDM enrollment/profile/SCEP and lifecycle coverage.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant API as Service
  participant DS as Datastore
  participant Cmd as MDMAppleCommander
  participant Push as APNs Push
  participant Host as iOS/iPadOS Device

  rect rgb(244,248,253)
  note over API,Host: Lock (iOS/iPadOS) via Lost Mode
  API->>DS: Create lock activity / status
  API->>Cmd: EnableLostMode(host, cmdUUID, orgName)
  Cmd->>Cmd: Build EnableLostMode plist
  Cmd->>DS: EnqueueDeviceLockCommand(cmd, pin="")
  Cmd->>Push: Send push
  Push-->>Host: MDM notify
  Host-->>DS: Command result (EnableLostMode)
  DS-->>API: Update lock_ref/status
  end
Loading
sequenceDiagram
  autonumber
  participant API as Service
  participant DS as Datastore
  participant Cmd as MDMAppleCommander
  participant Push as APNs Push
  participant Host as iOS/iPadOS Device

  rect rgb(244,248,253)
  note over API,Host: Unlock (iOS/iPadOS) via Disable Lost Mode
  API->>DS: Create unlock activity / status
  API->>Cmd: DisableLostMode(host, cmdUUID)
  Cmd->>Cmd: Build DisableLostMode plist
  Cmd->>DS: EnqueueDeviceUnlockCommand(cmd)
  Cmd->>Push: Send push
  Push-->>Host: MDM notify
  Host-->>DS: Command result (DisableLostMode)
  DS-->>API: Update unlock_ref/status
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

:ai

Suggested reviewers

  • rachaelshaw
  • lucasmrod
  • getvictor

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR surface includes extensive changes beyond iOS/iPadOS Lost Mode, notably new integration tests for SCEP enrollment, policy automation, VPP apps, and Android provisioning hooks in mocks, which are unrelated to the linked issue’s narrow MDM lost mode enhancements. Please remove or separate unrelated modifications such as the broad integration test expansions and Android provisioning mock changes so that the PR solely focuses on enabling Lost Mode for iOS and iPadOS.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues Check ✅ Passed The implementation removes macOS-only restrictions and adds Lost Mode enable/disable flows for iOS and iPadOS across the service, datastore, and MDM command layers as specified in issue #33416, including corresponding tests for verification.
Title Check ✅ Passed The title succinctly captures the main enhancement of enabling Lost Mode functionality for iOS and iPadOS devices and accurately reflects the core change in the pull request.
Description Check ✅ Passed The pull request description follows the repository template by including the related issue, confirming a changes file was added, detailing automated tests, and noting manual QA, and it sensibly omits sections not applicable to this change.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 33416-lm-backend

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
server/datastore/mysql/nanomdm_storage_test.go (1)

94-145: Consider expanding test coverage for unlock scenarios.

The test successfully validates the happy path for unlock command enqueueing. However, it lacks coverage for important edge cases:

  1. Conflict handling: What happens if unlock is called twice on the same device?
  2. State prerequisites: Can unlock be called when no lock exists?
  3. Lock-unlock interaction: Does unlock properly clear the lock state created by EnqueueDeviceLockCommand?

Similar comprehensive testing exists for lock operations (see testGetPendingLockCommand lines 147-235 and testEnqueueDeviceLockCommandRaceCondition lines 237-370).

Consider adding test cases that verify:

// Example additional test structure
func testEnqueueDeviceUnlockCommandEdgeCases(t *testing.T, ds *Datastore) {
    // Test 1: Unlock without prior lock
    // Test 2: Multiple unlock attempts (conflict handling)
    // Test 3: Lock followed by unlock clears state
    // Test 4: Race condition handling for concurrent unlocks
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff333f7 and f8477fb.

📒 Files selected for processing (17)
  • changes/30889-enable-lost-mode-ios-ipados (1 hunks)
  • ee/server/service/hosts.go (3 hunks)
  • server/datastore/mysql/apple_mdm.go (1 hunks)
  • server/datastore/mysql/apple_mdm_test.go (3 hunks)
  • server/datastore/mysql/nanomdm_storage.go (2 hunks)
  • server/datastore/mysql/nanomdm_storage_test.go (2 hunks)
  • server/datastore/mysql/scripts.go (3 hunks)
  • server/fleet/apple_mdm.go (1 hunks)
  • server/fleet/datastore.go (2 hunks)
  • server/fleet/scripts.go (2 hunks)
  • server/mdm/apple/commander.go (1 hunks)
  • server/mdm/apple/commander_test.go (2 hunks)
  • server/mock/datastore_mock.go (9 hunks)
  • server/mock/mdm/datastore_mdm_mock.go (3 hunks)
  • server/service/apple_mdm.go (2 hunks)
  • server/service/integration_mdm_commands_test.go (1 hunks)
  • server/service/integration_mdm_test.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

When reviewing SQL queries that are added or modified, ensure that appropriate filtering criteria are applied—especially when a query is intended to return data for a specific entity (e.g., a single host). Check for missing WHERE clauses or incorrect filtering that could lead to incorrect or non-deterministic results (e.g., returning the first row instead of the correct one). Flag any queries that may return unintended results due to lack of precise scoping.

Files:

  • server/mock/mdm/datastore_mdm_mock.go
  • server/fleet/datastore.go
  • server/fleet/apple_mdm.go
  • server/fleet/scripts.go
  • server/datastore/mysql/scripts.go
  • server/datastore/mysql/nanomdm_storage_test.go
  • server/datastore/mysql/apple_mdm_test.go
  • server/datastore/mysql/apple_mdm.go
  • server/datastore/mysql/nanomdm_storage.go
  • server/service/apple_mdm.go
  • server/service/integration_mdm_test.go
  • server/mdm/apple/commander_test.go
  • server/service/integration_mdm_commands_test.go
  • server/mock/datastore_mock.go
  • server/mdm/apple/commander.go
  • ee/server/service/hosts.go
🔇 Additional comments (6)
server/datastore/mysql/nanomdm_storage.go (1)

245-264: Good parity for lost-mode unlock bookkeeping

Mirrors the existing lock/wipe flows nicely—enqueuing under retry and clearing unlock_pin while updating unlock_ref keeps host_mdm_actions in a consistent state for the new lost-mode path.

server/fleet/scripts.go (2)

463-465: LGTM! Fields added to track iOS/iPadOS unlock.

The new UnlockMDMCommand and UnlockMDMCommandResult fields enable tracking of Lost Mode disable operations for iOS/iPadOS devices, aligning with the broader PR objective to support these platforms.


538-551: iOS/iPadOS unlock logic is consistent. Datastore populates UnlockMDMCommand/UnlockMDMCommandResult the same way as lock, and IsPendingUnlock() mirrors IsPendingLock(). The service’s DisableLostMode enqueues the MDM command correctly. No changes required.

server/mdm/apple/commander_test.go (2)

94-95: Formatting adjustment for updated signature.

The GetAllMDMConfigAssetsByNameFunc mock now includes an additional sqlx.QueryerContext parameter, aligning with the updated method signature in the datastore interface. This is a necessary change to support the new unlock command enqueueing logic.


168-200: LGTM! Test coverage for Lost Mode enable/disable.

The new test blocks validate:

  • EnableLostMode: Confirms the command RequestType is "EnableLostMode", the orgName is included in the payload, and the pin is empty.
  • DisableLostMode: Confirms the command RequestType is "DisableLostMode" via EnqueueDeviceUnlockCommandFunc.

Both tests properly assert invocation flags and reset them after validation, ensuring correct behavior.

Consider adding edge-case tests for:

  1. EnableLostMode with empty orgName: Verify handling of missing or empty organization names.
  2. Concurrent EnableLostMode/DisableLostMode calls: Similar to TestMDMAppleCommanderConcurrentDeviceLock, validate behavior under concurrent requests.
  3. Push notification failures during Lost Mode operations: Extend TestMDMAppleCommanderDeviceLockPushNotificationFailure pattern to cover EnableLostMode/DisableLostMode.

Would you like me to generate these additional test cases or open a new issue to track them?

server/fleet/apple_mdm.go (1)

25-26: LGTM. The new EnableLostMode and DisableLostMode methods are implemented in MDMAppleCommander, covered by commander tests, and invoked correctly in the hosts service.

@MagnusHJensen MagnusHJensen changed the title [DRAFT]: Add lost mode behaviour for iOS/iPadOS Add lost mode behaviour for iOS/iPadOS Oct 14, 2025
@MagnusHJensen MagnusHJensen marked this pull request as ready for review October 14, 2025 13:44
@MagnusHJensen MagnusHJensen requested a review from a team as a code owner October 14, 2025 13:44
Copy link
Member

@JordanMontgomery JordanMontgomery left a comment

Choose a reason for hiding this comment

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

Looks good to me. Glad we can ship this this sprint!

@MagnusHJensen MagnusHJensen merged commit bdb7673 into main Oct 14, 2025
42 checks passed
@MagnusHJensen MagnusHJensen deleted the 33416-lm-backend branch October 14, 2025 14:30
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.

LM: Backend allow lock for ios / ipados

3 participants