Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
@@ -0,0 +1,25 @@
package io.openaev.api.inject_result.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import io.openaev.database.model.ExecutionTrace;
import io.openaev.database.model.PayloadCommandBlock;
import jakarta.validation.constraints.NotEmpty;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class InjectResultPayloadExecutionOutput {

@JsonProperty("payload_command_blocks")
@NotEmpty
private List<PayloadCommandBlock> payloadCommandBlocks = new ArrayList<>();

@JsonProperty("execution_execution_traces")
@NotEmpty
private List<ExecutionTrace> traces = new ArrayList<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import io.openaev.database.model.*;
import io.openaev.database.raw.RawDocument;
import io.openaev.database.repository.ExerciseRepository;
import io.openaev.database.repository.GrantRepository;
import io.openaev.database.repository.InjectRepository;
import io.openaev.database.repository.UserRepository;
import io.openaev.database.specification.InjectSpecification;
Expand All @@ -28,7 +27,6 @@
import io.openaev.rest.inject.service.InjectExportService;
import io.openaev.rest.inject.service.InjectService;
import io.openaev.rest.payload.form.DetectionRemediationOutput;
import io.openaev.service.InjectImportService;
import io.openaev.service.UserService;
import io.openaev.service.targets.TargetService;
import io.openaev.utils.FilterUtilsJpa;
Expand Down Expand Up @@ -70,15 +68,13 @@ public class InjectApi extends RestBehavior {
private final ExerciseRepository exerciseRepository;
private final InjectRepository injectRepository;
private final InjectService injectService;
private final InjectImportService injectImportService;
private final InjectExecutionService injectExecutionService;
private final InjectExportService injectExportService;
private final TargetService targetService;
private final UserRepository userRepository;
private final PayloadMapper payloadMapper;
private final UserService userService;
private final DocumentService documentService;
private final GrantRepository grantRepository;

// -- INJECTS --

Expand Down Expand Up @@ -499,7 +495,8 @@ public List<ExecutionTraceOutput> getInjectTracesFromInjectAndTarget(
@RequestParam String injectId,
@RequestParam String targetId,
@RequestParam TargetType targetType) {
return this.injectService.getInjectTracesFromInjectAndTarget(injectId, targetId, targetType);
return this.injectService.getInjectTracesOutputFromInjectAndTarget(
injectId, targetId, targetType);
}

@Operation(description = "Get InjectStatus with global execution traces")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.openaev.rest.inject;

import io.openaev.aop.RBAC;
import io.openaev.api.inject_result.dto.InjectResultPayloadExecutionOutput;
import io.openaev.database.model.Action;
import io.openaev.database.model.ResourceType;
import io.openaev.rest.helper.RestBehavior;
import io.openaev.utils.TargetType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequiredArgsConstructor
public class InjectExecutionResultApi extends RestBehavior {

public static final String INJECT_EXECUTION_URI = "/api/injects/{injectId}";

private final InjectExecutionResultService injectExecutionService;

@GetMapping(INJECT_EXECUTION_URI + "/payload_result")
Copy link
Contributor

@savacano28 savacano28 Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: We prefer this format (guidelines): /payload-result

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well seen, I forget this one.

@RBAC(resourceId = "#injectId", actionPerformed = Action.READ, resourceType = ResourceType.INJECT)
public InjectResultPayloadExecutionOutput injectExecutionResultPayload(
@PathVariable @NotBlank final String injectId,
@RequestParam @NotBlank final String targetId,
@RequestParam @NotNull final TargetType targetType) {
return this.injectExecutionService.injectExecutionResultPayload(injectId, targetId, targetType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.openaev.rest.inject;

import static io.openaev.database.model.ExecutionTraceAction.EXECUTION;

import io.openaev.aop.RBAC;
import io.openaev.api.inject_result.dto.InjectResultPayloadExecutionOutput;
import io.openaev.database.model.*;
import io.openaev.rest.inject.service.InjectService;
import io.openaev.rest.inject.service.InjectStatusService;
import io.openaev.utils.TargetType;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
@Slf4j
public class InjectExecutionResultService {

private final InjectService injectService;
private final InjectStatusService injectStatusService;

@RBAC(resourceId = "#injectId", actionPerformed = Action.READ, resourceType = ResourceType.INJECT)
public InjectResultPayloadExecutionOutput injectExecutionResultPayload(
@NotBlank final String injectId,
@NotBlank final String targetId,
@NotNull final TargetType targetType) {
InjectStatus injectStatus = this.injectStatusService.findInjectStatusByInjectId(injectId);
InjectResultPayloadExecutionOutput output = new InjectResultPayloadExecutionOutput();
output.setPayloadCommandBlocks(
Optional.of(injectStatus)
.map(InjectStatus::getPayloadOutput)
.map(StatusPayload::getPayloadCommandBlocks)
.orElse(new ArrayList<>()));

List<ExecutionTrace> traces =
this.injectService.getInjectTracesFromInjectAndTarget(injectId, targetId, targetType);
output.setTraces(traces.stream().filter(t -> EXECUTION.equals(t.getAction())).toList());

return output;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -929,24 +929,21 @@ public List<FilterUtilsJpa.Option> getOptionsByNameLinkedToFindings(
.toList();
}

public List<ExecutionTraceOutput> getInjectTracesFromInjectAndTarget(
public List<ExecutionTraceOutput> getInjectTracesOutputFromInjectAndTarget(
final String injectId, final String targetId, final TargetType targetType) {
switch (targetType) {
case AGENT:
return injectStatusMapper.toExecutionTracesOutput(
this.executionTraceRepository.findByInjectIdAndAgentId(injectId, targetId));
case ASSETS:
return injectStatusMapper.toExecutionTracesOutput(
this.executionTraceRepository.findByInjectIdAndAssetId(injectId, targetId));
case TEAMS:
return injectStatusMapper.toExecutionTracesOutput(
this.executionTraceRepository.findByInjectIdAndTeamId(injectId, targetId));
case PLAYERS:
return injectStatusMapper.toExecutionTracesOutput(
this.executionTraceRepository.findByInjectIdAndPlayerId(injectId, targetId));
default:
throw new BadRequestException("Target type " + targetType + " is not supported");
}
return injectStatusMapper.toExecutionTracesOutput(
getInjectTracesFromInjectAndTarget(injectId, targetId, targetType));
}

public List<ExecutionTrace> getInjectTracesFromInjectAndTarget(
final String injectId, final String targetId, final TargetType targetType) {
return switch (targetType) {
case AGENT -> this.executionTraceRepository.findByInjectIdAndAgentId(injectId, targetId);
case ASSETS -> this.executionTraceRepository.findByInjectIdAndAssetId(injectId, targetId);
case TEAMS -> this.executionTraceRepository.findByInjectIdAndTeamId(injectId, targetId);
case PLAYERS -> this.executionTraceRepository.findByInjectIdAndPlayerId(injectId, targetId);
default -> throw new BadRequestException("Target type " + targetType + " is not supported");
};
}

public InjectStatusOutput getInjectStatusWithGlobalExecutionTraces(String injectId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.openaev.utils.InjectUtils;
import jakarta.annotation.Nullable;
import jakarta.transaction.Transactional;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.Instant;
import java.util.Collections;
Expand All @@ -41,6 +42,13 @@ public List<InjectStatus> findPendingInjectStatusByType(String injectType) {
return this.injectStatusRepository.pendingForInjectType(injectType);
}

public InjectStatus findInjectStatusByInjectId(@NotBlank final String injectId) {
return this.injectStatusRepository
.findByInjectId(injectId)
.orElseThrow(
() -> new ElementNotFoundException("Inject status not found for :" + injectId));
}

@Transactional(rollbackOn = Exception.class)
public Inject updateInjectStatus(String injectId, InjectUpdateStatusInput input) {
Inject inject = injectRepository.findById(injectId).orElseThrow();
Expand Down
2 changes: 1 addition & 1 deletion openaev-front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"react-markdown": "10.1.0",
"react-redux": "9.2.0",
"react-router": "7.9.5",
"react-syntax-highlighter": "15.6.6",
"react-syntax-highlighter": "16.1.0",
"redux": "5.0.1",
"redux-thunk": "3.1.0",
"remark-flexible-markers": "1.3.1",
Expand Down
13 changes: 13 additions & 0 deletions openaev-front/src/actions/inject_status/inject-status-action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { simpleCall } from '../../utils/Action';
import type { Inject } from '../../utils/api-types';
import { INJECT_URI } from '../injects/inject-action';

// eslint-disable-next-line import/prefer-default-export
export const fetchInjectExecutionResult = (injectId: Inject['inject_id'], targetId: string = '', targetType: string = '') => {
const params = {
targetId,
targetType,
};
const uri = `${INJECT_URI}/${injectId}/payload_result`;
return simpleCall(uri, { params });
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useEffect, useState } from 'react';

import type { InjectExecutionPayloadOutput, InjectTarget } from '../../utils/api-types';
import { fetchInjectExecutionResult } from './inject-status-action';

const useFetchInjectExecutionResult = (injectId: string, target: InjectTarget) => {
const [injectExecutionResult, setInjectExecutionResult] = useState<InjectExecutionPayloadOutput>();
const [loading, setLoading] = useState(false);
const fetch = async () => {
if (!injectId || !target?.target_id || !target.target_type) return;
setLoading(true);
try {
const result = await fetchInjectExecutionResult(injectId, target.target_id, target.target_type);
setInjectExecutionResult(result.data || []);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetch();
}, [injectId, target?.target_id, target?.target_type]);
return ({
injectExecutionResult,
loading,
});
};

export default useFetchInjectExecutionResult;
2 changes: 1 addition & 1 deletion openaev-front/src/actions/injects/inject-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { MESSAGING$ } from '../../utils/Environment';
import * as schema from '../Schema';

const INJECT_URI = '/api/injects';
export const INJECT_URI = '/api/injects';

export const exportInjectSearch = (data: InjectExportFromSearchRequestInput) => {
const uri = '/api/injects/search/export';
Expand Down
Loading