SEC-010: Bound remote SSH output - #284
Conversation
18ad32e to
62eff66
Compare
There was a problem hiding this comment.
🟡 Changes recommended
A few newly introduced diagnostic/error paths are ambiguous or misleading (and one minor type duplication), which should be corrected to keep security-limit rejections actionable.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR hardens the remote-backend SSH tunnel and remote bootstrap path by bounding untrusted stdout/stderr parsing and retention to prevent unbounded memory growth and log amplification, while preserving the allowed maximum listdir protocol envelope.
Changes:
- Introduces an allocation-bounded line reader (
read_bounded_lines) that enforces per-line and per-stream byte limits before retained growth. - Updates the SSH tunnel stderr reader to enforce byte/line/log caps and to report reader-limit violations back to the child owner for kill/reap + task disposal.
- Bounds remote bootstrap stdout/stderr parsing, caps protocol record count/retained bytes, and adds regression tests for timeout and overflow ownership behavior.
File summaries
| File | Description |
|---|---|
| src-tauri/src/services/remote_backend/tunnel.rs | Replaces unbounded lines() stderr reading with bounded parsing + owner-controlled kill/reap and reader-task lifecycle management. |
| src-tauri/src/services/remote_backend/mod.rs | Wires in the new bounded-output module and adapts supervisor/establish flows to use the new tunnel lifecycle helpers. |
| src-tauri/src/services/remote_backend/daemon.rs | Bounds bootstrap stdout/stderr, caps protocol record/retained bytes, and adds tests for boundary envelopes + timeout kill/reap. |
| src-tauri/src/services/remote_backend/bounded_output.rs | New bounded line reader implementation + unit tests ensuring limits and UTF-8-split handling. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
62eff66 to
ce7f2de
Compare
There was a problem hiding this comment.
🟡 Changes recommended
There are confirmed edge-case correctness issues in process-wait timeout handling and tunnel stderr task disposal that can cause misclassification or loss of the output-rejection signal.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 3
- Review effort level: Lite
Reject excessive SSH line, stream, and protocol output before it can cause unbounded retention or log amplification. Kill and reap children on timeout and output-limit failures while preserving listdir capacity. Co-authored-by: Olabode Olaoke <olabode@squareup.com> Signed-off-by: Olabode Olaoke <olabode@squareup.com>
ce7f2de to
49739fc
Compare
There was a problem hiding this comment.
🟢 Approval recommended
The changes consistently enforce bounded reads/retention across tunnel + bootstrap paths and include targeted regressions for the key lifecycle and race edge-cases introduced by the new reader tasks.
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
morgmart
left a comment
There was a problem hiding this comment.
🤖 Automated code review
APPROVE. The completed static review of exact range 5c31189...49739fc found no publishable findings. The four changed files and all supplied allowed anchors are confined to the Rust remote-backend implementation, so this is non-UI work. All six supplied prior threads are resolved, have substantive human replies, and describe issues fixed at this head. Supplied GitHub check evidence is structurally valid but pending; required checks still govern merge readiness.
Deterministic publication result: 0 blocking and 0 non-blocking inline finding(s) publishable; 0 duplicate(s) suppressed; 0 blocking screenshot-evidence requirement(s) in this review body.
Pending checks: 1 check(s) are not complete.
This approval reflects the completed code review only; merge readiness remains governed by the repository's required checks.
Summary
Bound hostile SSH and remote-bootstrap output before it can cause unbounded memory retention or log amplification. The patch checks raw line and stream bytes before retained growth; separately caps protocol records, retained protocol bytes, diagnostic lines, redacted stderr tails, and tunnel stderr; and preserves the complete successful
listdirenvelope ofDIR+ 2,000 entries +LIST-DONE.Repository history makes lifecycle ownership part of the security boundary. Remote SSH (
3c234437) deliberately uses a durable remote Goose daemon behind a disposable local loopback tunnel; later generation/incarnation and log-drain hardening (baee7994) established stale-work rejection, resumable reconnects, and native-speed bounded draining as constraints. This fix therefore leaves daemon lifetime and reconnect policy unchanged. Output readers only report bounded-read failures; the owner of the TokioChildexclusively terminates and reaps, and reader tasks finish before lifecycle/reconnect disposition. The new established-supervisor regression exercises that same owner path after readiness.Remote SSH remains experiment-gated. The original feature excludes Windows remote hosts; that is distinct from using a supported Windows local Berd client. No current architectural law directly governs remote subprocess output (
LAWS/README.md,LAWS/AGENTS.md,LAWS/CHAT.md).The registry's older generation-owned numeric-PID teardown for disconnect/app exit is not represented as solved here. Replacing that authority with owner cancellation or an identity-safe handle is separate lifecycle-hardening scope.
Related issue
N/A — no public issue was opened because the underlying report is security-sensitive. No duplicate public issue or PR was found during the pre-submission search.
Testing
Validated resulting tree
33e0ac4a6e1629ad979fad825b27139e921c8d11, now exact head49739fc01bf2081e9d355436429b7bf5c391a351, onorigin/main5c31189a4d55437888bb8d0f921efada827c7d86; combined binary-diff SHA-2567c3b744ce3f41b0b527ef64f408861aa46a5259874cd401970709d9c5eb05c17.bin/just tauri-fmt-check— passedgit diff --check origin/main...HEAD— passedbin/just tauri-check— passedbin/just clippy— passed across all four lanesbin/just tauri-test— passedorigin/main49739fc0and reproduced the tree, base, and binary-diff fingerprintThe lifecycle runtime regressions are Unix-only because their fixtures use
sh,sleep, andyes. Windows receives Rust compile/test-lane coverage; this does not claim an equivalent native Windows runtime process-lifecycle test.The fully concurrent app-crate suite is not clean on the baseline: the prior behavior-equivalent head produced 957 passed / 10 failed, while clean
origin/mainproduced 945 passed / 12 failed. Both runs showed the same unrelated layout-default and provider-config failures plus timing-sensitive shell-contract failures; clean main had additional failures. This is baseline-noise evidence, not a claim that the fully concurrent suite is clean.