# LockStock FastAPI Integration

Production-ready middleware for securing FastAPI inference servers with LockStock chain-based authentication.

## Features

✅ **Sequential Chain Advancement** - Uses `asyncio.Lock` to serialize chain operations
✅ **Server Sync** - Syncs to LockStock server for dashboard visibility and audit trail
✅ **Concurrent Inference** - Lock released before inference, no throughput bottleneck
✅ **Timeout Protection** - Prevents hung Guard daemon from stalling pipeline
✅ **Audit Headers** - Every response includes `X-LockStock-*` headers
✅ **Configurable** - Environment variables or constructor args
✅ **Drop-in Middleware** - Works with any FastAPI application

## Installation

```bash
pip install lockstock-integrations[fastapi]
```

## Quick Start

### Step 1: Hardware Binding (One-time)

```bash
# On your server, bind agent to hardware
lockstock-guard bind --agent agent_abc123 --token <genesis-token>
```

### Step 2: Add Middleware

```python
from fastapi import FastAPI
from lockstock_fastapi import LockStockMiddleware

app = FastAPI()

# Add LockStock chain authentication
# NO SECRETS - uses chain state from Guard daemon (requires Step 1)
app.add_middleware(
    LockStockMiddleware,
    agent_id="agent_abc123",
    server_sync=True  # Enable dashboard visibility (default: True)
)

@app.post("/v1/chat/completions")
async def inference(request: ChatRequest):
    # Middleware automatically:
    # 1. Advances chain locally (daemon signing)
    # 2. Syncs to server via /verify endpoint
    # 3. Adds X-LockStock-* headers to response
    # 4. Updates dashboard audit trail
    return await model.generate(request)
```

### Step 3: Verify

```bash
curl -X POST http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "Hello"}]}' \
  -v | grep X-LockStock
```

Expected headers:
```
X-LockStock-Agent-Id: agent_abc123
X-LockStock-Seq: 42
X-LockStock-Hash: a7f3b2...
X-LockStock-Sig: e8c9d1...
X-LockStock-Task: network
```

## Configuration

### Via Constructor

```python
app.add_middleware(
    LockStockMiddleware,
    agent_id="agent_abc123",
    guard_socket="/var/run/lockstock-guard/guard.sock",
    task="network",
    block_on_failure=True,  # Reject on auth failure
    timeout=5.0,            # Guard daemon timeout
    paths=["/v1/chat/completions", "/v1/completions"],  # Protect specific paths
    server_url="https://lockstock-api-i9kp.onrender.com",  # LockStock API endpoint
    server_sync=True  # Enable server sync for dashboard visibility (default: True)
)
```

### Via Environment Variables

```bash
export LOCKSTOCK_AGENT_ID=agent_abc123
export LOCKSTOCK_SOCKET=/var/run/lockstock-guard/guard.sock
export LOCKSTOCK_TASK=network
export LOCKSTOCK_BLOCK_ON_FAILURE=true
export LOCKSTOCK_TIMEOUT=5.0
export LOCKSTOCK_SERVER_URL=https://lockstock-api-i9kp.onrender.com
export LOCKSTOCK_SERVER_SYNC=true  # Set to "false" to disable dashboard sync
```

```python
# No args needed - reads from environment
app.add_middleware(LockStockMiddleware)
```

## Architecture

### Sequential Chain with Concurrent Inference

```
Request 1 ──┐
Request 2 ──┼─→ [Chain Lock] ──→ Inference (concurrent)
Request 3 ──┘      ↓
                   Queue for chain advancement
                   (microseconds per request)
```

**Key Design:**
- Chain operations serialized via `asyncio.Lock`
- Lock held only for Guard daemon calls (~microseconds)
- Inference runs fully concurrent after lock release
- No race conditions, no retries, no 409 conflicts

### Throughput

Under 100 concurrent requests:
- Chain queueing adds ~few milliseconds total
- Inference dominates latency (seconds)
- **Bottleneck is inference, not chain operations**

## Production Configuration

### Strict Mode (Recommended)

```python
app.add_middleware(
    LockStockMiddleware,
    agent_id="agent_abc123",
    block_on_failure=True,  # Reject on auth failure
    timeout=2.0             # Fail fast
)
```

Requests **fail fast** if Guard daemon unavailable or chain auth fails.

### Permissive Mode (Development)

```python
app.add_middleware(
    LockStockMiddleware,
    agent_id="agent_abc123",
    block_on_failure=False,  # Log warning, continue
    timeout=5.0
)
```

Requests **proceed with warning** if auth fails. Useful for development.

## Error Handling

### 503 Service Unavailable
Guard daemon timeout - check daemon status:
```bash
lockstock-guard status
```

### 403 Forbidden
Chain authentication failed - check chain state:
```bash
lockstock-guard sync --agent agent_abc123
```

## Monitoring

### Check Audit Trail

```bash
curl https://lockstock-api.onrender.com/api/guard/audit?agent_id=agent_abc123
```

### Response Headers

Every successful request includes provenance headers:
```
X-LockStock-Agent-Id: agent_abc123
X-LockStock-Seq: 42          # Sequence number
X-LockStock-Hash: a7f3b2...   # Current chain head
X-LockStock-Sig: e8c9d1...    # HMAC signature
X-LockStock-Task: network     # Task type
```

## Advanced Usage

### Protect Specific Paths

```python
# Only protect inference endpoints
app.add_middleware(
    LockStockMiddleware,
    agent_id="agent_abc123",
    paths=["/v1/chat/completions", "/v1/completions"]
)

# Health checks not protected
@app.get("/health")  # Not protected
async def health():
    return {"status": "ok"}
```

### Custom Task Names

```python
# Use different task names for different operations
app.add_middleware(
    LockStockMiddleware,
    agent_id="agent_abc123",
    task="fileread"  # Or: network, shell, database, etc.
)
```

### Multiple Agents

```python
# Route-specific agents
from fastapi import Depends

async def get_agent_id(request: Request) -> str:
    # Extract agent from API key, header, etc.
    return request.headers.get("X-Agent-ID")

@app.post("/inference")
async def inference(agent_id: str = Depends(get_agent_id)):
    # Use dynamic agent_id
    # (Requires custom middleware implementation)
    pass
```

## Troubleshooting

### "agent_id is required"
Set via constructor or `LOCKSTOCK_AGENT_ID` environment variable.

### "lockstock_guard.client not available"
Install Guard client:
```bash
pip install lockstock-integrations[guard]
```

### "Chain state not initialized"
Sync chain state from server:
```bash
lockstock-guard sync --agent agent_abc123
```

### "Guard daemon timeout"
Check daemon is running:
```bash
lockstock-guard status
lockstock-guard start  # If not running
```

## Support

- Documentation: https://lockstock.dev/docs/fastapi
- Issues: https://gitlab.com/d3cipher/lockstock/-/issues
- API Reference: https://lockstock-api.onrender.com/docs
