Skip to content

Adding create vpp user recovery if the user is missing from db - #46345

Closed
georgekarrv wants to merge 1 commit into
mainfrom
gkarr-fix-byod-vpp-2
Closed

Adding create vpp user recovery if the user is missing from db#46345
georgekarrv wants to merge 1 commit into
mainfrom
gkarr-fix-byod-vpp-2

Conversation

@georgekarrv

@georgekarrv georgekarrv commented May 28, 2026

Copy link
Copy Markdown
Member

Fixing unreleased behavior where if a user was missing from the vpp users db that it would retrieve the current vpp user from apple to continue installing.

Summary by CodeRabbit

  • Bug Fixes

    • Improved VPP user synchronization by querying Apple's records when no locally cached registered user exists, ensuring users already registered with Apple are properly recognized and synced.
  • Tests

    • Added test coverage for VPP user recovery from Apple's system and updated existing tests to verify proper synchronization behavior.

Review Change Stack

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

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

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 a recovery path for Apple VPP /users/create failures with error 9635 ("Apple Account can't be associated with registered user"). When the local vpp_client_users mapping is missing but Apple still has the Managed Apple ID registered under a different clientUserId, Fleet now adopts Apple's existing identifier via a new /users/get call instead of failing the install. This recovery is applied for both top-level and per-user variants of the 9635 error.

Changes:

  • Add ErrorNumberUserAlreadyRegistered constant, IsUserAlreadyRegisteredError helper, GetUser API wrapper, and ItsIdHash helper in the VPP API package.
  • Add recoverExistingVPPClientUser flow in ensureVPPClientUser to look up the existing user via itsIdHash and re-seat vpp_client_users with Apple's clientUserId.
  • Add unit tests for GetUser, ItsIdHash, IsUserAlreadyRegisteredError, and a service-level recovery test.

Reviewed changes

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

File Description
server/mdm/apple/vpp/api.go Adds 9635 error helpers, /users/get wrapper, and ItsIdHash.
server/mdm/apple/vpp/api_test.go Tests for GetUser, ItsIdHash, IsUserAlreadyRegisteredError.
ee/server/service/vpp_users.go Recovers from 9635 by adopting Apple's existing clientUserId.
ee/server/service/vpp_users_test.go Test that 9635 → /users/get recovery re-seats the cache.

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

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

Failed to post review comments

Walkthrough

The PR extends the VPP user provisioning flow to query Apple for existing users when the local cache lacks a registered row. Instead of immediately registering new users, ensureVPPClientUser now calls vpp.GetUserByManagedAppleID to check if Apple already has a user for the given Managed Apple ID. If Apple returns an existing user, the service reuses that clientUserId and caches it as a Registered row; otherwise it falls back to registering a new user. Unit tests verify the Apple lookup occurs and handle the cache-miss recovery case. Integration tests are updated to support the new GET /users endpoint calls and adjust expectations for lookup and upsert counts across the VPP associate flow.

Possibly related PRs

  • fleetdm/fleet#45202: Main PR introducing the Apple-first resync logic in ensureVPPClientUser and GET /users endpoint handling that this PR's integration tests now exercise across VPP user provision and associate-asset flows.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the fix but lacks the structured template format, related issue number, and verification checklist items required by the repository template. Add the related issue number (Resolves #), complete the provided checklist items for testing and database migrations, and use the template structure.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding recovery logic when a VPP user is missing from the database by retrieving it from Apple.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gkarr-fix-byod-vpp-2

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

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

745-751: ⚡ Quick win

Add coverage for the “both fields set” invalid request case.

TestGetUser should assert rejection when both ClientUserId and ItsIdHash are provided, to lock the exactly-one contract and prevent regressions.

Suggested test addition
 func TestGetUser(t *testing.T) {
 	t.Run("rejects empty request", func(t *testing.T) {
 		_, err := GetUser("token", nil)
 		require.Error(t, err)

 		_, err = GetUser("token", &GetUserRequest{})
 		require.Error(t, err)
 	})
+
+	t.Run("rejects request with both clientUserId and itsIdHash", func(t *testing.T) {
+		_, err := GetUser("token", &GetUserRequest{
+			ClientUserId: "uuid-1",
+			ItsIdHash:    ItsIdHash("user@example.com"),
+		})
+		require.Error(t, err)
+		require.Contains(t, err.Error(), "mutually exclusive")
+	})
🤖 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_test.go` around lines 745 - 751, Add a test
asserting that GetUser rejects requests where both identifying fields are
provided: call GetUser("token", &GetUserRequest{ClientUserId: "...", ItsIdHash:
"..."}) and require an error; place this in the same TestGetUser t.Run block (or
a new t.Run "rejects both fields set") alongside the existing empty-request
checks so the exactly-one-of ClientUserId/ItsIdHash invariant is covered. Ensure
you reference GetUser and GetUserRequest in the assertion so the test fails if
both fields are accepted.
🤖 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 175-176: The log in svc.logger.InfoContext that currently emits
the raw managedAppleID should instead log a non-PII surrogate (e.g., a SHA-256
hex or other irreversible hash) to avoid exposing an email/identifier; compute
the hash of managedAppleID just before the log call and replace the
"managed_apple_id" value with the hashed string (or call a shared helper like
hashPII if available) while keeping "host_id" and "vpp_token_id" unchanged so
the log still correlates records without storing raw PII.

In `@server/mdm/apple/vpp/api.go`:
- Around line 345-348: Update the GetUser input validation in GetUser(token
string, params *GetUserRequest) to enforce "exactly one" of ClientUserId or
ItsIdHash: instead of allowing both to be set, return an error when both
ClientUserId and ItsIdHash are non-empty, and keep the existing error for both
empty; adjust the conditional that currently checks params == nil ||
(params.ClientUserId == "" && params.ItsIdHash == "") to also reject the case
where both fields are provided so the function only proceeds when exactly one
identifier is present.

---

Nitpick comments:
In `@server/mdm/apple/vpp/api_test.go`:
- Around line 745-751: Add a test asserting that GetUser rejects requests where
both identifying fields are provided: call GetUser("token",
&GetUserRequest{ClientUserId: "...", ItsIdHash: "..."}) and require an error;
place this in the same TestGetUser t.Run block (or a new t.Run "rejects both
fields set") alongside the existing empty-request checks so the exactly-one-of
ClientUserId/ItsIdHash invariant is covered. Ensure you reference GetUser and
GetUserRequest in the assertion so the test fails if both fields are accepted.
🪄 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: 17beeb19-f9b1-4d84-8afb-1d42fac5e5df

📥 Commits

Reviewing files that changed from the base of the PR and between d313300 and 5ed862ad8a5dcef6ffd9f2ecfffe0b4d7950db6c.

📒 Files selected for processing (4)
  • ee/server/service/vpp_users.go
  • ee/server/service/vpp_users_test.go
  • server/mdm/apple/vpp/api.go
  • server/mdm/apple/vpp/api_test.go

Comment thread ee/server/service/vpp_users.go Outdated
Comment thread server/mdm/apple/vpp/api.go Outdated
Comment on lines +345 to +348
func GetUser(token string, params *GetUserRequest) (*CreateUsersResult, error) {
if params == nil || (params.ClientUserId == "" && params.ItsIdHash == "") {
return nil, errors.New("GetUserRequest: one of ClientUserId or ItsIdHash is required")
}

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce mutual exclusivity in GetUser input validation.

Line 346 currently permits both ClientUserId and ItsIdHash, but this endpoint is documented here as “exactly one.” Allowing both can produce ambiguous requests and brittle behavior.

Suggested fix
 func GetUser(token string, params *GetUserRequest) (*CreateUsersResult, error) {
-	if params == nil || (params.ClientUserId == "" && params.ItsIdHash == "") {
-		return nil, errors.New("GetUserRequest: one of ClientUserId or ItsIdHash is required")
-	}
+	if params == nil {
+		return nil, errors.New("GetUserRequest: params cannot be nil")
+	}
+	hasClientUserID := params.ClientUserId != ""
+	hasItsIDHash := params.ItsIdHash != ""
+	switch {
+	case hasClientUserID && hasItsIDHash:
+		return nil, errors.New("GetUserRequest: ClientUserId and ItsIdHash are mutually exclusive")
+	case !hasClientUserID && !hasItsIDHash:
+		return nil, errors.New("GetUserRequest: one of ClientUserId or ItsIdHash is required")
+	}
🤖 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 345 - 348, Update the GetUser input
validation in GetUser(token string, params *GetUserRequest) to enforce "exactly
one" of ClientUserId or ItsIdHash: instead of allowing both to be set, return an
error when both ClientUserId and ItsIdHash are non-empty, and keep the existing
error for both empty; adjust the conditional that currently checks params == nil
|| (params.ClientUserId == "" && params.ItsIdHash == "") to also reject the case
where both fields are provided so the function only proceeds when exactly one
identifier is present.

@codecov

codecov Bot commented May 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.33333% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.90%. Comparing base (d313300) to head (daf1fb8).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
ee/server/service/vpp_users.go 83.33% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #46345   +/-   ##
=======================================
  Coverage   66.89%   66.90%           
=======================================
  Files        2783     2783           
  Lines      221736   221735    -1     
  Branches    11221    11221           
=======================================
+ Hits       148335   148342    +7     
+ Misses      60001    59994    -7     
+ Partials    13400    13399    -1     
Flag Coverage Δ
backend 68.67% <83.33%> (+<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.

@JordanMontgomery

Copy link
Copy Markdown
Member

We went a different way with this. CLosing this one

@georgekarrv
georgekarrv deleted the gkarr-fix-byod-vpp-2 branch May 28, 2026 20:53
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