feat: Task 3 — invalid jail config recovery (pre-validation, crash detection, rollback)

- Backend: extend activate_jail() with pre-validation and 4-attempt post-reload
  health probe; add validate_jail_config() and rollback_jail() service functions
- Backend: new endpoints POST /api/config/jails/{name}/validate,
  GET /api/config/pending-recovery, POST /api/config/jails/{name}/rollback
- Backend: extend JailActivationResponse with fail2ban_running + validation_warnings;
  add JailValidationIssue, JailValidationResult, PendingRecovery, RollbackResponse models
- Backend: health_check task tracks last_activation and creates PendingRecovery
  record when fail2ban goes offline within 60 s of an activation
- Backend: add fail2ban_start_command setting (configurable start cmd for rollback)
- Frontend: ActivateJailDialog — pre-validation on open, crash-detected callback,
  extended spinner text during activation+verify
- Frontend: JailsTab — Validate Config button for inactive jails, validation
  result panels (blocking errors + advisory warnings)
- Frontend: RecoveryBanner component — polls pending-recovery, shows full-width
  alert with Disable & Restart / View Logs buttons
- Frontend: MainLayout — mount RecoveryBanner at layout level
- Tests: 19 new backend service tests (validate, rollback, filter/action parsing)
  + 6 health_check crash-detection tests + 11 router tests; 5 RecoveryBanner
  frontend tests; fix mock setup in existing activate_jail tests
This commit is contained in:
2026-03-14 14:13:07 +01:00
parent ab11ece001
commit 0966f347c4
17 changed files with 1862 additions and 26 deletions

View File

@@ -549,6 +549,52 @@ export interface JailActivationResponse {
active: boolean;
/** Human-readable result message. */
message: string;
/** Whether fail2ban was still running after the reload. Defaults to true. */
fail2ban_running: boolean;
/** Non-fatal pre-activation validation warnings (e.g. missing log path). */
validation_warnings: string[];
}
// ---------------------------------------------------------------------------
// Jail config recovery models (Task 3)
// ---------------------------------------------------------------------------
/** A single validation issue found in a jail's config. */
export interface JailValidationIssue {
/** Config field that has the issue, e.g. "filter", "failregex". */
field: string;
/** Human-readable description of the issue. */
message: string;
}
/** Full result of pre-activation validation for a single jail. */
export interface JailValidationResult {
jail_name: string;
valid: boolean;
issues: JailValidationIssue[];
}
/**
* Recorded when fail2ban stops responding shortly after a jail activation.
* Surfaced by `GET /api/config/pending-recovery`.
*/
export interface PendingRecovery {
jail_name: string;
/** ISO-8601 datetime string. */
activated_at: string;
/** ISO-8601 datetime string. */
detected_at: string;
/** True once fail2ban comes back online after the crash. */
recovered: boolean;
}
/** Response from `POST /api/config/jails/{name}/rollback`. */
export interface RollbackResponse {
jail_name: string;
disabled: boolean;
fail2ban_running: boolean;
active_jails: number;
message: string;
}
// ---------------------------------------------------------------------------