From fe46e41a52247e145999a4a498d860da0dc01879 Mon Sep 17 00:00:00 2001 From: Steven Palmesano <3100993+spalmesano0@users.noreply.github.com> Date: Tue, 30 Jun 2026 14:20:37 -0500 Subject: [PATCH] Add public IP address to host search (#46809) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Related issue:** Resolves #4842 # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually ## Summary by CodeRabbit * **New Features** * IP-based host searches now match both private and public IP addresses. * Updated the host search box placeholder and tooltip to refer to “IP address” (instead of “private IP”). * **Tests** * Expanded backend coverage to verify matching (and non-matching) results for both private and public IPs when listing and searching hosts. --------- Co-authored-by: Lucas Manuel Rodriguez --- changes/4842-search-public-ip | 1 + frontend/utilities/constants.tsx | 4 ++-- server/datastore/mysql/hosts.go | 2 +- server/datastore/mysql/hosts_test.go | 28 ++++++++++++++++++++++++++- server/datastore/mysql/labels_test.go | 16 +++++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 changes/4842-search-public-ip diff --git a/changes/4842-search-public-ip b/changes/4842-search-public-ip new file mode 100644 index 0000000000..e1eedd04d2 --- /dev/null +++ b/changes/4842-search-public-ip @@ -0,0 +1 @@ +- Added public IP address to host search, so that searching by IP now matches both the primary (private) IP and the public IP. diff --git a/frontend/utilities/constants.tsx b/frontend/utilities/constants.tsx index 313175fc75..d223836cbd 100644 --- a/frontend/utilities/constants.tsx +++ b/frontend/utilities/constants.tsx @@ -338,13 +338,13 @@ export const SCHEDULE_PLATFORM_DROPDOWN_OPTIONS = [ ] as const; export const HOSTS_SEARCH_BOX_PLACEHOLDER = - "Search name, user email, hostname, UUID, serial number, or private IP address"; + "Search name, user email, hostname, UUID, serial number, or IP address"; export const HOSTS_SEARCH_BOX_TOOLTIP = ( <> Search hosts by name, user email, hostname,
- UUID, serial number, or private IP address. + UUID, serial number, or IP address. ); diff --git a/server/datastore/mysql/hosts.go b/server/datastore/mysql/hosts.go index 26375b3e7a..562496d744 100644 --- a/server/datastore/mysql/hosts.go +++ b/server/datastore/mysql/hosts.go @@ -38,7 +38,7 @@ var ( ) var ( - hostSearchColumns = []string{"hostname", "computer_name", "uuid", "h.hardware_serial", "primary_ip"} + hostSearchColumns = []string{"hostname", "computer_name", "uuid", "h.hardware_serial", "primary_ip", "public_ip"} wildCardableHostSearchColumns = []string{"hostname", "computer_name"} ) diff --git a/server/datastore/mysql/hosts_test.go b/server/datastore/mysql/hosts_test.go index b2b2c50e55..9f6d451902 100644 --- a/server/datastore/mysql/hosts_test.go +++ b/server/datastore/mysql/hosts_test.go @@ -1522,6 +1522,18 @@ func testHostsListQuery(t *testing.T, ds *Datastore) { gotHosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{ListOptions: fleet.ListOptions{MatchQuery: "b.cb"}}, 1) require.Equal(t, 1, len(gotHosts)) assert.Equal(t, hosts[2].ID, gotHosts[0].ID) // matches email dbca@b.cba + + // check that ListHosts also filters by public IP address + hosts[3].PublicIP = "203.0.113.42" + err = ds.UpdateHost(context.Background(), hosts[3]) + require.NoError(t, err) + + gotHosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{ListOptions: fleet.ListOptions{MatchQuery: "203.0.113.42"}}, 1) + require.Len(t, gotHosts, 1) + assert.Equal(t, hosts[3].ID, gotHosts[0].ID) + + gotHosts = listHostsCheckCount(t, ds, filter, fleet.HostListOptions{ListOptions: fleet.ListOptions{MatchQuery: "203.0.113.99"}}, 0) + assert.Empty(t, gotHosts) } func testHostsUnenrollFromMDM(t *testing.T, ds *Datastore) { @@ -2532,7 +2544,7 @@ func testHostsSearch(t *testing.T, ds *Datastore) { require.NoError(t, err) assert.Len(t, none, 0) - // check to make sure search on ip address works + // check to make sure search on private ip address works h2.PrimaryIP = "99.100.101.103" err = ds.UpdateHost(context.Background(), h2) require.NoError(t, err) @@ -2545,6 +2557,20 @@ func testHostsSearch(t *testing.T, ds *Datastore) { require.NoError(t, err) assert.Equal(t, 0, len(hits)) + // check that search on public ip address also works + h2.PublicIP = "1.2.3.4" + err = ds.UpdateHost(context.Background(), h2) + require.NoError(t, err) + + hits, err = ds.SearchHosts(context.Background(), filter, "1.2.3.4") + require.NoError(t, err) + require.Len(t, hits, 1) + assert.Equal(t, h2.ID, hits[0].ID) + + hits, err = ds.SearchHosts(context.Background(), filter, "1.2.3.9") + require.NoError(t, err) + assert.Empty(t, hits) + h3.PrimaryIP = "99.100.101.104" err = ds.UpdateHost(context.Background(), h3) require.NoError(t, err) diff --git a/server/datastore/mysql/labels_test.go b/server/datastore/mysql/labels_test.go index 133a78d8d7..fc1dfbdce3 100644 --- a/server/datastore/mysql/labels_test.go +++ b/server/datastore/mysql/labels_test.go @@ -458,6 +458,22 @@ func testLabelsListHostsInLabel(t *testing.T, db *Datastore) { listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{MDMNameFilter: ptr.String(fleet.WellKnownMDMSimpleMDM)}, 2) listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{MDMNameFilter: ptr.String(fleet.WellKnownMDMSimpleMDM), MDMEnrollmentStatusFilter: fleet.MDMEnrollStatusEnrolled}, 1) + // check that searching hosts in a label matches both the private and public IP address + h2.PrimaryIP = "99.100.101.102" + h2.PublicIP = "203.0.113.42" + err = db.UpdateHost(ctx, h2) + require.NoError(t, err) + + hosts = listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{ListOptions: fleet.ListOptions{MatchQuery: "99.100.101.102"}}, 1) + require.Len(t, hosts, 1) + require.Equal(t, h2.ID, hosts[0].ID) + + hosts = listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{ListOptions: fleet.ListOptions{MatchQuery: "203.0.113.42"}}, 1) + require.Len(t, hosts, 1) + require.Equal(t, h2.ID, hosts[0].ID) + + listHostsInLabelCheckCount(t, db, filter, l1.ID, fleet.HostListOptions{ListOptions: fleet.ListOptions{MatchQuery: "203.0.113.99"}}, 0) + // Test team label filtering team1, err := db.NewTeam(context.Background(), &fleet.Team{Name: "team1_listhosts"}) require.NoError(t, err)