Skip to content
Draft
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
Expand Up @@ -5,6 +5,7 @@
import io.openaev.aop.AccessControl;
import io.openaev.aop.LogExecutionTime;
import io.openaev.api.attack_pattern.dto.AttackPatternCoverageOutput;
import io.openaev.context.TxCtx;
import io.openaev.database.model.Action;
import io.openaev.database.model.ResourceType;
import io.openaev.rest.attack_pattern.service.AttackPatternService;
Expand Down Expand Up @@ -39,7 +40,7 @@ public class AttackPatternCoverageApi {
description =
"Tenant-wide ATT&CK matrix aggregating prevention and detection results across simulations (Elasticsearch, identical to the home security-coverage matrix)")
public List<AttackPatternCoverageOutput> attackPatternsCoverage(
@RequestParam(required = false) final Integer latest) {
TxCtx ctx, @RequestParam(required = false) final Integer latest) {
if (latest != null && latest < 1) {
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST, "The 'latest' parameter must be a positive integer");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.openaev.api.autonomous.dto.AutonomousAttackPathStepResult;
import io.openaev.api.autonomous.dto.AutonomousAttackPathStepState;
import io.openaev.api.autonomous.dto.AutonomousConvertToManualInput;
import io.openaev.api.autonomous.dto.AutonomousConvertToManualOutput;
import io.openaev.api.autonomous.dto.AutonomousDefaultAgentsInput;
import io.openaev.api.autonomous.dto.AutonomousDefaultAgentsOutput;
import io.openaev.api.autonomous.dto.AutonomousDirectiveInput;
Expand Down Expand Up @@ -344,16 +345,17 @@ public AutonomousRun promote(TxCtx ctx, @PathVariable String runId) {
+ " manual for good: it halts the orchestration, drops the autonomous run and its"
+ " timeline, and keeps the scenario + its simulation as a normal chained"
+ " scenario/simulation the operator can edit and delete. IN_PLACE is irreversible."
+ " Works whether the run is a built plan or has already executed. Returns the"
+ " resulting manual scenario.")
+ " Works whether the run is a built plan or has already executed. Returns the id of"
+ " the resulting manual scenario; read it back through the scenario endpoint.")
@PostMapping("/{runId}/convert-to-manual")
@Transactional
@AccessControl(skipRBAC = true, isEnterpriseEdition = true)
public Scenario convertToManual(
public AutonomousConvertToManualOutput convertToManual(
TxCtx ctx,
@PathVariable String runId,
@Valid @RequestBody AutonomousConvertToManualInput input) {
return autonomousRunService.convertToManual(runId, input.getMode());
Scenario scenario = autonomousRunService.convertToManual(runId, input.getMode());
return new AutonomousConvertToManualOutput(scenario.getId());
}

@Operation(summary = "Run decision timeline, optionally since a sequence cursor")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.openaev.api.autonomous.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;

/**
* The scenario the conversion landed on: the run's own scenario for IN_PLACE, the fresh copy for
* DUPLICATE. Only the id, so the caller refetches through the scenario read endpoint.
*/
@Schema(description = "Identifier of the manual scenario resulting from the conversion")
public record AutonomousConvertToManualOutput(
@JsonProperty("scenario_id") @Schema(description = "Id of the resulting manual scenario.")
String scenarioId) {}
46 changes: 0 additions & 46 deletions openaev-api/src/main/java/io/openaev/api/chaining/ChainingApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -152,29 +151,6 @@ public void createInjectForSimulationChaining(
}
}

@PostMapping(SIMULATION_URI + "/{simulationId}")
@AccessControl(
resourceId = "#simulationId",
actionPerformed = Action.DUPLICATE,
resourceType = ResourceType.SIMULATION,
isEnterpriseEdition = true)
@Transactional(rollbackFor = Exception.class)
public Exercise duplicateExercise(@PathVariable @NotBlank final String simulationId)
throws ChainingException {

Exercise simulation = exerciseService.getDuplicateExercise(simulationId);
Optional<Workflow> workflowOpt =
workflowService.findWorkflowTemplateBySimulationId(simulationId);
if (workflowOpt.isEmpty())
throw new ChainingException("No workflow TEMPLATE found. Simulation ID: " + simulationId);

Workflow workflowFrom = workflowOpt.get();
Workflow workflowTo = workflowService.duplicateSimulation(simulationId, simulation);
stepService.copyStepTemplate(workflowFrom, workflowTo);

return simulation;
}

// CREATE SCENARIO
@PostMapping(SCENARIO_URI)
@Transactional
Expand Down Expand Up @@ -237,26 +213,4 @@ public void createInjectForScenarioChaining(
// Todo return Action, Event and Link
}
}

@PostMapping(SCENARIO_URI + "/{scenarioId}")
@Transactional
@AccessControl(
resourceId = "#scenarioId",
actionPerformed = Action.DUPLICATE,
resourceType = ResourceType.SCENARIO,
isEnterpriseEdition = true)
public Scenario duplicateScenarioChaining(@PathVariable @NotBlank final String scenarioId)
throws ChainingException {

Scenario scenario = scenarioService.getDuplicateScenario(scenarioId);
Optional<Workflow> workflowOpt = workflowService.findWorkflowTemplateByScenarioId(scenarioId);
if (workflowOpt.isEmpty())
throw new ChainingException("No workflow TEMPLATE found. Scenario ID: " + scenarioId);

Workflow workflowFrom = workflowOpt.get();
Workflow workflowTo = workflowService.duplicateScenario(scenarioId, scenario);
stepService.copyStepTemplate(workflowFrom, workflowTo);

return scenario;
}
}
2 changes: 2 additions & 0 deletions openaev-api/src/main/java/io/openaev/importer/Importer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static java.util.Spliterators.spliteratorUnknownSize;

import com.fasterxml.jackson.databind.JsonNode;
import io.openaev.context.TxCtx;
import io.openaev.database.model.Asset;
import io.openaev.database.model.AssetGroup;
import io.openaev.database.model.Exercise;
Expand All @@ -18,6 +19,7 @@
public interface Importer {

ImportResult importData(
TxCtx ctx,
JsonNode importNode,
Map<String, ImportEntry> docReferences,
Exercise exercise,
Expand Down
Loading
Loading