Bump versions, add security middleware & deps
Browse filesNormalize project versioning to 1.0.0 and apply security/middleware and dependency updates. Changes include: update CHANGELOG, app.py and codelens.yaml versions; add TrustedHostMiddleware, ProxyHeadersMiddleware and an HTTP middleware to inject security headers (CSP, HSTS, X-Frame-Options, etc.), adjust CORS behavior and keep rate limiting; update health_check version. Update dashboard/package.json (version, $schema, bumped runtime and dev dependency versions) and expand/modernize dashboard/tsconfig.json compiler options for bundler/strict linting. Bump and relax multiple Python package pins in requirements.txt (fastapi, uvicorn, pydantic, httpx, openai, sqlmodel, pytest-cov, aiofiles, etc.). Also tidy changelog entries (testing, docker, CI/branding notes).
- CHANGELOG.md +15 -27
- app.py +28 -4
- codelens.yaml +1 -1
- dashboard/package.json +14 -13
- dashboard/tsconfig.json +17 -5
- requirements.txt +14 -14
|
@@ -3,7 +3,7 @@
|
|
| 3 |
All notable changes to this project are documented here.
|
| 4 |
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
| 5 |
|
| 6 |
-
## [
|
| 7 |
|
| 8 |
### Added
|
| 9 |
- **Models**: Complete Pydantic v2 models (`TaskId`, `Action`, `Scenario`, `EpisodeResult`, etc.)
|
|
@@ -23,36 +23,24 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
| 23 |
- **Security**:
|
| 24 |
- Rate limiting via `slowapi`: 60 req/min per IP (configurable)
|
| 25 |
- API key authentication: optional, off by default, enabled via `API_KEY_ENABLED=true`
|
|
|
|
| 26 |
- **Episode Lifecycle**: Auto-cleanup of expired episodes every 5 minutes (default 1hr)
|
| 27 |
- **Leaderboard**: Paginated `/leaderboard?limit=N&offset=M&task_id=X`
|
| 28 |
- **Baseline Agent**: Full rewrite with argparse CLI, `KeywordAgent` (35 rules), `LLMAgent` (Claude)
|
| 29 |
- **Evaluation**: `scripts/evaluate.py` for batch evaluation of all 30 scenarios with summary report and progress bars
|
| 30 |
-
- **
|
| 31 |
-
- **
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
- `tests/test_database.py`: Persistence layer unit tests
|
| 35 |
-
- **Dockerization**: Multi-stage `builder` + `production` builds with non-root user security
|
| 36 |
-
- **CI/CD**: Unified 5-job pipeline (`lint`, `test`, `validate`, `docker-build`, `publish` to GHCR)
|
| 37 |
-
- **Branding**: Full rebrand to **CodeLens.**, including signature typography and SVG iconography
|
| 38 |
|
| 39 |
### Fixed
|
| 40 |
-
- **CLI**: Port mismatch in `baseline.py` (8000 → 7860) and added `--url`, `--task`, `--seed` CLI flags
|
| 41 |
-
- **Crash Fixes**: Leaderboard submit crash after list slicing (captured rank before slice)
|
| 42 |
-
- **WebSocket**: Disconnect now handled with typed `WebSocketDisconnect` and `clients.discard()`
|
| 43 |
-
- **Metadata**: Incoherent weight structure in `codelens.yaml` replaced with named, accurate pairs
|
|
|
|
| 44 |
|
| 45 |
-
##
|
| 46 |
-
-
|
| 47 |
-
-
|
| 48 |
-
|
| 49 |
-
## [1.0.0] - Original Fork Baseline
|
| 50 |
-
|
| 51 |
-
### Added
|
| 52 |
-
- FastAPI skeleton with /reset, /step, /result, /leaderboard, /submit endpoints
|
| 53 |
-
- In-memory episode storage
|
| 54 |
-
- WebSocket event broadcasting at /ws/events
|
| 55 |
-
- Basic Dockerfile
|
| 56 |
-
- Pylint-only GitHub Actions workflow
|
| 57 |
-
- codelens.yaml placeholder
|
| 58 |
-
- README with roadmap
|
|
|
|
| 3 |
All notable changes to this project are documented here.
|
| 4 |
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
| 5 |
|
| 6 |
+
## [1.0.0] - 2026-04-05
|
| 7 |
|
| 8 |
### Added
|
| 9 |
- **Models**: Complete Pydantic v2 models (`TaskId`, `Action`, `Scenario`, `EpisodeResult`, etc.)
|
|
|
|
| 23 |
- **Security**:
|
| 24 |
- Rate limiting via `slowapi`: 60 req/min per IP (configurable)
|
| 25 |
- API key authentication: optional, off by default, enabled via `API_KEY_ENABLED=true`
|
| 26 |
+
- Added `TrustedHostMiddleware` and `Security Headers` (XSS, Frame protection)
|
| 27 |
- **Episode Lifecycle**: Auto-cleanup of expired episodes every 5 minutes (default 1hr)
|
| 28 |
- **Leaderboard**: Paginated `/leaderboard?limit=N&offset=M&task_id=X`
|
| 29 |
- **Baseline Agent**: Full rewrite with argparse CLI, `KeywordAgent` (35 rules), `LLMAgent` (Claude)
|
| 30 |
- **Evaluation**: `scripts/evaluate.py` for batch evaluation of all 30 scenarios with summary report and progress bars
|
| 31 |
+
- **Testing**: 155+ parametrized tests with full coverage reporting.
|
| 32 |
+
- **Dockerization**: Multi-stage `builder` + `production` builds with non-root user security.
|
| 33 |
+
- **CI/CD**: Unified 5-job pipeline (`lint`, `test`, `validate`, `docker-build`, `publish` to GHCR).
|
| 34 |
+
- **Branding**: Full rebrand to **CodeLens.**, including signature iconography.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
### Fixed
|
| 37 |
+
- **CLI**: Port mismatch in `baseline.py` (8000 → 7860) and added `--url`, `--task`, `--seed` CLI flags.
|
| 38 |
+
- **Crash Fixes**: Leaderboard submit crash after list slicing (captured rank before slice).
|
| 39 |
+
- **WebSocket**: Disconnect now handled with typed `WebSocketDisconnect` and `clients.discard()`.
|
| 40 |
+
- **Metadata**: Incoherent weight structure in `codelens.yaml` replaced with named, accurate pairs.
|
| 41 |
+
- **Security**: Implemented `TrustedHostMiddleware` and hardened headers.
|
| 42 |
|
| 43 |
+
## [0.1.0] - Initial Baseline Fork
|
| 44 |
+
- Initial FastAPI skeleton.
|
| 45 |
+
- In-memory episode storage.
|
| 46 |
+
- Basic Dockerfile and Pylint-only CI.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -64,11 +64,24 @@ app = FastAPI(
|
|
| 64 |
"Trains agents to detect bugs, security vulnerabilities, and architectural issues "
|
| 65 |
"in realistic Python PRs."
|
| 66 |
),
|
| 67 |
-
version="
|
| 68 |
lifespan=lifespan,
|
| 69 |
)
|
| 70 |
|
| 71 |
-
# ──
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
app.add_middleware(
|
| 73 |
CORSMiddleware,
|
| 74 |
allow_origins=["*"] if settings.app_env == "development" else [f"http://localhost:{settings.app_port}"],
|
|
@@ -77,7 +90,18 @@ app.add_middleware(
|
|
| 77 |
allow_headers=["*"],
|
| 78 |
)
|
| 79 |
|
| 80 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
limiter = Limiter(key_func=get_remote_address, default_limits=[f"{settings.rate_limit_per_minute}/minute"])
|
| 82 |
app.state.limiter = limiter
|
| 83 |
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
|
@@ -169,7 +193,7 @@ async def http_exception_handler(request, exc):
|
|
| 169 |
def health_check():
|
| 170 |
return {
|
| 171 |
"status": "ok",
|
| 172 |
-
"version": "
|
| 173 |
"env_ready": True,
|
| 174 |
"env": settings.app_env,
|
| 175 |
"active_episodes": len(episodes),
|
|
|
|
| 64 |
"Trains agents to detect bugs, security vulnerabilities, and architectural issues "
|
| 65 |
"in realistic Python PRs."
|
| 66 |
),
|
| 67 |
+
version="1.0.0",
|
| 68 |
lifespan=lifespan,
|
| 69 |
)
|
| 70 |
|
| 71 |
+
# ── Security & Middleware ──────────────────────────────────────────────────
|
| 72 |
+
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
| 73 |
+
from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware
|
| 74 |
+
|
| 75 |
+
# 1. Trusted Host (Prevent Host-header injection)
|
| 76 |
+
app.add_middleware(
|
| 77 |
+
TrustedHostMiddleware,
|
| 78 |
+
allowed_hosts=["*"] if settings.app_env == "development" else [f"localhost", "127.0.0.1", "*.github.io"]
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
# 2. Proxy Headers (Support Docker/Reverse-proxy)
|
| 82 |
+
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")
|
| 83 |
+
|
| 84 |
+
# 3. CORS
|
| 85 |
app.add_middleware(
|
| 86 |
CORSMiddleware,
|
| 87 |
allow_origins=["*"] if settings.app_env == "development" else [f"http://localhost:{settings.app_port}"],
|
|
|
|
| 90 |
allow_headers=["*"],
|
| 91 |
)
|
| 92 |
|
| 93 |
+
# 4. Security Headers Middleware
|
| 94 |
+
@app.middleware("http")
|
| 95 |
+
async def add_security_headers(request: Request, call_next):
|
| 96 |
+
response = await call_next(request)
|
| 97 |
+
response.headers["X-Content-Type-Options"] = "nosniff"
|
| 98 |
+
response.headers["X-Frame-Options"] = "DENY"
|
| 99 |
+
response.headers["X-XSS-Protection"] = "1; mode=block"
|
| 100 |
+
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
|
| 101 |
+
response.headers["Content-Security-Policy"] = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' ws: wss:;"
|
| 102 |
+
return response
|
| 103 |
+
|
| 104 |
+
# 5. Rate Limiting
|
| 105 |
limiter = Limiter(key_func=get_remote_address, default_limits=[f"{settings.rate_limit_per_minute}/minute"])
|
| 106 |
app.state.limiter = limiter
|
| 107 |
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
|
|
|
| 193 |
def health_check():
|
| 194 |
return {
|
| 195 |
"status": "ok",
|
| 196 |
+
"version": "1.0.0",
|
| 197 |
"env_ready": True,
|
| 198 |
"env": settings.app_env,
|
| 199 |
"active_episodes": len(episodes),
|
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
version: "
|
| 2 |
name: "agentorg-codereview"
|
| 3 |
owners: ["Arsh Verma", "Divyansh Rawat"]
|
| 4 |
description: >
|
|
|
|
| 1 |
+
version: "1.0.0"
|
| 2 |
name: "agentorg-codereview"
|
| 3 |
owners: ["Arsh Verma", "Divyansh Rawat"]
|
| 4 |
description: >
|
|
@@ -1,6 +1,7 @@
|
|
| 1 |
{
|
|
|
|
| 2 |
"name": "codelens-dashboard",
|
| 3 |
-
"version": "
|
| 4 |
"private": true,
|
| 5 |
"author": "Arsh Verma, Divyansh Rawat",
|
| 6 |
"type": "module",
|
|
@@ -11,21 +12,21 @@
|
|
| 11 |
},
|
| 12 |
"dependencies": {
|
| 13 |
"@fontsource/inter": "^5.1.0",
|
| 14 |
-
"@tanstack/react-query": "^5.
|
| 15 |
-
"clsx": "^2.1.
|
| 16 |
"lucide-react": "^0.475.0",
|
| 17 |
-
"react": "^
|
| 18 |
-
"react-dom": "^
|
| 19 |
-
"zustand": "^5.0.
|
| 20 |
},
|
| 21 |
"devDependencies": {
|
| 22 |
-
"@tailwindcss/vite": "^4.
|
| 23 |
-
"@types/node": "^
|
| 24 |
-
"@types/react": "^
|
| 25 |
-
"@types/react-dom": "^
|
| 26 |
-
"@vitejs/plugin-react": "^4.3.
|
| 27 |
-
"tailwindcss": "^4.
|
| 28 |
"typescript": "^5.7.0",
|
| 29 |
-
"vite": "^6.
|
| 30 |
}
|
| 31 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"$schema": "https://json.schemastore.org/package",
|
| 3 |
"name": "codelens-dashboard",
|
| 4 |
+
"version": "1.0.0",
|
| 5 |
"private": true,
|
| 6 |
"author": "Arsh Verma, Divyansh Rawat",
|
| 7 |
"type": "module",
|
|
|
|
| 12 |
},
|
| 13 |
"dependencies": {
|
| 14 |
"@fontsource/inter": "^5.1.0",
|
| 15 |
+
"@tanstack/react-query": "^5.62.0",
|
| 16 |
+
"clsx": "^2.1.1",
|
| 17 |
"lucide-react": "^0.475.0",
|
| 18 |
+
"react": "^19.0.0",
|
| 19 |
+
"react-dom": "^19.0.0",
|
| 20 |
+
"zustand": "^5.0.3"
|
| 21 |
},
|
| 22 |
"devDependencies": {
|
| 23 |
+
"@tailwindcss/vite": "^4.0.0",
|
| 24 |
+
"@types/node": "^22.10.0",
|
| 25 |
+
"@types/react": "^19.0.0",
|
| 26 |
+
"@types/react-dom": "^19.0.0",
|
| 27 |
+
"@vitejs/plugin-react": "^4.3.4",
|
| 28 |
+
"tailwindcss": "^4.0.0",
|
| 29 |
"typescript": "^5.7.0",
|
| 30 |
+
"vite": "^6.0.0"
|
| 31 |
}
|
| 32 |
}
|
|
@@ -1,16 +1,28 @@
|
|
| 1 |
{
|
|
|
|
| 2 |
"compilerOptions": {
|
| 3 |
-
"
|
| 4 |
-
"
|
|
|
|
|
|
|
|
|
|
| 5 |
"module": "ESNext",
|
|
|
|
|
|
|
|
|
|
| 6 |
"moduleResolution": "bundler",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
"jsx": "react-jsx",
|
|
|
|
|
|
|
| 8 |
"strict": true,
|
| 9 |
"noUnusedLocals": true,
|
| 10 |
"noUnusedParameters": true,
|
| 11 |
-
"noFallthroughCasesInSwitch": true
|
| 12 |
-
"skipLibCheck": true,
|
| 13 |
-
"types": ["vite/client", "node"]
|
| 14 |
},
|
| 15 |
"include": ["src"]
|
| 16 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"$schema": "https://json.schemastore.org/tsconfig",
|
| 3 |
"compilerOptions": {
|
| 4 |
+
"composite": true,
|
| 5 |
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
| 6 |
+
"target": "ES2020",
|
| 7 |
+
"useDefineForClassFields": true,
|
| 8 |
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
| 9 |
"module": "ESNext",
|
| 10 |
+
"skipLibCheck": true,
|
| 11 |
+
|
| 12 |
+
/* Bundler mode */
|
| 13 |
"moduleResolution": "bundler",
|
| 14 |
+
"allowImportingTsExtensions": true,
|
| 15 |
+
"resolveJsonModule": true,
|
| 16 |
+
"isolatedModules": true,
|
| 17 |
+
"moduleDetection": "force",
|
| 18 |
+
"noEmit": true,
|
| 19 |
"jsx": "react-jsx",
|
| 20 |
+
|
| 21 |
+
/* Linting */
|
| 22 |
"strict": true,
|
| 23 |
"noUnusedLocals": true,
|
| 24 |
"noUnusedParameters": true,
|
| 25 |
+
"noFallthroughCasesInSwitch": true
|
|
|
|
|
|
|
| 26 |
},
|
| 27 |
"include": ["src"]
|
| 28 |
}
|
|
@@ -1,16 +1,16 @@
|
|
| 1 |
-
fastapi>=0.
|
| 2 |
-
uvicorn>=0.
|
| 3 |
-
pydantic>=2.
|
| 4 |
pytest>=8.0.0
|
| 5 |
-
requests>=2.
|
| 6 |
-
websockets>=
|
| 7 |
-
httpx
|
| 8 |
-
openai>=1.
|
| 9 |
-
pydantic-settings=
|
| 10 |
-
slowapi=
|
| 11 |
-
python-dotenv=
|
| 12 |
-
sqlmodel=
|
| 13 |
-
aiosqlite=
|
| 14 |
-
pytest-cov=
|
| 15 |
-
aiofiles=
|
| 16 |
PyYAML>=6.0.1
|
|
|
|
| 1 |
+
fastapi>=0.115.0
|
| 2 |
+
uvicorn>=0.30.0
|
| 3 |
+
pydantic>=2.10.0
|
| 4 |
pytest>=8.0.0
|
| 5 |
+
requests>=2.32.0
|
| 6 |
+
websockets>=13.0
|
| 7 |
+
httpx>=0.28.0
|
| 8 |
+
openai>=1.50.0
|
| 9 |
+
pydantic-settings>=2.6.0
|
| 10 |
+
slowapi>=0.1.9
|
| 11 |
+
python-dotenv>=1.0.1
|
| 12 |
+
sqlmodel>=0.0.22
|
| 13 |
+
aiosqlite>=0.20.0
|
| 14 |
+
pytest-cov>=5.0.0
|
| 15 |
+
aiofiles>=24.0.0
|
| 16 |
PyYAML>=6.0.1
|