Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.openframe.api.dto.rmm.software;

import com.openframe.data.document.rmm.software.SoftwareAutoUpdateStatus;
import lombok.Data;

import java.util.List;
Expand All @@ -14,4 +15,6 @@ public class SoftwareFilterInput {
private SoftwareCveSeverity minSeverity;

private List<String> deviceTagIds;

private List<SoftwareAutoUpdateStatus> autoUpdateStatuses;
Comment thread
andrii-flamingo marked this conversation as resolved.
Resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class SoftwareFilters {
private List<SoftwareFilterOption> versionStatuses;
private List<SoftwareFilterOption> severities;

// empty until the auto-update policy backs it: the schema field is non-null
// non-null in the schema; the tenant-wide facet stays empty until the read model backs it
@Builder.Default
private List<SoftwareFilterOption> autoUpdateStatuses = List.of();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.openframe.api.dto.rmm.software;

import com.openframe.data.document.device.DeviceStatus;
import com.openframe.data.document.rmm.software.SoftwareAutoUpdateStatus;
import lombok.Data;

import java.util.List;
Expand All @@ -9,4 +11,8 @@ public class SoftwareOnDeviceFilterInput {

private List<SoftwareOnDeviceStatus> statuses;
private List<String> deviceTagIds;
private List<String> organizationIds;
private List<DeviceStatus> deviceStatuses;
private List<SoftwareSource> installedBy;
private List<SoftwareAutoUpdateStatus> autoUpdateStatuses;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class SoftwareOnDeviceFilters {

private List<SoftwareFilterOption> statuses;

// empty until the read model and the auto-update policy back them: the schema fields are non-null
// non-null in the schema; empty when no device has a value for them
@Builder.Default
private List<SoftwareFilterOption> installedBy = List.of();
@Builder.Default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public class SoftwareOnDeviceResponse {
private Machine device;
private String softwareVersion;
private SoftwareOnDeviceStatus status;
private SoftwareSource installedBy;
private SoftwareAutoUpdateStatus autoUpdate;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.openframe.api.dto.rmm.software;

import lombok.Data;

import java.util.List;

@Data
public class SoftwareVulnerabilityFilterInput {
private List<SoftwareCveSeverity> severities;
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,22 @@ public static SoftwareResponse toResponse(SoftwareTitle title) {
.name(title.getName())
.source(FleetSoftwareCategory.of(title.getSource()).source())
.currentVersion(current == null ? null : current.getVersion())
.latestVersion(latestVersion(versions))
.olderVersionsCount(olderVersionsCount(versions))
.devicesCount(title.getHostsCount())
.vulnerabilitySummary(rollUpVulnerabilities(versions))
.build();
}

// the highest version installed on the tenant's devices: Fleet does not say what the newest release is
private static String latestVersion(List<SoftwareTitleVersion> versions) {
return versions == null ? null : versions.stream()
.map(SoftwareTitleVersion::getVersion)
.filter(Objects::nonNull)
.max(SoftwareVersions::compare)
.orElse(null);
}

private static SoftwareTitleVersion pickCurrentVersion(List<SoftwareTitleVersion> versions) {
if (versions == null || versions.isEmpty()) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.openframe.api.util;

import lombok.experimental.UtilityClass;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

@UtilityClass
public class SoftwareVersions {

private static final Pattern LEADING_DIGITS = Pattern.compile("^\\d{1,18}");

// Numeric, segment-wise version order so "9.0" precedes "10.0" (plain String sort would not).
public static int compare(String a, String b) {
String[] pa = a.split("\\.");
String[] pb = b.split("\\.");
for (int i = 0; i < Math.max(pa.length, pb.length); i++) {
long va = i < pa.length ? parseSegment(pa[i]) : 0;
long vb = i < pb.length ? parseSegment(pb[i]) : 0;
if (va != vb) {
return Long.compare(va, vb);
}
}
return a.compareTo(b);
}
Comment thread
andrii-flamingo marked this conversation as resolved.
Resolved

// the leading number of a segment, so "3-beta" and "0_2" still count as 3 and 0
private static long parseSegment(String segment) {
Matcher digits = LEADING_DIGITS.matcher(segment.trim());
return digits.find() ? Long.parseLong(digits.group()) : 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import com.openframe.api.service.rmm.fleet.HostInventory;
import com.openframe.data.document.device.Machine;
import com.openframe.data.repository.tool.IntegratedToolRepository;
import com.openframe.data.repository.organization.OrganizationRepository;
import com.openframe.data.repository.tag.TagAssignmentRepository;
import com.openframe.data.service.TenantIdProvider;
import com.openframe.sdk.fleetmdm.FleetMdmClient;
import com.openframe.sdk.fleetmdm.model.FleetSoftware;
Expand Down Expand Up @@ -61,13 +63,15 @@ class SoftwareInventoryServiceFleetPagingTest {
@Mock private IntegratedToolRepository integratedToolRepository;
@Mock private DeviceHostInventoryLoader deviceHostInventoryLoader;
@Mock private SoftwareAutoUpdateService autoUpdateService;
@Mock private TagAssignmentRepository tagAssignmentRepository;
@Mock private OrganizationRepository organizationRepository;

private SoftwareInventoryService service;

@BeforeEach
void setUp() {
service = new SoftwareInventoryService(integratedToolRepository, deviceCountEnricher, hostMachineResolver,
tenantIdProvider, deviceHostInventoryLoader, autoUpdateService);
tenantIdProvider, deviceHostInventoryLoader, autoUpdateService, tagAssignmentRepository, organizationRepository);
ReflectionTestUtils.setField(service, "fleet", fleet);
ReflectionTestUtils.setField(service, "fleetPaging", true);
}
Expand Down Expand Up @@ -151,7 +155,7 @@ void listVulnerabilitiesForSoftware_detailsPerVersion_earliestDiscoveryWins() {

// execution
PageResult<SoftwareVulnerabilityResponse> result =
service.listVulnerabilitiesForSoftware("42", null, 0, 50, null, true);
service.listVulnerabilitiesForSoftware("42", null, null, 0, 50, null, true);

// verifications
assertThat(result.items())
Expand All @@ -171,7 +175,7 @@ void listVulnerabilitiesForSoftware_versionGoneFromFleet_rowWithoutDetails() {

// execution
PageResult<SoftwareVulnerabilityResponse> result =
service.listVulnerabilitiesForSoftware("42", null, 0, 50, null, true);
service.listVulnerabilitiesForSoftware("42", null, null, 0, 50, null, true);

// verifications
assertThat(result.items()).extracting(SoftwareVulnerabilityResponse::getCveId, SoftwareVulnerabilityResponse::getDiscoveredAt)
Expand All @@ -190,7 +194,7 @@ void listDevicesForSoftware_hostsOfEveryVersionCorrelated() {
when(hostMachineResolver.resolve(eq("t1"), anyList())).thenReturn(Map.of(10L, machine("m-10"), 11L, machine("m-11")));

// execution
PageResult<SoftwareOnDeviceResponse> result = service.listDevicesForSoftware("42", null, null, 0, 50);
PageResult<SoftwareOnDeviceResponse> result = service.listDevicesForSoftware("42", null, null, 0, 50, null);

// verifications
assertThat(result.items())
Expand Down
Loading
Loading