From 32ed65eb796322a005baecc5d2f812fba500668b Mon Sep 17 00:00:00 2001 From: Jordan Ramos Date: Tue, 9 Jun 2026 14:03:31 -0600 Subject: [PATCH] =?UTF-8?q?Fix=20owner-lookup=20hostId=20fast=20path=20?= =?UTF-8?q?=E2=80=94=20use=20asset-search=20owner=20data=20directly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The asset-search response wraps in { assets: [...] } and includes the full owner record. Previously we tried to extract just an _id from the top level (which didn't exist) and then made a separate getOwner() call that returned empty data for IPv6 assets. Now when hostId resolves via asset-search, we return the owner data directly from the search response — no second API call needed. This fixes the tooltip showing empty confirmed/unconfirmed for IPv6-only findings. --- backend/routes/cardApi.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/backend/routes/cardApi.js b/backend/routes/cardApi.js index ac5d2ab..eed018d 100644 --- a/backend/routes/cardApi.js +++ b/backend/routes/cardApi.js @@ -595,14 +595,28 @@ function createCardApiRouter() { const hostId = req.query.hostId; // Fast path: if Ivanti hostId is provided, try asset-search first + // The asset-search returns the full record including owner data, so we can + // return directly without a separate getOwner() call. let assetId = null; if (hostId && /^\d+$/.test(hostId)) { try { const searchResult = await searchByIvantiHostId(hostId); if (searchResult.ok) { const searchData = JSON.parse(searchResult.body); - // Extract asset_id from the search response (_id field or asset_id) - assetId = searchData._id || searchData.asset_id || searchData.id || null; + const assets = searchData.assets || []; + if (assets.length > 0) { + const asset = assets[0]; + const owner = asset.owner || {}; + return res.json({ + asset_id: asset._id || null, + ip: ip.trim(), + confirmed: owner.confirmed || null, + unconfirmed: owner.unconfirmed || null, + declined: owner.declined || [], + candidate: owner.candidate || [], + update_token: owner.update_token || null, + }); + } } } catch (_) { // Fall through to suffix resolution