Skip to content

feat(software): device lists sort and filter, type, installedBy and a real up-to-date status CU-17tkuw61fh5 - #2909

Open
andrii-flamingo wants to merge 4 commits into
mainfrom
feat/software-lists-api
Open

andrii-flamingo wants to merge 4 commits into
mainfrom
feat/software-lists-api

Conversation

@andrii-flamingo

@andrii-flamingo andrii-flamingo commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

ClickUp task: CU-17tkuw61fh5 BE: Software lists

What

The part of the Software lists that does not need the read model. Data still comes from Fleet, and Fleet is not changed.

  • softwareDevices: sort by softwareVersion in numeric order, and every filter of the contract: statuses, tags, customer, device status, installedBy, auto-update.
  • softwareDeviceFilters: installedBy, auto-update, device status and customer facets.
  • softwareVulnerabilities: the severities filter.
  • deviceSoftware: the auto-update filter and facet.
  • Software.type from Fleet's source, Software.devicesCount in the schema.
  • SoftwareOnDevice.installedBy: BREW or CHOCOLATEY when Fleet names them, otherwise null, because an app Fleet calls apps or programs may have come from winget or a cask.

Fix

SoftwareOnDevice.status was always OUTDATED: latestVersion was never set. It is now the highest version on the tenant's devices, so UP_TO_DATE means the newest here, not the newest released.

Not here

softwares filters, softwareFilters facets, publisher, versionStatus, cpeMatched and paging at the source come with the read model (#2651).

Notes

Change-Set: feat-software-lists-api

Change set flamingo-stack/feat-software-lists-api: this pull request is the only one in it so far. Another pull request joins by naming this one in a Depends-On line, or by carrying the same Change-Set line.

Linked work

Linked by the Depends-On / Change-Set lines in these descriptions; this block is maintained by the hub.

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

🦩 Flamingo Code Review

✅ Tests and checks passed on this commit (2 lanes).

✅ No findings on the current head.

Advisory: findings do not block the merge.

Files Lines 🔴 Action required 🟠 Recommended 🔵 Informational
15 +508 / -69 0 0 0

✅ What this change does well

  • SoftwareVersions.compare in openframe-api-lib/src/main/java/com/openframe/api/util/SoftwareVersions.java correctly handles numeric, segment-wise version comparison and is covered with targeted parameterized tests in SoftwareVersionsTest.java.
  • The new selected() helper in SoftwareInventoryService.java cleanly generalizes the 'empty filter matches all' semantics that previously had ad-hoc per-filter logic, reducing duplication across the many new device filter dimensions.
  • listDevicesForSoftware is restructured into clearly named phase methods (devicesWithAutoUpdate, taggedMachines, deviceOrder, matchesDeviceFilter) per OFJAVA-032, instead of one monolithic method.
7 possible problems checked and ruled out
  • openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/software/SoftwareOnDeviceFilterInput.java:9 SoftwareOnDeviceFilterInput duplicates a near-identical definition: SoftwareOnDeviceFilterInput and SoftwareActionFilterInput are different filter DTOs with distinct field sets for distinct queries; this is normal GraphQL input modeling, not real duplication worth merging.
  • openframe-api-lib/src/main/java/com/openframe/api/service/rmm/software/SoftwareInventoryService.java:321 listDevicesForSoftware and listVulnerabilitiesForSoftware grow another positional parameter instead of a parameter object: Six-seven parameters is borderline but these are query methods combining filter/pagination/sort, a common and explicit pattern; not a clear data clump warranting a parameter object per se, and stylistic at this count.
  • openframe-api-service-core/src/main/java/com/openframe/api/datafetcher/rmm/SoftwareDataFetcher.java:70 softwareDevices duplicates an existing definition: softwareDevices, deviceSoftware, and softwareVulnerabilities are separate DGS query handlers with different filter types and service calls; structural similarity is expected boilerplate for DGS data fetchers, not duplicated logic to extract.
  • openframe-api-lib/src/main/java/com/openframe/api/service/rmm/software/SoftwareInventoryService.java:392 taggedMachines returns null to signal "no tag filter", mixing null-as-sentinel with Set return type: taggedMachines is a private helper with a single caller that documents and correctly handles the null sentinel in-class; this is not the public-API null-return anti-pattern OFJAVA-013 targets (saveUser-style contracts), it's an internal implementation detail.
  • openframe-api-service-core/src/main/java/com/openframe/api/datafetcher/rmm/SoftwareDataFetcher.java:30 2 new or changed definitions have no test referencing them: SoftwareDataFetcher is a thin DGS controller/entry-point class delegating to SoftwareInventoryService; missing-test findings on framework wrapper classes are declarative boilerplate per the stated exclusion.
  • openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/software/SoftwareFilters.java:16 Comment on autoUpdateStatuses restates what the field already says, not a non-obvious why: The comment conveys a non-obvious why (field is empty pending a backing read model) which is exactly the kind of domain context OFJAVA-008 permits; not pure WHAT restatement.
  • openframe-api-lib/src/main/java/com/openframe/api/service/rmm/software/SoftwareInventoryService.java:382 Magic string list duplicated as both a field name and a sortable-fields message: DEVICE_SORT_FIELD is already a named constant used consistently; this is a stylistic nitpick about message construction, not an inline magic literal the rule targets.

Review again. New commits are not reviewed until you ask:

  • Review the new commits: only what was pushed since this review
  • Review the whole diff again: everything, including what was already reviewed

Or comment @flamingo-review (new commits) or @flamingo-review full (everything). Add the flamingo-review-always label to review every push.

🧪 Tests and mutation

Tests per lane

Language Project Command Status Counts Time
Java (Maven) . mvn -B -s ./.mvn/settings.xml test -pl openframe-api-lib,openframe-api-service-core -am ✅ passed openframe-agent-key 4 · openframe-api-lib 603 · openframe-api-service-core 747 (42 skipped) · openframe-core 150 · openframe-core-crypto 8 · openframe-data-cassandra 20 · openframe-data-kafka 19 · openframe-data-loki 96 · openframe-data-mongo-sync 463 (196 skipped) · openframe-data-nats 152 (4 skipped) · openframe-data-pinot 69 · openframe-exception 4 · openframe-graphql-node 76 · openframe-graphql-relay 69 · openframe-machine-delivery 134 · openframe-notification-core 98 (22 skipped) · openframe-notification-mail 4 · openframe-presence 12 · openframe-security-core 38 · fleetmdm 51 · 0 failures 318.1 s

Mutation testing

This build has no PIT plugin, so each module is mutated from the command line with pit-adhoc.sh, changing nothing in the repository.

Module Classes Whole classes New lines only Time
lib FleetSoftwareMapper, SoftwareFilters, SoftwareInventoryService, SoftwareVersions 310 mutants, 245 killed (79%), 39 survived, 26 no coverage, test strength 86%, line coverage 90% 62 mutants: 60 killed, 1 survived, 1 no coverage 124 s
service-core SoftwareDataFetcher 24 mutants, 0 killed (0%), 24 no coverage, line coverage 0% none on added lines 43 s

New code, its covering tests and the result

New code Covering tests Result
lambda$listVulnerabilitiesForSoftware$3 in SoftwareInventoryService, line 351 SoftwareInventoryServiceTest (3), 2 more killed
lambda$listDevicesForSoftware$0 in SoftwareInventoryService, line 365 SoftwareInventoryServiceTest (3), 6 more killed
listDevicesForSoftware in SoftwareInventoryService, line 368 SoftwareInventoryServiceTest (3), 7 more killed
devicesWithAutoUpdate in SoftwareInventoryService, lines 374-375 SoftwareInventoryServiceTest (3), 11 more killed
deviceOrder in SoftwareInventoryService, lines 379-388 SoftwareInventoryServiceTest (3), 8 more killed
taggedMachines in SoftwareInventoryService, lines 393-400 SoftwareInventoryServiceTest (3), 7 more killed
lambda$taggedMachines$0 in SoftwareInventoryService, line 396 SoftwareInventoryServiceTest (1) killed
matchesDeviceFilter in SoftwareInventoryService, lines 408-417 SoftwareInventoryServiceTest (3), 6 more killed
selected in SoftwareInventoryService, line 422 SoftwareInventoryServiceTest (3), 4 more killed
listSoftwareForDevice in SoftwareInventoryService, lines 432-439 SoftwareInventoryServiceTest (3), 9 more killed
lambda$listSoftwareForDevice$0 in SoftwareInventoryService, line 434 SoftwareInventoryServiceTest (3), 7 more killed
getDeviceSoftwareFilters in SoftwareInventoryService, line 445 SoftwareInventoryServiceTest (3), 1 more killed
getSoftwareDeviceFilters in SoftwareInventoryService, line 552 SoftwareInventoryServiceTest (3), 2 more killed
lambda$getSoftwareDeviceFilters$0 in SoftwareInventoryService, line 556 SoftwareInventoryServiceTest (3), 2 more killed
lambda$organizationFacet$0 in SoftwareInventoryService, line 563 SoftwareInventoryServiceTest (3), 2 more killed
organizationFacet in SoftwareInventoryService, lines 566-572 SoftwareInventoryServiceTest (3), 2 more killed
lambda$organizationFacet$1 in SoftwareInventoryService, line 570 SoftwareInventoryServiceTest (2) killed
lambda$organizationFacet$2 in SoftwareInventoryService, line 571 none no coverage (line 571)
lambda$allDevicesForSoftware$1 in SoftwareInventoryService, line 609 SoftwareInventoryServiceTest (3), 10 more killed
installedBy in SoftwareInventoryService, line 633 SoftwareInventoryServiceTest (3), 10 more killed
latestVersion in FleetSoftwareMapper, line 37 FleetSoftwareMapperTest (2), SoftwareInventoryServiceTest (1), 20 more killed
compare in SoftwareVersions, lines 17-24 SoftwareVersionsTest (2), FleetSoftwareMapperTest (1), 9 more 8 killed. Survived: line 17: changed conditional boundary
parseSegment in SoftwareVersions, line 30 SoftwareVersionsTest (1), FleetSoftwareMapperTest (1), SoftwareInventoryServiceTest (1), 9 more killed
The covering tests by name (22 methods)
  • SoftwareInventoryService.lambda$listVulnerabilitiesForSoftware$3: SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_nullEnrichment_noNpe, SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_dedupsByCve, SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_severitiesFilter, and 2 more
  • SoftwareInventoryService.lambda$listDevicesForSoftware$0: SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, SoftwareInventoryServiceTest.listDevices_statusFilter, and 6 more
  • SoftwareInventoryService.listDevicesForSoftware: SoftwareInventoryServiceTest.listDevices_nonNumericId_emptyNoFleet, SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, and 7 more
  • SoftwareInventoryService.devicesWithAutoUpdate: SoftwareInventoryServiceTest.listDevices_autoUpdateFilter_beforeThePage, SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets, SoftwareInventoryServiceTest.listDevices_filters, and 11 more
  • SoftwareInventoryService.deviceOrder: SoftwareInventoryServiceTest.listDevices_unknownSortField_rejectedBeforeFleet, SoftwareInventoryServiceTest.listDevices_nonNumericId_emptyNoFleet, SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, and 8 more
  • SoftwareInventoryService.taggedMachines: SoftwareInventoryServiceTest.listDevices_nonNumericId_emptyNoFleet, SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, and 7 more
  • SoftwareInventoryService.lambda$taggedMachines$0: SoftwareInventoryServiceTest.listDevices_filters
  • SoftwareInventoryService.matchesDeviceFilter: SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, SoftwareInventoryServiceTest.listDevices_statusFilter, and 6 more
  • SoftwareInventoryService.selected: SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_severitiesFilter, SoftwareInventoryServiceTest.listSoftwareForDevice_sourcesFilter_keepsMatchingTitlesOnly, SoftwareInventoryServiceTest.listSoftwareForDevice_minSeverityHigh_titlesBelowBandExcluded, and 4 more
  • SoftwareInventoryService.listSoftwareForDevice: SoftwareInventoryServiceTest.listSoftwareForDevice_autoUpdateFilterAndFacet, SoftwareInventoryServiceTest.listSoftwareForDevice_emptyInventory_emptyPageWithoutCatalogOrCountLookups, SoftwareInventoryServiceTest.listSoftwareForDevice_titleWithoutCves_summaryIsNull, and 9 more
  • SoftwareInventoryService.lambda$listSoftwareForDevice$0: SoftwareInventoryServiceTest.listSoftwareForDevice_titleWithoutCves_summaryIsNull, SoftwareInventoryServiceTest.listSoftwareForDevice_defaultOrder_byNameCaseInsensitive, SoftwareInventoryServiceTest.listSoftwareForDevice_pageRequested_everyFilteredRowCountedFromHostSoftwareNotPerRow, and 7 more
  • SoftwareInventoryService.getDeviceSoftwareFilters: SoftwareInventoryServiceTest.listSoftwareForDevice_autoUpdateFilterAndFacet, SoftwareInventoryServiceTest.getDeviceSoftwareFilters_emptyInventory_emptyFacets, SoftwareInventoryServiceTest.getDeviceSoftwareFilters_searchApplied_onlyMatchingTitlesCounted, and 1 more
  • SoftwareInventoryService.getSoftwareDeviceFilters: SoftwareInventoryServiceTest.softwareDeviceFilters_noOrganizationOnAnyDevice_noLookup, SoftwareInventoryServiceTest.softwareDeviceFilters_facetsByStatus, SoftwareInventoryServiceTest.softwareDeviceFilters_organizationWithoutName_labelledByItsId, and 2 more
  • SoftwareInventoryService.lambda$getSoftwareDeviceFilters$0: SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets, SoftwareInventoryServiceTest.softwareDeviceFilters_noOrganizationOnAnyDevice_noLookup, SoftwareInventoryServiceTest.softwareDeviceFilters_facetsByStatus, and 2 more
  • SoftwareInventoryService.lambda$organizationFacet$0: SoftwareInventoryServiceTest.softwareDeviceFilters_noOrganizationOnAnyDevice_noLookup, SoftwareInventoryServiceTest.softwareDeviceFilters_facetsByStatus, SoftwareInventoryServiceTest.softwareDeviceFilters_organizationWithoutName_labelledByItsId, and 2 more
  • SoftwareInventoryService.organizationFacet: SoftwareInventoryServiceTest.softwareDeviceFilters_noOrganizationOnAnyDevice_noLookup, SoftwareInventoryServiceTest.softwareDeviceFilters_organizationWithoutName_labelledByItsId, SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets, and 2 more
  • SoftwareInventoryService.lambda$organizationFacet$1: SoftwareInventoryServiceTest.softwareDeviceFilters_organizationWithoutName_labelledByItsId, SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets
  • SoftwareInventoryService.lambda$allDevicesForSoftware$1: SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, SoftwareInventoryServiceTest.listDevices_statusFilter, and 10 more
  • SoftwareInventoryService.installedBy: SoftwareInventoryServiceTest.listDevices_installedBy, SoftwareInventoryServiceTest.softwareDeviceFilters_facetsByStatus, SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets, and 10 more
  • FleetSoftwareMapper.latestVersion: FleetSoftwareMapperTest.toResponse_noVersions_noLatest, FleetSoftwareMapperTest.toResponse_latestVersionIsTheHighest_inNumericOrder, SoftwareInventoryServiceTest.listDevices_statusAgainstTheHighestVersion, and 20 more
  • SoftwareVersions.compare: SoftwareVersionsTest.sameVersion_isEqual, SoftwareVersionsTest.lowerComesFirst, FleetSoftwareMapperTest.toResponse_latestVersionIsTheHighest_inNumericOrder, and 9 more
  • SoftwareVersions.parseSegment: SoftwareVersionsTest.lowerComesFirst, FleetSoftwareMapperTest.toResponse_latestVersionIsTheHighest_inNumericOrder, SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_dedupsByCve, and 9 more

2 mutants on lines this change added are not caught (1 survived, 1 with no test reaching them): each is annotated on its line in the Flamingo Code Review / tests and mutation check.

1 gap (not tested here):

  • Java (Maven) .: SoftwareFilterInput.java, SoftwareOnDeviceFilterInput.java, SoftwareOnDeviceFilters.java, SoftwareOnDeviceResponse.java, SoftwareVulnerabilityFilterInput.java changed but not mutation-tested (outside the mutation targets openframe-api-lib configures)

Started 2026-10-30 21:10 UTC · updated 2026-10-30 21:12 UTC · workflow run

@andrii-flamingo
andrii-flamingo added this pull request to the merge queue Oct 30, 2026
@andrii-flamingo
andrii-flamingo removed this pull request from the merge queue due to a manual request Oct 30, 2026
@andrii-flamingo
andrii-flamingo added this pull request to the merge queue Oct 30, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Oct 30, 2026
@andrii-flamingo
andrii-flamingo added this pull request to the merge queue Oct 31, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Oct 31, 2026
@andrii-flamingo
andrii-flamingo added this pull request to the merge queue Oct 31, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Oct 31, 2026
@andrii-flamingo
andrii-flamingo added this pull request to the merge queue Oct 31, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Oct 31, 2026
@andrii-flamingo
andrii-flamingo added this pull request to the merge queue Nov 1, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Nov 1, 2026
@andrii-flamingo
andrii-flamingo added this pull request to the merge queue Nov 1, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Nov 1, 2026
@andrii-flamingo
andrii-flamingo added this pull request to the merge queue Nov 1, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants