diff --git a/scripts/build-wsl2-image.sh b/scripts/build-wsl2-image.sh new file mode 100755 index 0000000..8679fd7 --- /dev/null +++ b/scripts/build-wsl2-image.sh @@ -0,0 +1,193 @@ +#!/bin/bash +# build-wsl2-image.sh — Configure WSL2 instance as governed jumphost +# +# Usage: +# ./scripts/build-wsl2-image.sh # Configure current instance +# ./scripts/build-wsl2-image.sh --export # Configure + export hint +# +# Idempotent: safe to run multiple times. No sudo required for gsh setup. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +GSH_DIR="$(dirname "$SCRIPT_DIR")" +CORPUS_CID="sha256:dev-jumphost" +CORPUS_DIR="$HOME/.gsh/corpus/$CORPUS_CID" + +echo "=== Guildhouse WSL2 Jumphost Builder ===" +echo "" + +# ─── Step 1: System packages ───────────────────────────── +echo "[1/7] Checking system packages..." + +MISSING="" +for pkg in curl git jq openssh-client ca-certificates; do + dpkg -s "$pkg" &>/dev/null || MISSING="$MISSING $pkg" +done + +if [ -n "$MISSING" ]; then + echo " Missing:$MISSING" + if sudo -n true 2>/dev/null; then + sudo apt-get update -qq + sudo apt-get install -y -qq $MISSING 2>/dev/null + else + echo " Run: sudo apt-get install -y$MISSING" + fi +else + echo " All present" +fi + +# ─── Step 2: kubectl ───────────────────────────────────── +echo "[2/7] kubectl..." + +if command -v kubectl &>/dev/null; then + echo " $(kubectl version --client 2>/dev/null | head -1)" +else + echo " Installing kubectl..." + curl -sLo "$HOME/.local/bin/kubectl" "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x "$HOME/.local/bin/kubectl" + echo " Installed: $(kubectl version --client 2>/dev/null | head -1)" +fi + +# ─── Step 3: helm ──────────────────────────────────────── +echo "[3/7] helm..." + +if command -v helm &>/dev/null; then + echo " $(helm version --short 2>/dev/null)" +else + echo " Installing helm..." + curl -fsSL https://get.helm.sh/helm-v3.17.3-linux-amd64.tar.gz | tar xz -C /tmp linux-amd64/helm + mv /tmp/linux-amd64/helm "$HOME/.local/bin/helm" + chmod +x "$HOME/.local/bin/helm" + rm -rf /tmp/linux-amd64 + echo " Installed: $(helm version --short 2>/dev/null)" +fi + +# ─── Step 4: gsh binary ───────────────────────────────── +echo "[4/7] gsh..." + +if [ -f "$GSH_DIR/target/release/gsh" ]; then + mkdir -p "$HOME/.local/bin" + cp "$GSH_DIR/target/release/gsh" "$HOME/.local/bin/gsh" + chmod +x "$HOME/.local/bin/gsh" + echo " Installed to ~/.local/bin/gsh" +elif command -v gsh &>/dev/null; then + echo " Already on PATH: $(which gsh)" +else + echo " ERROR: gsh binary not found. Build first: cd ~/projects/gsh && cargo build --release" + exit 1 +fi + +# Ensure ~/.local/bin on PATH +if ! echo "$PATH" | grep -q "$HOME/.local/bin"; then + export PATH="$HOME/.local/bin:$PATH" +fi + +# ─── Step 5: Corpus directory ──────────────────────────── +echo "[5/7] Corpus..." + +mkdir -p "$CORPUS_DIR" + +for tool in kubectl helm; do + REAL_PATH=$(which $tool 2>/dev/null || true) + if [ -n "$REAL_PATH" ]; then + # Symlink to the real binary (simpler than wrapper scripts) + ln -sf "$REAL_PATH" "$CORPUS_DIR/$tool" 2>/dev/null || true + echo " $tool → $REAL_PATH" + fi +done + +echo " Corpus at: $CORPUS_DIR" + +# ─── Step 6: SSH config ───────────────────────────────── +echo "[6/7] SSH config..." + +mkdir -p "$HOME/.ssh" +chmod 700 "$HOME/.ssh" + +# Generate SSH key if none exists +if [ ! -f "$HOME/.ssh/id_ed25519" ]; then + ssh-keygen -t ed25519 -f "$HOME/.ssh/id_ed25519" -N "" -q + echo " Generated SSH key: ~/.ssh/id_ed25519" +fi + +# Add gsh SSH aliases if not present +add_ssh_host() { + local name="$1" host="$2" port="$3" + if ! grep -q "Host $name" "$HOME/.ssh/config" 2>/dev/null; then + cat >> "$HOME/.ssh/config" << EOF + +Host $name + HostName $host + Port $port + User \$(whoami) + StrictHostKeyChecking no + UserKnownHostsFile /dev/null +EOF + echo " Added: $name → $host:$port" + else + echo " Exists: $name" + fi +} + +touch "$HOME/.ssh/config" +chmod 600 "$HOME/.ssh/config" +add_ssh_host "dev.gsh" "127.0.0.1" "2223" +add_ssh_host "stg.gsh" "178.104.110.197" "30222" + +# ─── Step 7: Environment + shell config ────────────────── +echo "[7/7] Environment..." + +# .gshrc — governed shell defaults +cat > "$HOME/.gshrc" << GSHRC +# Guildhouse Governed Shell environment +# Sourced by .bashrc + +export GSAP_CORPUS_CID="$CORPUS_CID" +export GSH_CORPUS_DIR="\$HOME/.gsh/corpus" + +# Add gsh to PATH +export PATH="\$HOME/.local/bin:\$PATH" +GSHRC +echo " Created ~/.gshrc" + +# Source from .bashrc if not already +if ! grep -q "gshrc" "$HOME/.bashrc" 2>/dev/null; then + echo '' >> "$HOME/.bashrc" + echo '# Guildhouse governed shell' >> "$HOME/.bashrc" + echo '[ -f ~/.gshrc ] && source ~/.gshrc' >> "$HOME/.bashrc" + echo " Added .gshrc to .bashrc" +fi + +# ─── Done ──────────────────────────────────────────────── +echo "" +echo "=== Jumphost configured ===" +echo "" +echo " gsh: $(which gsh 2>/dev/null || echo '~/.local/bin/gsh')" +echo " kubectl: $(which kubectl)" +echo " helm: $(which helm)" +echo " corpus: $CORPUS_DIR/" +echo "" +echo "Connect:" +echo " ssh dev.gsh — governed shell (local Docker Desktop)" +echo " ssh stg.gsh — governed shell (Hetzner staging)" +echo " gsh — local ungoverned shell" +echo "" + +# ─── Optional: Export hint ─────────────────────────────── +if [ "${1:-}" = "--export" ]; then + echo "=== Export ===" + echo "" + echo "Clean build artifacts to reduce size:" + echo " rm -rf ~/projects/gsh/target/debug" + echo " rm -rf ~/projects/substrate-project/substrate/target/debug" + echo " sudo apt-get clean" + echo "" + + DISTRO_NAME=$(hostname 2>/dev/null || echo "gsh-jumphost") + echo "From PowerShell:" + echo " wsl --export $DISTRO_NAME gsh-jumphost.tar" + echo "" + echo "Import on another machine:" + echo " wsl --import gsh-jumphost C:\\WSL\\gsh-jumphost gsh-jumphost.tar" + echo " wsl -d gsh-jumphost" +fi