docs(setup): use ~/.bashrc hand-off instead of chsh for zsh switch #221
@@ -160,16 +160,16 @@ 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`. | ✅ |
|
||||
| [`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`. | ✅ |
|
||||
| [`60-tuning.sh`](scripts/60-tuning.sh) | `fs.inotify.max_user_watches=524288` (Vite / Nx watch). Prompt for hostname (only if generic). Add a 4 GB swapfile if none. | ✅ |
|
||||
| [`70-hardening.sh`](scripts/70-hardening.sh) | Best-effort UFW (allow SSH only by default), `unattended-upgrades` on security channel, `fail2ban`, sshd hardening (no root, no password). **Probes before applying** — skips what's already done. | ✅ |
|
||||
| [`80-dotfiles.sh`](scripts/80-dotfiles.sh) | Symlink `notes/aliases.zsh` → `~/.oh-my-zsh/custom/aliases.zsh`. Generate `~/.gitconfig` from `notes/gitconfig.txt`, prompt for identity (name + email). | ✅ |
|
||||
| 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 + 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`. | ✅ |
|
||||
| [`60-tuning.sh`](scripts/60-tuning.sh) | `fs.inotify.max_user_watches=524288` (Vite / Nx watch). Prompt for hostname (only if generic). Add a 4 GB swapfile if none. | ✅ |
|
||||
| [`70-hardening.sh`](scripts/70-hardening.sh) | Best-effort UFW (allow SSH only by default), `unattended-upgrades` on security channel, `fail2ban`, sshd hardening (no root, no password). **Probes before applying** — skips what's already done. | ✅ |
|
||||
| [`80-dotfiles.sh`](scripts/80-dotfiles.sh) | Symlink `notes/aliases.zsh` → `~/.oh-my-zsh/custom/aliases.zsh`. Generate `~/.gitconfig` from `notes/gitconfig.txt`, prompt for identity (name + email). | ✅ |
|
||||
|
||||
After bootstrap, reload your shell to pick up the new PATH + zsh:
|
||||
|
||||
|
||||
+12
-12
@@ -13,18 +13,18 @@ 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`. |
|
||||
| [`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. |
|
||||
| [`60-tuning.sh`](scripts/60-tuning.sh) | inotify watches → 524288, optional 4 GB swapfile, optional hostname rename (only prompts if generic). |
|
||||
| [`70-hardening.sh`](scripts/70-hardening.sh) | Best-effort UFW + unattended-upgrades + fail2ban + sshd hardening drop-in. Probes before applying — skips done items. |
|
||||
| [`80-dotfiles.sh`](scripts/80-dotfiles.sh) | Symlinks `notes/aliases.zsh` → `~/.oh-my-zsh/custom/aliases.zsh`. Copies `notes/gitconfig.txt` to `~/.gitconfig` with prompted identity. |
|
||||
| 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` (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. |
|
||||
| [`60-tuning.sh`](scripts/60-tuning.sh) | inotify watches → 524288, optional 4 GB swapfile, optional hostname rename (only prompts if generic). |
|
||||
| [`70-hardening.sh`](scripts/70-hardening.sh) | Best-effort UFW + unattended-upgrades + fail2ban + sshd hardening drop-in. Probes before applying — skips done items. |
|
||||
| [`80-dotfiles.sh`](scripts/80-dotfiles.sh) | Symlinks `notes/aliases.zsh` → `~/.oh-my-zsh/custom/aliases.zsh`. Copies `notes/gitconfig.txt` to `~/.gitconfig` with prompted identity. |
|
||||
|
||||
## `systemd/`
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user