feat: GitHub Event Scanner - Echtzeit-Monitoring öffentlicher Pushes

- Neuer GitHubEventScannerService (BackgroundService)
  - Pollt /events API alle 30s, filtert PushEvents
  - Lädt Head-Commit-Diffs, scannt nach Key-Patterns
  - Ringbuffer (10k IDs) für Event-Deduplication
  - Gefundene Keys werden sofort geprüft (AnthropicKeyChecker)
  - Rate-Limit-Handling (403/429 → Pause bis Reset)
- Feature-Toggle in Server-Einstellungen (GitHubEventScanner)
- Status-Endpoint + Log-Endpoint (/api/admin/api-keys/event-scanner/*)
- Live-Status in API-Keys-Seite mit klappbarem Log
- Auto-Refresh alle 30s
- Plans/ in .gitignore
This commit is contained in:
Meleki committed 2026-03-13 18:38:32 +01:00
1 parent 7352438b11
commit eb8844a4f1
9 files changed
+578 -2

No files matched your search

+28
View File
@@ -34,6 +34,10 @@ public static class ApiKeysEndpoint
app.MapPost("/api/admin/api-keys/scanned/{id}/adopt", HandleAdopt);
app.MapDelete("/api/admin/api-keys/scanned/{id}", HandleDeleteScanned);
// Event Scanner Status & Log
app.MapGet("/api/admin/api-keys/event-scanner/status", HandleEventScannerStatus);
app.MapGet("/api/admin/api-keys/event-scanner/log", HandleEventScannerLog);
// User-Endpoints (für alle authentifizierten User)
app.MapGet("/api/api-keys/available", HandleGetAvailable);
app.MapPut("/api/api-keys/select/{keyId}", HandleSelectKey);
@@ -466,4 +470,28 @@ public static class ApiKeysEndpoint
});
}
private static async Task HandleEventScannerStatus(HttpContext ctx, GitHubEventScannerService scanner)
{
if (!ctx.IsAdmin()) { ctx.Response.StatusCode = 403; return; }
await ctx.Response.WriteAsJsonAsync(new
{
enabled = scanner.Enabled,
running = scanner.IsRunning,
lastPoll = scanner.LastPoll,
eventsPerHour = scanner.EventsPerHour,
keysFoundTotal = scanner.KeysFoundTotal,
pollCount = scanner.PollCount,
lastError = scanner.LastError
});
}
private static async Task HandleEventScannerLog(HttpContext ctx, GitHubEventScannerService scanner)
{
if (!ctx.IsAdmin()) { ctx.Response.StatusCode = 403; return; }
var log = scanner.GetLog();
await ctx.Response.WriteAsJsonAsync(new { entries = log.Select(e => new { e.Time, e.Type, e.Message }) });
}
}
+1
View File
@@ -35,6 +35,7 @@ public static class ServerSettingsEndpoint
new SettingDefinition("SerperApiKey", "string", "", "Serper.dev API-Key für Google-Suche (Key-Scanner)", "password"),
new SettingDefinition("ProxyUrl", "string", "", "HTTP/SOCKS Proxy für alle Requests (z.B. socks5://127.0.0.1:1080)", "text"),
new SettingDefinition("ScanIntervalHours", "int", 0, "Key-Scanner Intervall in Stunden (0 = nur manuell)", "number"),
new SettingDefinition("GitHubEventScanner", "bool", false, "GitHub Event Scanner (Echtzeit-Monitoring öffentlicher Pushes)", "toggle"),
};
public static void MapServerSettingsEndpoints(this WebApplication app)