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
+22 -4
View File
@@ -1,7 +1,8 @@
import React, { Suspense, createContext, lazy, useCallback, useContext, useEffect, useMemo, useState } from "react";
import React, { Suspense, createContext, lazy, useCallback, useContext, useEffect, useMemo, useState, useSyncExternalStore } from "react";
import { Box, Button, IconButton, Typography } from "@mui/material";
import useMediaQuery from "@mui/material/useMediaQuery";
import { isCancel } from "axios";
import DashboardIcon from "@mui/icons-material/Dashboard";
import WorkOutlineIcon from "@mui/icons-material/WorkOutline";
@@ -42,6 +43,7 @@ import { AccountPlanProvider } from "./accountPlan";
import AppShell, { NavItem } from "./layout/AppShell";
import { getThemeModePref, setThemeModePref, subscribeToThemePreferenceChanges, ThemeModePref } from "./themePrefs";
import JobTrackerThemeProvider from "./ThemeProvider";
import { isSessionInvalidated, SESSION_INVALIDATED_EVENT } from "./sessionBoundary";
const AddJobModal = lazy(() => import("./components/AddJobModal"));
const KanbanBoard = lazy(() => import("./components/KanbanBoard"));
@@ -209,8 +211,8 @@ function Shell({ jobPageSize, setJobPageSize, jobColumns, setJobColumns, themeMo
setIsAdmin(Boolean(r.data?.roles?.includes("Admin")));
setAuthUserKey(r.data?.id || r.data?.email || r.data?.userName || null, false);
})
.catch(() => {
if (!active) return;
.catch((error) => {
if (!active || isCancel(error)) return;
setMe(null);
setIsAdmin(false);
clearAuthClientState(false);
@@ -252,7 +254,8 @@ function Shell({ jobPageSize, setJobPageSize, jobColumns, setJobColumns, themeMo
setIsAdmin(Boolean(r.data?.roles?.includes("Admin")));
setAuthUserKey(r.data?.id || r.data?.email || r.data?.userName || null, false);
})
.catch(() => {
.catch((error) => {
if (isCancel(error)) return;
setMe(null);
setIsAdmin(false);
clearAuthClientState(false);
@@ -422,7 +425,22 @@ function ThemeAwareShell(props: Omit<React.ComponentProps<typeof Shell>, "themeM
return <Shell {...props} {...controls} />;
}
function subscribeSessionBoundary(onChange: () => void) {
window.addEventListener(SESSION_INVALIDATED_EVENT, onChange);
return () => window.removeEventListener(SESSION_INVALIDATED_EVENT, onChange);
}
export default function App() {
const invalidated = useSyncExternalStore(subscribeSessionBoundary, isSessionInvalidated, () => false);
useEffect(() => {
if (invalidated) window.location.replace("/login?sessionChanged=1");
}, [invalidated]);
// Unmount providers as well as routes: confirmations/toasts can retain private text and
// callbacks. Passive effect navigation runs after the old forms' unload guards are removed.
return invalidated ? <main role="alert">Session changed. Clearing this page…</main> : <Application />;
}
function Application() {
const systemPrefersDark = useMediaQuery("(prefers-color-scheme: dark)", { defaultMatches: true, noSsr: true });
const [themeMode, setThemeMode] = useState<ThemeModePref>(() => getThemeModePref());