11 Commits

Author SHA1 Message Date
708f6373f1 feat: alerts view + created-at timestamps on decisions
All checks were successful
Deploy / deploy (push) Successful in 22s
Mirror cscli alerts list: new /alerts endpoint hits LAPI machine auth
with since/ip/scenario/origin filters, renders ID, scope:value, reason,
country, AS, events, decisions, created_at.

Decisions table gains a Created column derived from until - duration
(LAPI does not expose created_at on /v1/decisions). Both views format
timestamps locally and append a relative "x ago" via Intl.RelativeTimeFormat,
refreshed every 30s on the decisions view.
2026-06-21 15:13:14 +02:00
Alex
13e672c18d chore: test auto-redeploy from CI
All checks were successful
Deploy / deploy (push) Successful in 28s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-20 22:51:32 +02:00
f82ef9d82e chore(docker): add HEALTHCHECK probe
All checks were successful
Deploy / deploy (push) Successful in 17s
Python urllib GET / on 127.0.0.1:8000. start_period=30s
gives gunicorn workers time to boot. Lets Docker mark
container unhealthy if Flask app wedges, and feeds
Portainer + diagnose.sh signal that the app is alive.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-20 21:31:33 +02:00
55c4d990b2 test: verify end-to-end webhook flow
All checks were successful
Deploy / deploy (push) Successful in 17s
2026-06-20 12:18:56 +02:00
3f1d2341ce ci: migrate to Portainer Git stack + registry-pushed image
Some checks failed
Deploy / deploy (push) Failing after 24s
- Compose: build → image:latest from Gitea registry (ci namespace)
- Workflow: build + push image + POST Portainer webhook (vs. host docker compose up)
- Drop transient .env write — secrets now live in Portainer stack Env
- Add crowdsec@file middleware (defense-in-depth project rule)

Repo secrets required: REGISTRY_TOKEN, PORTAINER_WEBHOOK_URL.
Rollback branch: pre-portainer-migration.
2026-06-20 12:16:56 +02:00
ff8ed3428f feat: server-side reason/origin/limit filters + client-side row filter
All checks were successful
Deploy / deploy (push) Successful in 17s
Two new performance + UX wins:

- Server: /decisions now accepts reason (scenarios_containing), origin
  (origins), and limit. Default 200, max 2000. Header shows current count
  and warns when at the cap.
- Client: a "quick filter rows" input does substring match across all
  visible columns instantly with no server round-trip. Useful when the
  server-side result is small enough to scroll but you still want to find
  one scenario fast.
- Bulk select-all now toggles only currently visible rows so you can
  filter then bulk-unban.

Drops inline onclick handlers in favor of delegated change listeners to
keep per-row cost low at large limits.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-17 00:08:27 +02:00
a324d5a68d feat: bulk unban via checkboxes
All checks were successful
Deploy / deploy (push) Successful in 23s
Adds per-row checkboxes, a select-all toggle, a live "N selected" counter,
and an /unban-bulk endpoint that DELETEs each chosen decision id. Single-row
Unban buttons still work via hx-vals so they don't accidentally submit the
bulk form.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-17 00:02:59 +02:00
ffe08a3fc4 ci: retrigger after LAPI_BOUNCER_KEY secret added
All checks were successful
Deploy / deploy (push) Successful in 28s
2026-06-16 23:59:45 +02:00
5d589915f7 fix: split LAPI auth — bouncer key for read, machine JWT for delete
All checks were successful
Deploy / deploy (push) Successful in 19s
LAPI does not let machine JWTs hit GET /v1/decisions even after the machine
is validated (returns 403 access forbidden). Conversely, bouncer X-Api-Key
does not satisfy DELETE /v1/decisions (returns 401 "cookie token is empty").

The webapp now holds both credentials and routes each call to the right
authority. Adds LAPI_BOUNCER_KEY env var + Gitea secret.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-16 23:58:20 +02:00
a5971403b2 fix: drop docker healthcheck so Traefik routes immediately
All checks were successful
Deploy / deploy (push) Successful in 20s
Traefik docker provider skips routing for containers whose Docker HEALTHCHECK
reports unhealthy. Our /healthz returns 503 if LAPI is unreachable, which left
the container stuck unhealthy and the router never appeared — every request
returned 404 from Traefik.

/healthz still exists for manual probes; Kuma probes via Traefik also still
work.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-16 23:51:49 +02:00
9c8b4ca0cc feat: initial scaffold of CrowdSec admin webapp
All checks were successful
Deploy / deploy (push) Successful in 39s
Flask + htmx mini-app to list and delete CrowdSec decisions from a browser,
gated behind Authentik. Talks to host LAPI via host.docker.internal:8080
using machine JWT auth (bouncer X-Api-Key is read-only).

Gitea Actions CI/CD on push to main: runner rebuilds image and brings the
stack up via docker compose on the host (same pattern as flight-radar).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-16 23:39:20 +02:00