Context
v0.7.3 (#25) closed the SSH recording-policy bypass by carrying recorders/on_recording_failure into the domain SshAction and fail-closing (refusing) a session when a matched rule requires recording but no recorder transport exists. This is the faithful interim for a turnkey server with no recorder.
Ask (the deferred half)
Implement the actual recorder transport so a record-required session can proceed while being recorded (relaxing the interim fail-closed to Go's true default). Mirror Go tailscale.com/ssh/tailssh:
- Dial the
recorders (tailnet ip:port) — the connect path (sessionrecording/connect.go: V1 /record vs V2 with the ack frame).
- Stream the PTY session in asciinema CastV2 format — the cast header (
sessionrecording/header.go) + [t, "o", data] body frames, tee'd from the PTY I/O (src/ssh/shell.rs PTY read/write).
- On recorder-connect failure, apply
on_recording_failure: Go default is fail-open (proceed unrecorded) UNLESS reject_session_with_message is set (fail-closed). Once this transport exists, replace the interim "always fail-closed when recording required" with that exact Go semantics.
Greenfield I/O (a self-contained sub-protocol). Behind the ssh cargo feature.
Also deferred from #25
hold_and_delegate (check-mode): currently the field is carried but a rule bearing it is not silently accepted. Implementing the delegate round-trip needs a live control channel (Noise DoNoiseRequest-equivalent) the turnkey server may not have — verify and design before building.
Created using Claude Code
Context
v0.7.3 (#25) closed the SSH recording-policy bypass by carrying
recorders/on_recording_failureinto the domainSshActionand fail-closing (refusing) a session when a matched rule requires recording but no recorder transport exists. This is the faithful interim for a turnkey server with no recorder.Ask (the deferred half)
Implement the actual recorder transport so a record-required session can proceed while being recorded (relaxing the interim fail-closed to Go's true default). Mirror Go
tailscale.com/ssh/tailssh:recorders(tailnetip:port) — the connect path (sessionrecording/connect.go: V1/recordvs V2 with the ack frame).sessionrecording/header.go) +[t, "o", data]body frames, tee'd from the PTY I/O (src/ssh/shell.rsPTY read/write).on_recording_failure: Go default is fail-open (proceed unrecorded) UNLESSreject_session_with_messageis set (fail-closed). Once this transport exists, replace the interim "always fail-closed when recording required" with that exact Go semantics.Greenfield I/O (a self-contained sub-protocol). Behind the
sshcargo feature.Also deferred from #25
hold_and_delegate(check-mode): currently the field is carried but a rule bearing it is not silently accepted. Implementing the delegate round-trip needs a live control channel (NoiseDoNoiseRequest-equivalent) the turnkey server may not have — verify and design before building.Created using Claude Code