fix(security): enforce audited account, network and resource boundaries

Implement B01-B06 with regression coverage and retained validation evidence. Preserve the production ingress preflight; F04 runtime verification remains open.
This commit is contained in:
cesnimda
2026-09-09 18:21:47 +02:00
parent 7d641edc7b
commit 0954876295
116 changed files with 10101 additions and 122 deletions
@@ -13,8 +13,8 @@ type ImportJob = Omit<JobApplication, "id" | "company" | "savedAt"> & {
company: Pick<Company, "name" | "location" | "source">;
};
function downloadText(filename: string, text: string, mime: string) {
const blob = new Blob([text], { type: mime });
function downloadFile(filename: string, content: BlobPart, mime: string) {
const blob = new Blob([content], { type: mime });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
@@ -186,8 +186,8 @@ export default function ImportExportJobs() {
const url = `/export/jobs?format=${format}&includeDeleted=false`;
const res = await api.get(url, { responseType: "blob" });
const text = await res.data.text();
downloadText(`job-tracker-export-${stamp}.${format}`, text, format === "json" ? "application/json" : "text/csv");
// Keep the CSV's UTF-8 BOM: decoding through Blob.text() would discard it.
downloadFile(`job-tracker-export-${stamp}.${format}`, res.data, format === "json" ? "application/json" : "text/csv;charset=utf-8");
toast(t("exportedJobs", { format: format.toUpperCase() }), "success");
} catch {
toast(t("exportFailed"), "error");
@@ -238,7 +238,7 @@ export default function ImportExportJobs() {
const text = await file.text();
const jobs = csvToImportJobs(text);
const stamp = new Date().toISOString().slice(0, 10);
downloadText(`job-tracker-import-${stamp}.json`, JSON.stringify(jobs, null, 2), "application/json");
downloadFile(`job-tracker-import-${stamp}.json`, JSON.stringify(jobs, null, 2), "application/json");
toast(t("convertedRows", { count: jobs.length }), "success");
} catch {
toast(t("csvConversionFailed"), "error");