Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/assets/bundled/bootstrap/bash_body.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1420,6 +1420,22 @@ esac
source "$HOME/.profile"
fi

# Warp starts bash as an interactive shell, so also mirror the
# interactive (non-login) startup sequence, which reads ~/.bashrc.
# Without this, aliases and functions defined only in ~/.bashrc never
# exist inside Warp even though they work in other terminals. Notably,
# a user alias like `alias ssh="trzsz -d ssh"` would be silently
# dropped, and the `ssh` function installed by this bootstrap script
# above would take over interactive `ssh` invocations, bypassing the
# wrapper (see issue #16631). Guard against double-sourcing for users
# whose login rcfile already re-sources ~/.bashrc (the documented
# pattern for login/interactive unification), which is harmless but
# wasteful.
if [[ $- == *i* && -f "$HOME/.bashrc" && -z ${WARP_SOURCED_BASHRC:-} ]]; then
export WARP_SOURCED_BASHRC=1
source "$HOME/.bashrc"
fi

rcfiles_end_time="$(LC_ALL="C"; echo $EPOCHREALTIME)"
fi

Expand Down
1 change: 1 addition & 0 deletions crates/integration/src/bin/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ fn register_tests() -> HashMap<&'static str, BoxedBuilderFn> {
register_test!(test_bootstrap_with_no_script_execution_block);
register_test!(test_instant_prompt_bootstrap);
register_test!(test_rc_files_only_sourced_once_during_bootstrapping);
register_test!(test_bash_bootstraps_sources_bashrc_aliases);
register_test!(test_unescaped_prompt_bootstraps);
register_test!(test_detect_powerlevel10k);
register_test!(test_open_and_close_resource_center);
Expand Down
53 changes: 53 additions & 0 deletions crates/integration/src/test/bootstrapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,3 +508,56 @@ PROMPT_COMMAND=('printf "\033]0;SHAKA WHEN THE WALLS FELL\a"' 'custom_prompt')
),
)
}

/// Regression test for https://github.com/warpdotdev/warp/issues/16631.
///
/// Warp starts bash with a custom rcfile and then sources user rcfiles in
/// login order (`/etc/profile` -> `~/.bash_profile` | `~/.bash_login` |
/// `~/.profile`). Previously, `~/.bashrc` was never sourced, so aliases and
/// functions defined only there never existed inside Warp even though they
/// work in other terminals. In particular, an `alias ssh="trzsz -d ssh"`
/// (or any other ssh wrapper) would be silently dropped and the bootstrap
/// script's own `ssh` function would take over interactive `ssh`
/// invocations, bypassing the wrapper.
///
/// This test writes an alias solely into `~/.bashrc` (with a `.bash_profile`
/// present that does *not* re-source `.bashrc`, matching the reporter's
/// setup), then verifies after bootstrap that the alias is active and wins
/// over any same-named shell function.
pub fn test_bash_bootstraps_sources_bashrc_aliases() -> Builder {
new_builder()
.set_should_run_test(|| {
// Only run this one on bash
let (starter, _version) = current_shell_starter_and_version();
matches!(starter.shell_type(), shell::ShellType::Bash)
})
.with_setup(|utils| {
let dir = utils.test_dir();
// .bash_profile exists (so login-order sourcing stops there) but does
// NOT re-source .bashrc — the exact layout from the issue report.
write_rc_files_for_test(&dir, "export WARP_TEST_LOGIN_RCFILE=1", [ShellRcType::Bash]);
// The wrapper alias under test lives only in ~/.bashrc. It shadows
// the bootstrap script's own `ssh` function: bash resolves aliases
// before functions, so if this alias is active, `ssh` cannot reach
// the function.
write_rc_files_for_test(dir, "alias ssh='echo ssh-alias-won'", [ShellRcType::BashRc]);
})
.with_step(wait_until_bootstrapped_single_pane_for_tab(0))
// The login rcfile must have been sourced (sanity check of the setup).
.with_step(execute_command_for_single_terminal_in_tab(
0,
"test \"$WARP_TEST_LOGIN_RCFILE\" = 1 && echo login-rcfile-sourced".to_string(),
ExpectedExitStatus::Success,
"login-rcfile-sourced",
))
// If ~/.bashrc was sourced, the alias wins over the bootstrap's ssh
// function and `ssh` just echoes. Before the fix the alias never
// existed and `ssh` fell through to the bootstrap's ssh function
// (which would try to open a connection instead of printing this).
.with_step(execute_command_for_single_terminal_in_tab(
0,
"ssh".to_string(),
ExpectedExitStatus::Success,
"ssh-alias-won",
))
}
17 changes: 16 additions & 1 deletion crates/integration/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub fn get_input_buffer(
#[derive(EnumIter)]
pub enum ShellRcType {
Bash,
/// Bash's interactive (non-login) rcfile, `~/.bashrc`. Distinct from
/// [`ShellRcType::Bash`], which maps to the login-order files Warp
/// emulates during bootstrap (`~/.bash_profile` et al.).
BashRc,
Zsh,
Fish,
PowerShell,
Expand All @@ -39,6 +43,7 @@ impl ShellRcType {
fn rc_file_paths(&self, home_dir: impl AsRef<Path>) -> Vec<PathBuf> {
let relative_paths = match self {
ShellRcType::Bash => vec![Path::new(".bash_profile")],
ShellRcType::BashRc => vec![Path::new(".bashrc")],
ShellRcType::Zsh => vec![Path::new(".zshrc")],
ShellRcType::Fish => vec![Path::new(".config/fish/config.fish")],
#[cfg(not(windows))]
Expand Down Expand Up @@ -136,7 +141,17 @@ where
P: AsRef<Path>,
C: AsRef<str>,
{
write_rc_files_for_test(dir, rc_contents, ShellRcType::iter())
// `BashRc` is bash's *second* rc file (the interactive one, alongside the
// login-order `.bash_profile` covered by `Bash`). Writing both with the
// same contents would make bash sessions source the contents twice now
// that the bootstrap mirrors the interactive startup sequence too, so
// tests that assert on rcfile side effects must opt into `.bashrc`
// explicitly via `write_rc_files_for_test`.
write_rc_files_for_test(
dir,
rc_contents,
ShellRcType::iter().filter(|rc_type| !matches!(rc_type, ShellRcType::BashRc)),
)
}

/// Writes a histfile for `shell_types` to the given `dir`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ integration_tests! {
test_ps1_value_not_null_or_exit,
// Tests bash-specific behavior.
test_custom_ps1_expansion_bash,
// Tests bash-specific behavior: ~/.bashrc aliases survive bootstrap (#16631).
test_bash_bootstraps_sources_bashrc_aliases,
test_bash_honor_ps1_expands_dynamic_prompt_once,
// Tests zsh-specific behavior.
test_auto_title,
Expand Down
Loading