import { useDebugAuth } from '../../api/queries/debug';
import { ApiError } from '../../api/client';
import { EmptyState } from '../../components/ui/EmptyState';
import { ErrorState } from '../../components/ui/ErrorState';
import { LoadingState } from '../../components/ui/LoadingState';
import type {
AuthAnalysisView,
AuthCheckView,
AuthOperationView,
AuthRouteView,
AuthUnitView,
AuthValueRefView,
} from '../../api/types';
interface AuthAnalysisPanelProps {
file: string;
}
export function AuthAnalysisPanel({ file }: AuthAnalysisPanelProps) {
const { data, isLoading, error } = useDebugAuth(file);
if (isLoading) {
return ;
}
if (error) {
if (error instanceof ApiError && error.status === 400) {
return (
);
}
return ;
}
if (!data) {
return null;
}
if (!data.enabled) {
return (
);
}
if (data.routes.length === 0 && data.units.length === 0) {
return (
);
}
return (
{data.routes.length > 0 &&
}
{data.units.length > 0 &&
}
);
}
function AuthSummaryHeader({ data }: { data: AuthAnalysisView }) {
const totalChecks = data.units.reduce(
(acc, u) => acc + u.auth_checks.length,
0,
);
const totalOps = data.units.reduce((acc, u) => acc + u.operations.length, 0);
return (
Authorization Model
{data.routes.length} route{data.routes.length === 1 ? '' : 's'} ·{' '}
{data.units.length} unit{data.units.length === 1 ? '' : 's'} ·{' '}
{totalChecks} auth check{totalChecks === 1 ? '' : 's'} · {totalOps}{' '}
sensitive op{totalOps === 1 ? '' : 's'}
);
}
function AuthRoutesBlock({ routes }: { routes: AuthRouteView[] }) {
return (
Routes
{routes.length} registration{routes.length === 1 ? '' : 's'}
| Method |
Path |
Framework |
Middleware |
Handler Params |
Line |
Unit |
{routes.map((r, i) => (
|
{r.method}
|
{r.path} |
{r.framework} |
{r.middleware.length > 0 ? r.middleware.join(', ') : '-'}
|
{r.handler_params.length > 0
? r.handler_params.join(', ')
: '-'}
|
L{r.line} |
#{r.unit_idx} |
))}
);
}
function AuthUnitsBlock({ units }: { units: AuthUnitView[] }) {
return (
<>
{units.map((u, i) => (
'}-${i}`} unit={u} index={i} />
))}
>
);
}
function AuthUnitCard({ unit, index }: { unit: AuthUnitView; index: number }) {
const hasDetails =
unit.params.length > 0 ||
unit.self_actor_vars.length > 0 ||
unit.typed_bounded_vars.length > 0 ||
unit.authorized_sql_vars.length > 0 ||
unit.const_bound_vars.length > 0;
return (
#{index} {unit.name ?? ''}
{unit.kind} · L{unit.line}
{unit.auth_checks.length} check
{unit.auth_checks.length === 1 ? '' : 's'} · {unit.operations.length}{' '}
op
{unit.operations.length === 1 ? '' : 's'}
{hasDetails && (
{unit.params.length > 0 && (
)}
{unit.self_actor_vars.length > 0 && (
)}
{unit.typed_bounded_vars.length > 0 && (
)}
{unit.authorized_sql_vars.length > 0 && (
)}
{unit.const_bound_vars.length > 0 && (
)}
)}
{unit.auth_checks.length > 0 && (
)}
{unit.operations.length > 0 && (
)}
);
}
function DetailRow({ label, value }: { label: string; value: string }) {
return (
{label}
{value}
);
}
function AuthCheckTable({ checks }: { checks: AuthCheckView[] }) {
return (
Auth Checks
| Kind |
Callee |
Subjects |
Line |
{checks.map((c, i) => (
|
{c.kind}
|
{c.callee} |
{c.subjects.length === 0 ? (
'-'
) : (
)}
|
L{c.line} |
))}
);
}
function OperationTable({ operations }: { operations: AuthOperationView[] }) {
return (
Sensitive Operations
| Kind |
Sink Class |
Callee |
Subjects |
Line |
{operations.map((op, i) => (
|
{op.kind}
|
{op.sink_class ? (
{op.sink_class}
) : (
'-'
)}
|
{op.callee}
|
{op.subjects.length === 0 ? (
'-'
) : (
)}
|
L{op.line} |
))}
);
}
function SubjectChips({ subjects }: { subjects: AuthValueRefView[] }) {
return (
{subjects.map((s, i) => (
{s.name}
))}
);
}