Skip to content

feat(sessions): session-container command builders (Phase 1a) - #139

Merged
las7 merged 1 commit into
mainfrom
phase1/session-lifecycle
Jun 24, 2026
Merged

feat(sessions): session-container command builders (Phase 1a)#139
las7 merged 1 commit into
mainfrom
phase1/session-lifecycle

Conversation

@las7

@las7 las7 commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

What

First slice of Phase 1 (the run-once→run-forever inversion). Additive, wired into nothing, zero runtime behavior change — only tako_vm/execution/docker.py + a new test file. Adds:

  • build_session_run_command — builds docker run -d for a long-lived session container. Starts from base_isolation_args(..., auto_remove=False) so the gVisor posture is byte-for-byte identical to a job (and cannot drift), then appends --network=none (no egress in Phase 1), a read-write /workspace mount (the one writable cross-exec surface), the SESSION_ID label, and resource limits. No --rm (the container must outlive a single exec).
  • build_session_exec_command — builds docker exec into a live session, dropped to the unprivileged user, in /workspace, timeout-wrapped. Provisional drop model — the final root+gosu /tako-meta per-exec OOM/timeout classification lands in Phase 1b (flagged in-code).
  • container_running / stop_container — mirror the existing inspect_oom_killed / remove_container style.

Why

The single most important invariant of the whole session design: isolation flags are assembled in exactly one place (base_isolation_args) and the session path reuses it. This is the direct architectural fix for the class of bug where a separate session command path forgets --runtime=runsc and silently runs untrusted code on runc. This PR establishes the builder + the test that pins it.

Dynamic testing

  • tests/test_session_lifecycle_commands.py (87 tests) — across the full argument cross-product, assert the run command reuses every base_isolation_args flag (--read-only/--init/--cap-drop=ALL/runsc), always emits --network=none and -d, never --rm, carries the SESSION_ID label and exactly one read-write /workspace mount, and emits no escape-class flags (a --privileged/host-mount/host-network/extra-cap denylist). Exec command never runs as root/--privileged, targets /workspace, and timeout-wraps.
  • 87 passed; 126 passed combined with the Phase 0 isolation suite (no regression). Teeth-verified: flipping --network=nonebridge in the builder turns 17 tests red.
  • ruff check + format clean (pinned 0.15.16).
  • Independently code-reviewed → GO; one minor comment-accuracy fix applied (the exec drop is provisional, not a mirror of the run path's default root+gosu posture).

Scope

Branches off current main (post-Phase-0). Only docker.py + the new test touched. Nothing calls the new builders yet — they get wired in Phase 1c (SessionManager).

🤖 Generated with Claude Code

… (Phase 1a)

Foundation for long-lived session containers, wired into nothing (zero runtime
behavior change). Adds to execution/docker.py:
- build_session_run_command: builds `docker run -d` for a long-lived session,
  starting from base_isolation_args(auto_remove=False) so the gVisor posture is
  byte-for-byte identical to a job and cannot drift, then appending
  --network=none (no egress in Phase 1), a read-write /workspace mount, the
  SESSION_ID label, and resource limits.
- build_session_exec_command: builds `docker exec` into a live session, dropped
  to the unprivileged user, in /workspace, timeout-wrapped. Provisional drop
  model; the root+gosu /tako-meta classification path lands in Phase 1b.
- container_running / stop_container helpers mirroring the existing
  inspect/remove style.

Tests (tests/test_session_lifecycle_commands.py, 87): assert the session run
command reuses every base_isolation_args flag, always emits --network=none and
-d and never --rm, carries the session label and a read-write /workspace mount,
and emits no escape-class flags, across the full argument cross-product. This is
the tripwire that pins "the session path routes through base_isolation_args, so
it cannot bypass gVisor."

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@las7
las7 requested a review from ethanbailie as a code owner June 24, 2026 21:30
@las7
las7 merged commit e067db5 into main Jun 24, 2026
4 checks passed
@las7
las7 deleted the phase1/session-lifecycle branch June 24, 2026 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant