Saltar a contenido

Modo de Ejecucion Nativa (Sin Docker/Aislamiento)

Otros idiomas

Symbiont soporta la ejecucion de agentes sin Docker ni aislamiento de contenedores para entornos de desarrollo o despliegues de confianza donde se desea el maximo rendimiento y las minimas dependencias.

Advertencias de Seguridad

IMPORTANTE: El modo de ejecucion nativa omite todos los controles de seguridad basados en contenedores:

  • No hay aislamiento de procesos
  • No hay aislamiento del sistema de archivos
  • No hay aislamiento de red
  • No hay aplicacion de limites de recursos
  • Acceso directo al sistema anfitrion

La caracteristica native-sandbox no compilara en builds de release. Esta protegida por un compile_error! bajo not(debug_assertions), por lo que un binario de release nunca puede incluir el runner nativo. Es una ayuda de desarrollo solo para debug.

USAR SOLO PARA: - Desarrollo local con codigo de confianza - Entornos controlados con agentes de confianza - Pruebas y depuracion - Entornos donde Docker no esta disponible

NO USAR PARA: - Entornos de produccion con codigo no confiable - Despliegues multi-tenant - Servicios publicos - Procesamiento de entrada de usuarios no confiables

Arquitectura

Jerarquia de Niveles de Sandbox

┌─────────────────────────────────────────┐
│ SecurityTier::None (Native Execution)   │ ← No isolation
├─────────────────────────────────────────┤
│ SecurityTier::Tier1 (Docker)            │ ← Container isolation
├─────────────────────────────────────────┤
│ SecurityTier::Tier2 (gVisor)            │ ← Enhanced isolation
├─────────────────────────────────────────┤
│ SecurityTier::Tier3 (Firecracker)       │ ← Maximum isolation
└─────────────────────────────────────────┘

Flujo de Ejecucion Nativa

graph LR
    A[Agent Request] --> B{Security Tier?}
    B -->|None| C[Native Process Runner]
    B -->|Tier1+| D[Sandbox Orchestrator]

    C --> E[Direct Process Execution]
    E --> F[Host System]

    D --> G[Docker/gVisor/Firecracker]
    G --> H[Isolated Environment]

Configuracion

Opcion 1: Configuracion TOML

# symbiont.toml

[security]
# Allow native execution (default: false)
allow_native_execution = true

# La ejecucion nativa es su propia seccion de nivel superior (no anidada bajo [security]).
[native_execution]
enabled = true
default_executable = "python3"
working_directory = "/tmp/symbiont-native"
# Aplicar limites de recursos del SO incluso en modo nativo
enforce_resource_limits = true
max_memory_mb = 2048              # Option<u64>
max_cpu_seconds = 300             # Option<u64> — tiempo de CPU, no conteo de nucleos
max_execution_time_seconds = 300  # timeout de tiempo real
allowed_executables = ["python3", "node", "bash"]

Ejemplo de Configuracion Completa

Un config.toml completo con ejecucion nativa junto a otras configuraciones del sistema:

# config.toml
[api]
port = 8080
host = "127.0.0.1"
timeout_seconds = 30
max_body_size = 10485760

[database]
# Dimension del vector de embedding. LanceDB (el backend embebido predeterminado) no
# necesita mas configuracion. El backend se elige en tiempo de compilacion mediante la
# caracteristica Cargo `vector-lancedb` (predeterminada) o `vector-qdrant` — no existe
# una clave de configuracion `vector_backend`; usa la variable de entorno
# SYMBIONT_VECTOR_BACKEND para cambiar en tiempo de ejecucion.
vector_dimension = 384

# Usado al ejecutar con el backend Qdrant (SYMBIONT_VECTOR_BACKEND=qdrant):
# qdrant_url = "http://localhost:6333"
# qdrant_collection = "symbiont"

[logging]
level = "info"
format = "Pretty"
structured = true

[security]
key_provider = { Environment = { var_name = "SYMBIONT_KEY" } }
enable_compression = true
enable_backups = true
enable_safety_checks = true

[storage]
context_path = "./data/context"
git_clone_path = "./data/git"
backup_path = "./data/backups"
max_context_size_mb = 1024

[native_execution]
enabled = true
default_executable = "python3"
working_directory = "/tmp/symbiont-native"
enforce_resource_limits = true
max_memory_mb = 2048
max_cpu_seconds = 300
max_execution_time_seconds = 300
allowed_executables = ["python3", "python", "node", "bash", "sh"]

Campos de NativeExecutionConfig

Campo Tipo Predeterminado Descripcion
enabled bool false Habilitar el modo de ejecucion nativa
default_executable string "bash" Interprete/shell predeterminado
working_directory path /tmp/symbiont-native Directorio de ejecucion
enforce_resource_limits bool true Aplicar limites a nivel de SO
max_memory_mb Option Some(2048) Limite de memoria en MB
max_cpu_seconds Option Some(300) Limite de tiempo de CPU
max_execution_time_seconds u64 300 Timeout de tiempo real
allowed_executables Vec [bash, python3, etc.] Lista blanca de ejecutables

Opcion 2: Guardas de seguridad en tiempo de ejecucion (entorno)

No existen ajustes SYMBIONT_NATIVE_* / SYMBIONT_ALLOW_NATIVE_EXECUTION / SYMBIONT_DEFAULT_SANDBOX_TIER — la ejecucion nativa se configura mediante la seccion de configuracion [native_execution] de arriba. Las unicas variables de entorno relacionadas con lo nativo son las dos guardas de seguridad en tiempo de ejecucion, ambas de las cuales deben estar establecidas para ejecutar realmente el runner nativo (sin aislamiento):

export SYMBI_UNSAFE_NATIVE_SANDBOX=1   # reconoce el runner nativo
export SYMBIONT_ALLOW_UNISOLATED=1     # permite SandboxTier::None

Opcion 3: Configuracion a Nivel de Agente

metadata {
  version = "1.0.0"
  description = "Local Development Agent"
}

agent native_worker(task: String) -> String {
  capabilities = ["local_filesystem", "network"]

  policy dev_only {
    allow: ["local_filesystem", "network"] if true
  }

  # tier 0 = sin sandbox (ejecucion en el host); requiere los opt-ins anteriores
  with sandbox = "none" {
    return process(task);
  }
}

Ejemplos de Uso

Ejemplo 1: Modo de Desarrollo

use symbi_runtime::{Config, SecurityTier, SandboxOrchestrator};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Enable native execution for development
    let mut config = Config::default();
    config.security.allow_native_execution = true;

    let orchestrator = SandboxOrchestrator::new(config)?;

    // Execute code natively
    let result = orchestrator.execute_code(
        SecurityTier::None,
        "print('Hello from native execution!')",
        HashMap::new()
    ).await?;

    println!("Output: {}", result.stdout);
    Ok(())
}

Ejemplo 2: Compilar y ejecutar con el runner nativo

No existe un flag de CLI --native. La ejecucion nativa (en el host) requiere tres opt-ins explicitos:

  1. Compilar con la caracteristica native-sandbox — solo builds de debug. La caracteristica no proporciona aislamiento alguno y esta protegida por un compile_error! en builds de release:
cargo build --features native-sandbox    # solo debug; release no compilara
  1. Reconocer ambas guardas de runtime:
export SYMBI_UNSAFE_NATIVE_SANDBOX=1   # reconoce el runner nativo
export SYMBIONT_ALLOW_UNISOLATED=1     # permite SandboxTier::None en ejecuciones no-dev
  1. Seleccionar tier 0 (sin sandbox) en el DSL del agente:
with sandbox = "none" {
    // ...
}

Los limites de recursos (memoria/CPU/timeout) provienen del bloque with / config (ver arriba), no de flags de CLI.

Luego ejecuta normalmente:

symbi run agent.symbi

Ejemplo 3: Ejecucion Mixta

// Use native execution for trusted local operations
let local_result = orchestrator.execute_code(
    SecurityTier::None,
    local_code,
    env_vars
).await?;

// Use Docker for external/untrusted operations
let isolated_result = orchestrator.execute_code(
    SecurityTier::Tier1,
    untrusted_code,
    env_vars
).await?;

Detalles de Implementacion

Ejecutor de Procesos Nativos

El ejecutor nativo usa std::process::Command con limites de recursos opcionales:

pub struct NativeRunner {
    config: NativeConfig,
}

impl NativeRunner {
    pub async fn execute(&self, code: &str, env: HashMap<String, String>)
        -> Result<ExecutionResult> {
        // Direct process execution
        let mut command = Command::new(&self.config.executable);
        command.current_dir(&self.config.working_dir);
        command.envs(env);

        // Optional: Apply resource limits via rlimit (Unix)
        #[cfg(unix)]
        if self.config.enforce_limits {
            self.apply_resource_limits(&mut command)?;
        }

        let output = command.output().await?;

        Ok(ExecutionResult {
            stdout: String::from_utf8_lossy(&output.stdout).to_string(),
            stderr: String::from_utf8_lossy(&output.stderr).to_string(),
            exit_code: output.status.code().unwrap_or(-1),
            success: output.status.success(),
        })
    }
}

Limites de Recursos (Unix)

En sistemas Unix, la ejecucion nativa puede aplicar algunos limites:

  • Memoria: Usando setrlimit(RLIMIT_AS)
  • Tiempo de CPU: Usando setrlimit(RLIMIT_CPU)
  • Conteo de Procesos: Usando setrlimit(RLIMIT_NPROC)
  • Tamano de Archivo: Usando setrlimit(RLIMIT_FSIZE)

Soporte de Plataformas

Plataforma Ejecucion Nativa Limites de Recursos
Linux Completa rlimit
macOS Completa Parcial
Windows Completa Limitado

Migracion desde Docker

Paso 1: Actualizar la Configuracion

# symbiont.toml
[security]
+ allow_native_execution = true

+ [native_execution]
+ enabled = true

Luego selecciona el nivel 0 (sin sandbox) por agente en el DSL:

with sandbox = "none" { ... }

Paso 2: Compilar y ejecutar (solo debug)

# Ya no es necesario
# docker build -t symbi:latest .
# docker run ...

# La caracteristica native-sandbox es solo de debug (compile_error! en compilaciones release):
cargo build --features native-sandbox
SYMBI_UNSAFE_NATIVE_SANDBOX=1 SYMBIONT_ALLOW_UNISOLATED=1 \
  ./target/debug/symbi run agent.symbi

Enfoque Hibrido

Use ambos modos de ejecucion estrategicamente — nativo para operaciones locales de confianza, Docker para codigo no confiable:

// Trusted local operations
let local_result = orchestrator.execute_code(
    SecurityTier::None,  // Native
    trusted_code,
    env
).await?;

// External/untrusted operations
let isolated_result = orchestrator.execute_code(
    SecurityTier::Tier1,  // Docker
    external_code,
    env
).await?;

Paso 3: Gestionar Variables de Entorno

Docker aislaba automaticamente las variables de entorno. Con ejecucion nativa, configurelas explicitamente:

export AGENT_API_KEY="xxx"
export AGENT_DB_URL="postgresql://..."
export SYMBI_UNSAFE_NATIVE_SANDBOX=1
export SYMBIONT_ALLOW_UNISOLATED=1
symbi run agent.symbi   # el agente debe declarar: with sandbox = "none" { ... }

Comparacion de Rendimiento

Modo Inicio Rendimiento Memoria Aislamiento
Nativo ~10ms 100% Minima Ninguno
Docker ~500ms ~95% +128MB Bueno
gVisor ~800ms ~70% +256MB Mejor
Firecracker ~125ms ~90% +64MB El mejor

Solucion de Problemas

Problema: Permiso Denegado

# Solution: Ensure working directory is writable
mkdir -p /tmp/symbiont-native
chmod 755 /tmp/symbiont-native

Problema: Comando No Encontrado

# Solution: Ensure executable is in PATH or use absolute path
export PATH=$PATH:/usr/local/bin
# Or configure absolute path
allowed_executables = ["/usr/bin/python3", "/usr/bin/node"]

Problema: Limites de Recursos No Aplicados

La ejecucion nativa en Windows tiene soporte limitado de limites de recursos. Considere: - Usar Job Objects (especifico de Windows) - Monitorear y terminar procesos descontrolados - Actualizar a ejecucion basada en contenedores

Mejores Practicas

  1. Solo para Desarrollo: Usar ejecucion nativa principalmente para desarrollo
  2. Migracion Gradual: Comenzar con contenedores, cambiar a nativo cuando sea estable
  3. Monitoreo: Incluso sin aislamiento, monitorear el uso de recursos
  4. Listas de Permitidos: Restringir ejecutables y rutas permitidas
  5. Registro: Habilitar registro de auditoria completo
  6. Pruebas: Probar con contenedores antes de desplegar en nativo

Lista de Verificacion de Seguridad

Antes de habilitar la ejecucion nativa en cualquier entorno:

  • Todo el codigo de agentes proviene de fuentes de confianza
  • El entorno esta aislado de produccion
  • No se procesa entrada de usuarios externos
  • El monitoreo y registro estan habilitados
  • Los limites de recursos estan configurados
  • La lista de ejecutables permitidos es restrictiva
  • El acceso al sistema de archivos esta limitado
  • El equipo comprende las implicaciones de seguridad

Documentacion Relacionada


Recuerde: La ejecucion nativa intercambia seguridad por conveniencia. Siempre comprenda los riesgos y aplique los controles apropiados para su entorno de despliegue.