feat: add SQLCipher database encryption support and consolidate agent documentation
Some checks failed
Blockchain Synchronization Verification / sync-verification (push) Failing after 3s
CLI Tests / test-cli (push) Failing after 3s
Cross-Chain Functionality Tests / test-cross-chain-sync (push) Successful in 2s
Cross-Chain Functionality Tests / test-cross-chain-transactions (push) Successful in 3s
Cross-Chain Functionality Tests / test-cross-chain-bridge (push) Has been skipped
Cross-Chain Functionality Tests / test-multi-chain-consensus (push) Successful in 2s
Cross-Chain Functionality Tests / aggregate-results (push) Has been skipped
Deploy to Testnet / deploy-testnet (push) Successful in 1m12s
Documentation Validation / validate-docs (push) Failing after 8s
Documentation Validation / validate-policies-strict (push) Successful in 3s
Integration Tests / test-service-integration (push) Successful in 2m6s
Multi-Chain Island Architecture Tests / test-multi-chain-island (push) Successful in 2s
Multi-Node Blockchain Health Monitoring / health-check (push) Failing after 4s
P2P Network Verification / p2p-verification (push) Successful in 4s
Package Tests / Python package - aitbc-agent-sdk (push) Successful in 32s
Package Tests / Python package - aitbc-core (push) Successful in 14s
Package Tests / Python package - aitbc-crypto (push) Successful in 12s
Package Tests / Python package - aitbc-sdk (push) Successful in 9s
Package Tests / JavaScript package - aitbc-sdk-js (push) Successful in 8s
Package Tests / JavaScript package - aitbc-token (push) Successful in 17s
Python Tests / test-python (push) Successful in 15s
Security Scanning / security-scan (push) Successful in 27s
Node Failover Simulation / failover-test (push) Successful in 7s
Multi-Node Stress Testing / stress-test (push) Successful in 6s
Cross-Node Transaction Testing / transaction-test (push) Successful in 4s

- Add SQLCipher encryption for ait-mainnet database with configurable flag
- Add db_encryption_enabled and db_encryption_key_path config settings
- Implement encryption key loading and PRAGMA key setup via connection events
- Add shutdown_db function for proper database cleanup
- Export middleware classes in aitbc/__init__.py
- Fix import path in sync.py for settings
- Remove duplicate agent documentation from docs
This commit is contained in:
aitbc
2026-05-03 12:00:38 +02:00
parent 8f6a2f208c
commit 19d415a235
361 changed files with 6432 additions and 4521 deletions

View File

@@ -46,6 +46,12 @@ from .exceptions import (
RetryError,
ValidationError,
)
from .middleware import (
RequestIDMiddleware,
PerformanceLoggingMiddleware,
RequestValidationMiddleware,
ErrorHandlerMiddleware,
)
from .paths import (
ensure_dir,
ensure_file_dir,

38
aitbc/logging.py Normal file
View File

@@ -0,0 +1,38 @@
"""
Logging module (alias for aitbc_logging)
This module provides a compatibility layer for imports from aitbc.logging
"""
import logging
import sys
from typing import Optional
def setup_logger(
name: str,
level: str = "INFO",
format_string: Optional[str] = None
) -> logging.Logger:
"""Setup a logger with consistent formatting"""
if format_string is None:
format_string = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
logger = logging.getLogger(name)
logger.setLevel(getattr(logging, level.upper()))
if not logger.handlers:
handler = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter(format_string)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
def get_logger(name: str) -> logging.Logger:
"""Get a logger instance"""
return logging.getLogger(name)
def configure_logging(level: str = "INFO", format_string: str = None):
"""Configure logging with default settings"""
return setup_logger("aitbc", level=level, format_string=format_string)
__all__ = ["get_logger", "setup_logger", "configure_logging"]

View File

@@ -0,0 +1,15 @@
"""
Shared middleware for AITBC services
"""
from .request_id import RequestIDMiddleware
from .performance import PerformanceLoggingMiddleware
from .validation import RequestValidationMiddleware
from .error_handler import ErrorHandlerMiddleware
__all__ = [
"RequestIDMiddleware",
"PerformanceLoggingMiddleware",
"RequestValidationMiddleware",
"ErrorHandlerMiddleware",
]

View File

@@ -0,0 +1,61 @@
"""
Standardized error response middleware for FastAPI
"""
from typing import Callable
from fastapi import Request, HTTPException
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp
from aitbc.aitbc_logging import get_logger
logger = get_logger(__name__)
class ErrorHandlerMiddleware(BaseHTTPMiddleware):
"""Middleware to standardize error responses"""
async def dispatch(self, request: Request, call_next: Callable) -> JSONResponse:
try:
response = await call_next(request)
return response
except HTTPException as e:
logger.warning(
"HTTP exception",
status_code=e.status_code,
detail=e.detail,
path=request.url.path,
method=request.method,
)
return JSONResponse(
status_code=e.status_code,
content={
"error": {
"type": "http_error",
"message": e.detail,
"status_code": e.status_code,
"path": request.url.path,
}
},
)
except Exception as e:
logger.error(
"Unhandled exception",
error=str(e),
path=request.url.path,
method=request.method,
exc_info=True,
)
return JSONResponse(
status_code=500,
content={
"error": {
"type": "internal_error",
"message": "An internal server error occurred",
"status_code": 500,
"path": request.url.path,
}
},
)

View File

@@ -0,0 +1,41 @@
"""
Performance logging middleware for tracking request timing
"""
import time
from typing import Callable
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp
from aitbc.aitbc_logging import get_logger
logger = get_logger(__name__)
class PerformanceLoggingMiddleware(BaseHTTPMiddleware):
"""Middleware to log request performance metrics"""
async def dispatch(self, request: Request, call_next: Callable) -> Response:
start_time = time.perf_counter()
# Process request
response = await call_next(request)
# Calculate duration
duration = time.perf_counter() - start_time
# Log performance metrics
logger.info(
"Request performance",
method=request.method,
path=request.url.path,
status_code=response.status_code,
duration_ms=round(duration * 1000, 2),
)
# Add performance header
response.headers["X-Process-Time"] = f"{duration:.3f}"
return response

View File

@@ -0,0 +1,54 @@
"""
Request ID correlation middleware for structured logging
"""
import uuid
from typing import Callable
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp
from aitbc.aitbc_logging import get_logger
logger = get_logger(__name__)
class RequestIDMiddleware(BaseHTTPMiddleware):
"""Middleware to add request ID to all requests for correlation"""
def __init__(self, app: ASGIApp) -> None:
super().__init__(app)
self.header_name = "X-Request-ID"
async def dispatch(self, request: Request, call_next: Callable) -> Response:
# Generate or retrieve request ID
request_id = request.headers.get(self.header_name) or str(uuid.uuid4())
# Add request ID to request state for use in endpoints
request.state.request_id = request_id
# Bind request ID to logger context
logger = get_logger(__name__).bind(request_id=request_id)
# Log request start
logger.info(
"Incoming request",
method=request.method,
path=request.url.path,
client=request.client.host if request.client else "unknown",
)
# Process request
response = await call_next(request)
# Add request ID to response headers
response.headers[self.header_name] = request_id
# Log request completion
logger.info(
"Request completed",
status_code=response.status_code,
)
return response

View File

@@ -0,0 +1,67 @@
"""
Request validation middleware for FastAPI
"""
from typing import Callable
from fastapi import Request, HTTPException, Response
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp
from aitbc.aitbc_logging import get_logger
logger = get_logger(__name__)
class RequestValidationMiddleware(BaseHTTPMiddleware):
"""Middleware to validate incoming requests"""
def __init__(
self,
app: ASGIApp,
max_request_size: int = 10 * 1024 * 1024, # 10MB default
max_response_size: int = 10 * 1024 * 1024, # 10MB default
) -> None:
super().__init__(app)
self.max_request_size = max_request_size
self.max_response_size = max_response_size
async def dispatch(self, request: Request, call_next: Callable) -> Response:
# Validate request size
content_length = request.headers.get("content-length")
if content_length:
try:
size = int(content_length)
if size > self.max_request_size:
logger.warning(
"Request too large",
content_length=size,
max_size=self.max_request_size,
client=request.client.host if request.client else "unknown",
)
raise HTTPException(
status_code=413,
detail=f"Request too large. Maximum size is {self.max_request_size} bytes",
)
except ValueError:
logger.warning("Invalid content-length header", content_length=content_length)
# Process request
response = await call_next(request)
# Validate response size (skip for streaming responses)
if hasattr(response, "body"):
response_size = len(response.body)
if response_size > self.max_response_size:
logger.warning(
"Response too large",
response_size=response_size,
max_size=self.max_response_size,
path=request.url.path,
)
raise HTTPException(
status_code=500,
detail="Response too large",
)
return response