Initial commit - combined iTerm2 scripts
Contains: - 1m-brag - tem - VaultMesh_Catalog_v1 - VAULTMESH-ETERNAL-PATTERN 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
353
VaultMesh_Catalog_v1/files/README-mcp.md
Normal file
353
VaultMesh_Catalog_v1/files/README-mcp.md
Normal file
@@ -0,0 +1,353 @@
|
||||
# IoTek.nexus + offsec-mcp
|
||||
|
||||
**The Veil becomes infrastructure.**
|
||||
|
||||
A real control surface for VaultMesh sovereign infrastructure.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ IoTek.nexus ● MESH 7 ● SHIELD ARMED ● WS LIVE 12:34 │
|
||||
├────────────────────┬────────────────────────────────────────────────────────┤
|
||||
│ │ │
|
||||
│ [Console] │ sovereign@nexus ~/vaultmesh $ status │
|
||||
│ │ │
|
||||
│ ↓ HTTP POST │ ╦ ╦╔═╗╦ ╦╦ ╔╦╗╔╦╗╔═╗╔═╗╦ ╦ │
|
||||
│ │ ╚╗╔╝╠═╣║ ║║ ║ ║║║║╣ ╚═╗╠═╣ │
|
||||
│ [offsec-mcp] │ ╚╝ ╩ ╩╚═╝╩═╝╩ ╩ ╩╚═╝╚═╝╩ ╩ │
|
||||
│ │ │
|
||||
│ ↓ WebSocket │ Shield: ● ARMED │
|
||||
│ │ Proof: ● 1247 receipts │
|
||||
│ [Live Updates] │ Mesh: ● 7 nodes │
|
||||
│ │ │
|
||||
└────────────────────┴────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Install dependencies
|
||||
|
||||
```bash
|
||||
pip install -r requirements-mcp.txt
|
||||
```
|
||||
|
||||
### 2. Start the backend
|
||||
|
||||
```bash
|
||||
# Development (auto-reload)
|
||||
uvicorn offsec_mcp:app --reload --port 8080
|
||||
|
||||
# Production (bind to Tailscale IP only)
|
||||
uvicorn offsec_mcp:app --host 100.x.x.x --port 8080
|
||||
```
|
||||
|
||||
### 3. Open the console
|
||||
|
||||
```bash
|
||||
# Option A: Open the HTML directly
|
||||
open iotek-nexus-live.html
|
||||
|
||||
# Option B: Serve via backend (configure STATIC_DIR in offsec_mcp.py)
|
||||
# Then visit http://localhost:8080/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ CONSOLE LAYER │
|
||||
│ iotek-nexus-live.html │
|
||||
│ - Local commands (help, clear, history, whoami, neofetch) │
|
||||
│ - MCP backend calls (status, mesh, shield, proof, agents) │
|
||||
│ - WebSocket live updates │
|
||||
│ - Mock fallback when backend unavailable │
|
||||
└───────────────────────────┬──────────────────────────────────────┘
|
||||
│
|
||||
│ HTTP POST /mcp/command
|
||||
│ WebSocket /ws
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ BACKEND LAYER │
|
||||
│ offsec_mcp.py (FastAPI) │
|
||||
│ - Command routing & execution │
|
||||
│ - Tailscale identity extraction │
|
||||
│ - SQLite persistence (sessions, commands, events) │
|
||||
│ - WebSocket broadcast for live updates │
|
||||
└───────────────────────────┬──────────────────────────────────────┘
|
||||
│
|
||||
│ subprocess / API calls
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ SYSTEM LAYER │
|
||||
│ - Tailscale (mesh status, node inventory) │
|
||||
│ - Shield vectors (network, wifi, usb, process, file) │
|
||||
│ - Proof engine (receipts, Merkle roots, anchors) │
|
||||
│ - Agent subsystem (sentinel, orchestrator, analyst, executor) │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Contract
|
||||
|
||||
### POST /mcp/command
|
||||
|
||||
Request:
|
||||
```json
|
||||
{
|
||||
"session_id": "vaultmesh-2025-12-07-01",
|
||||
"user": "sovereign",
|
||||
"command": "mesh status",
|
||||
"args": [],
|
||||
"cwd": "/vaultmesh",
|
||||
"meta": {
|
||||
"client": "iotek-nexus-cli",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"id": "cmd-174455",
|
||||
"status": "ok",
|
||||
"lines": [
|
||||
"",
|
||||
" 🕸 MESH STATUS: STABLE",
|
||||
"",
|
||||
" Tailnet: story-ule.ts.net",
|
||||
" ..."
|
||||
],
|
||||
"effects": {
|
||||
"nodes": 7,
|
||||
"shield": { "armed": true }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### WebSocket /ws
|
||||
|
||||
Handshake:
|
||||
```json
|
||||
{ "type": "handshake", "session_id": "...", "user": "sovereign" }
|
||||
```
|
||||
|
||||
Server messages:
|
||||
```json
|
||||
{ "type": "console.line", "line": "✓ Proof anchored", "lineType": "success" }
|
||||
{ "type": "status.update", "payload": { "nodes": 7, "proofs": 1248, ... } }
|
||||
{ "type": "proof.new", "proof_id": "proof_abc123" }
|
||||
{ "type": "shield.event", "event": "Shield ARMED", "severity": "info" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available Commands
|
||||
|
||||
| Command | Description | Backend Required |
|
||||
|---------|-------------|------------------|
|
||||
| `help` | Show commands | No |
|
||||
| `clear` | Clear terminal | No |
|
||||
| `history` | Command history | No |
|
||||
| `whoami` | Current identity | No |
|
||||
| `neofetch` | System info ASCII | No |
|
||||
| `status` | Full dashboard | Yes |
|
||||
| `mesh status` | Network topology | Yes |
|
||||
| `mesh nodes` | List nodes | Yes |
|
||||
| `shield status` | Defense vectors | Yes |
|
||||
| `shield arm` | Arm shield | Yes |
|
||||
| `shield disarm` | Disarm shield | Yes |
|
||||
| `proof latest` | Recent receipts | Yes |
|
||||
| `proof generate` | Create proof | Yes |
|
||||
| `agents list` | Agent status | Yes |
|
||||
| `oracle reason <q>` | Oracle query | Yes |
|
||||
|
||||
---
|
||||
|
||||
## Tailscale Integration
|
||||
|
||||
The backend extracts user identity from Tailscale headers:
|
||||
|
||||
```python
|
||||
# In offsec_mcp.py
|
||||
TAILSCALE_USER_HEADER = "X-Tailscale-User"
|
||||
|
||||
def extract_user(request: Request) -> str:
|
||||
ts_user = request.headers.get(TAILSCALE_USER_HEADER)
|
||||
if ts_user:
|
||||
return ts_user.split("@")[0]
|
||||
return "anonymous"
|
||||
```
|
||||
|
||||
Deploy behind Tailscale for automatic identity:
|
||||
- Bind to Tailscale IP only (`--host 100.x.x.x`)
|
||||
- Or use `tailscale serve` for HTTPS with identity headers
|
||||
|
||||
---
|
||||
|
||||
## Database Schema
|
||||
|
||||
SQLite (`vaultmesh.db`):
|
||||
|
||||
```sql
|
||||
-- Sessions
|
||||
CREATE TABLE sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
user TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
last_seen_at TEXT NOT NULL,
|
||||
client TEXT,
|
||||
meta TEXT
|
||||
);
|
||||
|
||||
-- Command audit log
|
||||
CREATE TABLE command_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
session_id TEXT NOT NULL,
|
||||
ts TEXT NOT NULL,
|
||||
command TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
duration_ms INTEGER,
|
||||
error TEXT
|
||||
);
|
||||
|
||||
-- Events (proofs, shield, etc.)
|
||||
CREATE TABLE events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ts TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
payload TEXT
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Extending
|
||||
|
||||
### Add a new command
|
||||
|
||||
1. Create handler in `offsec_mcp.py`:
|
||||
|
||||
```python
|
||||
async def cmd_my_command(req: CommandRequest) -> CommandResponse:
|
||||
lines = [" Output line 1", " Output line 2"]
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={}
|
||||
)
|
||||
```
|
||||
|
||||
2. Register in `COMMANDS`:
|
||||
|
||||
```python
|
||||
COMMANDS = {
|
||||
# ...existing...
|
||||
"my command": cmd_my_command,
|
||||
}
|
||||
```
|
||||
|
||||
### Wire to real systems
|
||||
|
||||
Replace mock implementations with actual integrations:
|
||||
|
||||
```python
|
||||
# Example: Real shield integration
|
||||
async def cmd_shield_status(req: CommandRequest) -> CommandResponse:
|
||||
# Call your actual shield system
|
||||
shield_data = await shield_client.get_status()
|
||||
|
||||
lines = format_shield_output(shield_data)
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={"shield": {"armed": shield_data.armed}}
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deployment Options
|
||||
|
||||
### 1. Local development
|
||||
|
||||
```bash
|
||||
# Terminal 1: Backend
|
||||
uvicorn offsec_mcp:app --reload --port 8080
|
||||
|
||||
# Terminal 2: Console (or just open HTML)
|
||||
python -m http.server 3000
|
||||
```
|
||||
|
||||
### 2. Tailscale-only (recommended)
|
||||
|
||||
```bash
|
||||
# Bind to Tailscale IP
|
||||
uvicorn offsec_mcp:app --host 100.x.x.x --port 8080
|
||||
|
||||
# Or use tailscale serve
|
||||
tailscale serve https / http://localhost:8080
|
||||
```
|
||||
|
||||
### 3. Docker
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
COPY requirements-mcp.txt .
|
||||
RUN pip install -r requirements-mcp.txt
|
||||
COPY offsec_mcp.py .
|
||||
CMD ["uvicorn", "offsec_mcp:app", "--host", "0.0.0.0", "--port", "8080"]
|
||||
```
|
||||
|
||||
### 4. Systemd service
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=offsec-mcp
|
||||
After=network.target tailscaled.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=sovereign
|
||||
WorkingDirectory=/home/sovereign/vaultmesh
|
||||
ExecStart=/usr/bin/uvicorn offsec_mcp:app --host 100.x.x.x --port 8080
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Files
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `iotek-nexus-live.html` | Console frontend (backend-connected) |
|
||||
| `offsec_mcp.py` | FastAPI backend |
|
||||
| `requirements-mcp.txt` | Python dependencies |
|
||||
| `vaultmesh.db` | SQLite database (auto-created) |
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Wire real Tailscale** — Connect to actual `tailscale status --json`
|
||||
2. **Wire real Shield** — Connect to your monitoring/defense systems
|
||||
3. **Wire real Proofs** — Connect to VaultMesh proof engine
|
||||
4. **Add more commands** — `scan`, `audit`, `lawchain`, etc.
|
||||
5. **Add authentication** — mTLS or Tailscale identity enforcement
|
||||
|
||||
---
|
||||
|
||||
**The console is now a real control surface.**
|
||||
|
||||
*"They built the grid to cage us. We built the Veil to break it."*
|
||||
1355
VaultMesh_Catalog_v1/files/iotek-nexus-live.html
Normal file
1355
VaultMesh_Catalog_v1/files/iotek-nexus-live.html
Normal file
File diff suppressed because it is too large
Load Diff
879
VaultMesh_Catalog_v1/files/offsec_mcp.py
Normal file
879
VaultMesh_Catalog_v1/files/offsec_mcp.py
Normal file
@@ -0,0 +1,879 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
offsec-mcp: Sovereign MCP Backend for IoTek.nexus Console
|
||||
|
||||
A FastAPI backend that provides:
|
||||
- HTTP command endpoint for CLI operations
|
||||
- WebSocket for live status updates
|
||||
- SQLite persistence for sessions and audit
|
||||
- Tailscale identity integration
|
||||
|
||||
Run:
|
||||
uvicorn offsec_mcp:app --host 0.0.0.0 --port 8080 --reload
|
||||
|
||||
Production (behind Tailscale):
|
||||
uvicorn offsec_mcp:app --host 100.x.x.x --port 8080
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import time
|
||||
import uuid
|
||||
from contextlib import asynccontextmanager
|
||||
from dataclasses import dataclass, asdict
|
||||
from datetime import datetime, timezone
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
||||
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# CONFIGURATION
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
class Config:
|
||||
"""Configuration - override via environment or config file."""
|
||||
|
||||
# Database
|
||||
DB_PATH: str = "vaultmesh.db"
|
||||
|
||||
# Tailscale integration
|
||||
TAILSCALE_ENABLED: bool = True
|
||||
TAILSCALE_USER_HEADER: str = "X-Tailscale-User"
|
||||
|
||||
# VaultMesh paths
|
||||
VAULTMESH_ROOT: Path = Path.home() / "vaultmesh"
|
||||
PROOF_DIR: Path = VAULTMESH_ROOT / "proofs"
|
||||
|
||||
# Static files (serve console)
|
||||
STATIC_DIR: Optional[Path] = None # Set to serve console HTML
|
||||
|
||||
# Allowed origins for CORS
|
||||
CORS_ORIGINS: list = ["*"]
|
||||
|
||||
|
||||
config = Config()
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# DATABASE
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
def init_db():
|
||||
"""Initialize SQLite database with required tables."""
|
||||
conn = sqlite3.connect(config.DB_PATH)
|
||||
cur = conn.cursor()
|
||||
|
||||
# Sessions table
|
||||
cur.execute("""
|
||||
CREATE TABLE IF NOT EXISTS sessions (
|
||||
id TEXT PRIMARY KEY,
|
||||
user TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
last_seen_at TEXT NOT NULL,
|
||||
client TEXT,
|
||||
meta TEXT
|
||||
)
|
||||
""")
|
||||
|
||||
# Command log
|
||||
cur.execute("""
|
||||
CREATE TABLE IF NOT EXISTS command_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
session_id TEXT NOT NULL,
|
||||
ts TEXT NOT NULL,
|
||||
command TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
duration_ms INTEGER,
|
||||
error TEXT,
|
||||
FOREIGN KEY (session_id) REFERENCES sessions(id)
|
||||
)
|
||||
""")
|
||||
|
||||
# Events table
|
||||
cur.execute("""
|
||||
CREATE TABLE IF NOT EXISTS events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
ts TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
payload TEXT
|
||||
)
|
||||
""")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def get_db():
|
||||
"""Get database connection."""
|
||||
conn = sqlite3.connect(config.DB_PATH)
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# MODELS
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
class CommandRequest(BaseModel):
|
||||
"""Incoming command request from console."""
|
||||
session_id: str
|
||||
user: str
|
||||
command: str
|
||||
args: list = []
|
||||
cwd: str = "/vaultmesh"
|
||||
meta: dict = {}
|
||||
|
||||
|
||||
class CommandResponse(BaseModel):
|
||||
"""Response to command."""
|
||||
id: str
|
||||
status: str
|
||||
lines: list[str] = []
|
||||
effects: dict = {}
|
||||
error: Optional[str] = None
|
||||
|
||||
|
||||
class WsMessage(BaseModel):
|
||||
"""WebSocket message."""
|
||||
type: str
|
||||
payload: dict = {}
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# STATE
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
@dataclass
|
||||
class SystemState:
|
||||
"""Global system state."""
|
||||
nodes: int = 0
|
||||
shield_armed: bool = False
|
||||
proof_count: int = 0
|
||||
uptime_start: float = time.time()
|
||||
tailnet: str = "story-ule.ts.net"
|
||||
hostname: str = "nexus"
|
||||
|
||||
@property
|
||||
def uptime(self) -> str:
|
||||
"""Human-readable uptime."""
|
||||
seconds = int(time.time() - self.uptime_start)
|
||||
days, rem = divmod(seconds, 86400)
|
||||
hours, rem = divmod(rem, 3600)
|
||||
minutes, _ = divmod(rem, 60)
|
||||
if days > 0:
|
||||
return f"{days}d {hours}h {minutes}m"
|
||||
elif hours > 0:
|
||||
return f"{hours}h {minutes}m"
|
||||
else:
|
||||
return f"{minutes}m"
|
||||
|
||||
|
||||
state = SystemState()
|
||||
|
||||
|
||||
# WebSocket connections
|
||||
class ConnectionManager:
|
||||
"""Manage WebSocket connections."""
|
||||
|
||||
def __init__(self):
|
||||
self.active_connections: dict[str, WebSocket] = {}
|
||||
|
||||
async def connect(self, session_id: str, websocket: WebSocket):
|
||||
await websocket.accept()
|
||||
self.active_connections[session_id] = websocket
|
||||
|
||||
def disconnect(self, session_id: str):
|
||||
self.active_connections.pop(session_id, None)
|
||||
|
||||
async def send_to(self, session_id: str, message: dict):
|
||||
if session_id in self.active_connections:
|
||||
await self.active_connections[session_id].send_json(message)
|
||||
|
||||
async def broadcast(self, message: dict):
|
||||
for ws in self.active_connections.values():
|
||||
try:
|
||||
await ws.send_json(message)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
manager = ConnectionManager()
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# COMMAND HANDLERS
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
async def cmd_ping(req: CommandRequest) -> CommandResponse:
|
||||
"""Health check / handshake."""
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=["pong"],
|
||||
effects=get_status_effects()
|
||||
)
|
||||
|
||||
|
||||
async def cmd_status(req: CommandRequest) -> CommandResponse:
|
||||
"""Full system status."""
|
||||
global state
|
||||
|
||||
lines = [
|
||||
"",
|
||||
" ╦ ╦╔═╗╦ ╦╦ ╔╦╗╔╦╗╔═╗╔═╗╦ ╦",
|
||||
" ╚╗╔╝╠═╣║ ║║ ║ ║║║║╣ ╚═╗╠═╣",
|
||||
" ╚╝ ╩ ╩╚═╝╩═╝╩ ╩ ╩╚═╝╚═╝╩ ╩",
|
||||
"",
|
||||
" Sovereign Infrastructure Status",
|
||||
"",
|
||||
f" Shield: {'● ARMED' if state.shield_armed else '○ STANDBY'}",
|
||||
f" Proof: ● ACTIVE ({state.proof_count} receipts)",
|
||||
f" Mesh: ● STABLE ({state.nodes} nodes)",
|
||||
f" Agents: ● READY (4 configured)",
|
||||
f" Oracle: ● ONLINE",
|
||||
f" Lawchain: ● SYNCED",
|
||||
"",
|
||||
f" Uptime: {state.uptime} | Epoch: Citrinitas",
|
||||
""
|
||||
]
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects=get_status_effects()
|
||||
)
|
||||
|
||||
|
||||
async def cmd_mesh_status(req: CommandRequest) -> CommandResponse:
|
||||
"""Mesh network status."""
|
||||
global state
|
||||
|
||||
# Try to get real Tailscale status
|
||||
nodes = await get_tailscale_nodes()
|
||||
state.nodes = len(nodes)
|
||||
|
||||
lines = [
|
||||
"",
|
||||
" 🕸 MESH STATUS: STABLE",
|
||||
"",
|
||||
f" Tailnet: {state.tailnet}",
|
||||
" Protocol: WireGuard + Tailscale",
|
||||
""
|
||||
]
|
||||
|
||||
if nodes:
|
||||
lines.append(" NODE TYPE STATUS LATENCY")
|
||||
lines.append(" " + "─" * 50)
|
||||
for node in nodes:
|
||||
status = "● online" if node.get("online") else "○ offline"
|
||||
lines.append(f" {node['name']:<14} {node['type']:<8} {status:<10} {node.get('latency', '—')}")
|
||||
else:
|
||||
lines.append(" (No nodes detected - check Tailscale status)")
|
||||
|
||||
lines.append("")
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={"nodes": state.nodes}
|
||||
)
|
||||
|
||||
|
||||
async def cmd_shield_status(req: CommandRequest) -> CommandResponse:
|
||||
"""Shield defense status."""
|
||||
global state
|
||||
|
||||
lines = [
|
||||
"",
|
||||
f" 🛡 SHIELD STATUS: {'ARMED' if state.shield_armed else 'STANDBY'}",
|
||||
"",
|
||||
" VECTOR STATUS LAST EVENT",
|
||||
" " + "─" * 50,
|
||||
" network ● monitoring 2s ago: normal traffic",
|
||||
" wifi ● monitoring 45s ago: all clear",
|
||||
" bluetooth ● monitoring 3m ago: no threats",
|
||||
" usb ● monitoring 12m ago: all clear",
|
||||
" process ● monitoring 1s ago: processes nominal",
|
||||
" file ● monitoring 8s ago: integrity OK",
|
||||
"",
|
||||
" Response level: BLOCK | Dry-run: OFF",
|
||||
""
|
||||
]
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={"shield": {"armed": state.shield_armed}}
|
||||
)
|
||||
|
||||
|
||||
async def cmd_shield_arm(req: CommandRequest) -> CommandResponse:
|
||||
"""Arm the shield."""
|
||||
global state
|
||||
state.shield_armed = True
|
||||
|
||||
# Log event
|
||||
log_event("shield.armed", {"user": req.user})
|
||||
|
||||
# Broadcast to all connected clients
|
||||
await manager.broadcast({
|
||||
"type": "shield.event",
|
||||
"event": "Shield ARMED",
|
||||
"severity": "info"
|
||||
})
|
||||
|
||||
lines = [
|
||||
"",
|
||||
" ⚡ Arming shield...",
|
||||
" 🛡 Shield ARMED - All vectors active",
|
||||
"",
|
||||
" ✓ Generating proof receipt...",
|
||||
f" ✓ Receipt anchored: shield_arm_{uuid.uuid4().hex[:8]}",
|
||||
""
|
||||
]
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={"shield": {"armed": True}}
|
||||
)
|
||||
|
||||
|
||||
async def cmd_shield_disarm(req: CommandRequest) -> CommandResponse:
|
||||
"""Disarm the shield."""
|
||||
global state
|
||||
state.shield_armed = False
|
||||
|
||||
log_event("shield.disarmed", {"user": req.user})
|
||||
|
||||
await manager.broadcast({
|
||||
"type": "shield.event",
|
||||
"event": "Shield DISARMED",
|
||||
"severity": "warning"
|
||||
})
|
||||
|
||||
lines = [
|
||||
"",
|
||||
" ⚠ Disarming shield...",
|
||||
" ○ Shield STANDBY - Vectors paused",
|
||||
"",
|
||||
f" ✓ Receipt anchored: shield_disarm_{uuid.uuid4().hex[:8]}",
|
||||
""
|
||||
]
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={"shield": {"armed": False}}
|
||||
)
|
||||
|
||||
|
||||
async def cmd_proof_latest(req: CommandRequest) -> CommandResponse:
|
||||
"""Show latest proof receipts."""
|
||||
global state
|
||||
|
||||
# Try to read real proofs
|
||||
proofs = await get_latest_proofs(5)
|
||||
|
||||
lines = [
|
||||
"",
|
||||
" 📜 PROOF SYSTEM: ACTIVE",
|
||||
"",
|
||||
f" Total Receipts: {state.proof_count}",
|
||||
f" Merkle Root: 0x{uuid.uuid4().hex[:16]}",
|
||||
f" Last Anchor: 12s ago",
|
||||
" Anchor Type: mesh + ots",
|
||||
"",
|
||||
" LATEST RECEIPTS:",
|
||||
" " + "─" * 50,
|
||||
]
|
||||
|
||||
if proofs:
|
||||
for p in proofs:
|
||||
lines.append(f" {p['id']:<20} {p['ts']:<20} {p['type']}")
|
||||
else:
|
||||
lines.append(" (Generate proofs with 'proof generate')")
|
||||
|
||||
lines.append("")
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={"proofs": state.proof_count}
|
||||
)
|
||||
|
||||
|
||||
async def cmd_proof_generate(req: CommandRequest) -> CommandResponse:
|
||||
"""Generate a new proof receipt."""
|
||||
global state
|
||||
state.proof_count += 1
|
||||
|
||||
proof_id = f"proof_{uuid.uuid4().hex[:12]}"
|
||||
ts = datetime.now(timezone.utc).isoformat()
|
||||
|
||||
# Log event
|
||||
log_event("proof.generated", {"proof_id": proof_id, "user": req.user})
|
||||
|
||||
# Broadcast to clients
|
||||
await manager.broadcast({
|
||||
"type": "proof.new",
|
||||
"proof_id": proof_id
|
||||
})
|
||||
|
||||
lines = [
|
||||
"",
|
||||
" ⚙ Generating cryptographic proof...",
|
||||
f" Action: manual_generation",
|
||||
f" Timestamp: {ts}",
|
||||
f" Data hash: blake3:{uuid.uuid4().hex[:32]}",
|
||||
"",
|
||||
f" ✓ Proof generated: {proof_id}",
|
||||
f" ✓ Anchored to mesh ({state.proof_count} total)",
|
||||
""
|
||||
]
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={"proofs": state.proof_count}
|
||||
)
|
||||
|
||||
|
||||
async def cmd_agents_list(req: CommandRequest) -> CommandResponse:
|
||||
"""List agent status."""
|
||||
|
||||
agents = [
|
||||
{"name": "Sentinel", "role": "Monitor & Guard", "status": "ACTIVE", "tasks": 47},
|
||||
{"name": "Orchestrator", "role": "Assign & Route", "status": "ACTIVE", "tasks": 156},
|
||||
{"name": "Analyst", "role": "Interpret & Correlate", "status": "IDLE", "tasks": 0},
|
||||
{"name": "Executor", "role": "Act & Apply", "status": "IDLE", "tasks": 0},
|
||||
]
|
||||
|
||||
lines = [
|
||||
"",
|
||||
" AGENTS STATUS",
|
||||
"",
|
||||
" NAME ROLE STATUS TASKS",
|
||||
" " + "─" * 55,
|
||||
]
|
||||
|
||||
for a in agents:
|
||||
status_icon = "●" if a["status"] == "ACTIVE" else "○"
|
||||
lines.append(f" {a['name']:<13} {a['role']:<20} {status_icon} {a['status']:<6} {a['tasks']}")
|
||||
|
||||
lines.append("")
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={}
|
||||
)
|
||||
|
||||
|
||||
async def cmd_oracle_reason(req: CommandRequest) -> CommandResponse:
|
||||
"""Oracle reasoning query."""
|
||||
query = " ".join(req.args) if req.args else req.command.replace("oracle reason", "").strip()
|
||||
|
||||
lines = [
|
||||
"",
|
||||
" 🔮 Oracle reasoning...",
|
||||
"",
|
||||
f" Query: \"{query or 'system analysis'}\"",
|
||||
" Analyzing context...",
|
||||
" Cross-referencing Lawchain...",
|
||||
"",
|
||||
" ✓ Reasoning complete",
|
||||
"",
|
||||
" Recommendation: Continue current operational posture.",
|
||||
" Confidence: HIGH | Risk: MINIMAL",
|
||||
"",
|
||||
f" Receipt: oracle_{uuid.uuid4().hex[:8]}",
|
||||
""
|
||||
]
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="ok",
|
||||
lines=lines,
|
||||
effects={}
|
||||
)
|
||||
|
||||
|
||||
# Command registry
|
||||
COMMANDS = {
|
||||
"ping": cmd_ping,
|
||||
"status": cmd_status,
|
||||
"mesh status": cmd_mesh_status,
|
||||
"mesh nodes": cmd_mesh_status,
|
||||
"shield status": cmd_shield_status,
|
||||
"shield arm": cmd_shield_arm,
|
||||
"shield disarm": cmd_shield_disarm,
|
||||
"proof latest": cmd_proof_latest,
|
||||
"proof status": cmd_proof_latest,
|
||||
"proof generate": cmd_proof_generate,
|
||||
"agents list": cmd_agents_list,
|
||||
}
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# HELPERS
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
def get_status_effects() -> dict:
|
||||
"""Get current status as effects payload."""
|
||||
global state
|
||||
return {
|
||||
"nodes": state.nodes,
|
||||
"shield": {"armed": state.shield_armed},
|
||||
"proofs": state.proof_count,
|
||||
"uptime": state.uptime,
|
||||
"tailnet": state.tailnet,
|
||||
"node": state.hostname
|
||||
}
|
||||
|
||||
|
||||
async def get_tailscale_nodes() -> list[dict]:
|
||||
"""Get Tailscale node status."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["tailscale", "status", "--json"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
if result.returncode == 0:
|
||||
data = json.loads(result.stdout)
|
||||
nodes = []
|
||||
for peer_id, peer in data.get("Peer", {}).items():
|
||||
nodes.append({
|
||||
"name": peer.get("HostName", "unknown"),
|
||||
"type": "PEER",
|
||||
"online": peer.get("Online", False),
|
||||
"latency": f"{peer.get('CurAddr', '').split(':')[0]}"
|
||||
})
|
||||
# Add self
|
||||
if data.get("Self"):
|
||||
nodes.insert(0, {
|
||||
"name": data["Self"].get("HostName", "self"),
|
||||
"type": "SELF",
|
||||
"online": True,
|
||||
"latency": "0ms"
|
||||
})
|
||||
return nodes
|
||||
except Exception as e:
|
||||
print(f"Tailscale query failed: {e}")
|
||||
return []
|
||||
|
||||
|
||||
async def get_latest_proofs(limit: int = 5) -> list[dict]:
|
||||
"""Get latest proof receipts from database."""
|
||||
conn = get_db()
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
SELECT * FROM events
|
||||
WHERE type LIKE 'proof.%'
|
||||
ORDER BY ts DESC
|
||||
LIMIT ?
|
||||
""", (limit,))
|
||||
rows = cur.fetchall()
|
||||
conn.close()
|
||||
|
||||
proofs = []
|
||||
for row in rows:
|
||||
payload = json.loads(row["payload"]) if row["payload"] else {}
|
||||
proofs.append({
|
||||
"id": payload.get("proof_id", f"proof_{row['id']}"),
|
||||
"ts": row["ts"][:19],
|
||||
"type": row["type"]
|
||||
})
|
||||
return proofs
|
||||
|
||||
|
||||
def log_event(event_type: str, payload: dict):
|
||||
"""Log event to database."""
|
||||
conn = get_db()
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
INSERT INTO events (ts, type, payload)
|
||||
VALUES (?, ?, ?)
|
||||
""", (
|
||||
datetime.now(timezone.utc).isoformat(),
|
||||
event_type,
|
||||
json.dumps(payload)
|
||||
))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def log_command(session_id: str, command: str, status: str, duration_ms: int, error: str = None):
|
||||
"""Log command to database."""
|
||||
conn = get_db()
|
||||
cur = conn.cursor()
|
||||
cur.execute("""
|
||||
INSERT INTO command_log (session_id, ts, command, status, duration_ms, error)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
session_id,
|
||||
datetime.now(timezone.utc).isoformat(),
|
||||
command,
|
||||
status,
|
||||
duration_ms,
|
||||
error
|
||||
))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def update_session(session_id: str, user: str, meta: dict):
|
||||
"""Create or update session."""
|
||||
conn = get_db()
|
||||
cur = conn.cursor()
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
|
||||
cur.execute("SELECT id FROM sessions WHERE id = ?", (session_id,))
|
||||
if cur.fetchone():
|
||||
cur.execute("""
|
||||
UPDATE sessions SET last_seen_at = ? WHERE id = ?
|
||||
""", (now, session_id))
|
||||
else:
|
||||
cur.execute("""
|
||||
INSERT INTO sessions (id, user, created_at, last_seen_at, client, meta)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
session_id,
|
||||
user,
|
||||
now,
|
||||
now,
|
||||
meta.get("client"),
|
||||
json.dumps(meta)
|
||||
))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def extract_user(request: Request) -> str:
|
||||
"""Extract user identity from request."""
|
||||
if config.TAILSCALE_ENABLED:
|
||||
ts_user = request.headers.get(config.TAILSCALE_USER_HEADER)
|
||||
if ts_user:
|
||||
return ts_user.split("@")[0] # Extract username from email
|
||||
return "anonymous"
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# FASTAPI APP
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""App lifespan handler."""
|
||||
# Startup
|
||||
init_db()
|
||||
|
||||
# Get initial node count
|
||||
nodes = await get_tailscale_nodes()
|
||||
state.nodes = len(nodes)
|
||||
|
||||
# Load proof count from DB
|
||||
conn = get_db()
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT COUNT(*) FROM events WHERE type LIKE 'proof.%'")
|
||||
state.proof_count = cur.fetchone()[0]
|
||||
conn.close()
|
||||
|
||||
print(f"🚀 offsec-mcp started | Nodes: {state.nodes} | Proofs: {state.proof_count}")
|
||||
|
||||
yield
|
||||
|
||||
# Shutdown
|
||||
print("👋 offsec-mcp shutting down")
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title="offsec-mcp",
|
||||
description="Sovereign MCP Backend for IoTek.nexus",
|
||||
version="1.0.0",
|
||||
lifespan=lifespan
|
||||
)
|
||||
|
||||
# CORS
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=config.CORS_ORIGINS,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# ROUTES
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
@app.post("/mcp/command", response_model=CommandResponse)
|
||||
async def handle_command(req: CommandRequest, request: Request):
|
||||
"""Handle command from console."""
|
||||
start = time.time()
|
||||
|
||||
# Extract real user if available
|
||||
ts_user = extract_user(request)
|
||||
if ts_user != "anonymous":
|
||||
req.user = ts_user
|
||||
|
||||
# Update session
|
||||
update_session(req.session_id, req.user, req.meta)
|
||||
|
||||
# Find handler
|
||||
cmd_lower = req.command.lower().strip()
|
||||
handler = None
|
||||
|
||||
# Exact match
|
||||
if cmd_lower in COMMANDS:
|
||||
handler = COMMANDS[cmd_lower]
|
||||
else:
|
||||
# Prefix match (for commands with args like "oracle reason <query>")
|
||||
for key in COMMANDS:
|
||||
if cmd_lower.startswith(key):
|
||||
handler = COMMANDS[key]
|
||||
# Extract args from command
|
||||
remaining = cmd_lower[len(key):].strip()
|
||||
if remaining:
|
||||
req.args = remaining.split()
|
||||
break
|
||||
|
||||
if not handler:
|
||||
duration_ms = int((time.time() - start) * 1000)
|
||||
log_command(req.session_id, req.command, "error", duration_ms, "Unknown command")
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="error",
|
||||
lines=[
|
||||
f" Unknown command: {req.command}",
|
||||
" Type 'help' for available commands."
|
||||
],
|
||||
error="Unknown command"
|
||||
)
|
||||
|
||||
try:
|
||||
response = await handler(req)
|
||||
duration_ms = int((time.time() - start) * 1000)
|
||||
log_command(req.session_id, req.command, "ok", duration_ms)
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
duration_ms = int((time.time() - start) * 1000)
|
||||
log_command(req.session_id, req.command, "error", duration_ms, str(e))
|
||||
|
||||
return CommandResponse(
|
||||
id=f"cmd-{uuid.uuid4().hex[:8]}",
|
||||
status="error",
|
||||
lines=[f" Error: {str(e)}"],
|
||||
error=str(e)
|
||||
)
|
||||
|
||||
|
||||
@app.websocket("/ws")
|
||||
async def websocket_endpoint(websocket: WebSocket):
|
||||
"""WebSocket for live updates."""
|
||||
session_id = None
|
||||
|
||||
try:
|
||||
await websocket.accept()
|
||||
|
||||
# Wait for handshake
|
||||
data = await websocket.receive_json()
|
||||
if data.get("type") == "handshake":
|
||||
session_id = data.get("session_id", str(uuid.uuid4()))
|
||||
user = data.get("user", "anonymous")
|
||||
|
||||
# Register connection
|
||||
manager.active_connections[session_id] = websocket
|
||||
|
||||
# Send welcome
|
||||
await websocket.send_json({
|
||||
"type": "status.update",
|
||||
"payload": get_status_effects()
|
||||
})
|
||||
|
||||
print(f"WS connected: {session_id} ({user})")
|
||||
|
||||
# Keep connection alive and handle messages
|
||||
while True:
|
||||
try:
|
||||
msg = await asyncio.wait_for(
|
||||
websocket.receive_json(),
|
||||
timeout=30 # Ping every 30s
|
||||
)
|
||||
|
||||
# Handle client messages if needed
|
||||
if msg.get("type") == "ping":
|
||||
await websocket.send_json({"type": "pong"})
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
# Send keepalive
|
||||
await websocket.send_json({
|
||||
"type": "status.update",
|
||||
"payload": get_status_effects()
|
||||
})
|
||||
|
||||
except WebSocketDisconnect:
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f"WS error: {e}")
|
||||
finally:
|
||||
if session_id:
|
||||
manager.disconnect(session_id)
|
||||
print(f"WS disconnected: {session_id}")
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
"""Health check endpoint."""
|
||||
return {
|
||||
"status": "ok",
|
||||
"nodes": state.nodes,
|
||||
"proofs": state.proof_count,
|
||||
"uptime": state.uptime
|
||||
}
|
||||
|
||||
|
||||
# Serve console HTML if configured
|
||||
if config.STATIC_DIR and config.STATIC_DIR.exists():
|
||||
app.mount("/static", StaticFiles(directory=str(config.STATIC_DIR)), name="static")
|
||||
|
||||
@app.get("/")
|
||||
async def serve_console():
|
||||
return FileResponse(config.STATIC_DIR / "iotek-nexus-live.html")
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
# MAIN
|
||||
# ═══════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
"offsec_mcp:app",
|
||||
host="0.0.0.0",
|
||||
port=8080,
|
||||
reload=True
|
||||
)
|
||||
5
VaultMesh_Catalog_v1/files/requirements-mcp.txt
Normal file
5
VaultMesh_Catalog_v1/files/requirements-mcp.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
# offsec-mcp dependencies
|
||||
fastapi>=0.104.0
|
||||
uvicorn[standard]>=0.24.0
|
||||
pydantic>=2.0.0
|
||||
websockets>=12.0
|
||||
Reference in New Issue
Block a user