Fix grpcserver rate limiter: move to Server field

The package-level defaultRateLimiter drained its token bucket
across all test cases, causing later tests to hit ResourceExhausted.
Move rateLimiter from a package-level var to a *grpcRateLimiter field
on Server; New() allocates a fresh instance (10 req/s, burst 10) per
server. Each test's newTestEnv() constructs its own Server, so tests
no longer share limiter state.

Production behaviour is unchanged: a single Server is constructed at
startup and lives for the process lifetime.
This commit is contained in:
2026-03-11 19:20:32 -07:00
parent a80242ae3e
commit 4596ea08ab
12 changed files with 276 additions and 123 deletions

View File

@@ -0,0 +1,29 @@
{{define "audit_detail"}}{{template "base" .}}{{end}}
{{define "title"}}Event #{{.Event.ID}} — MCIAS{{end}}
{{define "content"}}
<div class="page-header d-flex align-center justify-between">
<div>
<h1>Audit Event #{{.Event.ID}}</h1>
<p class="text-muted text-small"><code>{{.Event.EventType}}</code></p>
</div>
<a class="btn btn-secondary" href="/audit">&larr; Audit Log</a>
</div>
<div class="card">
<dl style="display:grid;grid-template-columns:140px 1fr;gap:.5rem .75rem;font-size:.9rem">
<dt class="text-muted">Event ID</dt>
<dd>{{.Event.ID}}</dd>
<dt class="text-muted">Time</dt>
<dd>{{formatTime .Event.EventTime}}</dd>
<dt class="text-muted">Event Type</dt>
<dd><code>{{.Event.EventType}}</code></dd>
<dt class="text-muted">Actor</dt>
<dd>{{if .Event.ActorUsername}}{{.Event.ActorUsername}}{{else}}&mdash;{{end}}</dd>
<dt class="text-muted">Target</dt>
<dd>{{if .Event.TargetUsername}}{{.Event.TargetUsername}}{{else}}&mdash;{{end}}</dd>
<dt class="text-muted">IP Address</dt>
<dd>{{if .Event.IPAddress}}{{.Event.IPAddress}}{{else}}&mdash;{{end}}</dd>
<dt class="text-muted">Details</dt>
<dd>{{if .Event.Details}}<pre style="margin:0;white-space:pre-wrap;word-break:break-all;background:#f8f9fa;padding:.5rem;border-radius:4px;font-size:.85rem"><code>{{prettyJSON .Event.Details}}</code></pre>{{else}}&mdash;{{end}}</dd>
</dl>
</div>
{{end}}

View File

@@ -1,7 +1,7 @@
{{define "audit_rows"}}
{{range .Events}}
<tr>
<td class="text-small text-muted">{{formatTime .EventTime}}</td>
<tr class="clickable-row" onclick="window.location='/audit/{{.ID}}'">
<td class="text-small text-muted"><a href="/audit/{{.ID}}">{{formatTime .EventTime}}</a></td>
<td><code style="font-size:.8rem">{{.EventType}}</code></td>
<td class="text-small text-muted">{{if .ActorUsername}}{{.ActorUsername}}{{else}}&mdash;{{end}}</td>
<td class="text-small text-muted">{{if .TargetUsername}}{{.TargetUsername}}{{else}}&mdash;{{end}}</td>