Skip to content

Fixing unreleased issue with vpp installs on byod - #46108

Merged
georgekarrv merged 6 commits into
mainfrom
gkarr-fix-byod-vpp
May 27, 2026
Merged

Fixing unreleased issue with vpp installs on byod#46108
georgekarrv merged 6 commits into
mainfrom
gkarr-fix-byod-vpp

Conversation

@georgekarrv

@georgekarrv georgekarrv commented May 22, 2026

Copy link
Copy Markdown
Member

Summary

Three fixes for the BYOD/User-Enrollment VPP install flow shipped under #31138, all caught during QA on gkarr-fix-byod-vpp:

1. Switch VPP user registration from v2 (async) to v1 (sync)

The original implementation called Apple's /mdm/v2/users/create, which is asynchronous: a 200 response only confirms the registration was queued, with no userId returned. Fleet was storing the row as registered based on the eventId alone, which masked failures and left apple_user_id permanently NULL. Switched to Apple's legacy v1 registerVPPUserSrv endpoint, which returns the full user record (including Apple's userId) in the same response, so we know definitively whether registration succeeded.

  • New vpp.RegisterUser(token, clientUserID, managedAppleID) posts to https://vpp.itunes.apple.com/mdm/registerVPPUserSrv with the token in the request body (v1 doesn't use the Authorization header).
  • ensureVPPClientUser no longer writes "pending" rows on failure — v1's sync contract means we either succeed or surface the error.
  • Removed the now-unused v2 CreateUsers types and tests.

2. Show a clear error when an end user already has the app installed personally

On BYOD/User-Enrolled hosts, when an end user has already installed an app from the App Store outside of Fleet, Apple's InstallApplication command fails with "The app with iTunes Store ID <id> is already installed." (code 12042). Previously Fleet treated this as success and entered the InstalledApplicationList verification loop — which never resolves on User Enrollment, since Apple's managedAppsOnly: true filter doesn't return personally-installed apps. The install appeared stuck.

  • BYOD hosts now mark the install as failed instead of routing to verification, skip the retry path (the same install would just fail again), and surface the Figma-specified copy: "Failed. This app is already installed. Please delete app first, an install via self-service."
  • Fully-managed hosts retain the existing behavior — MDM can take ownership of personally-installed apps on those devices, so the success-treatment is correct there.

3. Self-heal a stale vpp_client_users cache against Apple

If Fleet's cached client_user_id ever drifts from Apple's record (DB restore from a stale backup, manual tampering, future bug), Apple rejects AssociateAssets with code 9609 "Unable to find the registered user." and the install fails terminally. Apple enforces one VPP user per (location, managed_apple_id), so blindly re-registering hits a different error (9635). The recovery is two-step:

  1. On 9609, look up the existing user via GET /mdm/v2/users?managedAppleId=…. If Apple has an active record, upsert that clientUserId back into vpp_client_users and retry the associate.
  2. If Apple genuinely has no active user (only Retired entries), register a fresh one via the v1 endpoint and retry.

Each branch logs a distinct WARN so the self-heal is visible in operator dashboards. Only one retry — if the follow-up associate fails, the second error is surfaced.

Test plan

  • make lint-go-incremental — clean
  • go test ./server/mdm/apple/vpp/... ./ee/server/service/... ./server/service/ -run '<targeted>' — all green
  • Manual repro against a local k8s Fleet against Apple's production VPP endpoint:
    • Confirmed the original v2 install left apple_user_id NULL.
    • Confirmed the 9609 path triggers the lookup-then-recover branch after corrupting vpp_client_users.client_user_id and observing the WARN line + restored UUID.
  • Manual install of a personally-installed App Store app on a BYOD-enrolled iPhone, verify the new error message is shown in self-service.
  • Manual install of a VPP app on a managed iOS host — verify "already installed" still routes to verification (no regression in the managed path).

Summary by CodeRabbit

  • Bug Fixes

    • One-time self-heal for a specific Apple associate failure: recovers or re-registers the Apple-side user and retries association once; unrelated associate errors still surface.
    • BYOD “app already installed” errors now show a friendlier, actionable message and skip unnecessary retries.
    • Installer UI now surfaces precise install error messages from the API for non-script installs.
  • New Features

    • Added synchronous VPP register-user and user-lookup support plus unknown-client-user error classification.
  • Tests

    • Expanded tests for registration, lookup, recovery flows, and error matching.

Review Change Stack

Comment thread ee/server/service/software_installers.go Fixed
@codecov

codecov Bot commented May 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.06897% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.84%. Comparing base (83d0673) to head (9b59288).
⚠️ Report is 80 commits behind head on main.

Files with missing lines Patch % Lines
ee/server/service/software_installers.go 72.97% 5 Missing and 5 partials ⚠️
server/mdm/apple/vpp/api.go 86.56% 6 Missing and 3 partials ⚠️
ee/server/service/vpp_users.go 80.00% 2 Missing and 2 partials ⚠️
...details/cards/Software/SelfService/SelfService.tsx 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #46108      +/-   ##
==========================================
+ Coverage   66.82%   66.84%   +0.01%     
==========================================
  Files        2754     2761       +7     
  Lines      220138   220945     +807     
  Branches    10905    10919      +14     
==========================================
+ Hits       147117   147699     +582     
- Misses      59730    59870     +140     
- Partials    13291    13376      +85     
Flag Coverage Δ
backend 68.65% <83.57%> (+0.02%) ⬆️
frontend 55.79% <40.00%> (-0.04%) ⬇️

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.

@georgekarrv
georgekarrv marked this pull request as ready for review May 23, 2026 14:07
@georgekarrv
georgekarrv requested a review from a team as a code owner May 23, 2026 14:07
Copilot AI review requested due to automatic review settings May 23, 2026 14:07

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

@georgekarrv

Copy link
Copy Markdown
Member Author

@claude review once

@coderabbitai

coderabbitai Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

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

This PR migrates Fleet's VPP client-user registration from asynchronous v2 CreateUsers to Apple's synchronous v1 registerVPPUserSrv endpoint. It adds error classification for unknown/retired client-user failures, implements self-healing recovery when personal-enrollment asset association fails, and introduces BYOD-specific handling for already-installed errors. Changes span the VPP API client, user-registration service logic, asset-assignment orchestration, command result handling, and comprehensive integration and unit tests.

Possibly related PRs

  • fleetdm/fleet#45202: Both PRs modify the VPP install post-validation path and underlying ensureVPPClientUser/client-user registration + Apple associate-assets handling (including switching/expecting different VPP user-registration requests) within the same software_installers.go, vpp_users.go, and install_vpp_associate_test.go flow.
  • fleetdm/fleet#45467: The main PR’s frontend changes to HostSoftwareLibrary/helpers.tsx (including getInstallErrorMessage/error-message rendering for install flows) are directly related to the retrieved PR’s additions to HostSoftwareLibrary/helpers.tsx/helpers.tests.tsx around getInstallErrorMessage behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% 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 'Fixing unreleased issue with vpp installs on byod' is directly related to the changeset which implements three specific fixes for BYOD/User-Enrollment VPP install flow issues.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the three main fixes with implementation details, test plans, and remaining manual verification tasks, fully addressing the repository's description template requirements.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 gkarr-fix-byod-vpp

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

🧹 Nitpick comments (2)
server/mdm/apple/vpp/api.go (1)

107-109: 💤 Low value

Redundant substring check.

The third clause strings.Contains(msg, "user") makes the first two clauses ("registered user" and "client user") redundant, since both contain "user". If this broad matching is intentional, the code can be simplified:

-	if strings.Contains(msg, "unable to find") &&
-		(strings.Contains(msg, "registered user") || strings.Contains(msg, "client user") || strings.Contains(msg, "user")) {
+	if strings.Contains(msg, "unable to find") && strings.Contains(msg, "user") {

If you intended narrower matching (only "registered user" or "client user"), remove the final || strings.Contains(msg, "user").

🤖 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/mdm/apple/vpp/api.go` around lines 107 - 109, The conditional in
api.go that checks error messages uses strings.Contains(msg, "registered user")
|| strings.Contains(msg, "client user") || strings.Contains(msg, "user"), making
the first two checks redundant; update the condition in the function containing
this check to either (A) narrow matching by removing the final
strings.Contains(msg, "user") so it only matches "registered user" or "client
user", or (B) simplify by keeping only strings.Contains(msg, "user") if the
broad match was intended — adjust the boolean expression accordingly where this
conditional appears.
ee/server/service/install_vpp_associate_test.go (1)

378-379: 💤 Low value

Minor typo in comment: "non-9612" should be "non-9609".

The self-heal logic triggers on error 9609 ("Unable to find the registered user"), not 9612. The test correctly uses 9610 to verify self-heal doesn't run for unrelated errors.

-	t.Run("personal enrollment does not self-heal on unrelated associate error", func(t *testing.T) {
-		// Make sure a non-9612 associate error still bubbles up — we don't
+	t.Run("personal enrollment does not self-heal on unrelated associate error", func(t *testing.T) {
+		// Make sure a non-9609 associate error still bubbles up — we don't
🤖 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/install_vpp_associate_test.go` around lines 378 - 379,
Update the inline comment in the test t.Run("personal enrollment does not
self-heal on unrelated associate error", ...) to correct the typo: change
"non-9612" to "non-9609" so it correctly references the self-heal trigger error
code used by the self-heal logic (and leave the rest of the comment and the test
using 9610 as-is).
🤖 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/mdm/apple/util.go`:
- Around line 117-123: Update the user-facing constant
AppAlreadyInstalledBYODUserMessage to correct grammar and clarity: change its
string from "Failed. This app is already installed. Please delete app first, an
install via self-service." to the proposed wording "Failed. This app is already
installed. Please delete the app first, then reinstall via Self Service." so it
includes the missing article and a complete, actionable instruction; make the
edit where AppAlreadyInstalledBYODUserMessage is defined.

---

Nitpick comments:
In `@ee/server/service/install_vpp_associate_test.go`:
- Around line 378-379: Update the inline comment in the test t.Run("personal
enrollment does not self-heal on unrelated associate error", ...) to correct the
typo: change "non-9612" to "non-9609" so it correctly references the self-heal
trigger error code used by the self-heal logic (and leave the rest of the
comment and the test using 9610 as-is).

In `@server/mdm/apple/vpp/api.go`:
- Around line 107-109: The conditional in api.go that checks error messages uses
strings.Contains(msg, "registered user") || strings.Contains(msg, "client user")
|| strings.Contains(msg, "user"), making the first two checks redundant; update
the condition in the function containing this check to either (A) narrow
matching by removing the final strings.Contains(msg, "user") so it only matches
"registered user" or "client user", or (B) simplify by keeping only
strings.Contains(msg, "user") if the broad match was intended — adjust the
boolean expression accordingly where this conditional appears.
🪄 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: afd630d8-0ad6-4d13-af86-3524cda273fb

📥 Commits

Reviewing files that changed from the base of the PR and between fc10afe and dae5806.

📒 Files selected for processing (10)
  • ee/server/service/install_vpp_associate_test.go
  • ee/server/service/software_installers.go
  • ee/server/service/vpp_users.go
  • ee/server/service/vpp_users_test.go
  • server/mdm/apple/util.go
  • server/mdm/apple/vpp/api.go
  • server/mdm/apple/vpp/api_test.go
  • server/service/apple_mdm.go
  • server/service/apple_mdm_test.go
  • server/service/integration_mdm_setup_experience_test.go

Comment thread server/mdm/apple/util.go Outdated

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 fixes several BYOD (Account-Driven User Enrollment) VPP install flow issues introduced under #31138 by (1) switching VPP user registration to Apple’s synchronous v1 endpoint, (2) correctly treating “already installed” as a terminal failure on BYOD to avoid infinite verification loops, and (3) adding a self-heal path when Fleet’s cached clientUserId drifts from Apple’s record.

Changes:

  • Replace async v2 VPP user creation with synchronous v1 registerVPPUserSrv, and remove v2 create-user types/tests.
  • Enrollment-aware handling of InstallApplication “already installed” errors (fail on BYOD, keep “success” behavior on fully-managed).
  • Add BYOD-only recovery flow for Apple error 9609 by looking up user via v2 /users and resyncing (or re-registering) before retrying associate once.

Reviewed changes

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

Show a summary per file
File Description
server/service/integration_mdm_setup_experience_test.go Updates test commentary to reflect the v1 registration endpoint.
server/service/apple_mdm.go Adds enrollment-type lookup and routes “already installed” handling + retry behavior accordingly.
server/service/apple_mdm_test.go Extends test coverage for managed vs BYOD “already installed” behavior.
server/mdm/apple/vpp/api.go Adds v1 RegisterUser + v2 lookup-by-managedAppleID + unknown-client-user detection; updates auth header handling for v1.
server/mdm/apple/vpp/api_test.go Replaces CreateUsers tests with RegisterUser/GetUserByManagedAppleID/IsUnknownClientUserError tests.
server/mdm/apple/util.go Adds BYOD-specific user-facing error message constant.
ee/server/service/vpp_users.go Switches ensureVPPClientUser to v1 registration and adds registerVPPClientUser helper.
ee/server/service/vpp_users_test.go Updates tests for v1 registration behavior and error handling.
ee/server/service/software_installers.go Adds BYOD “unknown clientUserId” self-heal and single-retry associate logic.
ee/server/service/install_vpp_associate_test.go Updates mock VPP server routing for v1 register + adds self-heal test cases.

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

Comment thread ee/server/service/vpp_users.go
Comment thread server/mdm/apple/util.go Outdated
Comment thread server/service/apple_mdm.go Outdated

@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 (1)
server/service/apple_mdm.go (1)

4033-4045: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't coerce lookup misses into the managed-host path.

When either lookup returns NotFound, this helper reports false, nil, so the caller can't distinguish "managed" from "unknown". In the InstallApplication 12042 path, that can incorrectly promote a BYOD result to Acknowledged, which re-enters verification/retry instead of preserving the terminal BYOD failure behavior.

Suggested direction
-func (svc *MDMAppleCheckinAndCommandService) hostIsPersonalEnrollment(ctx context.Context, enrollmentIdentifier string) (bool, error) {
+func (svc *MDMAppleCheckinAndCommandService) hostIsPersonalEnrollment(ctx context.Context, enrollmentIdentifier string) (isPersonal bool, known bool, err error) {
 	host, err := svc.ds.HostLiteByIdentifier(ctx, enrollmentIdentifier)
 	if err != nil {
 		if fleet.IsNotFound(err) {
-			return false, nil
+			return false, false, nil
 		}
-		return false, ctxerr.Wrap(ctx, err, "host lite by identifier")
+		return false, false, ctxerr.Wrap(ctx, err, "host lite by identifier")
 	}
 	hostMDM, err := svc.ds.GetHostMDM(ctx, host.ID)
 	if err != nil {
 		if fleet.IsNotFound(err) {
-			return false, nil
+			return false, false, nil
 		}
-		return false, ctxerr.Wrap(ctx, err, "get host mdm")
+		return false, false, ctxerr.Wrap(ctx, err, "get host mdm")
 	}
-	return hostMDM.IsPersonalEnrollment, nil
+	return hostMDM.IsPersonalEnrollment, true, nil
}

Then keep the original error/no-retry behavior when known == false, instead of treating it as fully managed.

🤖 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/apple_mdm.go` around lines 4033 - 4045, The helper is
swallowing NotFound from svc.ds.HostLiteByIdentifier and svc.ds.GetHostMDM by
returning (false, nil), which hides lookup misses from callers (e.g.,
InstallApplication) and can promote BYOD to managed; change those branches so
NotFound is propagated (return the original NotFound error or a wrapped ctxerr —
e.g., return false, err or return false, ctxerr.Wrap(ctx, err, "host lite by
identifier"/"get host mdm")) instead of returning false,nil so callers can
distinguish unknown hosts from managed ones.
🤖 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/vpp_users.go`:
- Around line 57-80: The current resync logic runs only when a stale local row
(existing != nil) is present; add the same Apple lookup/resync on the cache-miss
path or on duplicate-register errors so a transient DB write failure doesn't
become permanent. Concretely: before calling
registerVPPUserSrv/registerVPPClientUser when existing == nil, call
vpp.GetUserByManagedAppleID(ctx, token.Token, managedAppleID) and if it returns
an appleUser, create a fleet.VPPClientUser and persist it via
svc.ds.InsertVPPClientUser and return appleUser.ClientUserID; additionally, if
registerVPPUserSrv/registerVPPClientUser fails with a duplicate/409-style error,
catch that error, call GetUserByManagedAppleID, resync via
svc.ds.InsertVPPClientUser, and return the found ClientUserID. Ensure you use
the same ctx, token.ID and managedAppleID when constructing the VPPClientUser.

---

Outside diff comments:
In `@server/service/apple_mdm.go`:
- Around line 4033-4045: The helper is swallowing NotFound from
svc.ds.HostLiteByIdentifier and svc.ds.GetHostMDM by returning (false, nil),
which hides lookup misses from callers (e.g., InstallApplication) and can
promote BYOD to managed; change those branches so NotFound is propagated (return
the original NotFound error or a wrapped ctxerr — e.g., return false, err or
return false, ctxerr.Wrap(ctx, err, "host lite by identifier"/"get host mdm"))
instead of returning false,nil so callers can distinguish unknown hosts from
managed ones.
🪄 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: 88a26eca-94b7-4e5a-b2ba-239d93eb32d1

📥 Commits

Reviewing files that changed from the base of the PR and between dae5806 and 65ca643.

📒 Files selected for processing (5)
  • ee/server/service/software_installers.go
  • ee/server/service/vpp_users.go
  • ee/server/service/vpp_users_test.go
  • server/mdm/apple/util.go
  • server/service/apple_mdm.go
💤 Files with no reviewable changes (1)
  • ee/server/service/software_installers.go

Comment thread ee/server/service/vpp_users.go Outdated
Comment thread ee/server/service/vpp_users.go Outdated
svc.logger.ErrorContext(ctx, "persisting pending vpp client user after CreateUsers failure",
"host_id", host.ID, "vpp_token_id", token.ID, "err", insertErr)
// Non-registered row (typically a legacy 'pending' entry from the prior
// v2 async flow, or a row left over from a failed registration). Apple

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.

This comment is a little misleading since we never technically shipped the v2 flow. Not a huge deal

Comment thread server/service/apple_mdm.go Outdated
Co-authored-by: Jordan Montgomery <elijah.jordan.montgomery@gmail.com>

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

🧹 Nitpick comments (1)
server/service/apple_mdm.go (1)

4263-4266: ⚡ Quick win

Drop the stale err branch after switching to r.Type.

isPersonal is computed locally now, so Lines 4264-4266 only read the outer err, which is already nil on this path. Keeping the old wrap here is dead code and leaves a misleading failure message.

♻️ Proposed cleanup
-			isPersonal := r.Type == mdm.UserEnrollmentDevice
-			if err != nil {
-				return nil, ctxerr.Wrap(r.Context, err, "looking up enrollment type for InstallApplication already-installed result")
-			}
+			isPersonal := r.Type == mdm.UserEnrollmentDevice
🤖 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/apple_mdm.go` around lines 4263 - 4266, The if err {
ctxerr.Wrap(...) } block after computing isPersonal := r.Type ==
mdm.UserEnrollmentDevice is dead code and should be removed: since r.Type is
computed locally here and the outer err is nil on this path, delete the
error-checking branch (the lines that reference err and call ctxerr.Wrap for
"looking up enrollment type for InstallApplication already-installed result") so
the function no longer reads a stale outer err; leave the isPersonal assignment
and continue the InstallApplication result handling unchanged.
🤖 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.

Nitpick comments:
In `@server/service/apple_mdm.go`:
- Around line 4263-4266: The if err { ctxerr.Wrap(...) } block after computing
isPersonal := r.Type == mdm.UserEnrollmentDevice is dead code and should be
removed: since r.Type is computed locally here and the outer err is nil on this
path, delete the error-checking branch (the lines that reference err and call
ctxerr.Wrap for "looking up enrollment type for InstallApplication
already-installed result") so the function no longer reads a stale outer err;
leave the isPersonal assignment and continue the InstallApplication result
handling unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 378d32a9-bce2-4f33-ae7e-674145839065

📥 Commits

Reviewing files that changed from the base of the PR and between 65ca643 and 2e47fc0.

📒 Files selected for processing (1)
  • server/service/apple_mdm.go

@georgekarrv
georgekarrv requested a review from a team as a code owner May 27, 2026 14:37

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

🧹 Nitpick comments (1)
frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx (1)

52-54: ⚡ Quick win

Add coverage for the new “Software title is not available for install” passthrough.

This new user-visible branch should get a dedicated getInstallErrorMessage test to prevent regressions in toast text behavior.

Suggested test addition
diff --git a/frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tests.tsx b/frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tests.tsx
@@
   it("returns no available licenses message as-is", () => {
     const result = getInstallErrorMessage(makeErr("No available licenses."));
     expect(result).toBe("No available licenses");
   });

+  it("returns software title unavailable message as-is", () => {
+    const result = getInstallErrorMessage(
+      makeErr(
+        "Couldn't install software. Software title is not available for install. Please add software package or App Store app to install."
+      )
+    );
+    expect(result).toBe(
+      "Couldn't install software. Software title is not available for install. Please add software package or App Store app to install"
+    );
+  });
+
   it("surfaces the missing Managed Apple ID message as-is", () => {
🤖 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/cards/HostSoftwareLibrary/helpers.tsx` around
lines 52 - 54, The new passthrough branch that checks for "Software title is not
available for install" in getInstallErrorMessage needs a dedicated unit test to
prevent regressions: add a test for the getInstallErrorMessage function that
passes an error message containing "Software title is not available for install"
and asserts the returned toast text matches the expected user-facing string;
mirror the existing test style used for the "hasn't received a Managed Apple ID"
case (same file helper reference: getInstallErrorMessage) so both branches are
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.

Nitpick comments:
In `@frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx`:
- Around line 52-54: The new passthrough branch that checks for "Software title
is not available for install" in getInstallErrorMessage needs a dedicated unit
test to prevent regressions: add a test for the getInstallErrorMessage function
that passes an error message containing "Software title is not available for
install" and asserts the returned toast text matches the expected user-facing
string; mirror the existing test style used for the "hasn't received a Managed
Apple ID" case (same file helper reference: getInstallErrorMessage) so both
branches are covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d0ae9f51-941c-419e-82a7-c2fd4d691e8e

📥 Commits

Reviewing files that changed from the base of the PR and between 2e47fc0 and 6978be2.

📒 Files selected for processing (3)
  • frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tests.tsx
  • frontend/pages/hosts/details/cards/HostSoftwareLibrary/helpers.tsx
  • frontend/pages/hosts/details/cards/Software/SelfService/SelfService.tsx

Comment thread ee/server/service/vpp_users.go Outdated
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.

4 participants