78 lines
2.4 KiB
Python
78 lines
2.4 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
|
|
import uvicorn
|
|
|
|
from app.adapters import TrustedDnsResolver
|
|
from app.api import create_app
|
|
from app.config import ActiveConfig, validate_config
|
|
from app.db import engine_and_sessions
|
|
from app.file_pipeline import ClamAvInstream, DependencyFailure
|
|
from app.repository import Repository
|
|
from app.service import SafetyService
|
|
from app.settings import BootstrapSettings, EmergencyMode
|
|
from app.telemetry import init_telemetry, instrument_fastapi, shutdown_telemetry
|
|
|
|
|
|
async def build_runtime() -> tuple[object, object]:
|
|
settings = BootstrapSettings()
|
|
assert settings.database_url and settings.service_token
|
|
engine, sessions = engine_and_sessions(settings.database_url.get_secret_value())
|
|
repository = Repository(sessions)
|
|
row = await repository.active_config()
|
|
rules, detector, digest = validate_config(row.config, settings.artifacts_dir)
|
|
if digest != row.config_sha256:
|
|
raise RuntimeError("active config hash mismatch")
|
|
config = ActiveConfig(row.version, row.config, rules, detector)
|
|
mode = EmergencyMode.from_file(settings.mode_file)
|
|
resolver = TrustedDnsResolver(
|
|
[item.strip() for item in settings.dns_resolvers.split(",") if item.strip()]
|
|
)
|
|
clamav = ClamAvInstream(settings.clamav_host, settings.clamav_port)
|
|
if mode.mock:
|
|
signatures_version = "unavailable"
|
|
files_ready = False
|
|
else:
|
|
try:
|
|
signatures_version = await clamav.signatures_version()
|
|
files_ready = True
|
|
except DependencyFailure:
|
|
signatures_version = "unavailable"
|
|
files_ready = False
|
|
service = SafetyService(
|
|
repository,
|
|
config,
|
|
mode,
|
|
resolver,
|
|
files_ready=files_ready,
|
|
signatures_version=signatures_version,
|
|
)
|
|
app = create_app(service, settings.service_token.get_secret_value())
|
|
instrument_fastapi(app)
|
|
return app, engine
|
|
|
|
|
|
async def serve() -> None:
|
|
settings = BootstrapSettings()
|
|
init_telemetry("api")
|
|
engine = None
|
|
try:
|
|
app, engine = await build_runtime()
|
|
server = uvicorn.Server(
|
|
uvicorn.Config(app, host=settings.host, port=settings.port, proxy_headers=False)
|
|
)
|
|
await server.serve()
|
|
finally:
|
|
if engine is not None:
|
|
await engine.dispose()
|
|
shutdown_telemetry()
|
|
|
|
|
|
def run() -> None:
|
|
asyncio.run(serve())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run()
|