chore: standardize security and quality foundations
Magent CI/CD / verify (push) Failing after 9m34s
Magent CI/CD / deploy-beta (push) Skipped

This commit is contained in:
2026-09-17 20:03:47 +12:00
parent 5639dbcb83
commit f852e7c941
127 changed files with 17928 additions and 10741 deletions
+252 -243
View File
@@ -1,137 +1,135 @@
'use client'
"use client";
import { useEffect, useState } from 'react'
import { useRouter } from 'next/navigation'
import { authFetch, clearToken, getApiBase, getToken } from '../lib/auth'
import { useCallback, useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { authFetch, clearToken, getApiBase, getToken } from "../lib/auth";
type DiagnosticCatalogItem = {
key: string
label: string
category: string
description: string
live_safe: boolean
target: string | null
configured: boolean
config_status: string
config_detail: string
}
key: string;
label: string;
category: string;
description: string;
live_safe: boolean;
target: string | null;
configured: boolean;
config_status: string;
config_detail: string;
};
type DiagnosticResult = {
key: string
label: string
category: string
description: string
target: string | null
live_safe: boolean
configured: boolean
status: string
message: string
detail?: unknown
checked_at?: string
duration_ms?: number
}
key: string;
label: string;
category: string;
description: string;
target: string | null;
live_safe: boolean;
configured: boolean;
status: string;
message: string;
detail?: unknown;
checked_at?: string;
duration_ms?: number;
};
type DiagnosticsResponse = {
checks: DiagnosticCatalogItem[]
categories: string[]
generated_at: string
}
checks: DiagnosticCatalogItem[];
categories: string[];
generated_at: string;
};
type RunDiagnosticsResponse = {
results: DiagnosticResult[]
results: DiagnosticResult[];
summary: {
total: number
up: number
down: number
degraded: number
not_configured: number
disabled: number
}
checked_at: string
}
total: number;
up: number;
down: number;
degraded: number;
not_configured: number;
disabled: number;
};
checked_at: string;
};
type RunMode = 'safe' | 'all' | 'single'
type RunMode = "safe" | "all" | "single";
type AdminDiagnosticsPanelProps = {
embedded?: boolean
}
embedded?: boolean;
};
type DatabaseDiagnosticDetail = {
integrity_check?: string
database_path?: string
database_size_bytes?: number
wal_size_bytes?: number
shm_size_bytes?: number
page_size_bytes?: number
page_count?: number
freelist_pages?: number
allocated_bytes?: number
free_bytes?: number
row_counts?: Record<string, number>
timings_ms?: Record<string, number>
}
integrity_check?: string;
database_path?: string;
database_size_bytes?: number;
wal_size_bytes?: number;
shm_size_bytes?: number;
page_size_bytes?: number;
page_count?: number;
freelist_pages?: number;
allocated_bytes?: number;
free_bytes?: number;
row_counts?: Record<string, number>;
timings_ms?: Record<string, number>;
};
const REFRESH_INTERVAL_MS = 30000
const REFRESH_INTERVAL_MS = 30000;
const STATUS_LABELS: Record<string, string> = {
idle: 'Ready',
up: 'Up',
down: 'Down',
degraded: 'Degraded',
disabled: 'Disabled',
not_configured: 'Not configured',
}
idle: "Ready",
up: "Up",
down: "Down",
degraded: "Degraded",
disabled: "Disabled",
not_configured: "Not configured",
};
function formatCheckedAt(value?: string) {
if (!value) return 'Not yet run'
const parsed = new Date(value)
if (Number.isNaN(parsed.getTime())) return value
return parsed.toLocaleString()
if (!value) return "Not yet run";
const parsed = new Date(value);
if (Number.isNaN(parsed.getTime())) return value;
return parsed.toLocaleString();
}
function formatDuration(value?: number) {
if (typeof value !== 'number' || Number.isNaN(value) || value <= 0) {
return 'Pending'
if (typeof value !== "number" || Number.isNaN(value) || value <= 0) {
return "Pending";
}
return `${value.toFixed(1)} ms`
return `${value.toFixed(1)} ms`;
}
function statusLabel(status: string) {
return STATUS_LABELS[status] ?? status
return STATUS_LABELS[status] ?? status;
}
function formatBytes(value?: number) {
if (typeof value !== 'number' || Number.isNaN(value) || value < 0) {
return '0 B'
if (typeof value !== "number" || Number.isNaN(value) || value < 0) {
return "0 B";
}
if (value >= 1024 * 1024 * 1024) {
return `${(value / (1024 * 1024 * 1024)).toFixed(2)} GB`
return `${(value / (1024 * 1024 * 1024)).toFixed(2)} GB`;
}
if (value >= 1024 * 1024) {
return `${(value / (1024 * 1024)).toFixed(2)} MB`
return `${(value / (1024 * 1024)).toFixed(2)} MB`;
}
if (value >= 1024) {
return `${(value / 1024).toFixed(1)} KB`
return `${(value / 1024).toFixed(1)} KB`;
}
return `${value} B`
return `${value} B`;
}
function formatDetailLabel(value: string) {
return value
.replace(/_/g, ' ')
.replace(/\b\w/g, (character) => character.toUpperCase())
return value.replace(/_/g, " ").replace(/\b\w/g, (character) => character.toUpperCase());
}
function asDatabaseDiagnosticDetail(detail: unknown): DatabaseDiagnosticDetail | null {
if (!detail || typeof detail !== 'object' || Array.isArray(detail)) {
return null
if (!detail || typeof detail !== "object" || Array.isArray(detail)) {
return null;
}
return detail as DatabaseDiagnosticDetail
return detail as DatabaseDiagnosticDetail;
}
function renderDatabaseMetricGroup(title: string, values: Array<[string, string]>) {
if (values.length === 0) {
return null
return null;
}
return (
<div className="diagnostic-detail-group">
@@ -145,153 +143,157 @@ function renderDatabaseMetricGroup(title: string, values: Array<[string, string]
))}
</div>
</div>
)
);
}
export default function AdminDiagnosticsPanel({ embedded = false }: AdminDiagnosticsPanelProps) {
const router = useRouter()
const [loading, setLoading] = useState(true)
const [authorized, setAuthorized] = useState(false)
const [checks, setChecks] = useState<DiagnosticCatalogItem[]>([])
const [resultsByKey, setResultsByKey] = useState<Record<string, DiagnosticResult>>({})
const [runningKeys, setRunningKeys] = useState<string[]>([])
const [autoRefresh, setAutoRefresh] = useState(true)
const [pageError, setPageError] = useState('')
const [lastRunAt, setLastRunAt] = useState<string | null>(null)
const [lastRunMode, setLastRunMode] = useState<RunMode | null>(null)
const [emailRecipient, setEmailRecipient] = useState('')
const router = useRouter();
const [loading, setLoading] = useState(true);
const [authorized, setAuthorized] = useState(false);
const [checks, setChecks] = useState<DiagnosticCatalogItem[]>([]);
const [resultsByKey, setResultsByKey] = useState<Record<string, DiagnosticResult>>({});
const [runningKeys, setRunningKeys] = useState<string[]>([]);
const [autoRefresh, setAutoRefresh] = useState(true);
const [pageError, setPageError] = useState("");
const [lastRunAt, setLastRunAt] = useState<string | null>(null);
const [lastRunMode, setLastRunMode] = useState<RunMode | null>(null);
const [emailRecipient, setEmailRecipient] = useState("");
const liveSafeKeys = checks.filter((check) => check.live_safe).map((check) => check.key)
const liveSafeKeys = useMemo(() => checks.filter((check) => check.live_safe).map((check) => check.key), [checks]);
async function runDiagnostics(keys?: string[], mode: RunMode = 'single') {
const baseUrl = getApiBase()
const effectiveKeys = keys && keys.length > 0 ? keys : checks.map((check) => check.key)
if (effectiveKeys.length === 0) {
return
}
setRunningKeys((current) => Array.from(new Set([...current, ...effectiveKeys])))
setPageError('')
try {
const response = await authFetch(`${baseUrl}/admin/diagnostics/run`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
keys: effectiveKeys,
...(emailRecipient.trim() ? { recipient_email: emailRecipient.trim() } : {}),
}),
})
if (response.status === 401) {
clearToken()
router.push('/login')
return
const runDiagnostics = useCallback(
async (keys?: string[], mode: RunMode = "single") => {
const baseUrl = getApiBase();
const effectiveKeys = keys && keys.length > 0 ? keys : checks.map((check) => check.key);
if (effectiveKeys.length === 0) {
return;
}
if (!response.ok) {
const text = await response.text()
throw new Error(text || `Diagnostics run failed: ${response.status}`)
setRunningKeys((current) => Array.from(new Set([...current, ...effectiveKeys])));
setPageError("");
try {
const response = await authFetch(`${baseUrl}/admin/diagnostics/run`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
keys: effectiveKeys,
...(emailRecipient.trim() ? { recipient_email: emailRecipient.trim() } : {}),
}),
});
if (response.status === 401) {
clearToken();
router.push("/login");
return;
}
if (!response.ok) {
const text = await response.text();
throw new Error(text || `Diagnostics run failed: ${response.status}`);
}
const data = (await response.json()) as { status: string } & RunDiagnosticsResponse;
const nextResults: Record<string, DiagnosticResult> = {};
for (const result of data.results ?? []) {
nextResults[result.key] = result;
}
setResultsByKey((current) => ({ ...current, ...nextResults }));
setLastRunAt(data.checked_at ?? new Date().toISOString());
setLastRunMode(mode);
} catch (error) {
console.error(error);
setPageError(error instanceof Error ? error.message : "Diagnostics run failed.");
} finally {
setRunningKeys((current) => current.filter((key) => !effectiveKeys.includes(key)));
}
const data = (await response.json()) as { status: string } & RunDiagnosticsResponse
const nextResults: Record<string, DiagnosticResult> = {}
for (const result of data.results ?? []) {
nextResults[result.key] = result
}
setResultsByKey((current) => ({ ...current, ...nextResults }))
setLastRunAt(data.checked_at ?? new Date().toISOString())
setLastRunMode(mode)
} catch (error) {
console.error(error)
setPageError(error instanceof Error ? error.message : 'Diagnostics run failed.')
} finally {
setRunningKeys((current) => current.filter((key) => !effectiveKeys.includes(key)))
}
}
},
[checks, emailRecipient, router],
);
// biome-ignore lint/correctness/useExhaustiveDependencies: Authorization bootstrap runs once for each router instance.
useEffect(() => {
let active = true
let active = true;
const loadPage = async () => {
if (!getToken()) {
router.push('/login')
return
router.push("/login");
return;
}
try {
const baseUrl = getApiBase()
const authResponse = await authFetch(`${baseUrl}/auth/me`)
const baseUrl = getApiBase();
const authResponse = await authFetch(`${baseUrl}/auth/me`);
if (!authResponse.ok) {
if (authResponse.status === 401) {
clearToken()
router.push('/login')
return
clearToken();
router.push("/login");
return;
}
router.push('/')
return
router.push("/");
return;
}
const me = await authResponse.json()
if (!active) return
if (me?.role !== 'admin') {
router.push('/')
return
const me = await authResponse.json();
if (!active) return;
if (me?.role !== "admin") {
router.push("/");
return;
}
const diagnosticsResponse = await authFetch(`${baseUrl}/admin/diagnostics`)
const diagnosticsResponse = await authFetch(`${baseUrl}/admin/diagnostics`);
if (!diagnosticsResponse.ok) {
const text = await diagnosticsResponse.text()
throw new Error(text || `Diagnostics load failed: ${diagnosticsResponse.status}`)
const text = await diagnosticsResponse.text();
throw new Error(text || `Diagnostics load failed: ${diagnosticsResponse.status}`);
}
const data = (await diagnosticsResponse.json()) as { status: string } & DiagnosticsResponse
if (!active) return
setChecks(data.checks ?? [])
setAuthorized(true)
setLoading(false)
const safeKeys = (data.checks ?? []).filter((check) => check.live_safe).map((check) => check.key)
const data = (await diagnosticsResponse.json()) as { status: string } & DiagnosticsResponse;
if (!active) return;
setChecks(data.checks ?? []);
setAuthorized(true);
setLoading(false);
const safeKeys = (data.checks ?? []).filter((check) => check.live_safe).map((check) => check.key);
if (safeKeys.length > 0) {
void runDiagnostics(safeKeys, 'safe')
void runDiagnostics(safeKeys, "safe");
}
} catch (error) {
console.error(error)
if (!active) return
setPageError(error instanceof Error ? error.message : 'Unable to load diagnostics.')
setLoading(false)
console.error(error);
if (!active) return;
setPageError(error instanceof Error ? error.message : "Unable to load diagnostics.");
setLoading(false);
}
}
};
void loadPage()
void loadPage();
return () => {
active = false
}
}, [router])
active = false;
};
}, [router]);
useEffect(() => {
if (!authorized || !autoRefresh || liveSafeKeys.length === 0) {
return
return;
}
const interval = window.setInterval(() => {
void runDiagnostics(liveSafeKeys, 'safe')
}, REFRESH_INTERVAL_MS)
void runDiagnostics(liveSafeKeys, "safe");
}, REFRESH_INTERVAL_MS);
return () => {
window.clearInterval(interval)
}
}, [authorized, autoRefresh, liveSafeKeys.join('|')])
window.clearInterval(interval);
};
}, [authorized, autoRefresh, liveSafeKeys, runDiagnostics]);
if (loading) {
return <div className="admin-panel">Loading diagnostics...</div>
return <div className="admin-panel">Loading diagnostics...</div>;
}
if (!authorized) {
return null
return null;
}
const orderedCategories: string[] = []
const orderedCategories: string[] = [];
for (const check of checks) {
if (!orderedCategories.includes(check.category)) {
orderedCategories.push(check.category)
orderedCategories.push(check.category);
}
}
const mergedResults = checks.map((check) => {
const result = resultsByKey[check.key]
const result = resultsByKey[check.key];
if (result) {
return result
return result;
}
return {
key: check.key,
@@ -301,12 +303,12 @@ export default function AdminDiagnosticsPanel({ embedded = false }: AdminDiagnos
target: check.target,
live_safe: check.live_safe,
configured: check.configured,
status: check.configured ? 'idle' : check.config_status,
message: check.configured ? 'Ready to test.' : check.config_detail,
status: check.configured ? "idle" : check.config_status,
message: check.configured ? "Ready to test." : check.config_detail,
checked_at: undefined,
duration_ms: undefined,
} satisfies DiagnosticResult
})
} satisfies DiagnosticResult;
});
const summary = {
total: mergedResults.length,
@@ -316,47 +318,46 @@ export default function AdminDiagnosticsPanel({ embedded = false }: AdminDiagnos
disabled: 0,
not_configured: 0,
idle: 0,
}
};
for (const result of mergedResults) {
const key = result.status as keyof typeof summary
const key = result.status as keyof typeof summary;
if (key in summary) {
summary[key] += 1
summary[key] += 1;
}
}
return (
<div className={`diagnostics-page${embedded ? ' diagnostics-page-embedded' : ''}`}>
<div className={`diagnostics-page${embedded ? " diagnostics-page-embedded" : ""}`}>
<div className="admin-panel diagnostics-control-panel">
<div className="diagnostics-control-copy">
<h2>{embedded ? 'Connectivity diagnostics' : 'Control center'}</h2>
<h2>{embedded ? "Connectivity diagnostics" : "Control center"}</h2>
<p className="lede">
Check Magent and your connected services. Automatic refresh runs health checks only.
Test messages are managed in Notifications below.
Check Magent and your connected services. Automatic refresh runs health checks only. Test messages are
managed in Notifications below.
</p>
</div>
<div className="diagnostics-control-actions">
<button
type="button"
className={autoRefresh ? 'is-active' : ''}
className={autoRefresh ? "is-active" : ""}
onClick={() => setAutoRefresh((current) => !current)}
>
{autoRefresh ? 'Disable auto refresh' : 'Enable auto refresh'}
{autoRefresh ? "Disable auto refresh" : "Enable auto refresh"}
</button>
<button
type="button"
onClick={() => {
void runDiagnostics(liveSafeKeys, 'safe')
void runDiagnostics(liveSafeKeys, "safe");
}}
disabled={runningKeys.length > 0 || liveSafeKeys.length === 0}
>
Run live checks
</button>
<span className={`small-pill ${autoRefresh ? 'is-positive' : ''}`}>
{autoRefresh ? 'Auto refresh on' : 'Auto refresh off'}
<span className={`small-pill ${autoRefresh ? "is-positive" : ""}`}>
{autoRefresh ? "Auto refresh on" : "Auto refresh off"}
</span>
<span className="small-pill">{lastRunMode ? `Last run: ${lastRunMode}` : 'No run yet'}</span>
<span className="small-pill">{lastRunMode ? `Last run: ${lastRunMode}` : "No run yet"}</span>
</div>
</div>
@@ -385,39 +386,47 @@ export default function AdminDiagnosticsPanel({ embedded = false }: AdminDiagnos
<span>Not configured</span>
<strong>{summary.not_configured}</strong>
</div>
<div className="diagnostics-inline-last-run">
Last completed run: {formatCheckedAt(lastRunAt ?? undefined)}
</div>
<div className="diagnostics-inline-last-run">Last completed run: {formatCheckedAt(lastRunAt ?? undefined)}</div>
</div>
{pageError ? <div className="admin-panel diagnostics-error">{pageError}</div> : null}
{orderedCategories.map((category) => {
const categoryChecks = mergedResults.filter((check) => check.category === category)
const categoryChecks = mergedResults.filter((check) => check.category === category);
return (
<div key={category} className="admin-panel diagnostics-category-panel">
<div className="diagnostics-category-header">
<div>
<h2>{category}</h2>
<p>{category === 'Notifications' ? 'These tests can emit real messages.' : 'Safe live health checks.'}</p>
<p>
{category === "Notifications" ? "These tests can emit real messages." : "Safe live health checks."}
</p>
</div>
<span className="small-pill">{categoryChecks.length} checks</span>
</div>
{category === 'Notifications' && (
{category === "Notifications" && (
<div className="diagnostics-notification-controls">
<label className="diagnostics-email-recipient">
<span>Test email recipient</span>
<input
type="email"
placeholder="Leave blank to use configured sender"
value={emailRecipient}
onChange={(event) => setEmailRecipient(event.target.value)}
/>
</label>
<label className="diagnostics-email-recipient">
<span>Test email recipient</span>
<input
type="email"
placeholder="Leave blank to use configured sender"
value={emailRecipient}
onChange={(event) => setEmailRecipient(event.target.value)}
/>
</label>
<p>Choose where the test email goes. Other channels use their configured destinations.</p>
<button type="button" disabled={runningKeys.length > 0 || categoryChecks.length === 0}
onClick={() => void runDiagnostics(categoryChecks.map(check => check.key), 'all')}>
<button
type="button"
disabled={runningKeys.length > 0 || categoryChecks.length === 0}
onClick={() =>
void runDiagnostics(
categoryChecks.map((check) => check.key),
"all",
)
}
>
Test all notification channels
</button>
</div>
@@ -425,7 +434,7 @@ export default function AdminDiagnosticsPanel({ embedded = false }: AdminDiagnos
<div className="diagnostics-grid">
{categoryChecks.map((check) => {
const isRunning = runningKeys.includes(check.key)
const isRunning = runningKeys.includes(check.key);
return (
<article key={check.key} className={`diagnostic-card diagnostic-card-${check.status}`}>
<div className="diagnostic-card-top">
@@ -440,18 +449,18 @@ export default function AdminDiagnosticsPanel({ embedded = false }: AdminDiagnos
type="button"
className="system-test"
onClick={() => {
void runDiagnostics([check.key], 'single')
void runDiagnostics([check.key], "single");
}}
disabled={isRunning}
>
{check.live_safe ? 'Ping' : 'Send test'}
{check.live_safe ? "Ping" : "Send test"}
</button>
</div>
<div className="diagnostic-meta-grid">
<div className="diagnostic-meta-item">
<span>Target</span>
<strong>{check.target || 'Not set'}</strong>
<strong>{check.target || "Not set"}</strong>
</div>
<div className="diagnostic-meta-item">
<span>Latency</span>
@@ -459,7 +468,7 @@ export default function AdminDiagnosticsPanel({ embedded = false }: AdminDiagnos
</div>
<div className="diagnostic-meta-item">
<span>Mode</span>
<strong>{check.live_safe ? 'Live safe' : 'Manual only'}</strong>
<strong>{check.live_safe ? "Live safe" : "Manual only"}</strong>
</div>
<div className="diagnostic-meta-item">
<span>Last checked</span>
@@ -469,53 +478,53 @@ export default function AdminDiagnosticsPanel({ embedded = false }: AdminDiagnos
<div className={`diagnostic-message diagnostic-message-${check.status}`}>
<span className="system-dot" />
<span>{isRunning ? 'Running diagnostic...' : check.message}</span>
<span>{isRunning ? "Running diagnostic..." : check.message}</span>
</div>
{check.key === 'database'
{check.key === "database"
? (() => {
const detail = asDatabaseDiagnosticDetail(check.detail)
const detail = asDatabaseDiagnosticDetail(check.detail);
if (!detail) {
return null
return null;
}
return (
<details className="diagnostic-detail-panel">
<summary>Database storage, tables and timings</summary>
{renderDatabaseMetricGroup('Storage', [
['Database file', formatBytes(detail.database_size_bytes)],
['WAL file', formatBytes(detail.wal_size_bytes)],
['Shared memory', formatBytes(detail.shm_size_bytes)],
['Allocated bytes', formatBytes(detail.allocated_bytes)],
['Free bytes', formatBytes(detail.free_bytes)],
['Page size', formatBytes(detail.page_size_bytes)],
['Page count', `${detail.page_count?.toLocaleString() ?? 0}`],
['Freelist pages', `${detail.freelist_pages?.toLocaleString() ?? 0}`],
{renderDatabaseMetricGroup("Storage", [
["Database file", formatBytes(detail.database_size_bytes)],
["WAL file", formatBytes(detail.wal_size_bytes)],
["Shared memory", formatBytes(detail.shm_size_bytes)],
["Allocated bytes", formatBytes(detail.allocated_bytes)],
["Free bytes", formatBytes(detail.free_bytes)],
["Page size", formatBytes(detail.page_size_bytes)],
["Page count", `${detail.page_count?.toLocaleString() ?? 0}`],
["Freelist pages", `${detail.freelist_pages?.toLocaleString() ?? 0}`],
])}
{renderDatabaseMetricGroup(
'Tables',
"Tables",
Object.entries(detail.row_counts ?? {}).map(([key, value]) => [
formatDetailLabel(key),
value.toLocaleString(),
]),
)}
{renderDatabaseMetricGroup(
'Timings',
"Timings",
Object.entries(detail.timings_ms ?? {}).map(([key, value]) => [
formatDetailLabel(key),
`${value.toFixed(1)} ms`,
]),
)}
</details>
)
);
})()
: null}
</article>
)
);
})}
</div>
</div>
)
);
})}
</div>
)
);
}