8000 fix(minimald): bound wedged transport writes with an inactivity deadline by gominimal-aw-bot[bot] · Pull Request #2303 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

fix(minimald): bound wedged transport writes with an inactivity deadline - #2303

Merged
norrietaylor merged 3 commits into
mainfrom
inbox-patch/fix/wedged-transport-write-inactivity-deadline-ec4a433782b5e15f
Oct 18, 2026
Merged

norrietaylor merged 3 commits into
mainfrom
inbox-patch/fix/wedged-transport-write-inactivity-deadline-ec4a433782b5e15f

Conversation

@gominimal-aw-bot
@gominimal-aw-bot gominimal-aw-bot Bot commented Oct 17, 2026 •
Copy link
Copy Markdown
Contributor

Routing-Key: inbox-route/I_kwDOSUhdos8AAAABQrDSRg

The defect

An established SSH attach over vsock could go dark in both directions and stay that way far past every keepalive budget. The mechanism: russh bounds every session-loop transport write only by the inactivity timer, and minimald set inactivity_timeout: None. A transport write that never completed (a wedged vsock peer, a full buffer nobody drains) therefore parked the session loop forever. Keepalives are dispatched from that same loop, so they stopped firing too — the connection was dead in both directions yet outlived the entire keepalive budget, because the only deadline that could reclaim it was disarmed.

The fix

Arm the inactivity timer instead of disabling it — at the full keepalive budget (interval × (max + 1) = 2h at the current 30min/3 settings):

  • inactivity_timeout: Some(INACTIVITY_TIMEOUT) in build_russh_config, replacing None, with the rationale rewritten to state both halves: why it must not reap a healthy idle attach, and why None is not safe.
  • A healthy idle attach answers each keepalive within one interval, and a completed write/flush resets the inactivity clock, so a live session is never reaped — the previous concern (the default 600s reaper killing quiet attaches) does not apply at a 2h budget.
  • A wedged write is now bounded: the session future resolves with russh::Error::InactivityTimeout, which propagates through ConnectionError::Protocol, tearing the connection down one interval past the budget.
  • Two stale comments in diag.rs that asserted inactivity_timeout: None as a design invariant are updated to the new truth.

The SSH-id handshake phase is unaffected: it completes eagerly inside from_stream, which is already bounded separately by HANDSHAKE_DEADLINE (30s).

Verification

Gate commands, all with --manifest-path target/Cargo.toml:

  • cargo fmt --all -- --check — pass.
  • cargo clippy --workspace --all-targets --locked -- -D warnings — pass.
  • cargo test --locked -p minimald --lib a_wedged — the new mechanism test passes: connection::tests::a_wedged_transport_write_ends_the_session_on_the_inactivity_deadline ... ok. The test handshakes a real russh client against the server through a flippable write-wedged transport, then proves the session future resolves with ConnectionError::Protocol(russh::Error::InactivityTimeout) on the inactivity deadline — while 8000 under the old inactivity_timeout: None the same future never resolves and the outer timeout fires instead (regression guard). keepalive_max is set far above the inactivity budget in the test so the resolution is by the inactivity deadline, not by exhausting keepalives.
  • Full suite: 1000 passed / 11 failed on this branch vs 999 passed / 11 failed on the pristine baseline — the identical 11 failure names (egress/switch, direct_tcpip, rpc tests; they pass in isolation and fail under full-suite parallel load in this sandboxed environment, which has no egress networking). The net::answerer flake that rotates between runs also reproduces identically on the pristine baseline. Net effect of this change: +1 passing test, nothing broken.

CI lanes that cover this change: native-daemon-e2e (ci-linux-native), test-kvm (ci-linux-kvm), and macos e2e (ci-macos) all trigger on crates/minimald/** and run live-session e2e for minimald, which this sandbox cannot host.

Full diff audit performed: 3 files, 162 insertions, 10 deletions — every hunk traces to the defect (the config change + its comment, the two stale-comment truth updates, the one new mechanism test).

Summary by CodeRabbit

  • Bug Fixes
    • SSH sessions with stalled transport writes now time out instead of hanging indefinitely. The inactivity limit is two hours, while healthy connections remain active by sending keepalives.
  • Documentation
    • Clarified how the inactivity timeout relates to the keepalive budget.

russh bounds every session-loop transport write only by the
inactivity timer, and minimald set it to None, so a write that
never completed parked the session loop forever. Keepalives are
dispatched from that same loop, so they stopped firing too: an
attach whose transport wedged went dark in both directions and
survived every keepalive budget.

Arm the timer at the full keepalive budget instead. A healthy
idle attach answers each keepalive and resets the clock, so it is
never reaped; a wedged one is torn down one interval past the
budget. Add a mechanism test that wedges the write side of an
otherwise-live russh session and proves the session future now
resolves with InactivityTimeout instead of parking.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@gominimal-aw-bot
gominimal-aw-bot Bot requested a review from a team as a code owner October 17, 2026 12:37
@gominimal-aw-bot gominimal-aw-bot Bot added the agent:fix Agentic fix PR eligible for review iteration; min-aw's worker-iterate gates on it. label Oct 17, 2026
@coderabbitai
coderabbitai Bot commented Oct 17, 2026 •
Copy link
Copy Markdown
Contributor

Review in Change Stack →

Warning

Review limit reached

  • Run on-demand review

This review includes 3 billable files and costs up to $0.75.

Or wait 34 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available. Your 56 included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 8c060ff0-54bd-40d3-a68e-66ddc1400841
📥 Commits

Reviewing files that changed from the base of the PR and between c484563 and d3aace9.

📒 Files selected for processing: 3
  • crates/minimald/src/connection.rs
  • crates/minimald/src/diag.rs
  • crates/minimald/src/server.rs

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 37151502-e4a5-4dcd-8765-7b6746ca647c
📥 Commits

Reviewing files that changed from the base of the PR and between 11b0b44 and c484563.

📒 Files selected for processing: 3
  • crates/minimald/src/connection.rs
  • crates/minimald/src/diag.rs
  • crates/minimald/src/server.rs

Included review availability: This review used your included allowance. 3 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.

📝 Walkthrough

The SSH server now configures russh with an inactivity timeout derived from the keepalive limit. Documentation reflects that setting, and an async regression test verifies that a stalled transport write ends the session with InactivityTimeout.

Changes: SSH inactivity timeout

Layer / File(s) Summary
Configure the inactivity timeout
crates/minimald/src/server.rs, crates/minimald/src/diag.rs
The server sets russh’s inactivity timeout to one keepalive interval beyond the maximum tolerated unanswered keepalives. The request-timeout documentation and test comment describe the configured timeout.
Verify stalled writes time out
crates/minimald/src/connection.rs
An async regression test stalls transport writes after SSH authentication and checks that the session returns InactivityTimeout.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~15 minutes

Change: Bug fix

Suggested reviewers: norrietaylor

Merge Risk: ⚪ Minimal · up to c4845

The change bounds stalled SSH transport writes without an identified regression. It is ready to merge after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
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.
Title check Passed The title clearly and concisely describes the main change: adding an inactivity deadline to bound wedged transport writes. It follows the required Conventional Commit format.
Description check Passed The description thoroughly explains the defect, fix, behavior, and verification results. It includes equivalent Summary and Testing content, although it does not include the template's Checklist headi…
Full details: Description check

Explanation

The description thoroughly explains the defect, fix, behavior, and verification results. It includes equivalent Summary and Testing content, although it does not include the template's Checklist heading. This omission is non-critical because the description addresses documentation updates and does not identify a breaking change.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

A rabbit checks the keepalive beat
A stalled write waits, then meets its fate
The server ends the quiet wait
The session returns its timeout
I hop along, the test is green!

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

coderabbitai[bot]
coderabbitai Bot approved these change 8000 s Oct 17, 2026
@gominimal-aw-bot gominimal-aw-bot Bot added the agent:resolve Consent gate: pr-conflict-resolver may rewrite this branch label Oct 17, 2026
@norrietaylor norrietaylor changed the title fix: fix(minimald): bound wedged transport writes with an inactivity deadline fix(minimald): bound wedged transport writes with an inactivity deadline Oct 18, 2026
…deadline

Share the wedgeable-transport setup between the wedge test and a new
healthy-idle test that answers keepalives for several inactivity windows,
widen the test deadlines so KEX and auth cannot trip them on a loaded
runner, and assert the production russh config arms INACTIVITY_TIMEOUT.
@norrietaylor
Copy link
Copy Markdown
Member

/review

@minimal-foundry
minimal-foundry Bot commented Oct 18, 2026 •
Copy link
Copy Markdown
Contributor

Approved: no findings at d3aace925bc5.

Nothing to do.

Clobber: none: git log on the three changed files shows only this PR's commits (c484563, fc0c2ad, d3aace9) plus unrelated renames; nothing reverts recent work.

@norrietaylor
Copy link
Copy Markdown
Member

/review

@minimal-foundry minimal-foundry Bot left a comment
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.

minimal-review — advisory review

Verdict COMMENT — No findings.

Panel: 2 of 3 personas ran (correctness, security); did not complete: supply-chain.

@minimal-foundry minimal-foundry Bot added the review:approved minimal-review approved the current head label Oct 18, 2026
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved on ARCH PASS at d3aace9.

@norrietaylor
norrietaylor added this pull request to the merge queue Oct 18, 2026
Merged via the queue into main with commit 02f3af9 Oct 18, 2026
47 of 51 checks passed
@norrietaylor
norrietaylor deleted the inbox-patch/fix/wedged-transport-write-inactivity-deadline-ec4a433782b5e15f branch October 18, 2026 07:37
norrietaylor pushed a commit that referenced this pull request Nov 4, 2026
…ine (#2303)

russh bounds every session-loop transport write only by the inactivity timer, and minimald set
it to None, so a write that never completed parked the session loop forever. Keepalives are
dispatched from that same loop, so they stopped firing too: an attach whose transport wedged
went dark in both directions and survived every keepalive budget. The timer is now armed one
interval past the keepalive budget, so a healthy idle attach is never reaped and a wedged one is
torn down.

Backport of #2303. Adapted to the line: the test module gains the small accept-all client
handler main's connection tests already had.

(cherry picked from commit 02f3af9)
norrietaylor pushed a commit that referenced this pull request Nov 5 8000 , 2026
…ine (#2303)

russh bounds every session-loop transport write only by the inactivity timer, and minimald set
it to None, so a write that never completed parked the session loop forever. Keepalives are
dispatched from that same loop, so they stopped firing too: an attach whose transport wedged
went dark in both directions and survived every keepalive budget. The timer is now armed one
interval past the keepalive budget, so a healthy idle attach is never reaped and a wedged one is
torn down.

Backport of #2303. Adapted to the line: the test module gains the small accept-all client
handler main's connection tests already had.

(cherry picked from commit 02f3af9)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent:fix Agentic fix PR eligible for review iteration; min-aw's worker-iterate gates on it. agent:resolve Consent gate: pr-conflict-resolver may rewrite this branch review:approved minimal-review approved the current head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0