Add public IP address to host search (#46809)

**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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## 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.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
This commit is contained in:
Steven Palmesano
2026-06-30 16:20:37 -03:00
committed by GitHub
co-authored by Lucas Manuel Rodriguez
parent ea94ddf92f
commit fe46e41a52
5 changed files with 47 additions and 4 deletions
+1
View File
@@ -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.
+2 -2
View File
@@ -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,
<br />
UUID, serial number, or private IP address.
UUID, serial number, or IP address.
</>
);
+1 -1
View File
@@ -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"}
)
+27 -1
View File
@@ -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)
+16
View File
@@ -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)