mirror of
https://github.com/apidoorman/doorman.git
synced 2026-02-08 18:18:46 -06:00
updates
This commit is contained in:
31
README.md
31
README.md
@@ -121,9 +121,40 @@ Defaults
|
||||
- Backend: http://localhost:5001
|
||||
- Web: http://localhost:3000 (set NEXT_PUBLIC_SERVER_URL accordingly)
|
||||
|
||||
## Docker
|
||||
- Compose up: `docker compose up --build`
|
||||
- Services: backend (`:5001`), web (`:3000`), redis (`:6379`)
|
||||
- Secrets: set `JWT_SECRET_KEY`, `TOKEN_ENCRYPTION_KEY`, `MEM_ENCRYPTION_KEY` via env/secret manager (avoid checking into git)
|
||||
- Override backend envs: `docker compose run -e KEY=value backend ...`
|
||||
- Reset volumes/logs: `docker compose down -v`
|
||||
|
||||
Smoke checks
|
||||
- Liveness: `curl -s http://localhost:5001/platform/monitor/liveness` → `{ "status": "alive" }`
|
||||
- Readiness: `curl -s http://localhost:5001/platform/monitor/readiness` → `{ status: "ready", ... }`
|
||||
- Auth login: `curl -s -c cookies.txt -H 'Content-Type: application/json' -d '{"email":"admin@localhost","password":"password1"}' http://localhost:5001/platform/authorization`
|
||||
- Auth status: `curl -s -b cookies.txt http://localhost:5001/platform/authorization/status`
|
||||
- One-liner: `BASE_URL=http://localhost:5001 STARTUP_ADMIN_EMAIL=admin@localhost STARTUP_ADMIN_PASSWORD=password1 bash scripts/smoke.sh`
|
||||
|
||||
Production notes
|
||||
- Use Redis in production (`MEM_OR_EXTERNAL=REDIS`) for distributed rate limiting.
|
||||
- In memory-only mode, run a single worker: `THREADS=1`.
|
||||
- Optional: set `LOG_FORMAT=json` for structured logs.
|
||||
|
||||
Production security defaults
|
||||
- Set `CORS_STRICT=true` and explicitly whitelist your origins via `ALLOWED_ORIGINS`.
|
||||
- Enable `HTTPS_ONLY=true` and `HTTPS_ENABLED=true` so cookies are Secure and CSRF validation is enforced.
|
||||
|
||||
Quick go-live checklist
|
||||
- Start stack: `docker compose up --build`
|
||||
- Verify health:
|
||||
- `curl -s http://localhost:5001/platform/monitor/liveness` → `{ "status": "alive" }`
|
||||
- `curl -s http://localhost:5001/platform/monitor/readiness` → `{ status: "ready", ... }`
|
||||
- Smoke auth:
|
||||
- `curl -s -c cookies.txt -H 'Content-Type: application/json' -d '{"email":"admin@localhost","password":"password1"}' http://localhost:5001/platform/authorization`
|
||||
- `curl -s -b cookies.txt http://localhost:5001/platform/authorization/status`
|
||||
- Web: Ensure `web-client/.env.local` has `NEXT_PUBLIC_SERVER_URL=http://localhost:5001`, then `npm run build && npm start` (or use compose service `web`).
|
||||
|
||||
Optional: run `bash scripts/smoke.sh` (uses `BASE_URL`, `STARTUP_ADMIN_EMAIL`, `STARTUP_ADMIN_PASSWORD`).
|
||||
```
|
||||
|
||||
## Web UI
|
||||
|
||||
@@ -9,7 +9,7 @@ Recommended production defaults (see `.env`):
|
||||
- HTTPS_ONLY=true — set `Secure` flag on cookies
|
||||
- HTTPS_ENABLED=true — enforce CSRF double-submit for cookie auth
|
||||
- CORS_STRICT=true — disallow wildcard origins; whitelist your domains via `ALLOWED_ORIGINS`
|
||||
- HTTPS_ONLY=true and HTTPS_ENABLED=true — set Secure cookies and enforce CSRF double-submit
|
||||
- LOG_FORMAT=json — optional JSON log output for production log pipelines
|
||||
- MAX_BODY_SIZE_BYTES=1048576 — reject requests with Content-Length above 1 MB
|
||||
- STRICT_RESPONSE_ENVELOPE=true — platform APIs return consistent envelopes
|
||||
|
||||
@@ -56,6 +56,7 @@ Core variables:
|
||||
3. Set ALLOWED_ORIGINS to your web client domains; set ALLOW_CREDENTIALS=true only when needed.
|
||||
4. Provision Redis (recommended) and MongoDB (optional in memory-only mode). In memory mode, enable encryption key for dumps and consider TOKEN_ENCRYPTION_KEY for API keys.
|
||||
5. Rotate JWT_SECRET_KEY periodically; plan for key rotation and token invalidation.
|
||||
6. Memory-only mode requires a single worker (THREADS=1); multiple workers will have divergent in-memory state.
|
||||
|
||||
## Runbooks
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ from utils.database import database
|
||||
|
||||
import multiprocessing
|
||||
import logging
|
||||
import json
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
@@ -241,7 +242,22 @@ log_file_handler = RotatingFileHandler(
|
||||
backupCount=5,
|
||||
encoding="utf-8"
|
||||
)
|
||||
log_file_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
|
||||
if os.getenv("LOG_FORMAT", "plain").lower() == "json":
|
||||
class JSONFormatter(logging.Formatter):
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
payload = {
|
||||
"time": self.formatTime(record, "%Y-%m-%dT%H:%M:%S"),
|
||||
"name": record.name,
|
||||
"level": record.levelname,
|
||||
"message": record.getMessage(),
|
||||
}
|
||||
try:
|
||||
return json.dumps(payload, ensure_ascii=False)
|
||||
except Exception:
|
||||
return f'{payload}'
|
||||
log_file_handler.setFormatter(JSONFormatter())
|
||||
else:
|
||||
log_file_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
|
||||
|
||||
# Configure all doorman loggers to use the same handler and prevent propagation
|
||||
def configure_logger(logger_name):
|
||||
@@ -435,6 +451,12 @@ def run():
|
||||
max_threads = multiprocessing.cpu_count()
|
||||
env_threads = int(os.getenv("THREADS", max_threads))
|
||||
num_threads = min(env_threads, max_threads)
|
||||
try:
|
||||
if database.memory_only and num_threads != 1:
|
||||
gateway_logger.info("Memory-only mode detected; forcing single worker to avoid divergent state")
|
||||
num_threads = 1
|
||||
except Exception:
|
||||
pass
|
||||
gateway_logger.info(f"Started doorman with {num_threads} threads on port {server_port}")
|
||||
uvicorn.run(
|
||||
"doorman:doorman",
|
||||
|
||||
25
scripts/smoke.sh
Normal file
25
scripts/smoke.sh
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
BASE_URL="${BASE_URL:-http://localhost:5001}"
|
||||
EMAIL="${STARTUP_ADMIN_EMAIL:-admin@localhost}"
|
||||
PASSWORD="${STARTUP_ADMIN_PASSWORD:-password1}"
|
||||
|
||||
echo "[1/4] Checking liveness..."
|
||||
curl -sfS "$BASE_URL/platform/monitor/liveness" | grep -q '"alive"' && echo "OK" || { echo "Liveness failed"; exit 1; }
|
||||
|
||||
echo "[2/4] Checking readiness..."
|
||||
curl -sfS "$BASE_URL/platform/monitor/readiness" | grep -q '"ready"' && echo "OK" || { echo "Readiness degraded"; exit 1; }
|
||||
|
||||
echo "[3/4] Logging in..."
|
||||
COOKIE_JAR="$(mktemp)"
|
||||
trap 'rm -f "$COOKIE_JAR"' EXIT
|
||||
curl -sfS -c "$COOKIE_JAR" -H 'Content-Type: application/json' \
|
||||
-d "{\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\"}" \
|
||||
"$BASE_URL/platform/authorization" > /dev/null && echo "OK" || { echo "Login failed"; exit 1; }
|
||||
|
||||
echo "[4/4] Verifying token status..."
|
||||
curl -sfS -b "$COOKIE_JAR" "$BASE_URL/platform/authorization/status" | grep -q '"Token is valid"' && echo "OK" || { echo "Token status check failed"; exit 1; }
|
||||
|
||||
echo "Smoke checks passed."
|
||||
|
||||
Reference in New Issue
Block a user