feat(auth): add recent activity logging to access tracker
CI / build-and-test (push) Failing after 0s

* Introduced AccessLogEntry type for logging access details
* Updated AccessTracker to maintain a recent activity log
* Modified Metrics to include recent activity log in response
* Added RecentActivityLog component to display logged activities
This commit is contained in:
2026-05-24 16:36:59 +02:00
parent e38a0377d5
commit 0227912325
6 changed files with 106 additions and 5 deletions
@@ -2,6 +2,7 @@
import type { StatusResponse } from '../../types';
import AccessTable from './AccessTable.svelte';
import ConnectionBreakdown from './ConnectionBreakdown.svelte';
import RecentActivityLog from './RecentActivityLog.svelte';
import StatusCards from './StatusCards.svelte';
const {
@@ -67,4 +68,7 @@
emptyLabel="No MCP tool calls recorded yet."
/>
</div>
<div class="mt-6">
<RecentActivityLog entries={data.metrics.recent_log ?? []} />
</div>
{/if}
@@ -0,0 +1,53 @@
<script lang="ts">
import type { AccessLogEntry } from '../../types';
const { entries }: { entries: AccessLogEntry[] } = $props();
function formatTime(value: string): string {
return new Date(value).toLocaleString();
}
</script>
<section class="rounded-3xl border border-white/10 bg-slate-900/80 p-6 shadow-xl shadow-slate-950/20 sm:p-8">
<h3 class="text-xl font-semibold text-white">Recent activity <span class="ml-2 text-sm font-normal text-slate-500">(last {entries.length})</span></h3>
{#if entries.length === 0}
<div class="mt-6 rounded-2xl border border-dashed border-white/10 bg-slate-950/40 px-4 py-10 text-center text-slate-500">
No activity recorded yet.
</div>
{:else}
<div class="mt-6 overflow-hidden rounded-2xl border border-white/10">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-white/10 text-left text-sm text-slate-300">
<thead class="bg-white/5 text-xs uppercase tracking-[0.2em] text-slate-500">
<tr>
<th class="px-4 py-3 font-medium">Time</th>
<th class="px-4 py-3 font-medium">Principal</th>
<th class="px-4 py-3 font-medium">IP</th>
<th class="px-4 py-3 font-medium">User Agent</th>
<th class="px-4 py-3 font-medium">Tool</th>
<th class="px-4 py-3 font-medium">Path</th>
</tr>
</thead>
<tbody class="divide-y divide-white/5 bg-slate-950/30">
{#each entries as entry}
<tr class="hover:bg-white/[0.03]">
<td class="whitespace-nowrap px-4 py-2.5 text-xs text-slate-400">{formatTime(entry.timestamp)}</td>
<td class="px-4 py-2.5"><code class="rounded bg-white/5 px-2 py-0.5 font-mono text-xs text-cyan-100">{entry.key_id}</code></td>
<td class="px-4 py-2.5"><code class="text-xs text-slate-200">{entry.ip || '—'}</code></td>
<td class="max-w-[16rem] truncate px-4 py-2.5 text-xs text-slate-400" title={entry.user_agent}>{entry.user_agent || '—'}</td>
<td class="px-4 py-2.5">
{#if entry.tool}
<code class="rounded bg-indigo-500/10 px-2 py-0.5 text-xs text-indigo-300">{entry.tool}</code>
{:else}
<span class="text-slate-600"></span>
{/if}
</td>
<td class="max-w-[14rem] truncate px-4 py-2.5"><code class="text-xs text-slate-300">{entry.path}</code></td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
{/if}
</section>
+10
View File
@@ -12,6 +12,15 @@ export type RequestAggregate = {
request_count: number;
};
export type AccessLogEntry = {
timestamp: string;
key_id: string;
ip: string;
user_agent: string;
tool: string;
path: string;
};
export type AccessMetrics = {
total_requests: number;
unique_principals: number;
@@ -21,6 +30,7 @@ export type AccessMetrics = {
top_ips: RequestAggregate[];
top_agents: RequestAggregate[];
top_tools: RequestAggregate[];
recent_log: AccessLogEntry[];
};
export type StatusResponse = {