feat(admin): list active IP auto-bans and lift a ban, audited #329

Merged
Claude-Run merged 1 commit from feat/BUNYIP-319-admin-ip-bans-api into main 2026-07-04 00:31:39 +02:00
Member

Add an admin-only API surface over the IP auto-ban subsystem. Handlers reach the shared AutoBanService via actix app data (web::Data::from the existing Arc registered in main.rs), so both operations act on the same in-memory ban map the middleware enforces rather than the ip_bans table directly.

  • GET /v1/admin/ip-bans returns every currently-active ban (IP, reason, strikes, banned_at, expires_at) via AutoBanService::list_bans. BanInfo now derives Serialize so it renders directly as the response element.
  • DELETE /v1/admin/ip-bans/{ip} parses the path IP (400 on a malformed value), lifts the ban via AutoBanService::unban (clears the in-memory map, strikes, and the persisted row), returns 404 when the IP was not banned, and records an audit entry on success.
  • New AuditAction::AdminIpBanLifted variant with as_str = admin_ip_ban_lifted, classified as an admin action; the recorded entry carries the acting admin and target IP.

Both routes are AdminUser-guarded. A middleware-level integration test drives the real AutoBanMiddleware: a banned IP is 403-ed, unban lifts it, and the same IP's next request passes with 200.

#BUNYIP-319

Add an admin-only API surface over the IP auto-ban subsystem. Handlers reach the shared `AutoBanService` via actix app data (`web::Data::from` the existing Arc registered in `main.rs`), so both operations act on the same in-memory ban map the middleware enforces rather than the `ip_bans` table directly. - `GET /v1/admin/ip-bans` returns every currently-active ban (IP, reason, strikes, banned_at, expires_at) via `AutoBanService::list_bans`. `BanInfo` now derives `Serialize` so it renders directly as the response element. - `DELETE /v1/admin/ip-bans/{ip}` parses the path IP (400 on a malformed value), lifts the ban via `AutoBanService::unban` (clears the in-memory map, strikes, and the persisted row), returns 404 when the IP was not banned, and records an audit entry on success. - New `AuditAction::AdminIpBanLifted` variant with `as_str` = `admin_ip_ban_lifted`, classified as an admin action; the recorded entry carries the acting admin and target IP. Both routes are AdminUser-guarded. A middleware-level integration test drives the real `AutoBanMiddleware`: a banned IP is 403-ed, `unban` lifts it, and the same IP's next request passes with 200. #BUNYIP-319
feat(admin): list active IP auto-bans and lift a ban, audited
All checks were successful
E2E / Playwright against deployment (pull_request) Successful in 27s
Check / fmt + clippy + build + tests (pull_request) Successful in 9m31s
Create release / Create release from merged PR (pull_request) Has been skipped
7ed090513e
Add an admin-only API surface over the IP auto-ban subsystem. Handlers reach the shared `AutoBanService` via actix app data (`web::Data::from` the existing Arc registered in `main.rs`), so both operations act on the same in-memory ban map the middleware enforces rather than the `ip_bans` table directly.

- `GET /v1/admin/ip-bans` returns every currently-active ban (IP, reason, strikes, banned_at, expires_at) via `AutoBanService::list_bans`. `BanInfo` now derives `Serialize` so it renders directly as the response element.
- `DELETE /v1/admin/ip-bans/{ip}` parses the path IP (400 on a malformed value), lifts the ban via `AutoBanService::unban` (clears the in-memory map, strikes, and the persisted row), returns 404 when the IP was not banned, and records an audit entry on success.
- New `AuditAction::AdminIpBanLifted` variant with `as_str` = `admin_ip_ban_lifted`, classified as an admin action; the recorded entry carries the acting admin and target IP.

Both routes are AdminUser-guarded. A middleware-level integration test drives the real `AutoBanMiddleware`: a banned IP is 403-ed, `unban` lifts it, and the same IP's next request passes with 200.

#BUNYIP-319
Claude-Run deleted branch feat/BUNYIP-319-admin-ip-bans-api 2026-07-04 00:31:39 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/bunyip!329
No description provided.