base dashboard and login
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Additional Instructions
|
||||
- personal overrides: @~/.claude/CLAUDE.md
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Build
|
||||
go build -o crowdsec-dashy ./cmd/server
|
||||
|
||||
# Production build (static binary, stripped)
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o crowdsec-dashy ./cmd/server
|
||||
|
||||
# Run
|
||||
./crowdsec-dashy
|
||||
|
||||
# Lint / vet
|
||||
go vet ./...
|
||||
|
||||
# Tests (none yet — project is in early build phases)
|
||||
go test ./...
|
||||
|
||||
# Docker
|
||||
docker compose up -d
|
||||
docker compose build
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
**Go 1.26. Zero external Go dependencies.** Stdlib only (`net/http`, `html/template`, `os/exec`, `encoding/json`).
|
||||
|
||||
### Data access — two parallel layers
|
||||
|
||||
| Layer | Package | Coverage |
|
||||
|---|---|---|
|
||||
| CrowdSec LAPI (REST) | `internal/crowdsec/lapi.go` | Decisions CRUD, Alerts, health |
|
||||
| `cscli` exec wrapper | `internal/crowdsec/cli.go` | Bouncers, Machines, Hub, Metrics |
|
||||
|
||||
All shared structs (Decision, Alert, Bouncer, Machine, HubItem, MetricsSection, etc.) live in `internal/crowdsec/types.go`.
|
||||
|
||||
Bouncers, machines, hub, and metrics are **not** exposed via REST — they require `cscli` hitting the database directly. Features that need `cscli` check `Deps.CLIAvailable` and render an inline warning banner when the binary is absent.
|
||||
|
||||
### Package layout
|
||||
|
||||
```
|
||||
cmd/server/main.go entrypoint — loads config, authenticates LAPI, starts HTTP server
|
||||
internal/config/config.go env-var loading; CscliAvailable() stat-checks the binary path
|
||||
internal/crowdsec/
|
||||
types.go all shared structs
|
||||
lapi.go REST client (JWT auth, auto-retry on 401)
|
||||
cli.go cscli exec wrapper (strict allow-list)
|
||||
internal/handlers/
|
||||
renderer.go Renderer, PageData, Deps, SidebarNav
|
||||
dashboard.go / api.go / ... one file per page + JSON API handler
|
||||
internal/middleware/middleware.go BasicAuth, Logger, SecureHeaders, Recovery
|
||||
internal/router/router.go constructs Deps, wires all routes
|
||||
web/templates/layouts/base.html sidebar shell
|
||||
web/templates/pages/*.html one file per page
|
||||
web/static/css/app.css all component styles
|
||||
web/static/js/dashboard.js live stat polling + sparklines
|
||||
web/static/js/tables.js client-side filter/sort/bulk-select
|
||||
```
|
||||
|
||||
### Request flow
|
||||
|
||||
```
|
||||
HTTP request
|
||||
→ middleware chain (BasicAuth → Logger → SecureHeaders → Recovery)
|
||||
→ router.go (stdlib mux)
|
||||
→ handler struct (receives Deps: Renderer, LAPI, CLI, CLIAvailable, PollInterval)
|
||||
→ handler renders to bytes.Buffer first, then writes to ResponseWriter
|
||||
```
|
||||
|
||||
### Dependency injection
|
||||
|
||||
`Deps` struct (`internal/handlers/renderer.go:246`) is constructed once in `router.New()` and passed to every handler constructor. Handlers are structs, not functions.
|
||||
|
||||
### Template system
|
||||
|
||||
`Renderer` (`internal/handlers/renderer.go`) parses all page templates at startup: each page in `web/templates/pages/*.html` is combined with `web/templates/layouts/base.html` into a named `*template.Template`. Templates are keyed by filename without extension (e.g. `"dashboard"`, `"decisions"`). All render calls go through `Renderer.Render(w, name, data)` using the buffer-then-write pattern.
|
||||
|
||||
Template functions available: `inc`, `dec`, `dict`, `decisionBadgeClass`, `originBadgeClass`, `hubStatusClass`, `safeHTML`, `boolIcon`, `truncate`, `join`.
|
||||
|
||||
### LAPI authentication
|
||||
|
||||
On startup, `lapi.Login()` POSTs to `/v1/watchers/login` → JWT stored in memory. All subsequent requests carry `Authorization: Bearer <jwt>`. On 401, `doJSON()` auto-retries with a fresh login once before failing.
|
||||
|
||||
### `cscli` exec security
|
||||
|
||||
All args passed as a slice (never through shell). Two allow-lists enforced before `exec.CommandContext`:
|
||||
- `allowedSubcommands` (first arg): bouncers, machines, collections, parsers, scenarios, postoverflows, hub, metrics, version
|
||||
- `allowedActions` (second arg): list, add, delete, install, remove, update, upgrade, validate
|
||||
- All other user-supplied values validated against `safeArg` regex `^[a-zA-Z0-9_./:@\-]+$`
|
||||
|
||||
### POST pattern
|
||||
|
||||
All state-changing POST handlers use PRG (Post/Redirect/Get). Flash messages are attached to `PageData` via `WithFlash(type, msg)` and displayed on the redirected GET. All POST handlers must apply `http.MaxBytesReader` before parsing the body.
|
||||
|
||||
### Internal JSON API
|
||||
|
||||
Used by frontend JS — all return JSON, protected by the same BasicAuth middleware.
|
||||
|
||||
| Method | Path | Description |
|
||||
|---|---|---|
|
||||
| GET | `/api/v1/stats` | Dashboard summary counts |
|
||||
| GET | `/api/v1/health` | LAPI health + cscli availability |
|
||||
|
||||
### Adding a new page
|
||||
|
||||
1. `internal/handlers/mypage.go` — handler struct with `ServeHTTP` or named methods
|
||||
2. `web/templates/pages/mypage.html` — starts with `{{template "base" .}}`
|
||||
3. Add `NavItem` to `SidebarNav` in `renderer.go`
|
||||
4. `router.go` — `mux.Handle("/mypage", handlers.NewMyPageHandler(deps))`
|
||||
|
||||
### UI design
|
||||
|
||||
Dark industrial aesthetic. Palette: near-black surface `#080b10`, blue-grey panels `#0f1520`, cyan accent `#00d4ff`, threat-red `#ff3b3b`, safe-green `#00e676`. Fonts: `JetBrains Mono` for data, `IBM Plex Sans` for labels. All styles in `web/static/css/app.css`. No external JS frameworks — sparklines drawn with inline SVG `<polyline>`.
|
||||
|
||||
Dashboard live stats poll `/api/v1/stats` via `web/static/js/dashboard.js`. Client-side table filter/sort/bulk-select in `web/static/js/tables.js`.
|
||||
|
||||
### Environment variables
|
||||
|
||||
| Variable | Default | Notes |
|
||||
|---|---|---|
|
||||
| `PORT` | `:8080` | Listen address |
|
||||
| `CROWDSEC_API_URL` | `http://localhost:8080` | LAPI base URL |
|
||||
| `CROWDSEC_API_LOGIN` | *(required)* | Machine login |
|
||||
| `CROWDSEC_API_PASSWORD` | *(required)* | Machine password |
|
||||
| `CSCLI_PATH` | `/usr/local/bin/cscli` | Binary path; CLI features disabled if absent |
|
||||
| `UI_USERNAME` | `admin` | Basic Auth username |
|
||||
| `UI_PASSWORD` | `changeme` | Basic Auth password |
|
||||
| `UI_SESSION_SECRET` | *(required, ≥32 chars)* | HMAC signing key |
|
||||
| `POLL_INTERVAL_SEC` | `15` | Dashboard poll interval (seconds) |
|
||||
Reference in New Issue
Block a user