From 7edb9bdd35ff12cb9b1c5602e23bdbe446249b98 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 14 Apr 2026 15:47:04 +0000 Subject: [PATCH] fix(headers): replace MutableHeaders.pop() with compatible delete pattern The starlette MutableHeaders class does not have a pop() method. Replace with a guard + del pattern that works across all starlette versions. Also add AGENTS.md with Cursor Cloud specific development instructions. Co-authored-by: Bobcatsfan33 --- AGENTS.md | 30 ++++++++++++++++++++++++++++++ modules/security/headers.py | 3 ++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3174024 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,30 @@ +# AGENTS.md + +## Cursor Cloud specific instructions + +### Product overview + +TokenDNA / Aegis Security Platform — a zero-trust token integrity and session behavioral analytics FastAPI backend. See `README.md` for full architecture and API reference. + +### Required services + +| Service | How to start | Notes | +|---------|-------------|-------| +| **Redis** | `redis-server --daemonize yes` | Hard dependency. Must be running before the app starts. | +| **TokenDNA API** | `DEV_MODE=true uvicorn api:app --host 0.0.0.0 --port 8000 --reload` | `DEV_MODE=true` bypasses OIDC/JWT auth; uses a synthetic dev-user. | + +ClickHouse is optional for local dev — the app starts without it (reports `clickhouse: false` in health check). Slack/SIEM webhooks and OIDC providers are also optional. + +### Environment setup caveats + +- The `/data` directory must exist and be writable (used for SQLite tenant DB). Run `sudo mkdir -p /data && sudo chmod 777 /data` if it doesn't exist. +- Copy `.env.example` to `.env` and set `DEV_MODE=true`, `REDIS_HOST=localhost`, `CLICKHOUSE_HOST=localhost`. +- `starlette` must be pinned to `<1.0.0` (e.g. `starlette>=0.46.0,<1.0.0`) to avoid `MutableHeaders.pop()` incompatibility. The update script handles this. + +### Running commands + +- **Lint:** `ruff check .` (config in `pyproject.toml`) +- **Tests:** `pytest tests/ -v` (155 unit tests, no external services needed) +- **Dev server:** `DEV_MODE=true uvicorn api:app --host 0.0.0.0 --port 8000 --reload` +- **Health check:** `curl http://localhost:8000/` +- **Token integrity check (dev):** `curl http://localhost:8000/secure` (uses synthetic dev-user in DEV_MODE) diff --git a/modules/security/headers.py b/modules/security/headers.py index d6350c5..e389908 100644 --- a/modules/security/headers.py +++ b/modules/security/headers.py @@ -114,7 +114,8 @@ async def dispatch(self, request: Request, call_next) -> Response: # ── Scrub server fingerprint ─────────────────────────────────────── response.headers["Server"] = "Aegis" - response.headers.pop("X-Powered-By", None) + if "X-Powered-By" in response.headers: + del response.headers["X-Powered-By"] # ── Correlation ID passthrough ───────────────────────────────────── response.headers["X-Correlation-ID"] = correlation_id