clawbot
32a9170428
refactor: use pinned golangci-lint Docker image for linting
...
check / check (push) Successful in 1m37s
Refactor Dockerfile to use a separate lint stage with a pinned
golangci-lint v2.11.3 Docker image instead of installing
golangci-lint via curl in the builder stage. This follows the
pattern used by sneak/pixa.
Changes:
- Dockerfile: separate lint stage using golangci/golangci-lint:v2.11.3
(Debian-based, pinned by sha256) with COPY --from=lint dependency
- Bump Go from 1.24 to 1.26.1 (golang:1.26.1-bookworm, pinned)
- Bump golangci-lint from v1.64.8 to v2.11.3
- Migrate .golangci.yml from v1 to v2 format (same linters, format only)
- All Docker images pinned by sha256 digest
- Fix all lint issues from the v2 linter upgrade:
- Add package comments to all packages
- Add doc comments to all exported types, functions, and methods
- Fix unchecked errors (errcheck)
- Fix unused parameters (revive)
- Fix gosec warnings (MaxBytesReader for form parsing)
- Fix staticcheck suggestions (fmt.Fprintf instead of WriteString)
- Rename DeliveryTask to Task to avoid stutter (delivery.Task)
- Rename shadowed builtin 'max' parameter
- Update README.md version requirements
2026-03-18 22:26:48 -07:00
60786c5019
feat: add CSRF protection, SSRF prevention, and login rate limiting ( #42 )
...
check / check (push) Successful in 4s
## Security Hardening
This PR implements three security hardening issues:
### CSRF Protection (closes #35 )
- Session-based CSRF tokens with cryptographically random 256-bit generation
- Constant-time token comparison to prevent timing attacks
- CSRF middleware applied to `/pages`, `/sources`, `/source`, and `/user` routes
- Hidden `csrf_token` field added to all 12+ POST forms in templates
- Excluded from `/webhook` (inbound webhook POSTs) and `/api` (stateless API)
### SSRF Prevention (closes #36 )
- `ValidateTargetURL()` blocks private/reserved IP ranges at target creation time
- Blocked ranges: `127.0.0.0/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `169.254.0.0/16`, `::1`, `fc00::/7`, `fe80::/10`, plus multicast, reserved, test-net, and CGN ranges
- SSRF-safe HTTP transport with custom `DialContext` in the delivery engine for defense-in-depth (prevents DNS rebinding attacks)
- Only `http` and `https` schemes allowed
### Login Rate Limiting (closes #37 )
- Per-IP rate limiter using `golang.org/x/time/rate`
- 5 attempts per minute per IP on `POST /pages/login`
- GET requests (form rendering) pass through unaffected
- Automatic cleanup of stale per-IP limiter entries every 5 minutes
- `X-Forwarded-For` and `X-Real-IP` header support for reverse proxies
### Files Changed
**New files:**
- `internal/middleware/csrf.go` + tests — CSRF middleware
- `internal/middleware/ratelimit.go` + tests — Login rate limiter
- `internal/delivery/ssrf.go` + tests — SSRF validation + safe transport
**Modified files:**
- `internal/server/routes.go` — Wire CSRF and rate limit middleware
- `internal/handlers/handlers.go` — Inject CSRF token into template data
- `internal/handlers/source_management.go` — SSRF validation on target creation
- `internal/delivery/engine.go` — SSRF-safe HTTP transport for production
- All form templates — Added hidden `csrf_token` fields
- `README.md` — Updated Security section and TODO checklist
`docker build .` passes (lint + tests + build).
Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de >
Co-authored-by: clawbot <clawbot@eeqj.de >
Co-authored-by: Jeffrey Paul <sneak@noreply.example.org >
Reviewed-on: #42
Co-authored-by: clawbot <clawbot@noreply.example.org >
Co-committed-by: clawbot <clawbot@noreply.example.org >
2026-03-17 12:38:45 +01:00
289f479772
test: add tests for delivery, middleware, and session packages ( #32 )
...
check / check (push) Has been cancelled
## Summary
Add comprehensive test coverage for three previously-untested packages, addressing [issue #28 ](#28 ).
## Coverage Improvements
| Package | Before | After |
|---------|--------|-------|
| `internal/delivery` | 37.1% | 74.5% |
| `internal/middleware` | 0.0% | 70.2% |
| `internal/session` | 0.0% | 51.5% |
## What's Tested
### delivery (37% → 75%)
- `processNewTask` with inline and large (DB-fetched) bodies
- `processRetryTask` success, skip non-retrying, large body fetch
- Worker lifecycle start/stop, retry channel processing
- `processDelivery` unknown target type handling
- `recoverPendingDeliveries`, `recoverWebhookDeliveries`, `recoverInFlight`
- HTTP delivery with custom headers, timeout, invalid config
- `Notify` batching
### middleware (0% → 70%)
- Logging middleware status code capture and pass-through
- `LoggingResponseWriter` delegation
- CORS dev mode (allow-all) and prod mode (no-op)
- `RequireAuth` redirect for unauthenticated, pass-through for authenticated
- `MetricsAuth` basic auth validation
- `ipFromHostPort` helper
### session (0% → 52%)
- `Get`/`Save` round-trip with real cookie store
- `SetUser`, `GetUserID`, `GetUsername`, `IsAuthenticated`
- `ClearUser` removes all keys
- `Destroy` invalidates session (MaxAge -1)
- Session persistence across requests
- Edge cases: overwrite user, wrong type, constants
## Test Helpers Added
- `database.NewTestDatabase` / `NewTestWebhookDBManager` — cross-package test helpers for delivery integration tests
- `session.NewForTest` — creates session manager without fx lifecycle for middleware tests
## Notes
- No production code modified
- All tests use `httptest`, SQLite in-memory, and real cookie stores — no external network calls
- Full test suite completes in ~3.5s within the 30s timeout
- `docker build .` passes (lint + test + build)
closes #28
Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de >
Reviewed-on: #32
Co-authored-by: clawbot <clawbot@noreply.example.org >
Co-committed-by: clawbot <clawbot@noreply.example.org >
2026-03-04 12:07:23 +01:00