Skip to content

fix(lume): preserve raw ssh command output#1701

Open
RitwijParmar wants to merge 1 commit into
trycua:mainfrom
RitwijParmar:codex/cua-lume-ssh-raw-stdout
Open

fix(lume): preserve raw ssh command output#1701
RitwijParmar wants to merge 1 commit into
trycua:mainfrom
RitwijParmar:codex/cua-lume-ssh-raw-stdout

Conversation

@RitwijParmar
Copy link
Copy Markdown

@RitwijParmar RitwijParmar commented May 26, 2026

Summary

Fixes #1513 by preserving raw stdout bytes from lume ssh <vm> <cmd> instead of forcing SSH channel output through UTF-8 before writing it back to the host.

The previous path decoded stdout into String in both SSH backends, which corrupts binary streams such as tar, gzip, encrypted blobs, or random bytes. This keeps the existing text-facing SSHResult.output API for current callers, but adds SSHResult.outputData as the canonical raw byte payload and has the CLI write those bytes directly to stdout.

Changes

  • Add SSHResult.outputData while preserving SSHResult.output for text/MCP/clipboard callers.
  • Have the NIO SSH command handler collect and return raw Data from ByteBuffer.
  • Have the system SSH fallback keep stdoutData intact instead of decoding it as UTF-8.
  • Write lume ssh command output with FileHandle.standardOutput.write(...) instead of print(...).
  • Add a small regression test that verifies SSHResult preserves invalid UTF-8 bytes.

Verification

  • git diff --check
  • swift build from libs/lume

Note: swift test --filter SSHResultTests compiled the lume target but failed before running tests because this local Swift toolchain does not provide the existing repo-wide Testing module imported by current tests.

Summary by CodeRabbit

  • New Features

    • SSH command results now preserve raw output data, improving support for binary and special character handling in command output.
  • Tests

    • Added test to verify raw output bytes are correctly preserved in SSH results.

Review Change Stack

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 26, 2026

@RitwijParmar is attempting to deploy a commit to the Cua Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

📝 Walkthrough

Walkthrough

SSH command output handling is refactored to preserve binary data throughout the entire pipeline. SSHResult now stores raw command output as Data in addition to a derived UTF-8 string, both SSH backends (NIO and system) produce bytes instead of decoded strings, and output is written to stdout using raw bytes to prevent corruption of binary streams.

Changes

SSH Binary Data Preservation

Layer / File(s) Summary
SSHResult binary data contract and tests
libs/lume/src/SSH/SSHClient.swift, libs/lume/tests/SSHResultTests.swift
SSHResult is extended with outputData: Data field; dual initializers convert between raw bytes and UTF-8 string representation; test verifies outputData is preserved unchanged during round-trip.
NIO SSH client binary output handling
libs/lume/src/SSH/SSHClient.swift
CommandExecHandler.checkCompletion switches from reading decoded string output to accumulating raw bytes and constructing SSHResult with outputData for both normal exit and fallback paths.
System SSH client binary output handling
libs/lume/src/SSH/SystemSSHClient.swift
execute(command:timeout:) retains stdout as raw bytes, conditionally appends filtered stderr bytes, and passes outputData to SSHResult instead of UTF-8 string concatenation.
Output delivery to host stdout
libs/lume/src/Commands/SSH.swift
Both NIO SSH and system SSH execution paths write result.outputData directly to FileHandle.standardOutput instead of printing result.output, preserving binary streams without UTF-8 coercion.

Sequence Diagram

sequenceDiagram
  participant Guest as VM Guest Process
  participant Handler as SSH Handler
  participant Result as SSHResult
  participant Host as Host Stdout
  Guest->>Handler: stdout/stderr bytes
  Handler->>Handler: accumulate raw Data
  Handler->>Result: outputData (raw bytes)
  Result->>Host: FileHandle.write(outputData)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • trycua/cua#1125: Introduces the system SSH fallback path that this PR builds upon by updating it to handle binary data correctly.

Suggested labels

release:lume

Poem

🐰 Binary streams now flow through unscathed,
No UTF-8 mangling, data safe,
Raw bytes preserved from guest to host,
The SSH pipe that welcomes most,
Binary tar, gzip, and more toast!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: preserving raw SSH command output instead of UTF-8 decoding, which directly addresses the core issue.
Linked Issues check ✅ Passed All coding objectives from issue #1513 are met: raw bytes are preserved in SSHResult.outputData, both SSH backends collect raw data, and the CLI writes bytes directly via FileHandle.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the binary output corruption issue; no unrelated modifications were introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/lume/src/SSH/SystemSSHClient.swift`:
- Around line 75-78: The code currently appends filtered stderr text bytes into
outputData (the stdout buffer) which corrupts binary stdout; revert this by
removing the append of errorData into outputData so outputData remains exactly
stdoutData, and instead preserve filteredError (or errorData) in its own
variable/return value if callers need stderr separately; update the logic around
outputData, stdoutData, filteredError in SystemSSHClient.swift (the
outputData/filteredError handling) so stdout bytes are never mutated with stderr
bytes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f684ddd6-cb31-4ee0-a2a6-98d7d80eaba1

📥 Commits

Reviewing files that changed from the base of the PR and between f51ce80 and b555860.

📒 Files selected for processing (4)
  • libs/lume/src/Commands/SSH.swift
  • libs/lume/src/SSH/SSHClient.swift
  • libs/lume/src/SSH/SystemSSHClient.swift
  • libs/lume/tests/SSHResultTests.swift

Comment on lines +75 to +78
var outputData = stdoutData
if !filteredError.isEmpty, let errorData = filteredError.data(using: .utf8) {
outputData.append(errorData)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not append stderr bytes into outputData.

This reintroduces stream corruption for binary stdout whenever non-filtered stderr exists, because outputData is no longer raw stdout-only bytes.

Suggested change
-        var outputData = stdoutData
-        if !filteredError.isEmpty, let errorData = filteredError.data(using: .utf8) {
-            outputData.append(errorData)
-        }
+        let outputData = stdoutData
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var outputData = stdoutData
if !filteredError.isEmpty, let errorData = filteredError.data(using: .utf8) {
outputData.append(errorData)
}
let outputData = stdoutData
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@libs/lume/src/SSH/SystemSSHClient.swift` around lines 75 - 78, The code
currently appends filtered stderr text bytes into outputData (the stdout buffer)
which corrupts binary stdout; revert this by removing the append of errorData
into outputData so outputData remains exactly stdoutData, and instead preserve
filteredError (or errorData) in its own variable/return value if callers need
stderr separately; update the logic around outputData, stdoutData, filteredError
in SystemSSHClient.swift (the outputData/filteredError handling) so stdout bytes
are never mutated with stderr bytes.

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.

lume ssh corrupts binary stdout (UTF-8 coercion, ~1.77x expansion on random data)

1 participant