Some checks failed
Invert the agent model: the agent IS the computer. The message pump becomes the kernel, handlers are sandboxed apps, and all access is mediated by the platform. Phase 1 — Container foundation: - Multi-stage Dockerfile (python:3.12-slim, non-root user, /data volume) - deploy/entrypoint.py with --dry-run config validation - docker-compose.yml (cap_drop ALL, read_only, no-new-privileges) - docker-compose.dev.yml overlay for development - CI Docker build smoke test Phase 2 — Security hardening: - xml_pipeline/security/ module with default-deny container mode - Permission gate: per-listener tool allowlist enforcement - Network policy: egress control (only declared LLM backend domains) - Shell tool: disabled in container mode - File tool: restricted to /data and /config in container mode - Fetch tool: integrates network egress policy - Config loader: parses security and network YAML sections Phase 3 — Management plane: - Agent app (port 8080): minimal /health, /inject, /ws only - Management app (port 9090): full API, audit log, dashboard - SQLite-backed audit log for tool invocations and security events - Static web dashboard (no framework, WebSocket-driven) - CLI --split flag for dual-port serving All 439 existing tests pass with zero regressions. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
85 lines
2.5 KiB
Python
85 lines
2.5 KiB
Python
"""
|
|
Default-deny configuration for container mode.
|
|
|
|
In container mode:
|
|
- Shell tool is disabled entirely
|
|
- File tool is restricted to /data/ and /config/ (read-only)
|
|
- Fetch tool only allows declared LLM backend domains
|
|
- All tools require explicit per-listener allowlist
|
|
|
|
In development mode:
|
|
- All tools available (current behavior preserved)
|
|
- No filesystem restrictions
|
|
- No network restrictions
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import os
|
|
from typing import Optional
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Module-level mode state
|
|
_organism_mode: Optional[str] = None
|
|
|
|
|
|
def get_organism_mode() -> str:
|
|
"""Get the current organism mode."""
|
|
global _organism_mode
|
|
if _organism_mode is None:
|
|
_organism_mode = os.environ.get("ORGANISM_MODE", "development")
|
|
return _organism_mode
|
|
|
|
|
|
def set_organism_mode(mode: str) -> None:
|
|
"""Set the organism mode explicitly."""
|
|
global _organism_mode
|
|
if mode not in ("container", "development"):
|
|
raise ValueError(f"Invalid mode: {mode}. Must be 'container' or 'development'.")
|
|
_organism_mode = mode
|
|
logger.info(f"Organism mode set to: {mode}")
|
|
|
|
|
|
def is_container_mode() -> bool:
|
|
"""Check if running in container (default-deny) mode."""
|
|
return get_organism_mode() == "container"
|
|
|
|
|
|
def apply_container_defaults() -> None:
|
|
"""
|
|
Apply default-deny security posture for container mode.
|
|
|
|
This configures all tool modules with restrictive defaults:
|
|
- Shell: disabled
|
|
- Files: restricted to /data (rw) and /config (ro)
|
|
- Fetch: blocks all non-LLM-backend domains by default
|
|
"""
|
|
set_organism_mode("container")
|
|
|
|
# Lock down shell tool
|
|
from xml_pipeline.tools.shell import set_container_mode as shell_lock
|
|
|
|
shell_lock(True)
|
|
logger.info("Shell tool: DISABLED (container mode)")
|
|
|
|
# Lock down file tool to /data and /config
|
|
from xml_pipeline.tools.files import configure_allowed_paths
|
|
|
|
configure_allowed_paths(["/data", "/config"])
|
|
logger.info("File tool: restricted to /data (rw), /config (ro)")
|
|
|
|
# Lock down fetch tool
|
|
from xml_pipeline.tools.fetch import set_container_mode as fetch_lock
|
|
|
|
fetch_lock(True)
|
|
logger.info("Fetch tool: egress restricted to allowlisted domains")
|
|
|
|
# Enable permission gate
|
|
from xml_pipeline.tools.permission_gate import enable_permission_gate
|
|
|
|
enable_permission_gate()
|
|
logger.info("Permission gate: ENABLED (tools require explicit allowlist)")
|
|
|
|
logger.info("Container security lockdowns applied")
|