Closes#45843
## Summary
- Table-qualify column names in `vulnerabilitiesAllowedOrderKeys` so
they resolve correctly in both `ORDER BY` and cursor `WHERE` clauses
- `cve` was ambiguous between `vhc.cve` and `cm.cve`
- `hosts_count` and `cve_published` were SELECT aliases not valid in
WHERE scope
- Also fixed `host_count_updated_at` / `hosts_count_updated_at` which
had the same alias issue
## Reproduction
### Bug (before fix)
The `ListVulnerabilities` query joins `vulnerability_host_counts vhc
LEFT JOIN cve_meta cm`. When cursor pagination appends `WHERE <column> >
?`, three order keys fail:
| `order_key` | Old column value | MySQL error |
|-------------|-----------------|-------------|
| `cve` | `cve` | `Error 1052: Column 'cve' in where clause is
ambiguous` (exists on both `vhc` and `cm`) |
| `hosts_count` | `hosts_count` | `Error 1054: Unknown column
'hosts_count' in 'where clause'` (SELECT alias, not a real column) |
| `cve_published` | `cve_published` | `Error 1054: Unknown column
'cve_published' in 'where clause'` (SELECT alias for `cm.published`) |
Reproduced locally by running the raw SQL the old code would generate:
```sql
-- BUG 1: ambiguous
... WHERE vhc.host_count > 0 AND cve > 'CVE-2023-0002' ORDER BY cve ASC;
-- ERROR 1052 (23000): Column 'cve' in where clause is ambiguous
-- BUG 2: alias not valid in WHERE
... WHERE vhc.host_count > 0 AND hosts_count > 10 ORDER BY hosts_count ASC;
-- ERROR 1054 (42S22): Unknown column 'hosts_count' in 'where clause'
-- BUG 3: alias not valid in WHERE
... WHERE vhc.host_count > 0 AND cve_published > '2020-01-01' ORDER BY cve_published ASC;
-- ERROR 1054 (42S22): Unknown column 'cve_published' in 'where clause'
```
### Fix
Changed the allowlist values from bare names/aliases to table-qualified
actual column names:
| `order_key` | Before | After | Why |
|-------------|--------|-------|-----|
| `cve` | `cve` | `vhc.cve` | Ambiguous: both `vhc` and `cm` have a
`cve` column |
| `cve_published` | `cve_published` | `cm.published` | SELECT alias, not
a real column; invalid in WHERE |
| `hosts_count` / `host_count` | `hosts_count` | `vhc.host_count` |
SELECT alias for `vhc.host_count`; invalid in WHERE |
| `hosts_count_updated_at` / `host_count_updated_at` |
`hosts_count_updated_at` | `vhc.updated_at` | SELECT alias for
`vhc.updated_at`; invalid in WHERE |
Table-qualified names work in both `ORDER BY` and `WHERE` clauses.
### Manual verification (after fix)
Started a local Fleet server (`--dev --dev_license`), seeded 6
vulnerability entries, and hit all three previously-broken API calls:
```
GET /api/v1/fleet/vulnerabilities?order_key=cve&order_direction=asc&per_page=3&after=CVE-2023-0002
--> 200 OK, returned CVE-2023-0003, CVE-2023-0004, CVE-2023-0005 (correct ascending order)
GET /api/v1/fleet/vulnerabilities?order_key=hosts_count&order_direction=asc&per_page=3&after=10
--> 200 OK, returned hosts_count=20, 30, 50 (correct ascending order)
GET /api/v1/fleet/vulnerabilities?order_key=cve_published&order_direction=asc&per_page=3&after=2020-01-01
--> 200 OK, returned 3 CVEs with publish dates after 2020-01-01
```
Regression checks (no breakage):
- `order_key=cvss_score` cursor pagination still works
- Page-based pagination (`page=0&per_page=3`) still returns correct
results with `has_next_results: true`
## Test plan
- [x] Added `testListVulnerabilitiesCursorPagination` integration test
covering all three broken order keys (`cve`, `hosts_count`,
`cve_published`)
- [x] Existing tests pass: sort, page-based pagination, team filter,
known exploit filter, count
- [x] Manual verification on local Fleet server (see above)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Bug Fixes
* Fixed cursor pagination for the vulnerabilities endpoint when sorting
by CVE, host count, or CVE publication date to prevent SQL errors and
ensure reliable result navigation.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45983?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->