Skip to content

Security

Security is crucial for protecting your codebase and API access. This guide covers security best practices for the DevFlow backend.


API Key Management

OpenAI API Key

The backend uses OpenAI API keys for AI features. Secure your keys properly:

# Environment variable (recommended)
export OPENAI_API_KEY="sk-your-secret-key"

# Or in .env file (ensure it's not committed to git)
OPENAI_API_KEY=sk-your-secret-key

Security Best Practices

  • Never commit API keys to version control
  • Use environment variables instead of hardcoded values
  • Rotate keys regularly for better security
  • Use different keys for development and production
  • Monitor API usage to detect unauthorized access

Environment Variables

Secure Configuration

# Production .env file (never commit this)
OPENAI_API_KEY=sk-production-key
API_HOST=0.0.0.0
API_PORT=8000
DEBUG=false
LOG_LEVEL=WARNING

# Development .env file (can be committed)
OPENAI_API_KEY=sk-dev-key
API_HOST=127.0.0.1
API_PORT=8000
DEBUG=true
LOG_LEVEL=DEBUG

Environment Variable Security

# Set file permissions
chmod 600 .env

# Use secrets management in production
# AWS Secrets Manager, Azure Key Vault, etc.

Authentication

Current State

The DevFlow backend currently does not require authentication. For production use, consider implementing:

API Key Authentication

# Example implementation
from fastapi import HTTPException, Depends
from fastapi.security import HTTPBearer

security = HTTPBearer()

async def verify_api_key(credentials = Depends(security)):
    if credentials.credentials != settings.API_KEY:
        raise HTTPException(status_code=401, detail="Invalid API key")
    return credentials.credentials

@router.post("/search")
async def search_codebase(request: SearchRequest, api_key = Depends(verify_api_key)):
    # Protected endpoint
    pass

JWT Authentication

# Example JWT implementation
import jwt
from datetime import datetime, timedelta

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=30)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm="HS256")
    return encoded_jwt

def verify_token(token: str):
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.JWTError:
        raise HTTPException(status_code=401, detail="Invalid token")

Rate Limiting

Built-in Protection

The backend includes rate limiting to prevent abuse:

# Configuration
RATE_LIMIT_REQUESTS = 100  # requests per window
RATE_LIMIT_WINDOW = 3600   # seconds (1 hour)

Custom Rate Limiting

# Per-endpoint rate limiting
@router.post("/search")
@rate_limit(max_requests=50, window=3600)
async def search_codebase(request: SearchRequest):
    pass

# IP-based rate limiting
@router.post("/index")
@rate_limit(max_requests=10, window=3600, key_func=get_client_ip)
async def index_codebase(request: IndexRequest):
    pass

Input Validation

Request Validation

All API endpoints use Pydantic models for automatic validation:

class SearchRequest(BaseModel):
    query: str
    limit: int = Field(ge=1, le=50)  # Between 1 and 50

class IndexRequest(BaseModel):
    path: str
    recursive: bool = True
    extensions: Optional[List[str]] = None

File Path Validation

# Validate file paths to prevent directory traversal
def validate_file_path(path: str) -> bool:
    # Ensure path is within workspace
    workspace_root = get_workspace_root()
    abs_path = os.path.abspath(path)
    return abs_path.startswith(workspace_root)

# Usage
if not validate_file_path(request.path):
    raise HTTPException(status_code=400, detail="Invalid file path")

HTTPS and TLS

Production Deployment

Always use HTTPS in production:

# Generate SSL certificate
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365

# Run with SSL
uvicorn app.main:app --ssl-keyfile=key.pem --ssl-certfile=cert.pem

Reverse Proxy

Use a reverse proxy like Nginx:

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Data Security

Vector Database Security

# Secure ChromaDB storage
CHROMA_DB_PATH=/secure/path/to/vector_store
chmod 700 /secure/path/to/vector_store

# Backup encryption
tar -czf backup.tar.gz --encrypt --password=secure_password data/

Metadata Database Security

# SQLite database security
METADATA_DB_PATH=/secure/path/to/metadata.db
chmod 600 /secure/path/to/metadata.db

# Regular backups
sqlite3 metadata.db ".backup '/backup/metadata-$(date +%Y%m%d).db'"

Logging and Monitoring

Security Logging

# Log security events
import logging

security_logger = logging.getLogger("security")

def log_security_event(event_type: str, details: dict):
    security_logger.warning(f"Security event: {event_type}", extra=details)

# Usage
log_security_event("rate_limit_exceeded", {
    "ip": client_ip,
    "endpoint": "/search",
    "timestamp": datetime.now().isoformat()
})

Monitoring

# Monitor suspicious activity
from collections import defaultdict
import time

request_counts = defaultdict(list)

def monitor_requests(client_ip: str, endpoint: str):
    now = time.time()
    request_counts[client_ip].append(now)

    # Clean old requests
    request_counts[client_ip] = [t for t in request_counts[client_ip] 
                                if now - t < 3600]

    # Alert if too many requests
    if len(request_counts[client_ip]) > 1000:
        log_security_event("suspicious_activity", {
            "ip": client_ip,
            "requests": len(request_counts[client_ip])
        })

Production Security Checklist

Before Deployment

  • [ ] API Keys: Secured and rotated
  • [ ] Environment Variables: Properly configured
  • [ ] HTTPS: SSL certificates installed
  • [ ] Authentication: Implemented if needed
  • [ ] Rate Limiting: Configured appropriately
  • [ ] Input Validation: All endpoints validated
  • [ ] File Permissions: Secure file access
  • [ ] Logging: Security events logged
  • [ ] Monitoring: Suspicious activity detection
  • [ ] Backups: Regular encrypted backups

Ongoing Security

  • [ ] Regular Updates: Keep dependencies updated
  • [ ] Security Audits: Regular security reviews
  • [ ] Access Monitoring: Monitor API usage
  • [ ] Incident Response: Plan for security incidents
  • [ ] Compliance: Meet relevant compliance requirements

Security Headers

Add Security Headers

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# Add security headers
@app.middleware("http")
async def add_security_headers(request, call_next):
    response = await call_next(request)
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["X-XSS-Protection"] = "1; mode=block"
    response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
    return response

CORS Configuration

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://your-domain.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["*"],
)

Following these security practices ensures your DevFlow backend is secure and ready for production use.