feat: Add Cortex XDR integration with data fetching and summary generation.

This commit is contained in:
jeremy bayse
2026-02-14 08:21:06 +01:00
parent 7555e6ea8c
commit 1f9d2f7875
2 changed files with 21 additions and 7 deletions

View File

@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
use App\Services\CortexXdrService; use App\Services\CortexXdrService;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
class CortexXdrController extends Controller class CortexXdrController extends Controller
{ {
@@ -23,7 +24,9 @@ class CortexXdrController extends Controller
public function getData(CortexXdrService $cortexService) public function getData(CortexXdrService $cortexService)
{ {
try { try {
$summary = $cortexService->getSummary(); $summary = Cache::remember('cortex_summary_data', 300, function () use ($cortexService) {
return $cortexService->getSummary();
});
return response()->json($summary); return response()->json($summary);
} catch (\Exception $e) { } catch (\Exception $e) {
return response()->json(['error' => $e->getMessage()], 500); return response()->json(['error' => $e->getMessage()], 500);

View File

@@ -37,9 +37,9 @@ class CortexXdrService
* Get Incidents * Get Incidents
* Using pagination to fetch up to $limit incidents. * Using pagination to fetch up to $limit incidents.
*/ */
public function getIncidents($limit = 1000) public function getIncidents($limit = 1000, $filters = [])
{ {
return $this->fetchAll('incidents/get_incidents', 'incidents', $limit); return $this->fetchAll('incidents/get_incidents', 'incidents', $limit, $filters);
} }
/** /**
@@ -54,7 +54,7 @@ class CortexXdrService
/** /**
* Generic fetch method with pagination. * Generic fetch method with pagination.
*/ */
private function fetchAll($endpoint, $dataKey, $limit) private function fetchAll($endpoint, $dataKey, $limit, $filters = [])
{ {
if (empty($this->apiKey) || empty($this->apiKeyId) || empty($this->baseUrl)) { if (empty($this->apiKey) || empty($this->apiKeyId) || empty($this->baseUrl)) {
Log::warning('Cortex XDR credentials missing.'); Log::warning('Cortex XDR credentials missing.');
@@ -81,10 +81,10 @@ class CortexXdrService
$response = Http::withHeaders($this->getHeaders()) $response = Http::withHeaders($this->getHeaders())
->post("{$this->baseUrl}/public_api/v1/{$endpoint}/", [ ->post("{$this->baseUrl}/public_api/v1/{$endpoint}/", [
'request_data' => [ 'request_data' => array_merge([
'search_from' => $offset, 'search_from' => $offset,
'search_to' => $offset + $currentBatchSize, 'search_to' => $offset + $currentBatchSize,
] ], !empty($filters) ? ['filters' => $filters] : [])
]); ]);
if ($response->successful()) { if ($response->successful()) {
@@ -122,7 +122,15 @@ class CortexXdrService
public function getSummary() public function getSummary()
{ {
try { try {
$incidents = $this->getIncidents(1000); // Limit incidents to 1000 recent // Filter to fetch only active incidents to improve performance
$filters = [
[
'field' => 'status',
'operator' => 'in',
'value' => ['new', 'under_investigation']
]
];
$incidents = $this->getIncidents(1000, $filters); // Limit incidents to 1000 recent active
$endpoints = $this->getEndpoints(1000); // Limit endpoints to 2000 $endpoints = $this->getEndpoints(1000); // Limit endpoints to 2000
} catch (\Exception $e) { } catch (\Exception $e) {
// In dashboard context, we verify configuration separately. // In dashboard context, we verify configuration separately.
@@ -137,6 +145,8 @@ class CortexXdrService
$endpointsDisconnected = collect($endpoints)->filter(fn($e) => strtolower($e['endpoint_status'] ?? '') === 'disconnected')->count(); $endpointsDisconnected = collect($endpoints)->filter(fn($e) => strtolower($e['endpoint_status'] ?? '') === 'disconnected')->count();
// Filter only Active Incidents (New or Under Investigation) // Filter only Active Incidents (New or Under Investigation)
// Since we now filter at API level, we can just use the result,
// but keeping the collection filter adds a layer of safety if filters change.
$activeIncidents = collect($incidents)->filter(fn($i) => in_array($i['status'] ?? '', ['new', 'under_investigation'])); $activeIncidents = collect($incidents)->filter(fn($i) => in_array($i['status'] ?? '', ['new', 'under_investigation']));
//die(var_dump($activeIncidents)); //die(var_dump($activeIncidents));
@@ -163,6 +173,7 @@ class CortexXdrService
'endpoints_types' => $endpointTypes, // New Data 'endpoints_types' => $endpointTypes, // New Data
'recent_incidents' => collect($incidents) 'recent_incidents' => collect($incidents)
->filter(fn($i) => !in_array($i['status'] ?? '', ['resolved_true_positive', 'resolved_false_positive'])) ->filter(fn($i) => !in_array($i['status'] ?? '', ['resolved_true_positive', 'resolved_false_positive']))
->sortByDesc('incident_id')
->slice(0, 10) ->slice(0, 10)
->values() ->values()
->all() ->all()