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:
@@ -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());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user