feat: ground-up .bashrc rewrite — sudo→mdo alias, ZFS safety (Sam & Hermes)

- shell-system.sh (runs last, step 6): rewrite .profile with agent launcher,
  full .bashrc with sudo() shell function that fire-and-forget snapshots
  zroot@cli-<ts> before mdo -u root. PATH, prompt, history, aliases (ll/la/lt).
  Agent fallback for non-login shells via ~/.ssh-agent-env.
- shell-ssh.sh (step 4): strip to ~/.ssh/config only. Agent/profile/tmux
  seeding moved to shell-system.sh so it is not overwritten.
- AGENTS.md: document sudo→mdo decision with rationale table (ISO size,
  audit surface, single privilege path, ZFS rollback safety).
This commit is contained in:
123kupola 2026-05-27 15:48:31 +02:00
parent f07144664e
commit f1dd03da0a
3 changed files with 78 additions and 57 deletions

View file

@ -101,11 +101,31 @@ inspection as final proof that SDDM/XFCE works.
**Privilege model:** distinguish build-host administration from live-USB runtime.
- On the FreeBSD 15 build host, operator-facing commands may use `sudo`.
- Inside the live USB, `sudo` is intentionally absent.
- Inside the live USB, `sudo` is intentionally absent (deleted via `pkg delete -f sudo`).
- Live privileged actions use FreeBSD `mac_do` via `mdo -u root <command>`.
- `~/.bashrc` aliases `sudo``mdo -u root` for muscle-memory compatibility.
The shell function wraps `mdo` with a fire-and-forget ZFS snapshot
(`zroot@cli-<timestamp>`) before each privileged invocation, so rollback
is always available without confirmation prompts or warning popups.
- Agent runtime code must not shell out to `sudo` for privileged host changes.
- Privileged Clawdie-AI host operations go through the hostd RPC layer.
**Why `sudo` as alias, not as pkg:**
| Approach | Install sudo pkg | Alias to mdo |
|----------|-----------------|--------------|
| Extra package | Yes (sudo + deps) | No |
| Two privilege paths | `sudo` AND `mdo` coexist | Single path (`mdo`) |
| Audit surface | Two tools to audit | One kernel-enforced MAC |
| ZFS safety net | Requires sudoers hooks | Built into bash function |
| Agent confusion | Agents try both paths | Agents use `sudo`, get `mdo` |
| ISO size | Larger | Zero bytes |
The alias approach keeps the ISO lean, eliminates dual-privilege-path
confusion, and bakes ZFS rollback safety directly into the operator shell.
`mac_do` is FreeBSD base system — no package dependency, kernel-enforced,
auditable via MAC framework.
---
## Installer Temp Files

View file

@ -25,7 +25,7 @@ clawdie_shell_ssh_setup() {
# 1. Configure SSH keys (if provided)
# 2. Set system passwords (if provided or auto-generate)
# 3. Configure SSH auth methods (key-only or key+password)
# 4. Seed SSH agent persistence (~/.ssh/config + ~/.tmux.conf)
# 4. Seed SSH client defaults (~/.ssh/config)
log_msg "[ssh] Starting SSH and password setup"
@ -43,8 +43,8 @@ clawdie_shell_ssh_setup() {
if [ -n "${SSH_PUBLIC_KEY:-}" ]; then
clawdie_shell_ssh_install_pubkey
clawdie_shell_ssh_disable_password_auth
clawdie_shell_ssh_seed_agent_config
log_msg "[ssh] SSH public key installed, password auth disabled, agent config seeded"
clawdie_shell_ssh_seed_client_config
log_msg "[ssh] SSH public key installed, password auth disabled, client config seeded"
else
clawdie_shell_ssh_enable_password_auth
log_msg "[ssh] No SSH key provided, password auth enabled (less secure)"
@ -105,45 +105,18 @@ clawdie_shell_ssh_install_pubkey() {
}
# ============================================================================
# SSH AGENT PERSISTENCE (seed ~/.profile, ~/.ssh/config, ~/.tmux.conf)
# SSH CLIENT CONFIGURATION (seed ~/.ssh/config)
# ============================================================================
clawdie_shell_ssh_seed_agent_config() {
# Seed SSH agent launcher, auto-load, and terminal preferences.
# FreeBSD: no systemd — use ~/.profile to start the agent on login.
# tmux's default update-environment already includes SSH_AUTH_SOCK;
# do NOT override it (would drop DISPLAY, XAUTHORITY, etc.).
clawdie_shell_ssh_seed_client_config() {
# Seed SSH client defaults for the clawdie user.
# .profile / .bashrc / .tmux.conf are handled by shell-system.sh
# (which runs after this module).
# Run after clawdie_shell_ssh_install_pubkey (requires user to exist).
local profile="/home/clawdie/.profile"
local ssh_config="/home/clawdie/.ssh/config"
local tmux_conf="/home/clawdie/.tmux.conf"
# --- Tier 1: ~/.profile — start agent on every login (FreeBSD, no systemd) ---
if [ ! -f "$profile" ]; then
cat > "$profile" <<'PROFEOF'
# Start SSH agent if not already running
if [ -z "$SSH_AUTH_SOCK" ]; then
eval $(ssh-agent -s) > /dev/null 2>&1
fi
PROFEOF
chmod 644 "$profile"
chown clawdie:clawdie "$profile" 2>/dev/null || true
log_msg "[ssh] Seeded ~/.profile with SSH agent launcher"
else
if ! grep -q 'ssh-agent -s' "$profile" 2>/dev/null; then
cat >> "$profile" <<'PROFEOF'
# Start SSH agent if not already running
if [ -z "$SSH_AUTH_SOCK" ]; then
eval $(ssh-agent -s) > /dev/null 2>&1
fi
PROFEOF
log_msg "[ssh] Appended SSH agent launcher to existing ~/.profile"
fi
fi
# --- Tier 2: ~/.ssh/config — auto-load key on first use ---
# --- ~/.ssh/config: auto-load key on first use, no agent forwarding ---
if [ ! -f "$ssh_config" ]; then
cat > "$ssh_config" <<'SSHEOF'
Host *
@ -160,20 +133,6 @@ SSHEOF
fi
fi
# --- Tier 3: ~/.tmux.conf — UI preferences only (agent socket is default) ---
# tmux update-environment already includes SSH_AUTH_SOCK + DISPLAY.
# Seed mouse + indexing; do NOT override update-environment.
if [ ! -f "$tmux_conf" ]; then
cat > "$tmux_conf" <<'TMUXEOF'
set -g base-index 1
setw -g pane-base-index 1
set -g mouse on
TMUXEOF
chmod 644 "$tmux_conf"
chown clawdie:clawdie "$tmux_conf" 2>/dev/null || true
log_msg "[ssh] Seeded ~/.tmux.conf (base-index 1, mouse on)"
fi
return 0
}

View file

@ -354,6 +354,12 @@ EOF
cat > /home/clawdie/.profile <<'EOF'
# Clawdie operator POSIX shell profile.
[ -r /etc/profile.d/clawdie.sh ] && . /etc/profile.d/clawdie.sh
# Start SSH agent on login (FreeBSD: no systemd, no X11 agent launcher).
# Non-login shells (tmux windows) use ~/.bashrc fallback instead.
if [ -z "$SSH_AUTH_SOCK" ]; then
eval $(ssh-agent -s) > /dev/null 2>&1
fi
EOF
cat > /home/clawdie/.bash_profile <<'EOF'
# Clawdie operator bash login profile.
@ -365,14 +371,50 @@ EOF
}
[ -r "${HOME}/.bashrc" ] && . "${HOME}/.bashrc"
EOF
cat > /home/clawdie/.bashrc <<'EOF'
# Clawdie operator interactive bash profile.
cat > /home/clawdie/.bashrc <<'BASHRC'
# Clawdie operator interactive bash shell.
# Non-interactive shells stop here.
case $- in *i*) ;; *) return ;; esac
# ── PATH (FreeBSD: /usr/local first) ──────────────────────────
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
[ -r /etc/profile.d/clawdie.sh ] && . /etc/profile.d/clawdie.sh
if [ -n "${PS1:-}" ]; then
export HISTFILE="${HISTFILE:-/tmp/clawdie/bash_history}"
mkdir -p /tmp/clawdie 2>/dev/null || true
# ── Privilege escalation ──────────────────────────────────────
# Clawdie ISO: no sudo pkg. Use FreeBSD mac_do instead.
# mac_do rules (gid=0>uid=0) allow wheel→root transitions.
# ZFS auto-snapshot provides safety net — no confirmation prompts.
sudo() {
local pool
pool=$(zpool list -H -o name 2>/dev/null | head -1)
if [ -n "$pool" ]; then
(zfs snapshot "${pool}@cli-$(date +%s)" 2>/dev/null &)
fi
mdo -u root "$@"
}
# ── SSH agent (fallback for non-login shells) ─────────────────
# .profile starts the agent for login shells; tmux windows
# (non-login) inherit via SSH_AUTH_SOCK if the parent had one,
# but if not, try a stored env file from a prior login.
if [ -z "$SSH_AUTH_SOCK" ] && [ -f ~/.ssh-agent-env ]; then
. ~/.ssh-agent-env 2>/dev/null || true
fi
EOF
# ── Prompt ────────────────────────────────────────────────────
PS1='\h:\w\$ '
# ── History ───────────────────────────────────────────────────
export HISTFILE="${HISTFILE:-/tmp/clawdie/bash_history}"
export HISTSIZE=5000
export HISTFILESIZE=10000
mkdir -p /tmp/clawdie 2>/dev/null || true
# ── Aliases ───────────────────────────────────────────────────
alias ll='ls -lah'
alias la='ls -A'
alias lt='ls -laht'
BASHRC
cat > /home/clawdie/.zprofile <<'EOF'
# Clawdie operator zsh login profile.
[ -r /etc/profile ] && . /etc/profile