Skip to content

fix(shell): avoid interactive job control in environment probes - #11275

Open
LouisDeconinck wants to merge 2 commits into
pingdotgg:mainfrom
LouisDeconinck:fix/login-shell-env-probe-no-interactive
Open

LouisDeconinck wants to merge 2 commits into
pingdotgg:mainfrom
LouisDeconinck:fix/login-shell-env-probe-no-interactive

Conversation

@LouisDeconinck

@LouisDeconinck LouisDeconinck commented Sep 11, 2026 •

Copy link
Copy Markdown

What Changed

Both login-shell environment probes now run shell -lc instead of shell -ilc:

  • readEnvironmentFromLoginShell in packages/shared/src/shell.ts (used by the server's fixPath, which runs on the remote during t3 serve boot over SSH)
  • The login-shell probe in apps/desktop/src/shell/DesktopShellEnvironment.ts (the local desktop twin)

Both call sites changed together so local and remote behavior stay consistent. Marker-delimited capture, merge behavior, timeouts, and Windows probing are unchanged.

Why

-i makes the shell initialize job control, which calls tcsetpgrp() on the session's controlling TTY. When the remote SSH session inherits a controlling TTY owned by a different process group (e.g. tailscaled's built-in SSH server started from an interactive terminal), the kernel stops the probe with SIGTTOU before it runs anything. desktop:ensure-ssh-environment then hangs until the 90s launch timeout, and the stopped remote process group is leaked.

Environment capture only needs login-shell semantics (/etc/profile, ~/.profile, ~/.zprofile, fish login config), not interactive job control. -lc is also what the SSH bootstrap itself already uses (sh -l -s, #7213). Verified on the affected host in the issue report: bash -lc returns instantly where bash -ilc hangs.

Tests assert the probe args are -lc (no -i) and that PATH/environment capture still works in both packages.

Tests run:

  • vp test run packages/shared/src/shell.test.ts apps/desktop/src/shell/DesktopShellEnvironment.test.ts — 48 passed
  • vp run --filter @t3tools/shared --filter @t3tools/desktop --filter t3 typecheck — passed
  • vp lint / vp fmt --check on the touched files — clean

Out of scope per the triage: remote process-group cleanup (SIGCONT/kill on launch timeout) and the offline-environment retry cadence (#4144) are follow-ups.

Fixes #11001

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Made with SWE-2 via Devin.

Summary by CodeRabbit

  • Bug Fixes

    • Improved shell environment detection across macOS and other platforms by applying shell-appropriate login startup behavior.
    • Improved PATH detection for zsh while preventing terminal job-control interruptions during shell checks.
    • Ensured login-shell commands execute correctly in mobile showcase environments.
  • Tests

    • Added and updated regression coverage for zsh and bash login-shell probing, including reliable PATH application.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 11, 2026
@coderabbitai

coderabbitai Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 627cc43c-6748-4a5e-a877-8f283373bae3

📥 Commits

Reviewing files that changed from the base of the PR and between f1ace2d and 05bf533.

📒 Files selected for processing (5)
  • apps/desktop/src/shell/DesktopShellEnvironment.test.ts
  • apps/desktop/src/shell/DesktopShellEnvironment.ts
  • packages/shared/src/shell.test.ts
  • packages/shared/src/shell.ts
  • scripts/mobile-showcase.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Login-shell probes now choose arguments by shell type. zsh uses +m -ilc to read interactive startup files without job control. Other shells use -lc. Tests verify flags and captured PATH.

Changes

Login shell probe

Layer / File(s) Summary
Shared shell probe behavior
packages/shared/src/shell.ts, packages/shared/src/shell.test.ts
The shared probe uses +m -ilc for zsh and -lc for other shells. Tests verify both forms and PATH capture.
Desktop shell integration
apps/desktop/src/shell/DesktopShellEnvironment.ts, apps/desktop/src/shell/DesktopShellEnvironment.test.ts
The desktop probe uses shell-specific arguments. macOS tests verify zsh and bash behavior and applied PATH values.
Showcase shell compatibility
scripts/mobile-showcase.ts
The generated showcase shell recognizes -lc and executes its command through /bin/sh -c.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant DesktopShellEnvironment
  participant ShellProbe
  participant LoginShell
  participant Environment
  DesktopShellEnvironment->>ShellProbe: select arguments by shell
  ShellProbe->>LoginShell: run zsh with +m -ilc or other shells with -lc
  LoginShell->>Environment: load login startup files
  Environment-->>LoginShell: set PATH
  LoginShell-->>DesktopShellEnvironment: return captured PATH
Loading

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to 05bf5

The shell probe changes preserve the intended zsh and non-zsh invocation forms, with no remaining actionable merge risk identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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 2 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change: avoiding interactive job control during shell environment probes.
Description check ✅ Passed The description includes complete What Changed and Why sections, explains the affected server and desktop probes, documents testing, scope, and the linked issue. UI evidence is not required because th…
Linked Issues check ✅ Passed Issue #11001 requires the login-shell probe to avoid the SIGTTOU job-control hang while preserving required environment capture. packages/shared/src/shell.ts and `apps/desktop/src/shell/DesktopShell…
Out of Scope Changes check ✅ Passed The changed probe logic, regression tests, comments, and mobile showcase shell-wrapper update all support the new -lc invocation behavior. No change implements the separate remote-process cleanup or…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment thread apps/desktop/src/shell/DesktopShellEnvironment.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Would Approve

Macroscope's review found this PR approvable — This is a narrowly scoped shell-probe bug fix that removes interactive job control while preserving the existing environment-capture and merge flow, with coverage for both affected call sites. A separate high-severity correctness finding flags that interactive-only PATH configuration such as zsh .zshrc entries may be omitted and represents a material risk to resolve.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

-lc skipped ~/.zshrc, dropping PATH entries from version managers and
custom bin dirs. zsh keeps -i but gets +m, which clears MONITOR before
startup so the probe still never calls tcsetpgrp() on a foreign
controlling TTY. bash stays -lc (login shells never read ~/.bashrc and
bash ignores +m at startup), fish reads config.fish for login shells.
@LouisDeconinck

Copy link
Copy Markdown
Author

Follow-up on the review finding: -lc skipped interactive startup files, so zsh never read ~/.zshrc and version-manager/custom PATH entries were dropped. The probe now runs zsh as +m -ilc: +m clears MONITOR before startup, so the shell still sources .zshrc but never calls tcsetpgrp() on a foreign controlling TTY (the original SIGTTOU hang). bash/fish/others stay -lc — login bash never reads .bashrc and still grabs the TTY even with +m, while fish reads config.fish for login shells. Verified +m -ilc exits cleanly in a backgrounded process group on an inherited controlling TTY where -ilc stops.

@github-actions github-actions Bot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 12, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: SSH environment setup hangs 90s when the remote session inherits a controlling TTY — bash -ilc PATH probe is stopped by SIGTTOU

1 participant