Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
288 changes: 288 additions & 0 deletions monitoring/grafana/tenet_dashboard.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": null,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "sum(rate(http_requests_total[5m])) by (endpoint, status)",
"legendFormat": "{{endpoint}} - {{status}}",
"refId": "A"
}
],
"title": "API Request Rate",
"type": "timeseries"
},
{
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 10,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"id": 4,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, endpoint))",
"legendFormat": "p95 {{endpoint}}",
"refId": "A"
}
],
"title": "Endpoint Latency (p95)",
"type": "timeseries"
},
{
"datasource": "Prometheus",
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 2,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 8
},
"id": 6,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"expr": "sum(rate(tenet_detections_total[5m])) by (threat_type, verdict)",
"legendFormat": "{{threat_type}} - {{verdict}}",
"refId": "A"
}
],
"title": "Threat Detections (Rate)",
"type": "timeseries"
}
],
"refresh": "5s",
"schemaVersion": 36,
"style": "dark",
"tags": ["tenet-ai", "security"],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "TENET AI - Security & Performance",
"uid": "tenet-ai-main",
"version": 1
}
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ requests>=2.33.1
python-dotenv>=1.2.2

# Utilities
python-dateutil>=2.8.2
python-dateutil>=2.8.2
prometheus-client>=0.20.0
12 changes: 12 additions & 0 deletions services/analyzer/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

from services.utils.logging_config import setup_logging
from services.security import SecurityManager
from services.utils.metrics import PrometheusMiddleware, increment_detection
from prometheus_client import make_asgi_app
logger = setup_logging(__name__)

# Environment configuration
Expand All @@ -45,6 +47,7 @@
# CORS middleware - configurable origins for security
CORS_ALLOWED_ORIGINS = os.getenv("CORS_ALLOWED_ORIGINS", "https://localhost:3000,https://localhost:5173")
allowed_origins = [origin.strip() for origin in CORS_ALLOWED_ORIGINS.split(",")]
app.add_middleware(PrometheusMiddleware)
app.add_middleware(
CORSMiddleware,
allow_origins=allowed_origins,
Expand All @@ -53,6 +56,10 @@
allow_headers=["*"],
)

# Mount Prometheus metrics endpoint
metrics_app = make_asgi_app()
app.mount("/metrics", metrics_app)

# Global state
redis_client: Optional[redis.Redis] = None
ml_model = None
Expand Down Expand Up @@ -202,6 +209,9 @@ async def analyze_prompt(
auth = await security.require_auth(x_api_key, required_permission="analyze")
prompt = request.prompt
result = run_analysis(prompt)

increment_detection(service="analyzer", threat_type=result.threat_type, verdict=result.verdict)

security.audit(
action="analyze_prompt",
result=result.verdict,
Expand Down Expand Up @@ -456,6 +466,8 @@ async def _process_single_event(event_json: str):
# Analyze the prompt
result = run_analysis(prompt)

increment_detection(service="analyzer_bg", threat_type=result.threat_type, verdict=result.verdict)

# Update and store event
await _update_and_store_event(event, event_id, result)

Expand Down
11 changes: 11 additions & 0 deletions services/ingest/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from fastapi import FastAPI, Header, HTTPException, Query

from services.security import SecurityManager
from services.utils.metrics import PrometheusMiddleware, increment_detection
from prometheus_client import make_asgi_app
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field

Expand Down Expand Up @@ -144,6 +146,7 @@ async def record_failure(self) -> None:
version="0.1.0",
)

app.add_middleware(PrometheusMiddleware)
app.add_middleware(
CORSMiddleware,
allow_origins=CORS_ORIGINS,
Expand All @@ -152,6 +155,10 @@ async def record_failure(self) -> None:
allow_headers=["*"],
)

# Mount Prometheus metrics endpoint
metrics_app = make_asgi_app()
app.mount("/metrics", metrics_app)

redis_client: Optional[redis.Redis] = None
redis_cb = CircuitBreaker("redis-ingest")
_shutdown_event = asyncio.Event()
Expand Down Expand Up @@ -314,6 +321,10 @@ async def ingest_llm_event(request: LLMEventRequest, x_api_key: str = Header(...
event_id = str(uuid.uuid4())
timestamp = datetime.utcnow().isoformat()
blocked, risk_score, verdict = quick_heuristic_check(request.prompt)

# Simple mapping based on risk score from quick_heuristic_check
threat_type = "prompt_injection" if risk_score >= 0.95 else ("jailbreak" if risk_score >= 0.90 else ("data_extraction" if risk_score >= 0.75 else "none"))
increment_detection(service="ingest", threat_type=threat_type, verdict=verdict)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

event_payload = {
"event_id": event_id,
Expand Down
Loading