docs(setup): use ~/.bashrc hand-off instead of chsh for zsh switch
CI / commits (pull_request) Successful in 3m1s
CI / check (pull_request) Successful in 3m11s
CI / scan (pull_request) Successful in 3m17s
CI / a11y (pull_request) Successful in 3m23s
Docs site / build (pull_request) Successful in 3m42s
CI / perf (pull_request) Successful in 5m11s

chsh is blocked on the corp dev VM (PAM-level restriction at user-
provisioning time). Drop the sudo chsh -s call from 20-zsh.sh and
append a guarded `exec zsh -l` block to ~/.bashrc instead — same UX
without needing infra escalation, also matches the legacy WSL setup
pattern in 02-wsl-terminal-setup.md.

The hand-off is guarded by `case $- in *i*)` so non-interactive bash
flows (scp, rsync, cron) are unaffected, and by a ZSH_VERSION absence
check to prevent re-exec loops.

Main doc and README table descriptions updated to match.
This commit is contained in:
Julien Gautier
2026-05-24 19:42:18 +02:00
parent 8a04540410
commit 5821c60195
3 changed files with 48 additions and 30 deletions
+2 -2
View File
@@ -161,9 +161,9 @@ The `bootstrap.sh` script runs every numbered script (`10-…` → `80-…`) in
What each script does:
| Script | Effect | Idempotent? |
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| [`10-base-packages.sh`](scripts/10-base-packages.sh) | `apt update` + install base packages (curl wget git build-essential ca-certificates gnupg software-properties-common) | ✅ |
| [`20-zsh.sh`](scripts/20-zsh.sh) | Install zsh, set as default shell. Install Oh My Zsh, Powerlevel10k, plugins (autosuggestions, syntax-highlighting). Patch `~/.zshrc`. | ✅ |
| [`20-zsh.sh`](scripts/20-zsh.sh) | Install zsh + Oh My Zsh + Powerlevel10k + plugins (autosuggestions, syntax-highlighting). Patch `~/.zshrc` (theme + plugins + fzf hook) and `~/.bashrc` (exec zsh on interactive shells — `chsh` is blocked on the corp VM). | ✅ |
| [`30-cli-tools.sh`](scripts/30-cli-tools.sh) | Install `bat eza fd-find ripgrep fzf zoxide ncdu keychain` + `jq yq httpie make tree htop tmux direnv dnsutils unzip`. Aliases for the Debian-renamed binaries (`batcat``bat`, `fdfind``fd`). | ✅ |
| [`40-node.sh`](scripts/40-node.sh) | Install nvm. Install Node from the repo's `.nvmrc` (currently `24`). Enable corepack, pin pnpm to `package.json`'s `packageManager`. | ✅ |
| [`50-docker.sh`](scripts/50-docker.sh) | Install Docker CE + compose plugin from the Docker apt repo. Add the current user to the `docker` group. Enable `docker.service`. | ✅ |
+2 -2
View File
@@ -14,11 +14,11 @@ Step-by-step setup procedures for new contributors. Each file is self-contained
Modular setup scripts called from the doc above. Each is idempotent, each can be re-run safely. Run via the orchestrator (`bootstrap.sh`) or individually.
| Script | Purpose |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`bootstrap.sh`](scripts/bootstrap.sh) | Run every numbered script in order with a confirmation prompt at each step. |
| [`lib.sh`](scripts/lib.sh) | Common helpers — colour logging, idempotent `apt_install` / `ensure_line`. |
| [`10-base-packages.sh`](scripts/10-base-packages.sh) | apt + base packages every other script assumes (`curl wget git build-essential …`). |
| [`20-zsh.sh`](scripts/20-zsh.sh) | zsh, Oh My Zsh, Powerlevel10k, autosuggestions, syntax-highlighting. Patches `~/.zshrc`. |
| [`20-zsh.sh`](scripts/20-zsh.sh) | zsh + Oh My Zsh + Powerlevel10k + autosuggestions + syntax-highlighting. Patches `~/.zshrc` (theme / plugins / fzf hook) and `~/.bashrc` (exec zsh — `chsh` blocked on corp VM). |
| [`30-cli-tools.sh`](scripts/30-cli-tools.sh) | `bat eza fd-find ripgrep fzf zoxide ncdu keychain` + dev extras (`jq yq httpie make tree htop tmux direnv`). |
| [`40-node.sh`](scripts/40-node.sh) | nvm + Node from the repo's `.nvmrc` + corepack pinned to `package.json#packageManager`'s pnpm version. |
| [`50-docker.sh`](scripts/50-docker.sh) | Docker CE + compose plugin from docker.com apt repo + user added to `docker` group + service enabled at boot. |
+26 -8
View File
@@ -9,15 +9,33 @@ require_not_root
apt_install zsh
# Make zsh the default shell for $USER (idempotent).
current_shell="$(getent passwd "$USER" | cut -d: -f7)"
zsh_path="$(command -v zsh)"
if [[ "$current_shell" != "$zsh_path" ]]; then
log "Setting zsh as default shell for $USER (sudo will prompt)."
sudo chsh -s "$zsh_path" "$USER"
ok "Default shell set to $zsh_path. Takes effect on next login."
# Hand off to zsh from ~/.bashrc rather than `chsh -s`. The corp infra
# locks the default shell at user-provisioning time and `chsh` is denied
# (the standard PAM-level restriction). The .bashrc hand-off achieves
# the same UX without needing infra escalation, and it's compatible with
# both interactive SSH sessions and VSCode Remote-SSH's bash bootstrap.
BASHRC="$HOME/.bashrc"
[[ -f "$BASHRC" ]] || touch "$BASHRC"
MARKER='# Managed by docs/setup/scripts/20-zsh.sh — apf-portal zsh hand-off.'
if grep -qF "$MARKER" "$BASHRC"; then
skip "zsh hand-off already in $BASHRC."
else
skip "zsh already default shell."
cat >> "$BASHRC" <<'EOF'
# Managed by docs/setup/scripts/20-zsh.sh — apf-portal zsh hand-off.
# Hand off to zsh on interactive shells. The `case $-` guard avoids
# breaking non-interactive bash (scp, rsync, cron, …), and the
# ZSH_VERSION check prevents an infinite re-exec loop.
case $- in
*i*)
if command -v zsh >/dev/null 2>&1 && [ -z "${ZSH_VERSION-}" ]; then
exec zsh -l
fi
;;
esac
EOF
ok "Patched $BASHRC to exec zsh on interactive shells."
fi
# Oh My Zsh — install with RUNZSH=no to avoid spawning zsh during the script.