Commit Graph

11 Commits

Author SHA1 Message Date
noroot
4675c6062e feat(alerts): "Quittierte löschen" — Backlog war nur seitenweise raeumbar
Gemeldet als "Loeschen tut nichts". Das Loeschen hat funktioniert: der
Audit-Eintrag zeigt deleted=25 und die IDs waren danach weg. Nur war das
unsichtbar — die Kopf-Checkbox der Tabelle markiert ausschliesslich die
AKTUELLE Seite (25 Zeilen), und bei einem Backlog von ~950 optisch
identischen backend.down-Alarmen ruecken sofort die naechsten 25 nach.
Fuer den Operator sah es aus, als sei nichts passiert; um den Backlog
leerzubekommen waeren ~38 Klick-Runden noetig gewesen.

Neu: POST /alerts/events/delete-acknowledged loescht alle quittierten
Events auf einmal — Gegenstueck zum bereits vorhandenen "Alle
quittieren". Bewusst nur die quittierten: was noch niemand gesehen hat,
soll nicht per Sammelaktion verschwinden. Der Button zeigt die Anzahl
ueber den gesamten Datensatz, nicht nur die sichtbare Seite.

Ausserdem meldet das seitenweise Loeschen jetzt die Anzahl zurueck
("N Alarme geloescht") statt nur "Loeschen" und leert die Auswahl —
damit ist erkennbar, dass etwas passiert ist, auch wenn die Liste
optisch gleich aussieht.

Die automatische Aufraeumung (90 Tage) arbeitet uebrigens korrekt, sie
loescht taeglich die Eintraege die ueber die Grenze rutschen — der
Backlog stammt aus dem Zeitraum davor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 12:59:15 +02:00
noroot
33cfc1a90d fix(fwlog): Live-Log war seit Tagen still tot + Seitengröße wirkungslos
Zwei unabhängige Bugs hinter "Live-Log zeigt Einträge, aber nichts Neues":

1) ulogd2 stirbt beim nächtlichen Logrotate. Der postinst nahm an, ulogd
   laufe als root — die Debian-Unit startet aber `ulogd --daemon --uid ulog`.
   Beim Start öffnet ulogd die JSONL noch als root und schreibt danach über
   den offenen fd weiter, egal wem sie gehört. Nachts schickt das Distro-
   Profil /etc/logrotate.d/ulogd2 ein SIGHUP; das Reopen läuft dann als
   `ulog` und scheitert an root:edgeguard 0640 ("can't open JSON log file:
   Permission denied"). ulogd wertet das als fatal und beendet sich mit
   Exit-Code 0 — Restart=on-failure hätte also nicht gegriffen, und ohne
   Restart= blieb der Dienst tot (auf utm-1 5 Tage unbemerkt). Die API
   servierte derweil weiter ihren In-Memory-Ring von vor der Rotation,
   deshalb sah die UI Einträge, aber nie neue.
   Fix: Owner ulog (Schreiber) : edgeguard (Leser), logrotate `create`
   passend, plus Drop-in Restart=always als Selbstheilung.

2) Seitengröße liess sich nicht umstellen. Die Tabellen übergaben ein
   literales `pagination={{ pageSize: N }}`. antd merged via
   extendsObject(innerPagination, paginationObj) — der Prop überschreibt
   bei jedem Render den State, den der Size-Changer gerade gesetzt hat.
   Bei einem Live-Log rendert das im Sekundentakt, der Klick auf 20/100
   war also sofort wieder weg. Fix: defaultPageSize (unkontrolliert).
   Betraf ausser dem Live-Log auch Logs, Backups-History, Routes,
   Alerts und CrowdSec.

Ausserdem: `t` aus den WS-Effect-Deps genommen. i18n wechselt dessen
Identität bei Store-Updates, was den Effect neu laufen liess — inklusive
setEntries([]), d.h. der Live-Puffer leerte sich ohne erkennbaren Grund.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 09:32:43 +02:00
Debian
dca40761a4 feat: CrowdSec journald-Acquisition + Alarm-Quittieren/Löschen — v1.3.5
- fix(crowdsec/packaging): postinst setzt die HAProxy-Acquisition deterministisch
  auf die journald-Unit (haproxy.service) statt der cscli-setup-Datei-Default
  (/var/log/haproxy.log existiert nicht → CrowdSec las nichts → HTTP/CVE-Szenarien
  liefen leer). Self-healing auf jedem configure; admin-Custom bleibt unangetastet.
- feat(alerts): Alarme (alert_events) bulk quittieren + löschen. Migration 0045
  (acknowledged_at + Teil-Index). Dashboard-Karte zählt nur noch OFFENE (open=true)
  → Quittieren lässt die "Aktuelle Alerts"-Meldung verschwinden, History bleibt.
  Events-Tab: Row-Selection, Quittieren/Löschen (Auswahl) + "Alle quittieren",
  Status-Spalte (offen/quittiert). Audit-geloggt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-31 10:58:27 +02:00
Debian
0ac91a7c59 feat: per-Backend timeout server + Alerts-Deeplink + Retention + Cert-Prune — v1.3.4
- feat(backends): per-Backend `server_timeout_seconds` (nullable, Default 60s).
  Rendert `timeout server <N>s` im HAProxy-Backend-Block — für langsam
  antwortende Upstreams (KI-/Inferenz-Server mit gepufferter Antwort).
  Migration 0044 (+CHECK 1..86400), Model/Repo/Template/UI + Render-Test.
- fix(ui): Dashboard-Alert-Karte verlinkt auf /alerts?tab=events; Alerts-Seite
  respektiert ?tab= (Deeplink landete bisher auf leerem Channels-Tab).
- feat(scheduler): alert_events-Retention (90d) im täglichen Cleanup-Tick —
  Schutz vor unbounded growth der node-lokalen Health-Event-History.
- fix(cluster): Cert-Sync prunt jetzt lokale .pem die der Primary nicht mehr
  hat (Waisen gelöschter Domains); schützt _default.pem + eigenen Node-Cert.
- fix(security): x/text v0.37→v0.39 (GO-2026-5970, Infinite-Loop; via ACME+goose
  aktiv aufgerufen — govulncheck-Release-Gate).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 15:59:55 +02:00
Debian
1c39a0e533 fix(alerts+diag): quickToggle SMTP-Datenverlust + Diagnostics Viewer-Gate
Alerts: quickToggle schickte den Channel durch buildPayload(), das SMTP-
Settings aus einem flachen ChannelFormValues rekonstruiert. Bei Email-
Channels wurde damit jedes aktiv/inaktiv-Toggle zum SMTP-Config-Wipe,
weil die Flat-Fields (smtp_host, smtp_port, from, ...) undefined waren.
Fix: raw Channel-Objekt mit geändertem active-Flag direkt PUT-ten.

testFire-Button fehlte disabled={isViewer} + Tooltip.

Diagnostics: kein isViewer-Check, Viewer sahen funktionierende Run-
Buttons und bekamen 403 ohne Erklärung. Fix: isViewer aus Auth-Store,
disabled-Prop in ToolCard, alle 5 Cards + Enter-Handler gegattet.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 14:44:58 +02:00
Debian
da554e9e82 feat(alerts): severity + kind filter selects on Events tab
Operators can now narrow the history table by severity (INFO/WARNING/
ERROR/CRITICAL) and by alert kind (dynamically derived from loaded
events, searchable). Filtering is client-side — no extra API calls.
v1.1.112.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 20:07:50 +02:00
Debian
0856c2fc10 feat(rbac): RBAC-Audit abschliessen — Viewer-Sperre für alle verbleibenden Seiten (1.1.93)
Domains, Backends (inkl. ServerPanel), Backups/History und Alerts:
isViewer-Check + disabled Switches, Tooltip-wrapped Add-Buttons,
bedingte Delete/Restore-Render (Viewer → disabled Tooltip statt Popconfirm).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 16:39:24 +02:00
Debian
bb14d2ac6c fix(i18n): hardkodierte Strings in Cluster/Users/Backups/Alerts bereinigen
- Cluster: statusTag() bekommt t-Parameter; Status-Labels (online/offline/
  joining/leaving/unknown) → cluster.status.* Keys
- Users: 'You'-Tag → t('users.you') / de: 'Ich'
- Backups: 'OK'-Status-Tag → t('backups.okTag')
- Alerts: Kanal-Kind-Labels + alle SMTP-Formular-Labels in t() überführt
- en/de: cluster.status.*, users.you, backups.okTag, alerts.smtp.*,
  alerts.kindWebhook/kindEmail ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 12:47:28 +02:00
Debian
661c810cde feat(alerts): Quick-Toggle für Alert-Kanäle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 11:47:21 +02:00
Debian
35b7308ce2 feat: umfangreiches UI+API-Polish (v1.1.36–1.1.42)
Backend:
- Audit-Log: Search-Endpoint mit ILIKE-Filter (actor/action/subject/date)
- NTP: /ntp/status via chronyc tracking (Stratum, Offset, Quelle)
- System: /service-restart mit Allowlist (haproxy/squid/unbound/chrony/scheduler)
- Domain-Response-Headers + Rate-Limit (Migration 0024)
- Join-Tokens (Migration 0025), Cluster-mTLS, Aggregator-Fan-Out
- apt-Service für Update-Banner (apt-get update + Versionsprüfung)
- Backup-Retry mit exponential backoff (retry_apt 3×)
- publish.sh fail-fast + cleanup-old.sh (max 10 Versionen)

Frontend:
- Audit-Log-Page (/audit) mit Filter + Pagination
- ErrorBoundary an React-Root + Vite build-target festgenagelt (iOS 15+)
- Storage-Schema-Stamp: auto-wipe bei Versions-Mismatch (blank-page-Fix)
- EmptyState-Komponente überall ausgerollt
- SSL: Aggregate-Karte (total/expiring/expired/errors)
- Backups: Aggregate-Karte (letzter Backup/Größe/Fehlschläge 24h) + Backup-Now
- NTP: Sync-Status-Karte (chronyc tracking live)
- Domains: Backend-UP/DOWN-Chip aus HAProxy-Stats
- Backends: HAProxy-Status-Spalte (UP/DEGRADED/DOWN)
- Settings: Service-Neustart-Karte (haproxy/squid/unbound/chrony/scheduler)
- Settings: Upgrade-Status-Card, Wartungsmodus, Auto-Update, Retention
- Dashboard: Recent-Alerts, Cluster-Health, License-Chip, Onboarding-Hint
- System-Regeln im Firewall als eigener Tab

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 16:18:41 +02:00
Debian
81a8217493 feat(alerts): Health-Alarme via Webhook + Email-SMTP
Sidebar → System → Alarme.

Migration 0021: alert_channels (kind=webhook|email, target, settings,
active) + alert_events (kind, severity=info/warning/error/critical,
subject, message, sent_to JSONB).

internal/services/alerts/:
  - Fire(kind, severity, subject, message) — broadcastet an alle
    aktiven Channels + persistiert Event mit per-Channel-Result
    (ok/error) in sent_to.
  - Webhook-Sender: POST JSON {kind, severity, subject, message,
    content, text, fired_at}. Slack/Discord/Teams akzeptieren das
    out-of-the-box ohne Adapter (content + text-Felder gleichzeitig).
  - Email-Sender: net/smtp + STARTTLS optional. Settings (smtp_host,
    smtp_port, username/password, from, use_tls) liegen in
    channel.settings JSONB.

internal/handlers/alerts.go: CRUD + POST /alerts/test + GET
/alerts/events (history).

Scheduler-Trigger:
  - cert.expiring  — TLS-Cert <14 Tage Restzeit (12h-dedupe pro cert)
                     severity warning, <3 Tage → error
  - cert.renew_failed       — Renewer-Cycle hat fails
  - cert.renewer.run_failed — Renewer-Cycle abgebrochen
  - backup.failed  — Scheduled Backup error
  - license.invalid — License-Server liefert valid=false

In-process Dedupe (12h TTL, map[key]time.Time) verhindert dass
identische Alerts in Schleifen feuern.

UI (pages/Alerts): Tabs Channels (CRUD-Tabelle, Add-Modal mit
conditional-Email-Fields) + History (200 letzte Events mit
severity-Tag + per-Channel-Delivery-Status). Header-Button
„Test-Alert" feuert einen Test-Event in alle aktiven Channels.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 15:57:05 +02:00