feat(M3): Host Management, Groups, Users, CIDR Discovery
- pm-core::models: Host, HostSummary, Group, User, DiscoveryResult types + request payloads for all CRUD operations - pm-core::audit: Tamper-evident hash-chained audit log writer (SHA-256 chain, non-fatal, covers all M3 events) - pm-web/routes/hosts: Full host CRUD with RBAC scoping; FQDN DNS resolution on registration; host↔group membership; operator group-scoped access enforcement; audit on register/remove - pm-web/routes/groups: Full group CRUD; host↔group and user↔group membership management; admin-only create/delete/update - pm-web/routes/users: Full user CRUD (admin); current user profile; password hashing (Argon2id); role management; session revocation - pm-web/routes/discovery: CIDR scan with bounded concurrency (128 workers), TCP probe with 2s timeout, reverse DNS lookup, scan results table, register-from-discovery flow with audit log - Frontend: HostsPage (filterable table with health chips), HostDetailPage, GroupsPage (create/delete dialog), UsersPage (create/revoke sessions) - App.tsx updated with all M3 routes wired to real pages - cargo check --workspace: zero errors Closes M3.
This commit is contained in:
@ -4,8 +4,12 @@ import { lightTheme } from './theme/theme'
|
||||
import { useAuthStore } from './store/authStore'
|
||||
import LoginPage from './pages/LoginPage'
|
||||
import MfaSetupPage from './pages/MfaSetupPage'
|
||||
import HostsPage from './pages/HostsPage'
|
||||
import HostDetailPage from './pages/HostDetailPage'
|
||||
import GroupsPage from './pages/GroupsPage'
|
||||
import UsersPage from './pages/UsersPage'
|
||||
|
||||
// Placeholder pages — implemented in M3+
|
||||
// Placeholder pages — implemented in later milestones
|
||||
const PlaceholderPage = ({ title }: { title: string }) => (
|
||||
<div style={{ padding: 32 }}>
|
||||
<h2>{title}</h2>
|
||||
@ -13,7 +17,6 @@ const PlaceholderPage = ({ title }: { title: string }) => (
|
||||
</div>
|
||||
)
|
||||
|
||||
// Guard component: redirects to /login if not authenticated
|
||||
function RequireAuth({ children }: { children: React.ReactNode }) {
|
||||
const isAuthenticated = useAuthStore((s) => s.isAuthenticated)
|
||||
return isAuthenticated ? <>{children}</> : <Navigate to="/login" replace />
|
||||
@ -24,25 +27,28 @@ function App() {
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<CssBaseline />
|
||||
<Routes>
|
||||
{/* Public routes */}
|
||||
{/* Public */}
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
|
||||
{/* Protected routes */}
|
||||
{/* Protected — M2 */}
|
||||
<Route path="/" element={<RequireAuth><Navigate to="/dashboard" replace /></RequireAuth>} />
|
||||
<Route path="/mfa/setup" element={<RequireAuth><MfaSetupPage /></RequireAuth>} />
|
||||
|
||||
{/* Protected — M3 */}
|
||||
<Route path="/dashboard" element={<RequireAuth><PlaceholderPage title="Dashboard" /></RequireAuth>} />
|
||||
<Route path="/hosts" element={<RequireAuth><PlaceholderPage title="Hosts" /></RequireAuth>} />
|
||||
<Route path="/hosts/:id" element={<RequireAuth><PlaceholderPage title="Host Detail" /></RequireAuth>} />
|
||||
<Route path="/hosts" element={<RequireAuth><HostsPage /></RequireAuth>} />
|
||||
<Route path="/hosts/:id" element={<RequireAuth><HostDetailPage /></RequireAuth>} />
|
||||
<Route path="/groups" element={<RequireAuth><GroupsPage /></RequireAuth>} />
|
||||
<Route path="/users" element={<RequireAuth><UsersPage /></RequireAuth>} />
|
||||
|
||||
{/* Protected — later milestones */}
|
||||
<Route path="/jobs" element={<RequireAuth><PlaceholderPage title="Jobs" /></RequireAuth>} />
|
||||
<Route path="/deployment" element={<RequireAuth><PlaceholderPage title="Patch Deployment" /></RequireAuth>} />
|
||||
<Route path="/maintenance" element={<RequireAuth><PlaceholderPage title="Maintenance Windows" /></RequireAuth>} />
|
||||
<Route path="/groups" element={<RequireAuth><PlaceholderPage title="Groups" /></RequireAuth>} />
|
||||
<Route path="/reports" element={<RequireAuth><PlaceholderPage title="Reports" /></RequireAuth>} />
|
||||
<Route path="/users" element={<RequireAuth><PlaceholderPage title="Users" /></RequireAuth>} />
|
||||
<Route path="/certificates" element={<RequireAuth><PlaceholderPage title="Certificates" /></RequireAuth>} />
|
||||
<Route path="/settings" element={<RequireAuth><PlaceholderPage title="Settings" /></RequireAuth>} />
|
||||
<Route path="/mfa/setup" element={<RequireAuth><MfaSetupPage /></RequireAuth>} />
|
||||
|
||||
{/* 404 */}
|
||||
<Route path="*" element={<PlaceholderPage title="404 Not Found" />} />
|
||||
</Routes>
|
||||
</ThemeProvider>
|
||||
|
||||
Reference in New Issue
Block a user