diff --git a/dist/.gitignore b/dist/.gitignore new file mode 100644 index 0000000..47d1a65 --- /dev/null +++ b/dist/.gitignore @@ -0,0 +1 @@ +*.tar diff --git a/scripts/build-substrate-wsl2.sh b/scripts/build-substrate-wsl2.sh new file mode 100755 index 0000000..4d06f3a --- /dev/null +++ b/scripts/build-substrate-wsl2.sh @@ -0,0 +1,167 @@ +#!/bin/bash +# build-substrate-wsl2.sh — Build Substrate WSL2 distro image (Fedora-based) +# +# Builds a minimal Fedora rootfs with gsh as the default governed shell. +# Output: ./dist/substrate-gsh.tar (importable via wsl --import) +# +# Usage: +# ./scripts/build-substrate-wsl2.sh +# +# # From PowerShell: +# wsl --import substrate-gsh C:\WSL\substrate-gsh .\substrate-gsh.tar +# wsl -d substrate-gsh +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +GSH_DIR="$(dirname "$SCRIPT_DIR")" +DIST_DIR="$GSH_DIR/dist" +BUILD_TAG="substrate-gsh-builder" +SUBSTRATE_DIR="${SUBSTRATE_DIR:-$(find ~/projects -maxdepth 2 -type d -name "substrate" -path "*/substrate-project/*" 2>/dev/null | head -1)}" + +echo "=== Substrate WSL2 Distro Builder ===" +echo "" + +# ─── Pre-flight ─────────────────────────────────────────── + +GSH_BIN="$GSH_DIR/target/release/gsh" +if [ ! -f "$GSH_BIN" ]; then + echo "Building gsh..." + (cd "$GSH_DIR" && cargo build --release 2>&1 | tail -3) +fi +echo "gsh: $(du -h "$GSH_BIN" | cut -f1)" + +PROXY_BIN="$SUBSTRATE_DIR/target/release/bascule-proxy" +if [ -f "$PROXY_BIN" ]; then + echo "bascule-proxy: $(du -h "$PROXY_BIN" | cut -f1)" +else + echo "bascule-proxy: not found (will be excluded)" + PROXY_BIN="" +fi + +# ─── Build context ──────────────────────────────────────── + +mkdir -p "$DIST_DIR" +BUILD_CTX=$(mktemp -d) +trap "rm -rf $BUILD_CTX" EXIT + +cp "$GSH_BIN" "$BUILD_CTX/gsh" +if [ -n "$PROXY_BIN" ]; then + cp "$PROXY_BIN" "$BUILD_CTX/bascule-proxy" +fi + +# ─── Dockerfile ─────────────────────────────────────────── + +cat > "$BUILD_CTX/Dockerfile" << 'DOCKERFILE' +FROM fedora:41 + +# System packages +RUN dnf install -y --setopt=install_weak_deps=False \ + bash coreutils findutils grep sed gawk \ + curl git jq openssh-clients ca-certificates \ + passwd sudo vim-minimal less procps-ng \ + iproute iputils hostname which tar gzip unzip \ + && dnf clean all + +# kubectl +RUN curl -fsSLo /usr/local/bin/kubectl \ + "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \ + && chmod +x /usr/local/bin/kubectl + +# helm +RUN curl -fsSL https://get.helm.sh/helm-v3.17.3-linux-amd64.tar.gz | tar xz -C /tmp \ + && mv /tmp/linux-amd64/helm /usr/local/bin/helm && chmod +x /usr/local/bin/helm \ + && rm -rf /tmp/linux-amd64 + +# gsh +COPY gsh /usr/local/bin/gsh +RUN chmod +x /usr/local/bin/gsh + +# bascule-proxy (optional) +COPY bascule-proxy* /tmp/ +RUN if [ -f /tmp/bascule-proxy ]; then \ + mv /tmp/bascule-proxy /usr/local/bin/bascule-proxy && chmod +x /usr/local/bin/bascule-proxy; \ + fi && rm -f /tmp/bascule-proxy* + +# Operator user (replace Fedora's system operator account) +RUN userdel operator 2>/dev/null; groupadd -f wheel \ + && useradd -m -s /bin/bash -G wheel operator \ + && mkdir -p /etc/sudoers.d \ + && echo '%wheel ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/wheel \ + && chmod 0440 /etc/sudoers.d/wheel \ + && echo /usr/local/bin/gsh >> /etc/shells \ + && chsh -s /usr/local/bin/gsh operator + +# Corpus +RUN mkdir -p /home/operator/.gsh/corpus/sha256:substrate-jumphost \ + && ln -s /usr/local/bin/kubectl /home/operator/.gsh/corpus/sha256:substrate-jumphost/kubectl \ + && ln -s /usr/local/bin/helm /home/operator/.gsh/corpus/sha256:substrate-jumphost/helm + +# SSH config +RUN mkdir -p /home/operator/.ssh && chmod 700 /home/operator/.ssh \ + && printf 'Host dev.gsh\n HostName 127.0.0.1\n Port 2223\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n\nHost stg.gsh\n HostName 178.104.110.197\n Port 30222\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' \ + > /home/operator/.ssh/config \ + && chmod 600 /home/operator/.ssh/config + +# gsh environment +RUN printf 'export GSAP_CORPUS_CID="sha256:substrate-jumphost"\nexport GSH_CORPUS_DIR="$HOME/.gsh/corpus"\nexport PATH="$HOME/.local/bin:$PATH"\n' \ + > /home/operator/.gshrc \ + && printf '[ -f ~/.gshrc ] && source ~/.gshrc\n' >> /home/operator/.bashrc + +# Fix ownership +RUN chown -R operator:operator /home/operator + +# WSL2 config +RUN printf '[boot]\nsystemd=true\n\n[user]\ndefault=operator\n\n[interop]\nenabled=true\nappendWindowsPath=false\n\n[network]\ngenerateResolvConf=true\n' \ + > /etc/wsl.conf + +# MOTD +RUN printf '\n Substrate Governed Shell — Guildhouse Edition\n\n ssh dev.gsh — local dev cluster\n ssh stg.gsh — Hetzner staging\n gsh — local ungoverned shell\n\n' \ + > /etc/motd +DOCKERFILE + +# If no bascule-proxy, create a placeholder so COPY doesn't fail +if [ -z "$PROXY_BIN" ]; then + touch "$BUILD_CTX/bascule-proxy-skip" +fi + +# ─── Build ──────────────────────────────────────────────── + +echo "" +echo "[1/3] Building Fedora rootfs..." +docker build -t "$BUILD_TAG" "$BUILD_CTX" 2>&1 | tail -10 + +# ─── Export ─────────────────────────────────────────────── + +echo "" +echo "[2/3] Exporting rootfs..." +CONTAINER_ID=$(docker create "$BUILD_TAG" /bin/true) +docker export "$CONTAINER_ID" > "$DIST_DIR/substrate-gsh.tar" +docker rm "$CONTAINER_ID" > /dev/null + +TAR_SIZE=$(du -h "$DIST_DIR/substrate-gsh.tar" | cut -f1) +echo "Exported: $DIST_DIR/substrate-gsh.tar ($TAR_SIZE)" + +# ─── Stage for Windows ──────────────────────────────────── + +echo "" +echo "[3/3] Staging..." +WIN_USER=$(cmd.exe /c "echo %USERNAME%" 2>/dev/null | tr -d '\r' || true) +if [ -n "$WIN_USER" ] && [ -d "/mnt/c/Users/$WIN_USER/Desktop" ]; then + cp "$DIST_DIR/substrate-gsh.tar" "/mnt/c/Users/$WIN_USER/Desktop/substrate-gsh.tar" + echo "Copied to Desktop: substrate-gsh.tar" +fi + +echo "" +echo "=== Build Complete ===" +echo "" +echo " Image: $DIST_DIR/substrate-gsh.tar ($TAR_SIZE)" +echo " gsh: /usr/local/bin/gsh (login shell)" +echo " kubectl: /usr/local/bin/kubectl" +echo " helm: /usr/local/bin/helm" +echo " proxy: $([ -n "$PROXY_BIN" ] && echo '/usr/local/bin/bascule-proxy' || echo 'not included')" +echo " User: operator (sudo, gsh login shell)" +echo " Corpus: sha256:substrate-jumphost" +echo "" +echo "From PowerShell:" +echo " wsl --import substrate-gsh C:\\WSL\\substrate-gsh .\\substrate-gsh.tar" +echo " wsl -d substrate-gsh"