diff --git a/kernel_ai/api/rest.py b/kernel_ai/api/rest.py index 24ed2c2..40592a6 100644 --- a/kernel_ai/api/rest.py +++ b/kernel_ai/api/rest.py @@ -1,142 +1,38 @@ -""" -REST API under ``/api``. Implementations are in ``kernel_ai.webapp`` (lazy import). -""" +"""REST API under ``/api``.""" from flask import Blueprint +from kernel_ai.http import api as h bp = Blueprint("api", __name__, url_prefix="/api") - -def _core(): - from kernel_ai import webapp as core - - return core - - -@bp.route("/syscalls-realtime") -def syscalls_realtime(): - return _core().syscalls_realtime() - - -@bp.route("/kernel-data") -def kernel_data(): - return _core().kernel_data() - - -@bp.route("/process-kernel-map") -def process_kernel_map(): - return _core().process_kernel_map() - - -@bp.route("/processes") -def get_processes(): - return _core().get_processes() - - -@bp.route("/nginx-files") -def nginx_files(): - return _core().nginx_files() - - -@bp.route("/active-connections") -def active_connections(): - return _core().active_connections() - - -@bp.route("/traceroute") -def traceroute_info(): - return _core().traceroute_info() - - -@bp.route("/network-stack-realtime") -def network_stack_realtime(): - return _core().network_stack_realtime() - - -@bp.route("/devices-realtime") -def devices_realtime(): - return _core().devices_realtime() - - -@bp.route("/filesystem-blocks") -def filesystem_blocks(): - return _core().filesystem_blocks() - - -@bp.route("/isolation-context") -def isolation_context(): - return _core().isolation_context() - - -@bp.route("/process//threads") -def get_process_threads(pid): - return _core().get_process_threads(pid) - - -@bp.route("/process//cpu") -def get_process_cpu(pid): - return _core().get_process_cpu(pid) - - -@bp.route("/process//fds") -def get_process_fds(pid): - return _core().get_process_fds(pid) - - -@bp.route("/processes-detailed") -def get_processes_detailed(): - return _core().get_processes_detailed() - - -@bp.route("/ipc-links") -def get_ipc_links(): - return _core().get_ipc_links() - - -@bp.route("/proc-matrix") -def get_proc_matrix(): - return _core().get_proc_matrix() - - -@bp.route("/proc-timeline") -def get_proc_timeline(): - return _core().get_proc_timeline() - - -@bp.route("/execution-context") -def get_execution_context(): - return _core().get_execution_context() - - -@bp.route("/kernel-dna") -def kernel_dna(): - return _core().kernel_dna() - - -@bp.route("/crypto-realtime") -def crypto_realtime(): - return _core().crypto_realtime() - - -@bp.route("/security-realtime") -def security_realtime(): - return _core().security_realtime() - - -@bp.route("/processes-realtime") -def processes_realtime(): - return _core().processes_realtime() - - -@bp.route("/frontend-logs", methods=["POST", "OPTIONS"]) -def ingest_frontend_logs(): - return _core().ingest_frontend_logs() - - -@bp.route("/proc-graph") -def proc_graph(): - return _core().get_proc_graph() - - -@bp.route("/process-files") -def process_files(): - return _core().get_process_files() +_API_ROUTES = [ + ("/syscalls-realtime", "syscalls_realtime", h.syscalls_realtime, None), + ("/kernel-data", "kernel_data", h.kernel_data, None), + ("/process-kernel-map", "process_kernel_map", h.process_kernel_map, None), + ("/processes", "get_processes", h.get_processes, None), + ("/nginx-files", "nginx_files", h.nginx_files, None), + ("/active-connections", "active_connections", h.active_connections, None), + ("/traceroute", "traceroute_info", h.traceroute_info, None), + ("/network-stack-realtime", "network_stack_realtime", h.network_stack_realtime, None), + ("/devices-realtime", "devices_realtime", h.devices_realtime, None), + ("/filesystem-blocks", "filesystem_blocks", h.filesystem_blocks, None), + ("/isolation-context", "isolation_context", h.isolation_context, None), + ("/process//threads", "get_process_threads", h.get_process_threads, None), + ("/process//cpu", "get_process_cpu", h.get_process_cpu, None), + ("/process//fds", "get_process_fds", h.get_process_fds, None), + ("/processes-detailed", "get_processes_detailed", h.get_processes_detailed, None), + ("/ipc-links", "get_ipc_links", h.get_ipc_links, None), + ("/proc-matrix", "get_proc_matrix", h.get_proc_matrix, None), + ("/proc-timeline", "get_proc_timeline", h.get_proc_timeline, None), + ("/execution-context", "get_execution_context", h.get_execution_context, None), + ("/kernel-dna", "kernel_dna", h.kernel_dna, None), + ("/crypto-realtime", "crypto_realtime", h.crypto_realtime, None), + ("/security-realtime", "security_realtime", h.security_realtime, None), + ("/processes-realtime", "processes_realtime", h.processes_realtime, None), + ("/frontend-logs", "ingest_frontend_logs", h.ingest_frontend_logs, ["POST", "OPTIONS"]), + ("/proc-graph", "proc_graph", h.get_proc_graph, None), + ("/process-files", "process_files", h.get_process_files, None), +] + +for rule, endpoint, view_func, methods in _API_ROUTES: + kwargs = {"methods": methods} if methods else {} + bp.add_url_rule(rule, endpoint=endpoint, view_func=view_func, **kwargs) diff --git a/kernel_ai/contracts/api_contracts.py b/kernel_ai/contracts/api_contracts.py index da06b93..88cf360 100644 --- a/kernel_ai/contracts/api_contracts.py +++ b/kernel_ai/contracts/api_contracts.py @@ -47,6 +47,32 @@ class FilesystemBlocksResponse(TypedDict): meta: dict +class ProcessesRealtimeResponse(TypedDict): + timestamp: str + syscalls_interception: list + network_tracing: list + security_hooks: list + neural_graph: dict + memory_visual: dict + meta: dict + + +class ExecutionContextResponse(TypedDict): + mode: str + cpu_state: str + syscall_active: bool + interrupts: list + irq_stack: dict + timestamp: str + + +class KernelDNAResponse(TypedDict): + nucleotides: list + genes: list + mutations: list + timestamp: str + + def _expect_dict(payload: Any, name: str) -> dict: if not isinstance(payload, dict): raise ValueError(f"{name} must be a JSON object") @@ -106,3 +132,32 @@ def validate_filesystem_blocks_response(payload: Any) -> None: _expect_key(data, "zones", list, "filesystem_blocks") _expect_key(data, "blocks", list, "filesystem_blocks") _expect_key(data, "meta", dict, "filesystem_blocks") + + +def validate_processes_realtime_response(payload: Any) -> None: + data = _expect_dict(payload, "processes_realtime") + _expect_key(data, "timestamp", str, "processes_realtime") + _expect_key(data, "syscalls_interception", list, "processes_realtime") + _expect_key(data, "network_tracing", list, "processes_realtime") + _expect_key(data, "security_hooks", list, "processes_realtime") + _expect_key(data, "neural_graph", dict, "processes_realtime") + _expect_key(data, "memory_visual", dict, "processes_realtime") + _expect_key(data, "meta", dict, "processes_realtime") + + +def validate_execution_context_response(payload: Any) -> None: + data = _expect_dict(payload, "execution_context") + _expect_key(data, "mode", str, "execution_context") + _expect_key(data, "cpu_state", str, "execution_context") + _expect_key(data, "syscall_active", bool, "execution_context") + _expect_key(data, "interrupts", list, "execution_context") + _expect_key(data, "irq_stack", dict, "execution_context") + _expect_key(data, "timestamp", str, "execution_context") + + +def validate_kernel_dna_response(payload: Any) -> None: + data = _expect_dict(payload, "kernel_dna") + _expect_key(data, "nucleotides", list, "kernel_dna") + _expect_key(data, "genes", list, "kernel_dna") + _expect_key(data, "mutations", list, "kernel_dna") + _expect_key(data, "timestamp", str, "kernel_dna") diff --git a/kernel_ai/views/pages.py b/kernel_ai/views/pages.py index fd59bfa..adf395e 100644 --- a/kernel_ai/views/pages.py +++ b/kernel_ai/views/pages.py @@ -1,82 +1,27 @@ -""" -Site pages: index, subsystem HTML, health, static files. - -View implementations live in ``kernel_ai.webapp``; this module only wires URLs (lazy import avoids cycles). -""" +"""Site pages: index, subsystem HTML, and health.""" from flask import Blueprint +from kernel_ai.http import pages as h bp = Blueprint("pages", __name__) - -def _core(): - from kernel_ai import webapp as core - - return core - - -@bp.route("/") -def index(): - return _core().index() - - -@bp.route("/linux-crypto-subsystem") -def linux_crypto_subsystem_page(): - return _core().linux_crypto_subsystem_page() - - -@bp.route("/crypto") -def crypto_page_legacy(): - return _core().crypto_page_legacy() - - -@bp.route("/linux-security-subsystem") -def linux_security_subsystem_page(): - return _core().linux_security_subsystem_page() - - -@bp.route("/security") -def security_page_legacy(): - return _core().security_page_legacy() - - -@bp.route("/linux-processes-subsystem") -def linux_processes_subsystem_page(): - return _core().linux_processes_subsystem_page() - - -@bp.route("/processes") -def processes_page_legacy(): - return _core().processes_page_legacy() - - -@bp.route("/linux-crypto-subsystem.html") -def linux_crypto_subsystem_html(): - return _core().linux_crypto_subsystem_html() - - -@bp.route("/linux-security-subsystem.html") -def linux_security_subsystem_html(): - return _core().linux_security_subsystem_html() - - -@bp.route("/linux-processes-subsystem.html") -def linux_processes_subsystem_html(): - return _core().linux_processes_subsystem_html() - - -@bp.route("/linux-memory-subsystem") -def linux_memory_subsystem_page(): - return _core().linux_memory_subsystem_page() - - -@bp.route("/linux-memory-subsystem.html") -def linux_memory_subsystem_html(): - return _core().linux_memory_subsystem_html() - - -@bp.route("/health") -def health_check(): - return _core().health_check() +_PAGE_ROUTES = [ + ("/", "index", h.index), + ("/linux-crypto-subsystem", "linux_crypto_subsystem_page", h.linux_crypto_subsystem_page), + ("/crypto", "crypto_page_legacy", h.crypto_page_legacy), + ("/linux-security-subsystem", "linux_security_subsystem_page", h.linux_security_subsystem_page), + ("/security", "security_page_legacy", h.security_page_legacy), + ("/linux-processes-subsystem", "linux_processes_subsystem_page", h.linux_processes_subsystem_page), + ("/processes", "processes_page_legacy", h.processes_page_legacy), + ("/linux-crypto-subsystem.html", "linux_crypto_subsystem_html", h.linux_crypto_subsystem_html), + ("/linux-security-subsystem.html", "linux_security_subsystem_html", h.linux_security_subsystem_html), + ("/linux-processes-subsystem.html", "linux_processes_subsystem_html", h.linux_processes_subsystem_html), + ("/linux-memory-subsystem", "linux_memory_subsystem_page", h.linux_memory_subsystem_page), + ("/linux-memory-subsystem.html", "linux_memory_subsystem_html", h.linux_memory_subsystem_html), + ("/health", "health_check", h.health_check), +] + +for rule, endpoint, view_func in _PAGE_ROUTES: + bp.add_url_rule(rule, endpoint=endpoint, view_func=view_func) # /static/ is served by Flask's built-in static handler (see ``app.static_folder`` in webapp).