Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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 @@
private SoftwareCveSeverity minSeverity;

private List<String> deviceTagIds;

private List<SoftwareAutoUpdateStatus> autoUpdateStatuses;

Check notice on line 19 in openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/software/SoftwareFilterInput.java

View check run for this annotation

Flamingo / Flamingo Code Review / tests and mutation

softwares ігнорує нове поле filter.autoUpdateStatuses

Поле читає лише deviceSoftware. Запит softwares передає в listSoftware лише vulnerable, тому фільтр за auto-update мовчки повертає весь список, хоча опис Software.autoUpdate називає його доступним. Risk: Фасет у softwareFilters порожній, тож UI цей фільтр не запропонує. Клієнт, що передасть його напряму, отримає нефільтрований список без помилки. Те саме вже стосується sources і deviceTagIds. Fix: Реалізувати в гілці read model (#2651).
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++) {

Check warning on line 17 in openframe-api-lib/src/main/java/com/openframe/api/util/SoftwareVersions.java

View check run for this annotation

Flamingo / Flamingo Code Review / tests and mutation

Mutant survived: ConditionalsBoundaryMutator

changed conditional boundary (in compare). A test runs this line, but none fails when it changes.
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);
}

Check warning on line 25 in openframe-api-lib/src/main/java/com/openframe/api/util/SoftwareVersions.java

View check run for this annotation

Flamingo / Flamingo Code Review / tests and mutation

SoftwareVersions.compare ставить передреліз вище за реліз і помиляється на суфіксах

Перевірено запуском на форматах із тестів Fleet: 3.14.0rc1 вважається новішою за 3.14.0, 2.23.0_9 новішою за 2.23.0_13, 5.4.0-99.118 новішою за 5.4.0-105.1, а версії з префіксом (v1.2, EAP GO-243.21565.42) нижчими за 1.0. Числа після _ і - та нечислові префікси не порівнюються, нічия вирішується порівнянням рядків. Risk: Цей результат тепер визначає latestVersion і status у softwareDevices: пристрій зі справді новою версією може показати OUTDATED, а зі старішою UP_TO_DATE. Даних це не псує, але в UI буде неправильний статус. Тести містять вигадані значення 1.2.3-beta і 20240101123456.0 і не покривають жоден із цих випадків. Fix: Розбирати версію на числа й слова за роздільниками . _ - + пробіл і кома, передрелізні слова (a, b, rc, alpha, beta, dev, pre, eap) ставити нижче за реліз, у тест додати реальні формати.
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