fix(rmm): correlate Fleet hosts to machines through the FLEET_MDM tool connection first - #2370
Merged
Merged
Conversation
…l connection first FleetHostMachineResolver matched osUuid -> serial -> hostname exactly; a machine registered without uuid/serial whose hostname differs from Fleet's lower-cased one never correlated, so deviceSoftware/deviceVulnerabilities came back empty and softwares/vulnerabilities undercounted devicesCount. ToolConnection(FLEET_MDM).agentToolId is the Fleet host id written at registration, so both the loader and the resolver read it first and keep the identifier match as a fallback. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013zAKs7Zs4rWvhKuP3Brmqk
Contributor
🦩 Flamingo Code Review1 finding(s) — 0 action required · 1 recommended · 0 informational Mode: advisory · 1 defect(s) outside any rule Inline comments: 1 new Need another pass? Commits pushed after this review are not reviewed automatically.
Prefer typing? Comment React 👍/👎 on inline comments to teach the reviewer. Started 2026-09-24 14:58 UTC · updated 2026-09-24 14:59 UTC · workflow run |
…rsing agentToolId Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013zAKs7Zs4rWvhKuP3Brmqk
…tion duplicate, foreign tenant, host gone from Fleet Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013zAKs7Zs4rWvhKuP3Brmqk
oleksandrd-flamingo
approved these changes
Sep 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
FleetHostMachineResolver(#2094) maps a Fleet host to aMachineby exactosUuid→hardware_serial→hostname. A machine registered without uuid/serial whose hostname differs from Fleet's lower-cased one (MacBook-Pro-Hryhorii.localvsmacbook-pro-hryhorii.local) never correlates. Two visible effects, both seen on QA (test-env, release 1.3.62 / oss 6.36.15):deviceSoftware/deviceVulnerabilities(Software Management: device-scoped deviceSoftware + deviceVulnerabilities #2351) return an empty connection for such a device — while the frontend's current Software tab shows data, because it reads Fleet directly by the machine'sagentToolId(/tools/fleetmdm-server/…/hosts/{id}). Example:MacBook-Pro-Hryhorii.local, ONLINE, Fleet CONNECTED,agentToolId = 29.devicesCountonsoftwares/vulnerabilitiesundercounts the same devices (pre-existing since Software Management. Full API + Interaction with Fleet #2094; fix(rmm): Software & Vulnerabilities lists count devices from one host fetch #2357 kept the resolver). QA: Google Chrome is installed on 13 Fleet hosts, 6–7 of them have a live OpenFrame machine,devicesCountsaid 5.Fix
ToolConnection(FLEET_MDM).agentToolIdis the Fleet host id —FleetMdmAgentIdTransformerwritesString.valueOf(host.getId())at registration,(tenantId, machineId, toolType)is a unique index, and the frontend already navigates Fleet by it. Both correlation points read it first and keep the identifier match as the fallback:FleetHostMachineResolver.resolve— stage 0:toolConnectionRepository.findByAgentToolIdInAndToolType(hostIds, FLEET_MDM)→machineRepository.findByTenantIdAndMachineIdIn(tenant-scoped, ONLINE/OFFLINE filter as before). The host id is taken from the input host list (no parsing ofagentToolId). When several connections point at one host (stale duplicateMachinerecords after re-enrollment — QA has hosts with 2–4 of them), the newestconnectedAtamong countable machines wins. Then osUuid → serial → hostname as today. FixesdevicesCountforsoftwares/vulnerabilitiesand every other caller.DeviceHostInventoryLoader.findHostId—findByMachineIdAndToolType(machineId, FLEET_MDM)→ numericagentToolId→ host id, no Fleet search at all; the search+resolve path stays as fallback for a machine without a connection (or a non-numeric id from a failed transform). Side effect: one Fleet call less perdeviceVulnerabilitiespage.No schema, config or SDK change. Two repository finders reused, both already existed.
Edge cases checked against live data
agentToolIdpointing at a host that left the tenant or was deleted: the Fleet fork answers 404 for a host id of another tenant (verified on QA for ids 78, 1, 5, 10, 100 — "Host N was not found in the datastore"),listHostSoftwaremaps 404 to null → empty inventory, no error.findByAgentToolIdInAndToolTypeis not tenant-scoped (dev/QA tenants share one Mongo): connections of foreign tenants come back, butfindByTenantIdAndMachineIdIndrops their machines, so they can never claim a host or block the identifier fallback.PENDING_DELETION/DELETEDduplicates never claim a host in the resolver even when their connection is newer (same ONLINE/OFFLINE rule as before). The device-scoped loader, like the frontend's direct Fleet read, answers for any machine that still has a connection — aPENDING_DELETIONrecord shows its last inventory instead of an empty tab.agentToolId(transform never matched a host) → loader falls back to the search, resolver ignores it.Verified on QA (test-env, release 1.3.63 / oss 6.36.17, 2026-09-24 17:44 UTC)
MacBook-Pro-Hryhorii.local:deviceSoftware0 → 539 titles,deviceVulnerabilities0 → 270 CVEs;sort cveCount DESC→ Python 75, Word 47, Excel 46, Safari 32, openssl@3 28.filteredCount> 0), before 6 of 16.softwares→ Google ChromedevicesCount5 → 7; fleet-widesoftwares974 → 1173 titles andvulnerabilities1010 → 1152 rows withdevicesCount> 0 (the newly correlated hosts' software surfaced); top rows count 8 devices.vm11619467 titles,el-romeo449 titles / 488 CVEs, disjoint cursor pages,NOT_FOUND/404 andBAD_REQUEST/400.Tests
FleetHostMachineResolverTest+5 (connection beats a case-mismatched hostname; newest of two connections wins; newest connection on a PENDING_DELETION duplicate → the live machine claims; foreign-tenant connection ignored, identifier match still applies; no connections → machine lookup skipped),DeviceHostInventoryLoaderTest+3 (host from the connection with no Fleet search and no resolver call; connected host gone from Fleet → empty inventory; non-numericagentToolId→ search fallback). Regression across the touched classes: 81 green.Known, not in this PR:
tool_connectionshas no index onagentToolId(the existingfindFirstByAgentToolIdOrderByConnectedAtDescscans too); the collection is small (machines × tools) and the batch lookup runs once per 2 minutes per tenant throughCorrelatedHostSoftwareCache, so it is a follow-up index migration, not a blocker.🤖 Generated with Claude Code
https://claude.ai/code/session_013zAKs7Zs4rWvhKuP3Brmqk