1.0.37
This commit is contained in:
101 files changed
+5097
-642
No files matched your search
@@ -0,0 +1,66 @@
|
||||
/** Shared helpers for the vulnerability export endpoints (env-wide + per-image). */
|
||||
import { findingsToSarif } from '$lib/utils/sarif';
|
||||
import type { Finding } from '$lib/utils/vulnerability';
|
||||
|
||||
/** JSON error response with the given status. */
|
||||
export function jsonError(message: string, status: number): Response {
|
||||
return new Response(JSON.stringify({ error: message }), {
|
||||
status,
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
/** Make a value safe for use in a download filename. */
|
||||
export function slugify(name: string, fallback = 'export'): string {
|
||||
return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the export download response for json | csv | sarif. The caller supplies
|
||||
* the format-specific JSON body and a CSV renderer; sarif is generated from the
|
||||
* shared findings so both endpoints emit identical SARIF.
|
||||
*/
|
||||
export function exportResponse(opts: {
|
||||
format: string;
|
||||
filenameBase: string;
|
||||
findings: Finding[];
|
||||
jsonBody: unknown;
|
||||
toCSV: (findings: Finding[]) => string;
|
||||
}): Response {
|
||||
const { format, filenameBase, findings, jsonBody, toCSV } = opts;
|
||||
|
||||
let content: string;
|
||||
let contentType: string;
|
||||
let ext: string;
|
||||
|
||||
switch (format) {
|
||||
case 'csv':
|
||||
content = toCSV(findings);
|
||||
contentType = 'text/csv';
|
||||
ext = 'csv';
|
||||
break;
|
||||
case 'sarif':
|
||||
content = JSON.stringify(findingsToSarif(findings), null, 2);
|
||||
contentType = 'application/sarif+json';
|
||||
ext = 'sarif';
|
||||
break;
|
||||
case 'json':
|
||||
default:
|
||||
content = JSON.stringify(jsonBody, null, 2);
|
||||
contentType = 'application/json';
|
||||
ext = 'json';
|
||||
break;
|
||||
}
|
||||
|
||||
// Defensively strip anything that could break out of the quoted filename or
|
||||
// inject a header, regardless of what the caller passed (today it's slug+date).
|
||||
const safeBase = filenameBase.replace(/[^\w.-]+/g, '-').replace(/^-+|-+$/g, '') || 'export';
|
||||
|
||||
return new Response(content, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': contentType,
|
||||
'Content-Disposition': `attachment; filename="${safeBase}.${ext}"`
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user