Skip to content

feat(minimald): handle git pushes natively - #347

Merged
twitchyliquid64 merged 1 commit into
mainfrom
tom/update
Jun 5, 2026
Merged

feat(minimald): handle git pushes natively#347
twitchyliquid64 merged 1 commit into
mainfrom
tom/update

Conversation

@twitchyliquid64

@twitchyliquid64 twitchyliquid64 commented Jun 4, 2026

Copy link
Copy Markdown
Member

If you install the git-remote-min script (in this PR) in your path, you will be able to

git push min://<session id> or git push min://<session name>

which is kinda cool.

Summary by CodeRabbit

  • New Features
    • Added git repository push functionality using the min:// protocol, enabling users to push code to remote sessions and automatically check out changes in the workspace.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 142370d0-c07b-402a-abc6-4f6dcc0ddd2f

📥 Commits

Reviewing files that changed from the base of the PR and between 40a3433 and 9e25818.

📒 Files selected for processing (5)
  • .minimal/minimal.toml
  • crates/minimald/Cargo.toml
  • crates/minimald/git-remote-min
  • crates/minimald/src/exec.rs
  • crates/minimald/src/test_harness.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • .minimal/minimal.toml
  • crates/minimald/src/test_harness.rs
  • crates/minimald/Cargo.toml
  • crates/minimald/git-remote-min
  • crates/minimald/src/exec.rs

📝 Walkthrough

Walkthrough

This PR implements end-to-end git push support via the minimal SSH protocol by introducing a client-side git-remote helper, server-side receive-pack handling with automatic repository initialization and post-receive hooks, and supporting test harness changes to bind real Unix Domain Sockets.

Changes

Git Push Over Minimal Protocol

Layer / File(s) Summary
Git-remote helper script
crates/minimald/git-remote-min
New POSIX shell script implementing the git-remote helper protocol, handling capabilities and connect commands to proxy git operations through SSH via a socat-based ProxyCommand to a fixed Unix socket, with SSH host key verification disabled.
Server-side receive-pack handling
crates/minimald/src/exec.rs
handle_exec detects git-receive-pack min:// requests and routes them to new handle_git_receive, which resolves the target session from environment or ident, ensures .git directory exists (running git init if needed), creates a temporary post-receive hook that checks out pushed refs, and runs git receive-pack with the hook directory configured; includes an end-to-end test (currently ignored) validating the push and checkout behavior.
Test harness and infrastructure
crates/minimald/src/test_harness.rs, crates/minimald/Cargo.toml, .minimal/minimal.toml
TestServer adds listen_on_uds method to bind and accept connections on real Unix Domain Sockets for end-to-end testing; tempfile is moved from dev-dependencies to main dependencies to support temporary hook directory creation; socat is added to harness runtime packages to enable socket proxying.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • gominimal/minimal#338: Both PRs modify crates/minimald/src/exec.rs's SSH handle_exec wiring; this PR adds git-receive-pack min:// handling that reuses the task/exec pipeline infrastructure from that PR.
  • gominimal/minimal#281: This PR extends SSH exec routing by adding handle_git_receive logic that reuses the existing ExecTask/TokioExec scaffolding introduced in that PR.

Suggested reviewers

  • 0chroma
  • evanspearman
  • jtnkminimal

Poem

🐰 A rabbit hops through git repos with glee,
Pushing refs through Unix sockets, wild and free,
With socat and hooks in a temp-file dance,
The minimal protocol gets its grand chance! 🚀

🚥 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 'feat(minimald): handle git pushes natively' accurately summarizes the main change: adding native git push support to minimald through a git-remote-min helper script and corresponding SSH exec request handling.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@crates/minimald/git-remote-min`:
- Around line 13-14: The current SSH invocation disables host key verification
via the flags '-o 'StrictHostKeyChecking=no'' and '-o
'UserKnownHostsFile=/dev/null''; remove these insecure options and instead
enable strict checking and use a dedicated known_hosts file for this transport.
Replace the two flags with something like '-o StrictHostKeyChecking=yes -o
UserKnownHostsFile=/path/to/transport_known_hosts' (or '-o
StrictHostKeyChecking=accept-new' if you need first-time acceptance), ensure the
code that runs the command (the invocation containing local "$arg" "$2")
creates/populates that known_hosts file or pins the server key before
connecting, and update any helper functions that build SSH options to reference
the new flags and file path.

In `@crates/minimald/src/exec.rs`:
- Around line 770-781: The code ignores errors from
tokio::fs::try_exists(&dotgit_dir), doesn't check git init's exit status, and
unwraps channel.close().await; update the block around try_exists/dotgit_dir and
the Command::new("git") invocation so that: 1) if try_exists returns Err(e) you
log/tracing::warn the error and close the channel (handle close errors instead
of unwrap) then return; 2) after awaiting .output(), check
output.status.success() and if false log the stdout/stderr and close the channel
(again handling close errors) and return; reference the dotgit_dir probe, the
Command::new("git")/.output() result and channel.close().await to locate and fix
the logic before proceeding to receive-pack.
- Around line 645-647: The git-receive-pack branch (argv.strip_prefix(...)
calling handle_git_receive) returns before the PTY validation and therefore
bypasses the PTY guard; move or duplicate the PTY validation so that the same
PTY rejection logic that runs later is applied before invoking
handle_git_receive. Concretely, ensure the PTY check (the existing PTY guard
logic used for normal exec handling) runs prior to the early return from the git
branch (or insert the same validation immediately before calling
handle_git_receive), referencing argv.strip_prefix("git-receive-pack min://")
and handle_git_receive(...) so the git path follows the same PTY accept/reject
flow as other execs.
🪄 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: 5ba67f29-203f-44c0-b223-b20ffd83c067

📥 Commits

Reviewing files that changed from the base of the PR and between a2b6393 and 0bb6ec5.

📒 Files selected for processing (2)
  • crates/minimald/git-remote-min
  • crates/minimald/src/exec.rs

Comment on lines +13 to +14
-o 'StrictHostKeyChecking=no' -o 'UserKnownHostsFile=/dev/null' \
local "$arg" "$2"

Copy link
Copy Markdown

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

Re-enable SSH host key verification for push transport.

Line 13 turns off host verification and disables known_hosts persistence, so a spoofed local endpoint can silently impersonate the server and receive pushed data. Please use host key pinning (or at least a dedicated known_hosts file with strict checking) instead of disabling verification.

Suggested hardening
-        exec ssh -o ProxyCommand="socat - UNIX-CONNECT:$HOME/.local/state/minimal/providers/local-0/ssh.sock" \
-		 -o 'StrictHostKeyChecking=no' -o 'UserKnownHostsFile=/dev/null' \
+        exec ssh -o ProxyCommand="socat - UNIX-CONNECT:$HOME/.local/state/minimal/providers/local-0/ssh.sock" \
+		 -o 'StrictHostKeyChecking=yes' -o "UserKnownHostsFile=$HOME/.local/state/minimal/known_hosts" \
 		 local "$arg" "$2"
🤖 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 `@crates/minimald/git-remote-min` around lines 13 - 14, The current SSH
invocation disables host key verification via the flags '-o
'StrictHostKeyChecking=no'' and '-o 'UserKnownHostsFile=/dev/null''; remove
these insecure options and instead enable strict checking and use a dedicated
known_hosts file for this transport. Replace the two flags with something like
'-o StrictHostKeyChecking=yes -o
UserKnownHostsFile=/path/to/transport_known_hosts' (or '-o
StrictHostKeyChecking=accept-new' if you need first-time acceptance), ensure the
code that runs the command (the invocation containing local "$arg" "$2")
creates/populates that known_hosts file or pins the server key before
connecting, and update any helper functions that build SSH options to reference
the new flags and file path.

Comment on lines +645 to +647
if let Some(ident) = argv.strip_prefix("git-receive-pack min://") {
return handle_git_receive(ident, serv, conn, id, session, channel, config).await;
}

Copy link
Copy Markdown

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

PTY validation is bypassed for git-receive-pack requests.

At Line 645, the early return routes git requests before the PTY rejection at Line 649, so unsupported PTY configs can slip through this path. Keep the same PTY guard for git as normal exec handling.

Suggested fix
 if let Some(ident) = argv.strip_prefix("git-receive-pack min://") {
+    if config.pty.is_some() {
+        tracing::warn!("channel {id}: pty requested but not yet supported");
+        session.channel_failure(id)?;
+        return Ok(());
+    }
     return handle_git_receive(ident, serv, conn, id, session, channel, config).await;
 }
🤖 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 `@crates/minimald/src/exec.rs` around lines 645 - 647, The git-receive-pack
branch (argv.strip_prefix(...) calling handle_git_receive) returns before the
PTY validation and therefore bypasses the PTY guard; move or duplicate the PTY
validation so that the same PTY rejection logic that runs later is applied
before invoking handle_git_receive. Concretely, ensure the PTY check (the
existing PTY guard logic used for normal exec handling) runs prior to the early
return from the git branch (or insert the same validation immediately before
calling handle_git_receive), referencing argv.strip_prefix("git-receive-pack
min://") and handle_git_receive(...) so the git path follows the same PTY
accept/reject flow as other execs.

Comment on lines +770 to +781
if let Ok(false) = tokio::fs::try_exists(&dotgit_dir).await {
let res = tokio::process::Command::new("git")
.arg("init")
.current_dir(workspace.as_utf8_path())
.output()
.await;
if let Err(e) = res {
tracing::warn!(error = %e, "git init failed");
channel.close().await.unwrap();
return;
}
}

Copy link
Copy Markdown

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

Handle .git probe/init failures explicitly before continuing.

At Line 770, try_exists errors are ignored; at Line 776, only execution errors are handled, while non-zero git init exit status still falls through to receive-pack. This can continue with an invalid repo state. Also avoid unwrap() on channel close (Line 778) in this error path.

Suggested fix
-        if let Ok(false) = tokio::fs::try_exists(&dotgit_dir).await {
-            let res = tokio::process::Command::new("git")
-                .arg("init")
-                .current_dir(workspace.as_utf8_path())
-                .output()
-                .await;
-            if let Err(e) = res {
-                tracing::warn!(error = %e, "git init failed");
-                channel.close().await.unwrap();
-                return;
-            }
-        }
+        match tokio::fs::try_exists(&dotgit_dir).await {
+            Ok(false) => {
+                match tokio::process::Command::new("git")
+                    .arg("init")
+                    .current_dir(workspace.as_utf8_path())
+                    .output()
+                    .await
+                {
+                    Ok(out) if out.status.success() => {}
+                    Ok(out) => {
+                        tracing::warn!(status = %out.status, "git init failed with non-zero status");
+                        let _ = channel.close().await;
+                        return;
+                    }
+                    Err(e) => {
+                        tracing::warn!(error = %e, "git init failed");
+                        let _ = channel.close().await;
+                        return;
+                    }
+                }
+            }
+            Ok(true) => {}
+            Err(e) => {
+                tracing::warn!(error = %e, "failed to check .git existence");
+                let _ = channel.close().await;
+                return;
+            }
+        }
🤖 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 `@crates/minimald/src/exec.rs` around lines 770 - 781, The code ignores errors
from tokio::fs::try_exists(&dotgit_dir), doesn't check git init's exit status,
and unwraps channel.close().await; update the block around try_exists/dotgit_dir
and the Command::new("git") invocation so that: 1) if try_exists returns Err(e)
you log/tracing::warn the error and close the channel (handle close errors
instead of unwrap) then return; 2) after awaiting .output(), check
output.status.success() and if false log the stdout/stderr and close the channel
(again handling close errors) and return; reference the dotgit_dir probe, the
Command::new("git")/.output() result and channel.close().await to locate and fix
the logic before proceeding to receive-pack.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
crates/minimald/src/exec.rs (2)

771-785: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stop on .git probe/init failures before continuing.

try_exists errors are still ignored, a non-zero git init exit still falls through to receive-pack, and channel.close().await.unwrap() can panic in the error path. That leaves this branch able to continue with an invalid repo state or turn a recoverable failure into a task panic.

Suggested fix
-        if let Ok(false) = tokio::fs::try_exists(&dotgit_dir).await {
-            let res = tokio::process::Command::new("git")
-                .arg("init")
-                .current_dir(workspace.as_utf8_path())
-                .output()
-                .await;
-            if let Err(e) = res {
-                tracing::warn!(error = %e, "git init failed");
-                channel.close().await.unwrap();
-                return;
-            }
-        }
+        match tokio::fs::try_exists(&dotgit_dir).await {
+            Ok(false) => match tokio::process::Command::new("git")
+                .arg("init")
+                .current_dir(workspace.as_utf8_path())
+                .output()
+                .await
+            {
+                Ok(out) if out.status.success() => {}
+                Ok(out) => {
+                    tracing::warn!(status = %out.status, stderr = %String::from_utf8_lossy(&out.stderr), "git init failed");
+                    let _ = channel.close().await;
+                    return;
+                }
+                Err(e) => {
+                    tracing::warn!(error = %e, "git init failed");
+                    let _ = channel.close().await;
+                    return;
+                }
+            },
+            Ok(true) => {}
+            Err(e) => {
+                tracing::warn!(error = %e, "failed to check .git existence");
+                let _ = channel.close().await;
+                return;
+            }
+        }
🤖 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 `@crates/minimald/src/exec.rs` around lines 771 - 785, The probe/init branch
currently ignores errors from tokio::fs::try_exists and a non-zero git init
result, and it calls channel.close().await.unwrap() which can panic; change the
logic in the block around tokio::fs::try_exists,
Command::new("git").arg("init").output().await and the subsequent error handling
so that: if try_exists returns Err treat it as a hard failure (log and stop
processing), when .output().await returns Ok check output.status.success() and
treat non-success as an error (log stderr/stdout and stop), and replace
channel.close().await.unwrap() with a non-panicking close (e.g. .await.ok() or
handle the Result) before returning instead of falling through to receive-pack.
Ensure logs include the command output for debugging.

646-648: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Apply the PTY guard before routing git-receive-pack.

This early return still bypasses the unsupported-PTY rejection at Lines 650-654, so git pushes can take a path normal execs explicitly reject.

Suggested fix
 if let Some(ident) = argv.strip_prefix("git-receive-pack min://") {
+    if config.pty.is_some() {
+        tracing::warn!("channel {id}: pty requested but not yet supported");
+        session.channel_failure(id)?;
+        return Ok(());
+    }
     return handle_git_receive(ident, serv, conn, id, session, channel, config).await;
 }
🤖 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 `@crates/minimald/src/exec.rs` around lines 646 - 648, The early return for
git-receive-pack bypasses the PTY rejection guard; move or invoke the PTY check
that's currently executed after this block (the unsupported-PTY rejection)
before the match that tests argv.strip_prefix("git-receive-pack min://"), so
that when `if let Some(ident) = argv.strip_prefix("git-receive-pack min://")`
triggers the code still runs the PTY guard first; ensure
`handle_git_receive(...)` is only called after the PTY validation passes (reuse
the same guard logic/condition used later to reject unsupported PTY).
🤖 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 `@crates/minimald/src/exec.rs`:
- Around line 787-825: The detached git task currently uses unwrap() when
creating/writing the temporary hook file and calling
hooks_tmp.path().to_str().unwrap(), which can panic after channel_success;
change the hook setup in the block that builds ExecTask/TokioExec to handle and
propagate IO/UTF-8 errors instead of unwrapping: perform fallible operations for
TempDir::new, tokio::fs::OpenOptions::open, file.write_all, and
hooks_tmp.path().to_str() with proper error handling (return Result or send a
controlled git failure), e.g., capture the error, log it and convert it into a
failed exec result that the git subprocess will see; update the code around
hooks_tmp, OpenOptions::open, write_all, and the construction of TokioExec/argv
to use these fallible paths rather than unwrap().

---

Duplicate comments:
In `@crates/minimald/src/exec.rs`:
- Around line 771-785: The probe/init branch currently ignores errors from
tokio::fs::try_exists and a non-zero git init result, and it calls
channel.close().await.unwrap() which can panic; change the logic in the block
around tokio::fs::try_exists, Command::new("git").arg("init").output().await and
the subsequent error handling so that: if try_exists returns Err treat it as a
hard failure (log and stop processing), when .output().await returns Ok check
output.status.success() and treat non-success as an error (log stderr/stdout and
stop), and replace channel.close().await.unwrap() with a non-panicking close
(e.g. .await.ok() or handle the Result) before returning instead of falling
through to receive-pack. Ensure logs include the command output for debugging.
- Around line 646-648: The early return for git-receive-pack bypasses the PTY
rejection guard; move or invoke the PTY check that's currently executed after
this block (the unsupported-PTY rejection) before the match that tests
argv.strip_prefix("git-receive-pack min://"), so that when `if let Some(ident) =
argv.strip_prefix("git-receive-pack min://")` triggers the code still runs the
PTY guard first; ensure `handle_git_receive(...)` is only called after the PTY
validation passes (reuse the same guard logic/condition used later to reject
unsupported PTY).
🪄 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: 83f83394-ec91-40fa-bc99-f77992eab82e

📥 Commits

Reviewing files that changed from the base of the PR and between 0bb6ec5 and 3ea16cb.

📒 Files selected for processing (4)
  • crates/minimald/Cargo.toml
  • crates/minimald/git-remote-min
  • crates/minimald/src/exec.rs
  • crates/minimald/src/test_harness.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/minimald/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/minimald/git-remote-min

Comment on lines +787 to +825
let hooks_tmp = TempDir::new().unwrap();
tokio::fs::OpenOptions::new()
.create_new(true)
.write(true)
.mode(0o755)
.open(hooks_tmp.path().join("post-receive"))
.await
.unwrap()
.write_all(
r#"#!/bin/sh
# post-receive runs with CWD = $GIT_DIR and GIT_DIR set in the env,
# which breaks worktree commands unless you clear it.
GIT_DIR_ABS=$(pwd -P) # .../tree/.git
WORK_TREE=$(dirname "$GIT_DIR_ABS") # .../tree
unset GIT_DIR GIT_WORK_TREE GIT_QUARANTINE_PATH

while read -r old new ref; do
case "$ref" in
refs/heads/*)
git --git-dir="$GIT_DIR_ABS" --work-tree="$WORK_TREE" \
checkout -f "${ref#refs/heads/}"
;;
esac
done"#
.as_bytes(),
)
.await
.unwrap();

let exec_task = ExecTask {
conn,
serv,
session: session_handle,
channel_id: id,
exec: TokioExec {
argv: format!(
"git -c core.hooksPath={} receive-pack .",
hooks_tmp.path().to_str().unwrap()
),

Copy link
Copy Markdown

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

Don't unwrap() hook setup after channel_success.

These unwrap()s run inside the detached git task after the exec request has already been accepted. Any tempdir/fs failure — or a non-UTF-8 temp path at to_str().unwrap() — turns the push into a panic and dropped channel instead of a controlled git failure.

Suggested fix
-        let hooks_tmp = TempDir::new().unwrap();
+        let hooks_tmp = match TempDir::new() {
+            Ok(dir) => dir,
+            Err(e) => {
+                tracing::warn!(error = %e, "failed to create git hooks dir");
+                let _ = channel.close().await;
+                return;
+            }
+        };

Apply the same pattern to the open(...), write_all(...), and to_str() sites before constructing TokioExec.

🤖 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 `@crates/minimald/src/exec.rs` around lines 787 - 825, The detached git task
currently uses unwrap() when creating/writing the temporary hook file and
calling hooks_tmp.path().to_str().unwrap(), which can panic after
channel_success; change the hook setup in the block that builds
ExecTask/TokioExec to handle and propagate IO/UTF-8 errors instead of
unwrapping: perform fallible operations for TempDir::new,
tokio::fs::OpenOptions::open, file.write_all, and hooks_tmp.path().to_str() with
proper error handling (return Result or send a controlled git failure), e.g.,
capture the error, log it and convert it into a failed exec result that the git
subprocess will see; update the code around hooks_tmp, OpenOptions::open,
write_all, and the construction of TokioExec/argv to use these fallible paths
rather than unwrap().

@twitchyliquid64
twitchyliquid64 force-pushed the tom/update branch 2 times, most recently from f9e766e to 40a3433 Compare June 5, 2026 17:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
crates/minimald/src/test_harness.rs (2)

115-116: ⚡ Quick win

Document the socket path precondition or handle cleanup.

The UnixListener::bind will panic if sock already exists (e.g., from a previous test run that didn't clean up). Consider either documenting that the caller must ensure the path is clean, or adding explicit cleanup:

let _ = std::fs::remove_file(sock); // Ignore error if not present
let listener = UnixListener::bind(sock).unwrap();

This helps prevent test flakes when socket files persist between runs.

🤖 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 `@crates/minimald/src/test_harness.rs` around lines 115 - 116, The
listen_on_uds function currently calls UnixListener::bind(sock) which will panic
if the socket path already exists; update listen_on_uds to either document that
callers must ensure sock is removed before calling or proactively remove any
existing socket file before binding (e.g., call std::fs::remove_file(sock) and
ignore NotFound errors) so UnixListener::bind(sock) succeeds reliably and avoids
test flakes.

119-130: 💤 Low value

Consider returning the outer JoinHandle for test control.

The spawned accept loop is fire-and-forget, which limits test flexibility:

  • No way to await listener shutdown
  • Accept errors are silently discarded (while let Ok(...) stops on first failure)
  • No mechanism to verify the listener is ready before clients connect

For more robust test infrastructure, consider returning the JoinHandle and logging accept errors:

♻️ Suggested enhancement
-pub(crate) async fn listen_on_uds(&self, sock: &Path) {
+pub(crate) async fn listen_on_uds(&self, sock: &Path) -> tokio::task::JoinHandle<()> {
     let listener = UnixListener::bind(sock).unwrap();
     let russh_config = self.russh_config.clone();
     let state = self.state.clone();
-    tokio::spawn(async move {
+    tokio::spawn(async move {
-        while let Ok((socket, _)) = listener.accept().await {
+        loop {
+            let (socket, _) = match listener.accept().await {
+                Ok(conn) => conn,
+                Err(e) => {
+                    eprintln!("UDS accept failed: {e}");
+                    break;
+                }
+            };
             let russh_config = russh_config.clone();
             let state = state.clone();
             tokio::spawn(async move {

This allows tests to join the accept loop if needed and makes failures visible.

🤖 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 `@crates/minimald/src/test_harness.rs` around lines 119 - 130, The accept loop
currently spawned with tokio::spawn is fire-and-forget which drops control and
silences accept errors; change the code that creates the listener accept loop to
return its outer JoinHandle (instead of discarding it) so callers/tests can
await shutdown or inspect panics, replace the `while let Ok((socket, _)) =
listener.accept().await` pattern with an explicit loop that logs accept errors
via the crate logger (or eprintln!) and breaks/continues as appropriate, and
keep the inner per-connection spawn that calls Connection::from_socket and
awaits session_fut; also consider adding a readiness signal (oneshot) from where
the JoinHandle is created so tests can wait until the listener is ready before
connecting.
🤖 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.

Nitpick comments:
In `@crates/minimald/src/test_harness.rs`:
- Around line 115-116: The listen_on_uds function currently calls
UnixListener::bind(sock) which will panic if the socket path already exists;
update listen_on_uds to either document that callers must ensure sock is removed
before calling or proactively remove any existing socket file before binding
(e.g., call std::fs::remove_file(sock) and ignore NotFound errors) so
UnixListener::bind(sock) succeeds reliably and avoids test flakes.
- Around line 119-130: The accept loop currently spawned with tokio::spawn is
fire-and-forget which drops control and silences accept errors; change the code
that creates the listener accept loop to return its outer JoinHandle (instead of
discarding it) so callers/tests can await shutdown or inspect panics, replace
the `while let Ok((socket, _)) = listener.accept().await` pattern with an
explicit loop that logs accept errors via the crate logger (or eprintln!) and
breaks/continues as appropriate, and keep the inner per-connection spawn that
calls Connection::from_socket and awaits session_fut; also consider adding a
readiness signal (oneshot) from where the JoinHandle is created so tests can
wait until the listener is ready before connecting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 83e3af7b-fac1-4377-bd09-29ed7419b3db

📥 Commits

Reviewing files that changed from the base of the PR and between f9e766e and 40a3433.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .minimal/minimal.toml
  • crates/minimald/Cargo.toml
  • crates/minimald/git-remote-min
  • crates/minimald/src/exec.rs
  • crates/minimald/src/test_harness.rs
✅ Files skipped from review due to trivial changes (1)
  • .minimal/minimal.toml
🚧 Files skipped from review as they are similar to previous changes (4)
  • .github/workflows/ci.yml
  • crates/minimald/git-remote-min
  • crates/minimald/src/exec.rs
  • crates/minimald/Cargo.toml

@twitchyliquid64
twitchyliquid64 merged commit 0f21eee into main Jun 5, 2026
18 checks passed
@twitchyliquid64
twitchyliquid64 deleted the tom/update branch June 5, 2026 17:57
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.

2 participants