From a12068ea7712528f5d56e8a39773250037bd4470 Mon Sep 17 00:00:00 2001 From: Andrii Koropets Date: Thu, 17 Sep 2026 01:10:42 +0300 Subject: [PATCH 1/2] Implemented test run --- .../rmm/schedule/ScriptScheduleResponse.java | 1 + .../api/dto/rmm/script/ScriptResponse.java | 1 + .../openframe/api/mapper/ScriptMapper.java | 19 ++-- .../api/mapper/ScriptScheduleMapper.java | 7 ++ .../rmm/command/CommandDispatchService.java | 7 +- .../rmm/command/CommandExecutionService.java | 9 +- .../rmm/script/ScriptDispatchService.java | 13 ++- .../rmm/script/ScriptExecutionService.java | 9 +- .../resources/schema/script-schedule.graphqls | 3 + .../src/main/resources/schema/script.graphqls | 4 + .../service/rmm/ScheduleFireDispatcher.java | 5 + .../rmm/command/CommandExecution.java | 1 + .../document/rmm/schedule/ScheduleScript.java | 1 + .../rmm/schedule/ScheduleScriptExecution.java | 1 + .../rmm/script/RunningExecutionRows.java | 1 + .../data/document/rmm/script/Script.java | 1 + .../document/rmm/script/ScriptExecution.java | 1 + ...ScheduleScriptExecutionRepositoryImpl.java | 10 +- .../CustomScriptExecutionRepositoryImpl.java | 13 ++- .../rmm/CustomScriptRepositoryImpl.java | 10 +- .../CustomScriptScheduleRepositoryImpl.java | 13 +++ ...iptRepositoryImplTestScriptShieldTest.java | 98 +++++++++++++++++++ 22 files changed, 207 insertions(+), 21 deletions(-) create mode 100644 openframe-data-mongo-sync/src/test/java/com/openframe/data/repository/rmm/CustomScriptRepositoryImplTestScriptShieldTest.java diff --git a/openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/schedule/ScriptScheduleResponse.java b/openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/schedule/ScriptScheduleResponse.java index 505262ada5..eec2413cfd 100644 --- a/openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/schedule/ScriptScheduleResponse.java +++ b/openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/schedule/ScriptScheduleResponse.java @@ -54,4 +54,5 @@ public class ScriptScheduleResponse { private Instant statusChangedAt; private Instant createdAt; private Instant updatedAt; + private boolean testScript; } diff --git a/openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/script/ScriptResponse.java b/openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/script/ScriptResponse.java index 452db6ff0f..b8bb38e390 100644 --- a/openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/script/ScriptResponse.java +++ b/openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/script/ScriptResponse.java @@ -36,4 +36,5 @@ public class ScriptResponse { private Instant statusChangedAt; private Instant createdAt; private Instant updatedAt; + private boolean testScript; } diff --git a/openframe-api-lib/src/main/java/com/openframe/api/mapper/ScriptMapper.java b/openframe-api-lib/src/main/java/com/openframe/api/mapper/ScriptMapper.java index 5fdb592bd2..5a8f9bded1 100644 --- a/openframe-api-lib/src/main/java/com/openframe/api/mapper/ScriptMapper.java +++ b/openframe-api-lib/src/main/java/com/openframe/api/mapper/ScriptMapper.java @@ -8,21 +8,22 @@ import com.openframe.data.document.rmm.script.Script; import com.openframe.data.document.rmm.script.ScriptEnvVar; import com.openframe.data.document.rmm.script.ScriptStatus; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.List; -/** - * Pure entity ↔ DTO mapping for scripts. Lives in {@code openframe-api-lib} - * so it can be reused by any service that talks to the script repository, - * regardless of transport (GraphQL / REST / messaging). - * - *

GraphQL-specific concerns (cursor pagination, Relay Connection / Edge - * envelope) live in {@code GraphQLScriptMapper} alongside the DGS resolver. - */ @Component public class ScriptMapper { + /** + * Tenant-instance test-mode switch. When {@code true}, every newly-created Script is + * stamped {@code testScript = true} and hidden from user-facing GraphQL reads by the + * repository shield. Default {@code false} — everything is visible. + */ + @Value("${openframe.rmm.test-mode.enabled:false}") + private boolean testModeEnabled; + public Script toEntity(String tenantId, CreateScriptInput input) { return Script.builder() .tenantId(tenantId) @@ -35,6 +36,7 @@ public Script toEntity(String tenantId, CreateScriptInput input) { .defaultTimeoutSeconds(input.getDefaultTimeoutSeconds()) .defaultArgs(input.getDefaultArgs()) .envVars(ScriptEnvVarMapper.toEntity(input.getEnvVars())) + .testScript(testModeEnabled) .build(); } @@ -67,6 +69,7 @@ public ScriptResponse toResponse(Script entity) { .statusChangedAt(entity.getStatusChangedAt()) .createdAt(entity.getCreatedAt()) .updatedAt(entity.getUpdatedAt()) + .testScript(entity.isTestScript()) .build(); } diff --git a/openframe-api-lib/src/main/java/com/openframe/api/mapper/ScriptScheduleMapper.java b/openframe-api-lib/src/main/java/com/openframe/api/mapper/ScriptScheduleMapper.java index b768ad0468..04ae900e69 100644 --- a/openframe-api-lib/src/main/java/com/openframe/api/mapper/ScriptScheduleMapper.java +++ b/openframe-api-lib/src/main/java/com/openframe/api/mapper/ScriptScheduleMapper.java @@ -11,6 +11,7 @@ import com.openframe.data.document.rmm.schedule.ScheduleScriptTrigger; import com.openframe.data.document.rmm.schedule.ScheduleTimeReference; import com.openframe.data.document.rmm.script.ScriptStatus; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.List; @@ -23,6 +24,10 @@ @Component public class ScriptScheduleMapper { + /** Same test-mode switch semantics as {@link ScriptMapper#testModeEnabled}. */ + @Value("${openframe.rmm.test-mode.enabled:false}") + private boolean testModeEnabled; + public ScheduleScript toEntity(String tenantId, CreateScriptScheduleInput input) { return ScheduleScript.builder() .tenantId(tenantId) @@ -37,6 +42,7 @@ public ScheduleScript toEntity(String tenantId, CreateScriptScheduleInput input) .reconnectWindowSeconds(input.getReconnectWindowSeconds()) .startAt(input.getStartAt()) .repeat(input.getRepeat()) + .testScript(testModeEnabled) .build(); } @@ -94,6 +100,7 @@ public ScriptScheduleResponse toResponse(ScheduleScript entity) { .statusChangedAt(entity.getStatusChangedAt()) .createdAt(entity.getCreatedAt()) .updatedAt(entity.getUpdatedAt()) + .testScript(entity.isTestScript()) .build(); } diff --git a/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/command/CommandDispatchService.java b/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/command/CommandDispatchService.java index d9bf16edcc..2f85bb85c0 100644 --- a/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/command/CommandDispatchService.java +++ b/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/command/CommandDispatchService.java @@ -10,6 +10,7 @@ import com.openframe.data.nats.rmm.publisher.CommandNatsPublisher; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; @@ -37,6 +38,9 @@ public class CommandDispatchService { private final DeviceService deviceService; private final CommandExecutionService commandExecutionService; + @Value("${openframe.rmm.test-mode.enabled:false}") + private boolean testModeEnabled; + public DispatchResponse runCommand(RunCommandInput input) { deviceService.verifyDispatchable(input.getMachineId()); @@ -76,7 +80,8 @@ public DispatchResponse batchRunCommand(BatchRunCommandInput input, String initi // Persist one RUNNING row per machine (tenant-scoped, via the service) before // anything hits the wire — the agent's result transitions each row later. commandExecutionService.createBatch(executionId, input.getCommand(), input.getShell(), - machineIds, input.getPrivilegeLevel(), input.getTimeoutSeconds(), initiatedBy); + machineIds, input.getPrivilegeLevel(), input.getTimeoutSeconds(), initiatedBy, + testModeEnabled); // Fan out the same payload (one executionId) to every machine. CommandMessage message = CommandMessage.builder() diff --git a/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/command/CommandExecutionService.java b/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/command/CommandExecutionService.java index fc1f89a8b7..9d24fc6937 100644 --- a/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/command/CommandExecutionService.java +++ b/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/command/CommandExecutionService.java @@ -38,11 +38,12 @@ public List createBatch(String executionId, List machineIds, PrivilegeLevel privilegeLevel, Integer timeoutSeconds, - String initiatedBy) { + String initiatedBy, + boolean testCommand) { Instant now = Instant.now(); List rows = machineIds.stream() .map(machineId -> buildRunningRow(executionId, command, shell, machineId, - privilegeLevel, timeoutSeconds, initiatedBy, now)) + privilegeLevel, timeoutSeconds, initiatedBy, now, testCommand)) .toList(); List saved = commandExecutionRepository.saveAll(rows); log.info("Persisted batch command execution rows: executionId={} machineCount={} initiatedBy={} status=RUNNING", @@ -72,7 +73,8 @@ private CommandExecution buildRunningRow(String executionId, PrivilegeLevel privilegeLevel, Integer timeoutSeconds, String initiatedBy, - Instant now) { + Instant now, + boolean testCommand) { return CommandExecution.builder() .tenantId(tenantIdProvider.getTenantId()) .executionId(executionId) @@ -85,6 +87,7 @@ private CommandExecution buildRunningRow(String executionId, .status(ExecutionStatus.RUNNING) .dispatchedAt(now) .statusChangedAt(now) + .testCommand(testCommand) .build(); } } diff --git a/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/script/ScriptDispatchService.java b/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/script/ScriptDispatchService.java index 696b26d88b..2b6fa782a9 100644 --- a/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/script/ScriptDispatchService.java +++ b/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/script/ScriptDispatchService.java @@ -27,6 +27,7 @@ import com.openframe.data.service.TenantIdProvider; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; @@ -64,6 +65,8 @@ public class ScriptDispatchService { private final ScheduleScriptExecutionRepository scheduleScriptExecutionRepository; private final TenantIdProvider tenantIdProvider; private final ScriptTimeoutValidator timeoutValidator; + @Value("${openframe.rmm.test-mode.enabled:false}") + private boolean testModeEnabled; public DispatchResponse runScript(RunScriptInput input, String initiatedBy, ExecutionSource source) { timeoutValidator.validate(input.getTimeoutSeconds()); @@ -77,7 +80,8 @@ public DispatchResponse runScript(RunScriptInput input, String initiatedBy, Exec // Persist the effective timeout on the row so the watchdog can derive a // per-execution stuck-threshold from it. scriptExecutionService.create(executionId, script.getId(), - input.getMachineId(), input.getPrivilegeLevel(), timeoutSeconds, initiatedBy, source); + input.getMachineId(), input.getPrivilegeLevel(), timeoutSeconds, initiatedBy, source, + testModeEnabled); ScriptMessage message = ScriptMessage.builder() .executionId(executionId) @@ -185,6 +189,7 @@ public DispatchResponse runSchedule(String scheduleId, String initiatedBy) { .status(ExecutionStatus.RUNNING) .totalMachineCount(machineIds.size()) .dispatchedAt(now) + .testScript(testModeEnabled) .build()); // 2. Leaves: N × M ScriptExecution rows (persist per-script batch), so the watchdog @@ -196,7 +201,7 @@ public DispatchResponse runSchedule(String scheduleId, String initiatedBy) { scriptExecutionService.createBatch(executionId, script.getId(), scheduleId, machineIds, script.getPrivilegeLevel(), effectiveTimeout(null, script.getDefaultTimeoutSeconds()), - initiatedBy, ExecutionSource.SCHEDULED); + initiatedBy, ExecutionSource.SCHEDULED, testModeEnabled); } // 3. Build the batched agent payload once — shared across every target machine. Per-script @@ -245,7 +250,9 @@ private DispatchResponse dispatchBatch(String executionId, ScriptResponse script // Persist the effective timeout per row so the watchdog can derive a // per-execution stuck-threshold from it. - scriptExecutionService.createBatch(executionId, script.getId(), null, machineIds, privilegeLevel, timeoutSeconds, initiatedBy, source); + // Server-side stamp — see runScript for rationale. + scriptExecutionService.createBatch(executionId, script.getId(), null, machineIds, privilegeLevel, + timeoutSeconds, initiatedBy, source, testModeEnabled); List args = ScriptArgsTokenizer.tokenize(argsOverride != null ? argsOverride : script.getDefaultArgs()); List envVars = mergeEnvVars(script.getEnvVars(), envVarsOverride); diff --git a/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/script/ScriptExecutionService.java b/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/script/ScriptExecutionService.java index 8a7f9106ca..4907f79e8a 100644 --- a/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/script/ScriptExecutionService.java +++ b/openframe-api-lib/src/main/java/com/openframe/api/service/rmm/script/ScriptExecutionService.java @@ -69,7 +69,8 @@ public ScriptExecutionResponse create(String executionId, PrivilegeLevel privilegeLevel, Integer timeoutSeconds, String initiatedBy, - ExecutionSource source) { + ExecutionSource source, + boolean testScript) { // Single ad-hoc run (runScript) never originates from a schedule → scheduleId null. List saved = scriptExecutionRepository.saveRunning(RunningExecutionRows.builder() .tenantId(tenantIdProvider.getTenantId()) @@ -80,6 +81,7 @@ public ScriptExecutionResponse create(String executionId, .timeoutSeconds(timeoutSeconds) .initiatedBy(initiatedBy) .source(source) + .testScript(testScript) .build()); log.info("Persisted execution row: executionId={} scriptId={} machineId={} initiatedBy={} source={} status=RUNNING", executionId, scriptId, machineId, initiatedBy, source); @@ -101,7 +103,8 @@ public List createBatch(String executionId, PrivilegeLevel privilegeLevel, Integer timeoutSeconds, String initiatedBy, - ExecutionSource source) { + ExecutionSource source, + boolean testScript) { List saved = scriptExecutionRepository.saveRunning(RunningExecutionRows.builder() .tenantId(tenantIdProvider.getTenantId()) .executionId(executionId) @@ -112,6 +115,7 @@ public List createBatch(String executionId, .timeoutSeconds(timeoutSeconds) .initiatedBy(initiatedBy) .source(source) + .testScript(testScript) .build()); log.info("Persisted batch execution rows: executionId={} scriptId={} scheduleId={} machineCount={} initiatedBy={} source={} status=RUNNING", executionId, scriptId, scheduleId, machineIds.size(), initiatedBy, source); @@ -152,6 +156,7 @@ public List createSoftwareBatch(String executionId, .packageManager(packageManager) .packageName(packageName) .softwareAction(softwareAction) + .testScript(false) .build()); log.info("Persisted software batch rows: executionId={} scriptId={} packageManager={} packageName={} action={} machineCount={} initiatedBy={} source={} status=RUNNING", executionId, scriptId, packageManager, packageName, softwareAction, machineIds.size(), initiatedBy, source); diff --git a/openframe-api-service-core/src/main/resources/schema/script-schedule.graphqls b/openframe-api-service-core/src/main/resources/schema/script-schedule.graphqls index 9ba57c48ed..5e0b12a7c0 100644 --- a/openframe-api-service-core/src/main/resources/schema/script-schedule.graphqls +++ b/openframe-api-service-core/src/main/resources/schema/script-schedule.graphqls @@ -152,6 +152,9 @@ type ScriptSchedule implements Node { updatedAt: Instant """The creating user (resolved from the internal createdBy id via the user DataLoader).""" author: User + """When true, this is a monitoring / QA fixture. Dispatch still runs, user-facing reads hide it. + Immutable at create-time.""" + testScript: Boolean! } enum ScriptScheduleTrigger { diff --git a/openframe-api-service-core/src/main/resources/schema/script.graphqls b/openframe-api-service-core/src/main/resources/schema/script.graphqls index c3f4417158..d1a3e77045 100644 --- a/openframe-api-service-core/src/main/resources/schema/script.graphqls +++ b/openframe-api-service-core/src/main/resources/schema/script.graphqls @@ -110,6 +110,10 @@ type Script implements Node { updatedAt: Instant """The creating user (resolved from the internal createdBy id via the user DataLoader). The raw createdBy id is not exposed — filter by author via authorIds.""" author: User + """When true, this is a monitoring / QA fixture created by the monitoring pipeline. Immutable at + create-time. Set by the pipeline via createScript; hidden from user-facing list/facets/getById + reads (query-builder shield) — visible only on direct id lookup performed by the pipeline itself.""" + testScript: Boolean! } type ScriptEnvVar { diff --git a/openframe-client-core/src/main/java/com/openframe/client/service/rmm/ScheduleFireDispatcher.java b/openframe-client-core/src/main/java/com/openframe/client/service/rmm/ScheduleFireDispatcher.java index 698d97493c..372906eb19 100644 --- a/openframe-client-core/src/main/java/com/openframe/client/service/rmm/ScheduleFireDispatcher.java +++ b/openframe-client-core/src/main/java/com/openframe/client/service/rmm/ScheduleFireDispatcher.java @@ -28,6 +28,7 @@ import com.openframe.data.service.rmm.ScheduleDeviceTargetResolver; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Component; @@ -55,6 +56,8 @@ public class ScheduleFireDispatcher { private final MachineRepository machineRepository; private final DeviceOnlineDispatchRepository dispatchRepository; private final ScriptDeliveryRetryStore retryStore; + @Value("${openframe.rmm.test-mode.enabled:false}") + private boolean testModeEnabled; public void dispatch(ScheduleScript schedule, Instant now) { List targets = targetResolver.resolveTargetMachineIds(schedule); @@ -185,6 +188,7 @@ private void saveHeader(Fire fire) { .status(ExecutionStatus.RUNNING) .totalMachineCount(fire.machineIds().size()) .dispatchedAt(fire.now()) + .testScript(testModeEnabled) .build()); } @@ -204,6 +208,7 @@ private void saveLeafRows(Fire fire) { .status(ExecutionStatus.QUEUED) .dispatchedAt(fire.now()) .statusChangedAt(fire.now()) + .testScript(testModeEnabled) .build())) .toList(); scriptExecutionRepository.saveAll(rows); diff --git a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/command/CommandExecution.java b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/command/CommandExecution.java index 1c1278d1e0..87ad130b5c 100644 --- a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/command/CommandExecution.java +++ b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/command/CommandExecution.java @@ -89,4 +89,5 @@ public class CommandExecution implements TenantScoped { private String stderr; private Boolean stderrTruncated; private String error; + private boolean testCommand; } diff --git a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/schedule/ScheduleScript.java b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/schedule/ScheduleScript.java index f74c1d48d2..7c01fd911a 100644 --- a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/schedule/ScheduleScript.java +++ b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/schedule/ScheduleScript.java @@ -83,4 +83,5 @@ public class ScheduleScript implements TenantScoped { private ScriptStatus status = ScriptStatus.ACTIVE; private Instant statusChangedAt; + private boolean testScript; } diff --git a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/schedule/ScheduleScriptExecution.java b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/schedule/ScheduleScriptExecution.java index c8a76f4cdd..05ef4f3a8a 100644 --- a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/schedule/ScheduleScriptExecution.java +++ b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/schedule/ScheduleScriptExecution.java @@ -56,4 +56,5 @@ public class ScheduleScriptExecution implements TenantScoped { @CreatedDate private Instant createdAt; + private boolean testScript; } diff --git a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/RunningExecutionRows.java b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/RunningExecutionRows.java index 7892d076e8..166338d96a 100644 --- a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/RunningExecutionRows.java +++ b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/RunningExecutionRows.java @@ -24,4 +24,5 @@ public class RunningExecutionRows { PackageManagerType packageManager; String packageName; SoftwareAction softwareAction; + boolean testScript; } diff --git a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/Script.java b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/Script.java index ddd1e4a110..e9b6932adb 100644 --- a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/Script.java +++ b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/Script.java @@ -111,4 +111,5 @@ public class Script implements TenantScoped { */ private Instant statusChangedAt; private String contentHash; + private boolean testScript; } diff --git a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/ScriptExecution.java b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/ScriptExecution.java index 3df9e21c46..3652c138e0 100644 --- a/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/ScriptExecution.java +++ b/openframe-data-mongo-common/src/main/java/com/openframe/data/document/rmm/script/ScriptExecution.java @@ -93,4 +93,5 @@ public class ScriptExecution implements TenantScoped { private String stderr; private Boolean stderrTruncated; private String error; + private boolean testScript; } diff --git a/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScheduleScriptExecutionRepositoryImpl.java b/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScheduleScriptExecutionRepositoryImpl.java index 9a1079f4bb..ca0d766230 100644 --- a/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScheduleScriptExecutionRepositoryImpl.java +++ b/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScheduleScriptExecutionRepositoryImpl.java @@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j; import org.bson.Document; import org.bson.types.ObjectId; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.Aggregation; @@ -54,11 +55,15 @@ public class CustomScheduleScriptExecutionRepositoryImpl implements CustomSchedu private static final String FIELD_DISPATCHED_AT = "dispatchedAt"; private static final String FIELD_COUNT = "count"; private static final String CURSOR_SEPARATOR = "|"; + private static final String FIELD_TEST_SCRIPT = "testScript"; private static final Set SORTABLE_FIELDS = Set.of(FIELD_ID, FIELD_DISPATCHED_AT); private final MongoTemplate mongoTemplate; + @Value("${openframe.rmm.test-mode.enabled}") + private boolean testModeEnabled; + @Override public List findPageForSchedule(String tenantId, String scriptScheduleId, @@ -204,9 +209,12 @@ private static Criteria facetCriteria(String tenantId, String scriptScheduleId, return criteria; } - private static Criteria baseCriteria(String tenantId, String scriptScheduleId, ScheduleRunQueryFilter filter) { + private Criteria baseCriteria(String tenantId, String scriptScheduleId, ScheduleRunQueryFilter filter) { Criteria criteria = Criteria.where(FIELD_TENANT_ID).is(tenantId) .and(FIELD_SCRIPT_SCHEDULE_ID).is(scriptScheduleId); + if (testModeEnabled) { + criteria.and(FIELD_TEST_SCRIPT).ne(true); + } if (filter == null) { return criteria; } diff --git a/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScriptExecutionRepositoryImpl.java b/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScriptExecutionRepositoryImpl.java index a372835bb7..5020a2d032 100644 --- a/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScriptExecutionRepositoryImpl.java +++ b/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScriptExecutionRepositoryImpl.java @@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j; import org.bson.Document; import org.bson.types.ObjectId; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.Aggregation; @@ -54,6 +55,7 @@ public class CustomScriptExecutionRepositoryImpl implements CustomScriptExecutio private static final String FIELD_FINISHED_AT = "finishedAt"; private static final String FIELD_STATUS_CHANGED_AT = "statusChangedAt"; private static final String FIELD_COUNT = "count"; + private static final String FIELD_TEST_SCRIPT = "testScript"; /** Sort-field allowlist. Anything not in here falls back to {@link #getDefaultSortField()}. */ private static final Set SORTABLE_FIELDS = Set.of( @@ -72,6 +74,9 @@ public class CustomScriptExecutionRepositoryImpl implements CustomScriptExecutio private final MongoTemplate mongoTemplate; + @Value("${openframe.rmm.test-mode.enabled}") + private boolean testModeEnabled; + @Override public List saveRunning(RunningExecutionRows request) { return save(request, ExecutionStatus.RUNNING); @@ -98,6 +103,7 @@ private List save(RunningExecutionRows request, ExecutionStatus .packageManager(request.getPackageManager()) .packageName(request.getPackageName()) .softwareAction(request.getSoftwareAction()) + .testScript(request.isTestScript()) .status(initialStatus) .dispatchedAt(now) .statusChangedAt(now) @@ -204,10 +210,13 @@ private static void applyOwner(Criteria criteria, ExecutionOwnerScope owner) { } } - private static Criteria baseCriteria(String tenantId, ExecutionOwnerScope owner, - ScriptExecutionQueryFilter filter, String excludedField) { + private Criteria baseCriteria(String tenantId, ExecutionOwnerScope owner, + ScriptExecutionQueryFilter filter, String excludedField) { Criteria criteria = Criteria.where(FIELD_TENANT_ID).is(tenantId); applyOwner(criteria, owner); + if (testModeEnabled) { + criteria.and(FIELD_TEST_SCRIPT).ne(true); + } if (filter == null) { return criteria; } diff --git a/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScriptRepositoryImpl.java b/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScriptRepositoryImpl.java index 9a010c80f9..25290f387f 100644 --- a/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScriptRepositoryImpl.java +++ b/openframe-data-mongo-sync/src/main/java/com/openframe/data/repository/rmm/CustomScriptRepositoryImpl.java @@ -10,6 +10,7 @@ import lombok.extern.slf4j.Slf4j; import org.bson.Document; import org.bson.types.ObjectId; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.Aggregation; @@ -59,6 +60,7 @@ public class CustomScriptRepositoryImpl implements CustomScriptRepository { private static final String FIELD_UPDATED_AT = "updatedAt"; private static final String FIELD_CREATED_BY = "createdBy"; private static final String FIELD_TYPE = "type"; + private static final String FIELD_TEST_SCRIPT = "testScript"; // tag_assignments fields used to resolve the tagIds filter into script ids. private static final String FIELD_TA_TAG_ID = "tagId"; @@ -71,6 +73,9 @@ public class CustomScriptRepositoryImpl implements CustomScriptRepository { private final MongoTemplate mongoTemplate; + @Value("${openframe.rmm.test-mode.enabled:false}") + private boolean testModeEnabled; + @Override public List