update_server/docs/agents/handoffs/07-security-deploy.md
2026-06-10 20:51:17 +03:00

134 lines
7.4 KiB
Markdown

# Agent
Name: Agent 07 - Security And Deployment Hardening
Stage: Security And Deployment Hardening
Date: 2026-04-15
## Scope
Hardened the existing Go/chi/SQLite application for internet-facing deployment without changing the product model or admin/client flow.
Completed in this stage:
- added stricter HTTP server defaults:
- `ReadHeaderTimeout`
- `MaxHeaderBytes`
- higher default read/write/idle timeouts suitable for uploads and authenticated downloads
- added global security headers and route-specific cache controls:
- `Content-Security-Policy`
- `X-Frame-Options`
- `X-Content-Type-Options`
- `Referrer-Policy`
- `Permissions-Policy`
- `Cross-Origin-Opener-Policy`
- `Cross-Origin-Resource-Policy`
- `Strict-Transport-Security` when `APP_BASE_URL` is `https`
- `Cache-Control: no-store` on admin and protected client API responses
- `Vary: Cookie` or `Vary: Authorization` on the appropriate routes
- added trusted-proxy awareness so forwarded headers are only trusted when `TRUST_PROXY_HEADERS=true`;
- added in-memory rate limiting for:
- `POST /admin/login`
- protected client API routes under `/api/v1`
- added CSRF protection for all admin POST flows, including login, logout, project/tag/API key forms, tag attach or detach, archive or restore, and multipart release upload;
- rotated or cleared the admin CSRF cookie on login and logout, and scoped both session and CSRF cookies to `/admin`;
- tightened local data directory permissions for SQLite and data storage;
- added regression coverage for CSRF rejection, hardened cookie defaults, security headers, and both rate-limited route groups;
- added first-pass deployment assets:
- multi-stage `Dockerfile`
- hardened `docker-compose.yml`
- Caddy example
- Nginx example
- env example
- deployment, Proxmox, backup, and restore notes.
## Files Changed
- `/Users/delete/projects/update_server/internal/config/config.go`
- `/Users/delete/projects/update_server/internal/app/app.go`
- `/Users/delete/projects/update_server/internal/db/open.go`
- `/Users/delete/projects/update_server/internal/auth/service.go`
- `/Users/delete/projects/update_server/internal/http/router.go`
- `/Users/delete/projects/update_server/internal/http/security.go`
- `/Users/delete/projects/update_server/internal/http/rate_limit.go`
- `/Users/delete/projects/update_server/internal/http/csrf.go`
- `/Users/delete/projects/update_server/internal/http/auth_handlers.go`
- `/Users/delete/projects/update_server/internal/http/admin_common.go`
- `/Users/delete/projects/update_server/internal/http/admin_api_keys.go`
- `/Users/delete/projects/update_server/internal/http/view_data.go`
- `/Users/delete/projects/update_server/internal/http/auth_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/projects_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/api_keys_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/security_integration_test.go`
- `/Users/delete/projects/update_server/web/templates/layouts/base.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/login.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/project_form.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/project_detail.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/tag_form.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/api_key_form.gohtml`
- `/Users/delete/projects/update_server/web/templates/partials/csrf_field.gohtml`
- `/Users/delete/projects/update_server/.dockerignore`
- `/Users/delete/projects/update_server/Dockerfile`
- `/Users/delete/projects/update_server/docker-compose.yml`
- `/Users/delete/projects/update_server/deploy/Caddyfile.example`
- `/Users/delete/projects/update_server/deploy/nginx.update-server.conf.example`
- `/Users/delete/projects/update_server/deploy/update-server.env.example`
- `/Users/delete/projects/update_server/docs/DEPLOYMENT.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/07-security-deploy.md`
## Database Changes
- no migrations or schema changes were required;
- SQLite remains the production database;
- deployment notes now explicitly call out WAL-mode backup and restore handling for:
- `db.sqlite`
- `db.sqlite-wal`
- `db.sqlite-shm`
- `artifacts/`.
## API Or Route Changes
- no new product endpoints were added;
- middleware behavior changed for existing routes:
- all `/admin` responses now emit hardened headers and `no-store` caching rules;
- all `/admin` POST routes now require a valid CSRF token;
- `POST /admin/login` is rate limited by client IP;
- protected `/api/v1` routes now emit hardened headers and `no-store` caching rules;
- protected `/api/v1` routes are rate limited by client IP before API-key auth;
- session cookies are now scoped to `/admin` and retain `HttpOnly`, `SameSite=Lax`, and conditional `Secure`;
- CSRF cookies are now scoped to `/admin` and use `HttpOnly`, `SameSite=Strict`, and conditional `Secure`.
## Commands And Tests Run
- `gofmt -w internal/config/config.go internal/app/app.go internal/db/open.go internal/auth/service.go internal/http/router.go internal/http/security.go internal/http/rate_limit.go internal/http/csrf.go internal/http/auth_handlers.go internal/http/view_data.go internal/http/admin_common.go internal/http/admin_api_keys.go internal/http/auth_integration_test.go internal/http/projects_integration_test.go internal/http/api_keys_integration_test.go internal/http/security_integration_test.go` - passed
- `go test ./internal/http` - passed
- `go test ./...` - passed
- `go build ./cmd/server` - passed
- `go build ./cmd/migrate` - passed
- `docker compose config` - could not run in this environment because `docker` is not installed
## Known Limitations
- rate limiting is in-memory and per-process, so counters reset on restart and are not shared across multiple app instances;
- Docker and reverse-proxy examples were added and reviewed statically, but they were not live-validated here because Docker is unavailable in this workspace;
- `Strict-Transport-Security` only appears when `APP_BASE_URL` is configured with `https`, which is the intended production setup behind TLS termination;
- the proxy still must be configured correctly to keep the app private and to strip or control forwarded headers before `TRUST_PROXY_HEADERS=true` is safe.
## Recommended Next Step
Run the Agent 07 validation pass, with special attention to:
- CSRF enforcement on every admin POST flow, including multipart upload;
- security headers and private-cache headers on admin and protected client API responses;
- login and client API rate limiting behavior;
- cookie flags and `/admin` cookie scoping;
- deployment docs and example proxy/container files on a host that has Docker and a reverse proxy available.
## Notes For Validator
- verify that a missing or invalid admin CSRF token returns `403` and that the normal admin flows still succeed when the token is present;
- verify that session cookies are only scoped to `/admin` and that secure-cookie behavior follows the configured `APP_BASE_URL` scheme;
- verify that `TRUST_PROXY_HEADERS=false` leaves client IP handling on the socket remote address;
- verify that protected `/api/v1` responses include `Cache-Control: no-store`, `Vary: Authorization`, and the shared security headers;
- if possible, validate `docker compose up --build` plus one reverse-proxy example on a real machine, since that could not be executed in this environment.