Add workspace network policy and published ports
Replace the workspace-level boolean network toggle with explicit network policies and attach localhost TCP publication to workspace services. Persist network_policy in workspace records, validate --publish requests, and run host-side proxy helpers that follow the service lifecycle so published ports are cleaned up on failure, stop, reset, and delete. Update the CLI, SDK, MCP contract, docs, roadmap, and examples for the new policy model, add coverage for the proxy and manager edge cases, and validate with uv lock, UV_CACHE_DIR=.uv-cache make check, UV_CACHE_DIR=.uv-cache make dist-check, and a real guest-backed published-port probe smoke.
This commit is contained in:
parent
fc72fcd3a1
commit
c82f4629b2
21 changed files with 1944 additions and 49 deletions
|
|
@ -64,6 +64,7 @@ Behavioral guarantees:
|
|||
- `pyro demo ollama` prints log lines plus a final summary line.
|
||||
- `pyro workspace create` auto-starts a persistent workspace.
|
||||
- `pyro workspace create --seed-path PATH` seeds `/workspace` from a host directory or a local `.tar` / `.tar.gz` / `.tgz` archive before the workspace is returned.
|
||||
- `pyro workspace create --network-policy {off,egress,egress+published-ports}` controls workspace guest networking and whether services may publish localhost ports.
|
||||
- `pyro workspace create --secret NAME=VALUE` and `--secret-file NAME=PATH` persist guest-only UTF-8 secrets outside `/workspace`.
|
||||
- `pyro workspace sync push WORKSPACE_ID SOURCE_PATH [--dest WORKSPACE_PATH]` imports later host-side directory or archive content into a started workspace.
|
||||
- `pyro workspace export WORKSPACE_ID PATH --output HOST_PATH` exports one file or directory from `/workspace` back to the host.
|
||||
|
|
@ -71,6 +72,7 @@ Behavioral guarantees:
|
|||
- `pyro workspace snapshot *` manages explicit named snapshots in addition to the implicit `baseline`.
|
||||
- `pyro workspace reset WORKSPACE_ID [--snapshot SNAPSHOT_NAME|baseline]` recreates the full sandbox and restores `/workspace` from the chosen snapshot.
|
||||
- `pyro workspace service *` manages long-running named services inside one started workspace with typed readiness probes.
|
||||
- `pyro workspace service start --publish GUEST_PORT` or `--publish HOST_PORT:GUEST_PORT` publishes one guest TCP port to `127.0.0.1` on the host.
|
||||
- `pyro workspace exec --secret-env SECRET_NAME[=ENV_VAR]` maps one persisted secret into one exec call.
|
||||
- `pyro workspace service start --secret-env SECRET_NAME[=ENV_VAR]` maps one persisted secret into one service start call.
|
||||
- `pyro workspace exec` runs in the persistent `/workspace` for that workspace and does not auto-clean.
|
||||
|
|
@ -78,9 +80,11 @@ Behavioral guarantees:
|
|||
- `pyro workspace shell *` manages persistent PTY sessions inside a started workspace.
|
||||
- `pyro workspace logs` returns persisted command history for that workspace until `pyro workspace delete`.
|
||||
- Workspace create/status results expose `workspace_seed` metadata describing how `/workspace` was initialized.
|
||||
- Workspace create/status/reset results expose `network_policy`.
|
||||
- Workspace create/status/reset results expose `reset_count` and `last_reset_at`.
|
||||
- Workspace create/status/reset results expose safe `secrets` metadata with each secret name and source kind, but never the secret values.
|
||||
- `pyro workspace status` includes aggregate `service_count` and `running_service_count` fields.
|
||||
- `pyro workspace service start`, `pyro workspace service list`, and `pyro workspace service status` expose published-port metadata when present.
|
||||
|
||||
## Python SDK Contract
|
||||
|
||||
|
|
@ -97,7 +101,7 @@ Supported public entrypoints:
|
|||
- `Pyro.inspect_environment(environment)`
|
||||
- `Pyro.prune_environments()`
|
||||
- `Pyro.create_vm(...)`
|
||||
- `Pyro.create_workspace(..., secrets=None)`
|
||||
- `Pyro.create_workspace(..., network_policy="off", secrets=None)`
|
||||
- `Pyro.push_workspace_sync(workspace_id, source_path, *, dest="/workspace")`
|
||||
- `Pyro.export_workspace(workspace_id, path, *, output_path)`
|
||||
- `Pyro.diff_workspace(workspace_id)`
|
||||
|
|
@ -105,7 +109,7 @@ Supported public entrypoints:
|
|||
- `Pyro.list_snapshots(workspace_id)`
|
||||
- `Pyro.delete_snapshot(workspace_id, snapshot_name)`
|
||||
- `Pyro.reset_workspace(workspace_id, *, snapshot="baseline")`
|
||||
- `Pyro.start_service(workspace_id, service_name, *, command, cwd="/workspace", readiness=None, ready_timeout_seconds=30, ready_interval_ms=500, secret_env=None)`
|
||||
- `Pyro.start_service(workspace_id, service_name, *, command, cwd="/workspace", readiness=None, ready_timeout_seconds=30, ready_interval_ms=500, secret_env=None, published_ports=None)`
|
||||
- `Pyro.list_services(workspace_id)`
|
||||
- `Pyro.status_service(workspace_id, service_name)`
|
||||
- `Pyro.logs_service(workspace_id, service_name, *, tail_lines=200, all=False)`
|
||||
|
|
@ -136,7 +140,7 @@ Stable public method names:
|
|||
- `inspect_environment(environment)`
|
||||
- `prune_environments()`
|
||||
- `create_vm(...)`
|
||||
- `create_workspace(..., secrets=None)`
|
||||
- `create_workspace(..., network_policy="off", secrets=None)`
|
||||
- `push_workspace_sync(workspace_id, source_path, *, dest="/workspace")`
|
||||
- `export_workspace(workspace_id, path, *, output_path)`
|
||||
- `diff_workspace(workspace_id)`
|
||||
|
|
@ -144,7 +148,7 @@ Stable public method names:
|
|||
- `list_snapshots(workspace_id)`
|
||||
- `delete_snapshot(workspace_id, snapshot_name)`
|
||||
- `reset_workspace(workspace_id, *, snapshot="baseline")`
|
||||
- `start_service(workspace_id, service_name, *, command, cwd="/workspace", readiness=None, ready_timeout_seconds=30, ready_interval_ms=500, secret_env=None)`
|
||||
- `start_service(workspace_id, service_name, *, command, cwd="/workspace", readiness=None, ready_timeout_seconds=30, ready_interval_ms=500, secret_env=None, published_ports=None)`
|
||||
- `list_services(workspace_id)`
|
||||
- `status_service(workspace_id, service_name)`
|
||||
- `logs_service(workspace_id, service_name, *, tail_lines=200, all=False)`
|
||||
|
|
@ -174,6 +178,7 @@ Behavioral defaults:
|
|||
- `allow_host_compat` defaults to `False` on `create_vm(...)` and `run_in_vm(...)`.
|
||||
- `allow_host_compat` defaults to `False` on `create_workspace(...)`.
|
||||
- `Pyro.create_workspace(..., seed_path=...)` seeds `/workspace` from a host directory or a local `.tar` / `.tar.gz` / `.tgz` archive before the workspace is returned.
|
||||
- `Pyro.create_workspace(..., network_policy="off"|"egress"|"egress+published-ports")` controls workspace guest networking and whether services may publish host ports.
|
||||
- `Pyro.create_workspace(..., secrets=...)` persists guest-only UTF-8 secrets outside `/workspace`.
|
||||
- `Pyro.push_workspace_sync(...)` imports later host-side directory or archive content into a started workspace.
|
||||
- `Pyro.export_workspace(...)` exports one file or directory from `/workspace` to an explicit host path.
|
||||
|
|
@ -184,6 +189,7 @@ Behavioral defaults:
|
|||
- `Pyro.reset_workspace(...)` recreates the full sandbox from `baseline` or one named snapshot and clears command, shell, and service history.
|
||||
- `Pyro.start_service(..., secret_env=...)` maps persisted workspace secrets into that service process as environment variables for that start call only.
|
||||
- `Pyro.start_service(...)` starts one named long-running process in a started workspace and waits for its typed readiness probe when configured.
|
||||
- `Pyro.start_service(..., published_ports=[...])` publishes one or more guest TCP ports to `127.0.0.1` on the host when the workspace network policy is `egress+published-ports`.
|
||||
- `Pyro.list_services(...)`, `Pyro.status_service(...)`, `Pyro.logs_service(...)`, and `Pyro.stop_service(...)` manage those persisted workspace services.
|
||||
- `Pyro.exec_vm(...)` runs one command and auto-cleans that VM after the exec completes.
|
||||
- `Pyro.exec_workspace(..., secret_env=...)` maps persisted workspace secrets into that exec call as environment variables for that call only.
|
||||
|
|
@ -243,6 +249,7 @@ Behavioral defaults:
|
|||
- `vm_run` and `vm_create` expose `allow_host_compat`, which defaults to `false`.
|
||||
- `workspace_create` exposes `allow_host_compat`, which defaults to `false`.
|
||||
- `workspace_create` accepts optional `seed_path` and seeds `/workspace` from a host directory or a local `.tar` / `.tar.gz` / `.tgz` archive before the workspace is returned.
|
||||
- `workspace_create` accepts `network_policy` with `off`, `egress`, or `egress+published-ports` to control workspace guest networking and service port publication.
|
||||
- `workspace_create` accepts optional `secrets` and persists guest-only UTF-8 secret material outside `/workspace`.
|
||||
- `workspace_sync_push` imports later host-side directory or archive content into a started workspace, with an optional `dest` under `/workspace`.
|
||||
- `workspace_export` exports one file or directory from `/workspace` to an explicit host path.
|
||||
|
|
@ -250,6 +257,7 @@ Behavioral defaults:
|
|||
- `snapshot_create`, `snapshot_list`, and `snapshot_delete` manage explicit named snapshots in addition to the implicit `baseline`.
|
||||
- `workspace_reset` recreates the full sandbox and restores `/workspace` from `baseline` or one named snapshot.
|
||||
- `service_start`, `service_list`, `service_status`, `service_logs`, and `service_stop` manage persistent named services inside a started workspace.
|
||||
- `service_start` accepts optional `published_ports` to expose guest TCP ports on `127.0.0.1` when the workspace network policy is `egress+published-ports`.
|
||||
- `vm_exec` runs one command and auto-cleans that VM after the exec completes.
|
||||
- `workspace_exec` accepts optional `secret_env` mappings for one exec call and leaves the workspace alive.
|
||||
- `service_start` accepts optional `secret_env` mappings for one service start call.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue