Skip to content

BYOF: Add support for unique token ADUE - #47407

Merged
MagnusHJensen merged 11 commits into
mainfrom
45598-unique-adue-token
Jun 16, 2026
Merged

BYOF: Add support for unique token ADUE#47407
MagnusHJensen merged 11 commits into
mainfrom
45598-unique-adue-token

Conversation

@MagnusHJensen

@MagnusHJensen MagnusHJensen commented Jun 11, 2026

Copy link
Copy Markdown
Member

Related issue: Resolves #45598

  1. Apple disregards query params in the 403 WWW-Authenticate URL, so setting it as the ?initiator= does not work, had to make a new route on the frontend to match the same URL but with a dynamic token.

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.

  • 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.

  • Timeouts are implemented and retries are limited to avoid infinite loops

  • If paths of existing endpoints are modified without backwards compatibility, checked the frontend/CLI for any necessary changes

Testing

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

Summary by CodeRabbit

Summary

  • New Features

    • Added support for a configured default fleet/team for BYO Apple enrollment.
    • Enabled account-driven Apple MDM enrollment using per-enrollment tokens.
    • Added tokenized Apple MDM service discovery and enrollment endpoints.
  • Bug Fixes & Improvements

    • Added automated daily cleanup of expired enrollment challenges.
    • Improved BYOD/account-driven enrollment challenge handling, including default team assignment and Managed Apple ID updates.
    • Reduced unnecessary BYOD MDM profile refetches during reenrollment.
  • Tests

    • Expanded coverage for token lookup, enrollment challenges, and updated BYOD/account-driven flows.

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 62.05788% with 118 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.18%. Comparing base (96fa2d9) to head (68621d2).
⚠️ Report is 22 commits behind head on main.

Files with missing lines Patch % Lines
server/service/apple_mdm.go 41.75% 44 Missing and 9 partials ⚠️
ee/server/service/apple_mdm.go 54.54% 10 Missing and 10 partials ⚠️
cmd/fleet/cron.go 0.00% 14 Missing ⚠️
server/datastore/mysql/apple_mdm.go 85.71% 8 Missing and 5 partials ⚠️
server/mdm/apple/apple_mdm.go 50.00% 4 Missing and 4 partials ⚠️
ee/server/service/mdm.go 73.91% 4 Missing and 2 partials ⚠️
cmd/fleet/serve.go 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #47407      +/-   ##
==========================================
+ Coverage   67.15%   67.18%   +0.03%     
==========================================
  Files        3616     3621       +5     
  Lines      229030   229299     +269     
  Branches    11787    11800      +13     
==========================================
+ Hits       153805   154064     +259     
- Misses      61370    61377       +7     
- Partials    13855    13858       +3     
Flag Coverage Δ
backend 68.82% <60.40%> (+0.03%) ⬆️
frontend 58.02% <100.00%> (+0.04%) ⬆️

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

☔ View full report in Codecov by Harness.
📢 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.

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

Adds per-ABM-token (unique token) support to Apple Account Driven User Enrollment (BYOD), enabling enrollments to be associated with a specific ABM token (and its default BYOD team) while preserving legacy URL behavior. This introduces ADUE enrollment challenges for single-use profile retrieval and updates service discovery to publish tokenized URLs per ABM token, with frontend routing to support Apple’s fixed SSO callback URL constraints.

Changes:

  • Add tokenized account-driven enrollment + service discovery routes and pass the token through the SSO initiator.
  • Introduce ADUE enrollment challenges (create/fetch/consume/cleanup) and use them in MDMSSOCallback, profile retrieval, and TokenUpdate team assignment.
  • Update integration/unit tests and frontend routing to cover tokenized and legacy flows.

Reviewed changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
server/service/testing_client_test.go Updates test helper initiator to include token; modifies SSO test gating.
server/service/integration_mdm_test.go Extends ADUE integration tests for tokenized + legacy URL and BYOD default team behavior.
server/service/integration_mdm_setup_experience_test.go Updates setup experience BYOD iOS test to use tokenized SSO initiator.
server/service/handler.go Adds tokenized account-driven enroll route and tokenized service discovery handler registration.
server/service/apple_mdm.go Adds token extraction to ADUE enroll decode, updates account-driven enroll endpoint flow, TokenUpdate challenge usage, and per-token service discovery assignment.
server/service/apple_mdm_test.go Updates TokenUpdate unit test to use ADUE challenge lookup (vs direct bearer UUID).
server/mock/service/service_mock.go Updates service mock method signature to accept enrollmentToken.
server/mock/datastore_mock.go Adds datastore mock methods for ABM unique token lookup and ADUE challenges CRUD/cleanup.
server/mdm/apple/apple_mdm.go Adds tokenized path constants and extracts push cert topic helper.
server/fleet/service.go Updates Service interface for GetMDMAccountDrivenEnrollmentSSOURL to accept enrollmentToken.
server/fleet/mdm.go Adds ABM BYOD default team + enrollment URL token fields; adds URL-safe 32-byte token generator.
server/fleet/datastore.go Adds datastore methods for ABM unique token lookup and ADUE challenges.
server/fleet/cron_schedules.go Adds cron schedule name for ADUE challenge cleanup.
server/fleet/apple_mdm.go Defines ADUE challenge expiration and struct.
server/datastore/mysql/apple_mdm.go Implements ABM unique token lookup and ADUE challenge insert/get/consume/cleanup.
server/datastore/mysql/apple_mdm_test.go Adds mysql datastore tests for ABM unique token lookup and ADUE challenges.
frontend/router/index.tsx Adds route for /mdm/apple/account_driven_enroll/sso/:token.
frontend/pages/MDMAppleSSOPage/MDMAppleSSOPage.tsx Builds initiator with token from route param when present.
ee/server/service/mdm.go Parses tokenized initiator for account-driven enrollment and issues ADUE challenges in callback.
ee/server/service/apple_mdm.go Implements EE account-driven enrollment SSO URL construction and challenge-backed profile generation/consumption.
cmd/fleet/serve.go Registers new cron schedule for ADUE challenge cleanup.
cmd/fleet/cron.go Adds the ADUE challenge cleanup cron schedule implementation.
changes/30871-default-byod-fleet Release note entry for default BYOD fleet support.

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

Comment thread server/service/testing_client_test.go Outdated
Comment thread server/service/integration_mdm_test.go Outdated
Comment thread server/service/integration_mdm_test.go Outdated
Comment thread server/service/integration_mdm_test.go Outdated
Comment thread server/service/apple_mdm.go
Comment thread server/service/apple_mdm.go
Comment thread server/datastore/mysql/apple_mdm.go
Comment thread server/datastore/mysql/apple_mdm.go Outdated
Comment thread server/mdm/apple/apple_mdm.go
Comment thread ee/server/service/apple_mdm.go Outdated
@MagnusHJensen
MagnusHJensen marked this pull request as ready for review June 11, 2026 14:07
@MagnusHJensen
MagnusHJensen requested review from a team as code owners June 11, 2026 14:07
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds per-ABM-token Apple account-driven enrollment: new ADUE challenge datastore APIs (insert/get/consume/cleanup with 1-hour expiration and single-use locking), ABM token fields for enrollment URL token and BYOD default team, token-aware SSO initiation/callback and enrollment endpoints, MDMPushCertTopic helper, daily cron to remove expired challenges, frontend/router updates for tokened SSO, mock/service adjustments, and expanded unit/integration tests validating tokened vs legacy enrollment and single-use challenge behavior.

Possibly related PRs

  • fleetdm/fleet#47161: Adds the MySQL schema migration introducing abm_tokens.enrollment_url_token/byod_default_team_id and the mdm_adue_enrollment_challenges table used by this PR.
  • fleetdm/fleet#45046: Modifies overlapping MDM SSO initiation/callback logic related to account-driven enrollment flows.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% 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 PR title clearly identifies the main change: adding support for unique Account-Driven User Enrollment (ADUE) tokens with a focus on BYOF (Bring Your Own Fleet), which is the primary objective of the changeset.
Description check ✅ Passed The PR description includes the related issue (#45598), explains the technical constraint (Apple ignoring query params), documents the solution (dynamic token route), and checks most required items including changes file, input validation, testing, and manual QA.
Linked Issues check ✅ Passed The PR implementation comprehensively addresses all coding requirements from #45598: datastore methods for ADUE challenges, per-token enrollment URLs, challenge creation/consumption, cron job for cleanup, team assignment via challenges, and TokenUpdate integration. Integration tests validate team assignment and challenge lifecycle.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing unique token ADUE support as specified in #45598. Files modified include datastore methods, service endpoints, cron jobs, mock implementations, and related integration tests—all essential to the token ADUE feature. No unrelated changes detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 45598-unique-adue-token

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: 6

Caution

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

⚠️ Outside diff range comments (1)
server/datastore/mysql/apple_mdm.go (1)

5833-5839: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

byod_default_team_id is only half-wired.

getABMToken now reads abt.byod_default_team_id, but the same file still omits that column from ListABMTokens, InsertABMToken, and SaveABMToken. That means the new BYOD default-team assignment won't round-trip through create/update flows and won't be visible in list responses.

Also applies to: 5934-5938

🤖 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/datastore/mysql/apple_mdm.go` around lines 5833 - 5839, ListABMTokens,
InsertABMToken, and SaveABMToken are missing the byod_default_team_id column and
associated select/params so the BYOD default-team value read by getABMToken
cannot round-trip; update the SQL in ListABMTokens to include
abt.byod_default_team_id (and COALESCE(t4.name, :no_team) as byod_team in the
SELECT joins), and update InsertABMToken and SaveABMToken to include
byod_default_team_id in their INSERT/UPDATE column lists and bind parameters,
and ensure the Go structs/scan/order of fields used by those functions match the
new column position so inserts, updates and list responses carry the BYOD
default-team correctly.
🧹 Nitpick comments (3)
frontend/pages/MDMAppleSSOPage/MDMAppleSSOPage.tsx (1)

25-35: 💤 Low value

Consider validating the token before interpolation.

While the token will ultimately be validated by the backend, adding a simple frontend check (e.g., ensuring params.token is a non-empty string) would provide earlier feedback and prevent sending a malformed initiator like account_driven_enroll:undefined if the token is somehow missing or invalid at the route level.

💡 Optional validation check
     if (pathname.startsWith("/mdm/apple/account_driven_enroll/sso")) {
       // While I acknowledge startsWith for route matching is a bit brittle
       // I couldn't find a better way, since the pathname is the actual resolved value and not the placeholder route.
-      if (params.token) {
+      if (params.token && typeof params.token === "string" && params.token.length > 0) {
         query.initiator = `account_driven_enroll:${params.token}`;
       } else {
         query.initiator = "account_driven_enroll";
       }
🤖 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/MDMAppleSSOPage/MDMAppleSSOPage.tsx` around lines 25 - 35,
Validate params.token before interpolating into query.initiator: in the block
where pathname.startsWith("/mdm/apple/account_driven_enroll/sso") is checked,
ensure params.token is a non-empty string (e.g., typeof params.token ===
"string" && params.token.trim().length > 0) before setting query.initiator =
`account_driven_enroll:${params.token}`; if the token is missing/invalid, fall
back to query.initiator = "account_driven_enroll" (or another safe default) to
avoid producing values like account_driven_enroll:undefined.
server/service/handler.go (1)

1318-1324: ⚡ Quick win

Prefer using the path constant with placeholder replacement for maintainability.

The tokenized enrollment URL is constructed by manually concatenating fullMDMEnrollmentURL + "/" + token (line 1321), which assumes the relationship between AccountDrivenEnrollPath and the tokenized path. However, the test expectation (from integration_mdm_test.go:21116) and the registered route both reference apple_mdm.AccountDrivenEnrollTokenPath with a {token} placeholder. For consistency and to avoid breakage if path constants evolve, construct the tokenized URL by replacing the placeholder in the constant.

♻️ Proposed fix to use path constant with placeholder replacement
 func registerMDMServiceDiscovery(
 	mux *http.ServeMux,
 	logger *slog.Logger,
 	serverURLPrefix string,
 	fleetConfig config.FleetConfig,
 ) error {
 	serviceDiscoveryLogger := logger.With("component", "mdm-apple-service-discovery")
-	fullMDMEnrollmentURL := fmt.Sprintf("%s%s", serverURLPrefix, apple_mdm.AccountDrivenEnrollPath)
 	serviceDiscoveryHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		var mdmEnrollmentURL string
 		token := r.PathValue("token")
 		if token != "" {
-			mdmEnrollmentURL = fmt.Sprintf("%s/%s", fullMDMEnrollmentURL, url.PathEscape(token))
+			tokenPath := strings.Replace(apple_mdm.AccountDrivenEnrollTokenPath, "{token}", url.PathEscape(token), 1)
+			mdmEnrollmentURL = serverURLPrefix + tokenPath
 		} else {
-			mdmEnrollmentURL = fullMDMEnrollmentURL
+			mdmEnrollmentURL = serverURLPrefix + apple_mdm.AccountDrivenEnrollPath
 		}
🤖 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/handler.go` around lines 1318 - 1324, Replace the manual
concatenation that builds mdmEnrollmentURL with code that substitutes the
"{token}" placeholder in the path constant instead of appending "/"+token: when
token != "" compute the tokenized path by replacing "{token}" in
apple_mdm.AccountDrivenEnrollTokenPath with url.PathEscape(token) (use
strings.Replace or ReplaceAll), then combine that replaced path with
fullMDMEnrollmentURL (ensuring no duplicate slashes, e.g., trim/right or format)
and assign to mdmEnrollmentURL; leave the token=="" branch to use
fullMDMEnrollmentURL.
server/service/integration_mdm_test.go (1)

16233-16264: 💤 Low value

Consider adding explicit validation that all devices were found.

The switch statement correctly validates the three enrolled devices and their team assignments. However, if a device UUID doesn't match for any reason, iPhoneHostID and iPadHostID would remain nil, causing a panic when dereferenced later rather than a clear assertion failure.

Consider adding explicit checks after the loop to improve test failure diagnostics:

require.NotNil(t, iPhoneHostID, "iPhone host not found in listing")
require.NotNil(t, iPadHostID, "iPad host not found in listing")

This would make test failures more immediately understandable, though the current implementation will still catch issues.

🤖 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/integration_mdm_test.go` around lines 16233 - 16264, After
iterating listHostsRes.Hosts and assigning iPhoneHostID and iPadHostID inside
the switch, add explicit assertions to verify both pointers are set (e.g.,
require.NotNil(t, iPhoneHostID, "iPhone host not found in listing") and
require.NotNil(t, iPadHostID, "iPad host not found in listing")) immediately
after the loop so missing-device cases fail with a clear test error; locate the
check after the for _, host := range listHostsRes.Hosts loop where iPhoneHostID
and iPadHostID are assigned.
🤖 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 `@ee/server/service/apple_mdm.go`:
- Around line 34-40: The code currently treats a nil enrollChallenge from
svc.ds.ConsumeADUEEnrollmentChallenge as an internal error (ctxerr.New) which
yields a 5xx; change that to return a client-facing authentication/validation
error (HTTP 4xx) so Apple sees a terminal auth failure: replace the
ctxerr.New(...) used when enrollChallenge == nil with the appropriate ctxerr
helper that signals an authentication/validation failure (e.g.,
ctxerr.NewUnauthenticated or ctxerr.NewValidation if available) and keep the
message "invalid enrollment reference" so the behavior of
ConsumeADUEEnrollmentChallenge and the enrollChallenge nil check is preserved
but surfaced as a 4xx client error rather than an internal server error.

In `@ee/server/service/mdm.go`:
- Around line 967-975: The callback currently treats an empty
account-driven-enroll suffix as a token and calls
svc.ds.GetABMTokenByUniqueToken on an empty string, causing an error; update the
block that uses strings.CutPrefix on ssoRequestData.Initiator (comparing to
fleet.SSOInitiatorAccountDrivenEnroll+":") to only call
svc.ds.GetABMTokenByUniqueToken and set abmTokenID when uniqueToken != ""
(non-empty), so the empty-suffix case is treated as the legacy flow the same way
InitiateMDMSSO does.

In `@server/datastore/mysql/apple_mdm.go`:
- Around line 7571-7576: The public GetADUEEnrollmentChallenge currently calls
getADUEEnrollmentChallenge via ds.reader but that helper includes a FOR UPDATE
lock; remove the locking read from the reader path by creating a non-locking
reader helper (e.g., getADUEEnrollmentChallenge without FOR UPDATE) and have
GetADUEEnrollmentChallenge call that; then create a separate tx-only locking
helper (e.g., getADUEEnrollmentChallengeForUpdate or reuse
getADUEEnrollmentChallenge but only from writer/transaction code) that includes
`FOR UPDATE` and is invoked only by ConsumeADUEEnrollmentChallenge (or other
writer functions) while passing a writer/transaction (not ds.reader); ensure the
reader helper uses the same SELECT fields but omits `FOR UPDATE` and that the
locking helper is only used inside a transaction taken from the writer pool so
locks behave correctly.
- Around line 7547-7564: InsertADUEEnrollmentChallenge currently sets expires_at
= time.Now().Add(expiration) which combined with the cleanup (lines around
7625-7627) yields retention = expiration + 24h; change the insert to set
expireAt = time.Now().Add(24*time.Hour) (ignore or validate the passed
expiration but enforce 24h per ADUE contract) so rows always expire 24 hours
from creation, and keep the cleanup logic as-is; update any function comment or
validation around InsertADUEEnrollmentChallenge to reflect that expires_at is
fixed to 24 hours.

In `@server/service/apple_mdm.go`:
- Around line 3877-3904: The BYOD team assignment happens after
EnqueueSetupExperienceItems is called, causing work to be queued against the
wrong team; fix by resolving the ADUE challenge/team prior to any enqueueing:
call svc.ds.GetADUEEnrollmentChallenge(...) and (if enrollChallenge.ABMTokenID
!= nil) fetch svc.ds.GetABMTokenByID(...) and determine
abmToken.BYODDefaultTeamID and, if non-nil, call svc.ds.AddHostsToTeam(...) or
set info.TeamID to the BYOD team before invoking
EnqueueSetupExperienceItems(..., info.TeamID); alternatively, after
AddHostsToTeam reload the effective team (e.g., refresh info.TeamID from the
datastore) before queuing setup/VPP work to ensure the enqueue uses the updated
team.
- Around line 6902-6912: The current handling in the block that calls
depSvc.GetMDMAppleServiceDiscoveryDetails returns from the parent function on
IsServiceDiscoveryNotSupported and on the default error branch, which aborts
processing remaining ABM tokens; change those returns into non-fatal handling so
the loop continues: for godep.IsServiceDiscoveryNotSupported(err) log the info
(logger.InfoContext) and continue processing the next token instead of return,
and for the default error branch replace the ctxerr.Wrap return with logging the
wrapped error (or logger.ErrorContext with ctxerr.Wrap(ctx, err, "...")) and
continue; keep the existing behavior for IsServiceDiscoveryNotFound. Ensure you
modify the code around depSvc.GetMDMAppleServiceDiscoveryDetails to use continue
rather than return so later tokens are still processed.

---

Outside diff comments:
In `@server/datastore/mysql/apple_mdm.go`:
- Around line 5833-5839: ListABMTokens, InsertABMToken, and SaveABMToken are
missing the byod_default_team_id column and associated select/params so the BYOD
default-team value read by getABMToken cannot round-trip; update the SQL in
ListABMTokens to include abt.byod_default_team_id (and COALESCE(t4.name,
:no_team) as byod_team in the SELECT joins), and update InsertABMToken and
SaveABMToken to include byod_default_team_id in their INSERT/UPDATE column lists
and bind parameters, and ensure the Go structs/scan/order of fields used by
those functions match the new column position so inserts, updates and list
responses carry the BYOD default-team correctly.

---

Nitpick comments:
In `@frontend/pages/MDMAppleSSOPage/MDMAppleSSOPage.tsx`:
- Around line 25-35: Validate params.token before interpolating into
query.initiator: in the block where
pathname.startsWith("/mdm/apple/account_driven_enroll/sso") is checked, ensure
params.token is a non-empty string (e.g., typeof params.token === "string" &&
params.token.trim().length > 0) before setting query.initiator =
`account_driven_enroll:${params.token}`; if the token is missing/invalid, fall
back to query.initiator = "account_driven_enroll" (or another safe default) to
avoid producing values like account_driven_enroll:undefined.

In `@server/service/handler.go`:
- Around line 1318-1324: Replace the manual concatenation that builds
mdmEnrollmentURL with code that substitutes the "{token}" placeholder in the
path constant instead of appending "/"+token: when token != "" compute the
tokenized path by replacing "{token}" in apple_mdm.AccountDrivenEnrollTokenPath
with url.PathEscape(token) (use strings.Replace or ReplaceAll), then combine
that replaced path with fullMDMEnrollmentURL (ensuring no duplicate slashes,
e.g., trim/right or format) and assign to mdmEnrollmentURL; leave the token==""
branch to use fullMDMEnrollmentURL.

In `@server/service/integration_mdm_test.go`:
- Around line 16233-16264: After iterating listHostsRes.Hosts and assigning
iPhoneHostID and iPadHostID inside the switch, add explicit assertions to verify
both pointers are set (e.g., require.NotNil(t, iPhoneHostID, "iPhone host not
found in listing") and require.NotNil(t, iPadHostID, "iPad host not found in
listing")) immediately after the loop so missing-device cases fail with a clear
test error; locate the check after the for _, host := range listHostsRes.Hosts
loop where iPhoneHostID and iPadHostID are assigned.
🪄 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: e52d3a56-4c83-4aa5-8fea-2ace33c9045b

📥 Commits

Reviewing files that changed from the base of the PR and between 557def9 and 92e82fa.

📒 Files selected for processing (25)
  • changes/30871-default-byod-fleet
  • cmd/fleet/cron.go
  • cmd/fleet/serve.go
  • ee/server/service/apple_mdm.go
  • ee/server/service/mdm.go
  • frontend/pages/MDMAppleSSOPage/MDMAppleSSOPage.tsx
  • frontend/router/index.tsx
  • pkg/mdm/mdmtest/apple.go
  • server/datastore/mysql/apple_mdm.go
  • server/datastore/mysql/apple_mdm_test.go
  • server/fleet/apple_mdm.go
  • server/fleet/cron_schedules.go
  • server/fleet/datastore.go
  • server/fleet/mdm.go
  • server/fleet/service.go
  • server/mdm/apple/apple_mdm.go
  • server/mock/datastore_mock.go
  • server/mock/service/service_mock.go
  • server/service/apple_mdm.go
  • server/service/apple_mdm_test.go
  • server/service/handler.go
  • server/service/integration_mdm_lifecycle_test.go
  • server/service/integration_mdm_setup_experience_test.go
  • server/service/integration_mdm_test.go
  • server/service/testing_client_test.go

Comment thread ee/server/service/apple_mdm.go
Comment thread ee/server/service/mdm.go Outdated
Comment thread server/datastore/mysql/apple_mdm.go
Comment thread server/datastore/mysql/apple_mdm.go
Comment thread server/service/apple_mdm.go
Comment thread server/service/apple_mdm.go

@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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 82853b92-2d97-47d1-9f4b-b3b9f659caed

📥 Commits

Reviewing files that changed from the base of the PR and between 92e82fa and 7d2eab7.

📒 Files selected for processing (8)
  • ee/server/service/apple_mdm.go
  • ee/server/service/mdm.go
  • server/datastore/mysql/apple_mdm.go
  • server/mdm/lifecycle/lifecycle.go
  • server/service/apple_mdm.go
  • server/service/handler.go
  • server/service/integration_mdm_test.go
  • server/service/testing_client_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • ee/server/service/mdm.go
  • ee/server/service/apple_mdm.go
  • server/service/integration_mdm_test.go
  • server/service/apple_mdm.go

Comment thread server/service/testing_client_test.go Outdated
@MagnusHJensen MagnusHJensen mentioned this pull request Jun 12, 2026
6 tasks
Comment thread frontend/pages/MDMAppleSSOPage/MDMAppleSSOPage.tsx
Comment thread pkg/mdm/mdmtest/apple.go
cdcme
cdcme previously approved these changes Jun 15, 2026

@nulmete nulmete left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed FE and logic LGTM, but I suggest not mutating the location object from react-router

Comment thread frontend/pages/MDMAppleSSOPage/MDMAppleSSOPage.tsx Outdated
@MagnusHJensen
MagnusHJensen merged commit 76de4ad into main Jun 16, 2026
49 checks passed
@MagnusHJensen
MagnusHJensen deleted the 45598-unique-adue-token branch June 16, 2026 12:56
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.

BYOF: Backend/enrollment changes

5 participants