Fix: IdP host vitals not automatically populated for Android hosts (#39254)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #38554

# Checklist for submitter

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

## Testing

- [x] Added/updated automated tests

There's already an integration test for `MaybeAssociateHostWithScimUser`
which is the function call I added as a fix. See
https://github.com/fleetdm/fleet/blob/b25c9522e4eb63a44e254904cf986440a7c30a95/server/datastore/mysql/hosts_test.go#L12242

- [x] QA'd all new/changed functionality manually

Enrolled physical Android device and verified that **Full name (IdP)**
and **Groups (IdP)** are populated.

<img width="1435" height="768" alt="Screenshot 2026-02-03 at 3 31 16 PM"
src="https://github.com/user-attachments/assets/0f7e8fc9-34f5-404c-bd1f-baed589aba60"
/>
This commit is contained in:
Nico
2026-02-06 09:15:30 -03:00
committed by GitHub
parent 0b149701cc
commit f099db37e7
3 changed files with 58 additions and 1 deletions
@@ -0,0 +1 @@
- Fixed Android enrollment to associate hosts with SCIM users, populating full name, groups, and department in host vitals.
+3
View File
@@ -549,6 +549,9 @@ func (svc *Service) addNewHost(ctx context.Context, device *androidmanagement.De
if err != nil {
return ctxerr.Wrap(ctx, err, "associating host with idp account")
}
if err := svc.fleetDS.MaybeAssociateHostWithScimUser(ctx, fleetHost.Host.ID); err != nil {
return ctxerr.Wrap(ctx, err, "associating android host with scim user")
}
}
// Create pending certificate templates for this newly enrolled host.
+54 -1
View File
@@ -182,6 +182,9 @@ func TestPubSubEnrollment(t *testing.T) {
mockDS.AssociateHostMDMIdPAccountFunc = func(ctx context.Context, hostUUID, accountUUID string) error {
return nil
}
mockDS.MaybeAssociateHostWithScimUserFunc = func(ctx context.Context, hostID uint) error {
return nil
}
enrollmentToken := enrollmentTokenRequest{
EnrollSecret: "global",
@@ -193,11 +196,61 @@ func TestPubSubEnrollment(t *testing.T) {
Name: createAndroidDeviceId("test-android"),
EnrollmentTokenData: string(enrollTokenData),
})
err = svc.ProcessPubSubPush(context.Background(), "value", enrollmentMessage)
err = svc.ProcessPubSubPush(t.Context(), "value", enrollmentMessage)
require.NoError(t, err)
require.True(t, mockDS.AssociateHostMDMIdPAccountFuncInvoked)
require.True(t, mockDS.NewAndroidHostFuncInvoked)
require.True(t, mockDS.MaybeAssociateHostWithScimUserFuncInvoked)
})
t.Run("associates scim user with correct host ID after idp association", func(t *testing.T) {
mockDS.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{
MDM: fleet.MDM{
AndroidEnabledAndConfigured: true,
},
}, nil
}
expectedHostID := uint(42)
mockDS.NewAndroidHostFunc = func(ctx context.Context, host *fleet.AndroidHost) (*fleet.AndroidHost, error) {
return &fleet.AndroidHost{Host: &fleet.Host{ID: expectedHostID}}, nil
}
var capturedIdpHostUUID, capturedIdpAcctUUID string
mockDS.AssociateHostMDMIdPAccountFunc = func(ctx context.Context, hostUUID, accountUUID string) error {
capturedIdpHostUUID = hostUUID
capturedIdpAcctUUID = accountUUID
return nil
}
var capturedScimHostID uint
mockDS.MaybeAssociateHostWithScimUserFunc = func(ctx context.Context, hostID uint) error {
capturedScimHostID = hostID
return nil
}
idpUUID := "test-idp-uuid"
enrollmentToken := enrollmentTokenRequest{
EnrollSecret: "global",
IdpUUID: idpUUID,
}
enrollTokenData, err := json.Marshal(enrollmentToken)
require.NoError(t, err)
enrollmentMessage := createEnrollmentMessage(t, androidmanagement.Device{
Name: createAndroidDeviceId("test-android-scim"),
EnrollmentTokenData: string(enrollTokenData),
})
err = svc.ProcessPubSubPush(t.Context(), "value", enrollmentMessage)
require.NoError(t, err)
require.True(t, mockDS.AssociateHostMDMIdPAccountFuncInvoked)
require.NotEmpty(t, capturedIdpHostUUID)
require.Equal(t, idpUUID, capturedIdpAcctUUID)
require.True(t, mockDS.MaybeAssociateHostWithScimUserFuncInvoked)
require.Equal(t, expectedHostID, capturedScimHostID)
})
})
}