0d3cb498a3
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
199 lines
6.1 KiB
Python
199 lines
6.1 KiB
Python
"""
|
|
CloudSwag Customer Service Bot - FastAPI Application
|
|
|
|
Main entry point for the swag store demo.
|
|
Demonstrates MCP tool integration with JWT-based session management.
|
|
"""
|
|
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.responses import FileResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
from mock_services.internal import router as internal_router
|
|
from mock_services.router import router as mock_router
|
|
|
|
from .config import ANTHROPIC_API_KEY, PROJECT_ROOT
|
|
from .mcp_client import get_mcp_client, shutdown_mcp_client
|
|
from .routers import auth, chat, products
|
|
from .security import get_security_status, is_debug_enabled, is_legacy_api_enabled
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""
|
|
Application lifespan handler.
|
|
Connects to MCP servers on startup, disconnects on shutdown.
|
|
"""
|
|
print("\n" + "=" * 60)
|
|
print("CloudSwag Customer Service Bot Starting...")
|
|
print("=" * 60)
|
|
|
|
# Display security configuration
|
|
print("\nSecurity Configuration (OWASP API Top 10):")
|
|
security_status = get_security_status()
|
|
for key, info in security_status.items():
|
|
level_text = {1: "WEAK (vulnerable)", 2: "MEDIUM", 3: "STRONG (secure)"}.get(
|
|
info["level"], "?"
|
|
)
|
|
print(f" {key}: Level {info['level']} - {level_text}")
|
|
|
|
# Check for API key
|
|
if not ANTHROPIC_API_KEY:
|
|
print("\nWARNING: ANTHROPIC_API_KEY not set!")
|
|
print("Set it in .env file or environment variable.")
|
|
print("Chat functionality will not work without it.\n")
|
|
|
|
# Connect to MCP servers
|
|
try:
|
|
print("\nConnecting to MCP servers...")
|
|
mcp_client = await get_mcp_client()
|
|
tools, _ = await mcp_client.get_all_tools()
|
|
print(f"Total tools available: {len(tools)}")
|
|
print("MCP servers connected successfully!\n")
|
|
except Exception as e:
|
|
print(f"\nWarning: MCP connection issue: {e}")
|
|
print("Some features may not work.\n")
|
|
|
|
print("=" * 60)
|
|
print("Server ready! Open http://localhost:8000 in your browser")
|
|
print("=" * 60 + "\n")
|
|
|
|
yield # Application runs here
|
|
|
|
# Cleanup on shutdown
|
|
print("\nShutting down MCP connections...")
|
|
await shutdown_mcp_client()
|
|
print("Goodbye!")
|
|
|
|
|
|
# Create FastAPI app
|
|
app = FastAPI(
|
|
title="CloudSwag Customer Service Bot",
|
|
description="Demo application showcasing MCP tool integration for a swag store chatbot",
|
|
version="1.0.0",
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
# CORS middleware for web UI
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"], # In production, restrict this
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# Include routers
|
|
app.include_router(auth.router)
|
|
app.include_router(chat.router)
|
|
app.include_router(products.router)
|
|
app.include_router(mock_router)
|
|
|
|
# Conditionally include debug router (API8: Security Misconfiguration)
|
|
if is_debug_enabled():
|
|
from .routers import debug
|
|
|
|
app.include_router(debug.router)
|
|
|
|
# Conditionally include legacy v1 router (API9: Improper Inventory Management)
|
|
if is_legacy_api_enabled():
|
|
from .routers import legacy
|
|
|
|
app.include_router(legacy.router)
|
|
|
|
# Include internal metadata endpoints (API7: SSRF demo target)
|
|
app.include_router(internal_router)
|
|
|
|
# Static files for web UI
|
|
static_dir = PROJECT_ROOT / "static"
|
|
if static_dir.exists():
|
|
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
|
|
|
|
|
|
@app.get("/")
|
|
async def root():
|
|
"""Serve the chat UI or redirect to it."""
|
|
index_path = static_dir / "index.html"
|
|
if index_path.exists():
|
|
return FileResponse(str(index_path))
|
|
return {
|
|
"message": "CloudSwag Customer Service Bot",
|
|
"docs": "/docs",
|
|
"chat_ui": "/static/index.html",
|
|
}
|
|
|
|
|
|
@app.get("/health")
|
|
async def health_check():
|
|
"""Health check endpoint."""
|
|
from .mcp_client import _mcp_client
|
|
|
|
mcp_status = (
|
|
"connected" if (_mcp_client and _mcp_client.is_connected) else "disconnected"
|
|
)
|
|
|
|
return {
|
|
"status": "healthy",
|
|
"mcp_servers": mcp_status,
|
|
"anthropic_configured": bool(ANTHROPIC_API_KEY),
|
|
}
|
|
|
|
|
|
@app.get("/security/status")
|
|
async def security_status():
|
|
"""
|
|
Get current security configuration levels.
|
|
Useful for understanding which vulnerabilities are enabled.
|
|
"""
|
|
return {
|
|
"description": "OWASP API Security Top 10 Vulnerability Configuration",
|
|
"levels": {
|
|
1: "Weak (easily exploitable)",
|
|
2: "Medium (bypassable with effort)",
|
|
3: "Strong (secure)",
|
|
},
|
|
"configuration": get_security_status(),
|
|
"active_endpoints": {
|
|
"debug": is_debug_enabled(),
|
|
"legacy_v1": is_legacy_api_enabled(),
|
|
},
|
|
}
|
|
|
|
|
|
@app.get("/api/info")
|
|
async def api_info():
|
|
"""Get API information and available endpoints."""
|
|
return {
|
|
"name": "CloudSwag Customer Service Bot",
|
|
"version": "1.0.0",
|
|
"endpoints": {
|
|
"chat": {
|
|
"POST /chat/": "Send a message to the bot",
|
|
"GET /chat/sessions": "List user's chat sessions",
|
|
"GET /chat/session/{id}/history": "Get session history",
|
|
"DELETE /chat/session/{id}": "Clear a session",
|
|
},
|
|
"auth": {
|
|
"POST /auth/token": "Generate JWT token for demo user",
|
|
"POST /auth/validate": "Validate a token",
|
|
"GET /auth/demo-users": "List available demo users",
|
|
"GET /auth/demo-tokens": "Get JWT tokens for all demo users",
|
|
},
|
|
"mock_services": {
|
|
"GET /mock/shipping/track/{tracking}": "Track a package",
|
|
"GET /mock/promotions/current": "Get current promotions",
|
|
"GET /mock/weather/{location}": "Get weather data",
|
|
},
|
|
},
|
|
"demo_users": ["alice", "bob", "charlie", "diana", "eve"],
|
|
"hint": "In mock auth mode, use demo user names directly as tokens",
|
|
}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import uvicorn
|
|
|
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|