Skip to content

feat(cli): attach owner-approved sandbox terminals over the relay - #163

Draft
tee8z wants to merge 2 commits into
tee8z/sandbox-attachfrom
tee8z/sandbox-attach-cli
Draft

tee8z wants to merge 2 commits into
tee8z/sandbox-attachfrom
tee8z/sandbox-attach-cli

Conversation

@tee8z

@tee8z tee8z commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Add buzz sandbox attach to connect a local terminal to one explicitly approved sandbox through relay events. Explicit channel/thread/agent targets work; with no flags, Paseo's existing BUZZ_PASEO_AGENTS mappings and a bounded recent-thread query drive interactive selection. The CLI resolves replies to their containing root and refuses plaintext relay transport.

A hosted gateway publishes a pending request and waits for buzz sandbox authorize --request <id> signed on the owner's machine. Owner self-attachment signs the same separate per-session approval locally. buzz sandbox revoke --grant <id> deletes an approval. Raw input begins only after the worker's Open acknowledgement. Control bytes are preserved, Ctrl-] detaches, resize follows the local TTY, and every exit restores terminal settings.

Depends on SDK #159, above gateway #154. This is a sibling SDK consumer of the forthcoming ACP PTY server. The full workflow requires both consumers and rebuilt CLI/agent images; this PR alone does not enable existing sandboxes. The SDK layer already separated the wire contract. This cohesive CLI layer has 1,192 changed lines, including its authority-boundary fixtures and controlling-PTY journey; splitting its approval, selection and raw-terminal paths would leave the interactive workflow incomplete. See CLI runbook and NIP-TA.

sequenceDiagram
    participant C as Attaching CLI
    participant O as Owner CLI
    participant R as Relay
    participant A as Agent worker
    C->>R: Signed pending request
    O->>R: Owner-signed approval
    C->>R: Encrypted Open
    R->>A: Open
    A->>R: Durable acceptance, then acknowledgement
    R->>C: Encrypted output and acknowledgement
    C->>R: Encrypted input and resize
    A->>R: Metadata-only end
Loading
Check Behavior
Session authority Current pending request and owner approval must still match
Membership and delegation Current relay-signed roster; live gateway grant for a gateway requester
Freshness Strong writer queries every five seconds, five-second total refresh timeout; expiry and missing authority close access
Transport WSS with normal certificate validation; NIP-44 frames bound to signer, recipient, channel, root and approval
Bounds Four frames / 64 KiB in flight, bounded retries and frame rate, five-minute idle, bounded input and target lists
Local cleanup Restore TTY after close, errors, revocation and handled termination signals

Validation: 510 CLI tests pass; all-target Clippy passes with warnings denied; Rust formatting and diff checks pass. Every normal cargo test/CI run now creates its own controlling PTY and drives the production client through a simulated NIP-42/WebSocket relay boundary: encrypted output, raw Ctrl-C/arrow/input bytes, peer close, and exact original termios restoration. Removing strong authority routing, WSS refusal, or TTY restoration fails its corresponding regression. The actual buzz binary's attach/authorize/revoke help and plaintext-refusal commands pass. Full just ci remains unavailable because this environment lacks native Tauri GLib development libraries (parent task evidence).

Human test after the ACP server is available: start an admitted sandbox thread, run attach from the configured gateway, authorize its printed request with the owner's key on the same relay, confirm shell input and resize, then revoke the approval and confirm close within ten seconds plus teardown with normal local terminal input restored. Repeat Ctrl-] detach. Independent agent review and human testing remain pending; keep this PR in draft. No scripts, previews, worktree management, tunnel or substrate exec API is added; terminal output consumes relay bandwidth.

Signed-off-by: Tee8z <tee8z@protonmail.com>
@tee8z tee8z self-assigned this Nov 10, 2026
@coderabbitai

coderabbitai Bot commented Nov 10, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@tee8z

tee8z commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

Independent first review of #163 at 9cbee6f against the owner-approved relay-only terminal contract.

Blocking: the controlling-PTY regression reports success without exercising the behavior in ordinary cargo/CI runs. real_tty_forwards_encrypted_raw_bytes_and_restores_after_close prints PTY_REQUIRED and returns when stdin is not a terminal. The default test lane therefore passes if raw forwarding/restoration breaks, and the external driver used for the implementation evidence is not in this PR. Add a committed parent driver/test that creates a controlling PTY and runs the real child flow automatically, checks forwarded control bytes and full original termios restoration, and fails on missing execution or child failure. A guard mutation must fail the ordinary runnable regression, not only an untracked local probe.

The current authority, immutable scope, signatures, WSS refusal, revocation checks, bounded transport, local detach, and explicit restoration paths otherwise look sound. I checked the published SDK: dropping excess input before cryptography is its stated backpressure policy, so I am not treating that as a defect.

Optional: the new authority helper checks its two-MiB response budget after the shared client has already read the body; a streaming cap would bound allocation too. Optional: refuse unsupported Unix-less attachment before publishing its pending request/approval, so unsupported platforms have no metadata side effects.

Minimalism 9/10, elegance 9/10, correctness 8/10 until the production regression is automatically exercised. Runtime server integration and human acceptance remain separate.

@tee8z

tee8z commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

Fixed the review blocker in signed e620fe3. The ordinary cargo/CI test now creates its own controlling-PTY child, forwards real encrypted Ctrl-C/arrow/raw bytes through the production client, and compares complete original termios after peer close. There is no pass-without-PTY branch. Removing explicit restoration fails this ordinary cargo test. Restored source: all 510 CLI tests, all-target Clippy with warnings denied, formatting and diff checks pass. PR remains draft; integrated server and human testing are still pending.

@tee8z

tee8z commented Nov 10, 2026

Copy link
Copy Markdown
Collaborator Author

Rechecked e620fe3: the controlling-PTY blocker is resolved. Ordinary cargo/CI execution now launches a committed Python PTY driver, runs the actual child flow, requires encrypted raw control-byte exchange and an explicit success marker, and compares the complete original terminal attributes. A missing terminal or unexecuted child fails rather than passing silently.

Independently ran the existing final test artifact with the exact test filter in a non-TTY tool process: it passed. The author's restoration-removal mutation also fails this ordinary regression; the restored full CLI suite and Clippy pass. No remaining blockers in this CLI layer; minimalism/elegance/correctness 9/10 each. The optional suggestions remain optional. Combined server integration and human acceptance are still required.

This branch has not been deployed

No deployments
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