mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: César Arroba <19954079+cesararroba@users.noreply.github.com> Co-authored-by: Alan Buscaglia <gentlemanprogramming@gmail.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com> Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com> Co-authored-by: HugoPBrito <hugopbrit@gmail.com> Co-authored-by: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Co-authored-by: Pepe Fagoaga <pepe@prowler.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: Chandrapal Badshah <Chan9390@users.noreply.github.com> Co-authored-by: Chandrapal Badshah <12944530+Chan9390@users.noreply.github.com> Co-authored-by: Adrián Peña <adrianjpr@gmail.com> Co-authored-by: Pedro Martín <pedromarting3@gmail.com> Co-authored-by: KonstGolfi <73020281+KonstGolfi@users.noreply.github.com> Co-authored-by: lydiavilchez <114735608+lydiavilchez@users.noreply.github.com> Co-authored-by: Prowler Bot <bot@prowler.com> Co-authored-by: prowler-bot <179230569+prowler-bot@users.noreply.github.com> Co-authored-by: StylusFrost <43682773+StylusFrost@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com> Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Co-authored-by: Víctor Fernández Poyatos <victor@prowler.com> Co-authored-by: bota4go <108249054+bota4go@users.noreply.github.com> Co-authored-by: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com> Co-authored-by: mchennai <50082780+mchennai@users.noreply.github.com> Co-authored-by: Ryan Nolette <sonofagl1tch@users.noreply.github.com> Co-authored-by: Ulissis Correa <123517149+ulissisc@users.noreply.github.com> Co-authored-by: Sergio Garcia <hello@mistercloudsec.com> Co-authored-by: Lee Trout <ltrout@watchpointlabs.com> Co-authored-by: Sergio Garcia <sergargar1@gmail.com> Co-authored-by: Alan-TheGentleman <alan@thegentleman.dev>
90 lines
2.7 KiB
TypeScript
90 lines
2.7 KiB
TypeScript
import { MetaDataProps } from "@/types";
|
|
import { AttackPathScan, AttackPathScansResponse } from "@/types/attack-paths";
|
|
|
|
/**
|
|
* Adapts raw scan API responses to enriched domain models
|
|
* - Transforms raw scan data with computed properties
|
|
* - Co-locates related data for better performance
|
|
* - Preserves pagination metadata for list operations
|
|
*
|
|
* Uses plugin architecture for extensibility:
|
|
* - Handles scan-specific response transformation
|
|
* - Can be composed with backend service plugins
|
|
* - Maintains separation of concerns between API layer and business logic
|
|
*/
|
|
|
|
/**
|
|
* Adapt attack path scans response with enriched data
|
|
*
|
|
* @param response - Raw API response from attack-paths-scans endpoint
|
|
* @returns Enriched scans data with metadata and computed properties
|
|
*/
|
|
export function adaptAttackPathScansResponse(
|
|
response: AttackPathScansResponse | undefined,
|
|
): {
|
|
data: AttackPathScan[];
|
|
metadata?: MetaDataProps;
|
|
} {
|
|
if (!response?.data) {
|
|
return { data: [] };
|
|
}
|
|
|
|
// Enrich scan data with computed properties
|
|
const enrichedData = response.data.map((scan) => ({
|
|
...scan,
|
|
attributes: {
|
|
...scan.attributes,
|
|
// Format duration for display
|
|
durationLabel: scan.attributes.duration
|
|
? formatDuration(scan.attributes.duration)
|
|
: null,
|
|
// Check if scan is recent (completed within last 24 hours)
|
|
isRecent: isRecentScan(scan.attributes.completed_at),
|
|
},
|
|
}));
|
|
|
|
// Transform links to MetaDataProps format if pagination exists
|
|
const metadata: MetaDataProps | undefined = response.links
|
|
? {
|
|
pagination: {
|
|
// Links-based pagination doesn't have traditional page numbers
|
|
// but we preserve the structure for consistency
|
|
page: 1,
|
|
pages: 1,
|
|
count: enrichedData.length,
|
|
itemsPerPage: [10, 25, 50, 100],
|
|
},
|
|
version: "1.0",
|
|
}
|
|
: undefined;
|
|
|
|
return { data: enrichedData, metadata };
|
|
}
|
|
|
|
/**
|
|
* Format duration in seconds to human-readable format
|
|
*
|
|
* @param seconds - Duration in seconds
|
|
* @returns Formatted duration string (e.g., "2m 30s")
|
|
*/
|
|
function formatDuration(seconds: number): string {
|
|
const minutes = Math.floor(seconds / 60);
|
|
const remainingSeconds = seconds % 60;
|
|
return `${minutes}m ${remainingSeconds}s`;
|
|
}
|
|
|
|
/**
|
|
* Check if a scan is recent (completed within last 24 hours)
|
|
*
|
|
* @param completedAt - Completion timestamp
|
|
* @returns true if scan completed within last 24 hours
|
|
*/
|
|
function isRecentScan(completedAt: string | null): boolean {
|
|
if (!completedAt) return false;
|
|
|
|
const completionTime = new Date(completedAt).getTime();
|
|
const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
|
|
|
|
return completionTime > oneDayAgo;
|
|
}
|