bootstrap: support USB/local-copy and private repo PAT

Three usage modes now documented and implemented:

1. Public repo: curl | sudo bash (unchanged)
2. Private repo, USB: copy whole repo to thumb drive, run bootstrap.sh
   from it — detects setup.sh alongside itself, copies to ~/ubuntu-post-install,
   execs setup.sh. No git auth, no internet needed for the scripts.
3. Private repo, PAT: bootstrap.sh --pat ghp_xxx — PAT stripped from
   stored remote URL after clone so it is not saved in plain text.

USB mode is the recommended approach for private repos: clone once,
put on a drive, run on every new machine.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
This commit is contained in:
Claude
2026-06-04 01:00:57 +00:00
parent 33f052ea0b
commit 9773dcfb63
2 changed files with 74 additions and 22 deletions
+17 -7
View File
@@ -5,20 +5,30 @@ install exactly what you need — interactively or by name.
## Quick start on a fresh box
**Public repo — paste on any new box:**
```bash
curl -fsSL https://raw.githubusercontent.com/outis1one/ubuntu-post-install/main/bootstrap.sh | sudo bash
```
That installs git (if missing), clones the repo to `~/ubuntu-post-install`,
and drops you into the interactive wizard.
If you already have git:
**Private repo — USB thumb drive (recommended):**
```bash
# Once, on any connected machine:
git clone https://github.com/outis1one/ubuntu-post-install.git
cd ubuntu-post-install
sudo ./setup.sh
cp -r ubuntu-post-install /media/user/DRIVE/
# On every new box — plug in USB, run:
sudo bash /media/$(whoami)/DRIVE/ubuntu-post-install/bootstrap.sh
```
No auth, no internet needed for the scripts. The bootstrap detects it is
running from the repo and copies it to `~/ubuntu-post-install` before
launching the wizard, so the USB can be unplugged once setup starts.
**Private repo — PAT (alternative):**
```bash
sudo bash bootstrap.sh --pat ghp_xxxxxxxxxxxxxxxxxxxx
```
Use a fine-grained read-only PAT scoped to just this repo (Contents: Read).
The PAT is stripped from the stored remote URL after cloning.
## Usage
+57 -15
View File
@@ -1,23 +1,39 @@
#!/bin/bash
# bootstrap.sh — get and run ubuntu-post-install on a fresh system.
#
# One command to paste into a new Ubuntu box:
# curl -fsSL https://raw.githubusercontent.com/outis1one/ubuntu-post-install/main/bootstrap.sh | sudo bash
# THREE ways to use this:
#
# What it does:
# 1. Installs git if missing (the only hard dependency)
# 2. Clones (or updates) the repo to ~/ubuntu-post-install
# 3. Launches the interactive setup wizard
# 1. Public repo — paste on any new box (internet required):
# curl -fsSL https://raw.githubusercontent.com/outis1one/ubuntu-post-install/main/bootstrap.sh | sudo bash
#
# 2. Private repo — copy just this file, supply a fine-grained read-only PAT:
# sudo bash bootstrap.sh --pat ghp_xxxxxxxxxxxxxxxxxxxx
#
# 3. USB / offline — copy the WHOLE REPO to a thumb drive, run from there
# (no auth, no internet needed for the scripts themselves):
# sudo bash /media/user/DRIVE/ubuntu-post-install/bootstrap.sh
#
# Option 3 is the recommended approach for private repos: clone once on a
# connected machine, put the directory on a USB drive, done.
set -euo pipefail
REPO_URL="https://github.com/outis1one/ubuntu-post-install.git"
DEST="${HOME:-/root}/ubuntu-post-install"
# Resolve actual user home when running under sudo
ACTUAL_HOME="${HOME:-/root}"
if [ -n "${SUDO_USER:-}" ]; then
ACTUAL_HOME="$(getent passwd "$SUDO_USER" | cut -d: -f6)"
DEST="$ACTUAL_HOME/ubuntu-post-install"
fi
DEST="$ACTUAL_HOME/ubuntu-post-install"
# Parse --pat flag
PAT=""
for arg in "$@"; do
case "$arg" in
--pat) shift; PAT="${1:-}" ;;
--pat=*) PAT="${arg#--pat=}" ;;
esac
done
echo ""
echo "╔══════════════════════════════════════════════════════════════╗"
@@ -25,23 +41,49 @@ echo "║ ubuntu-post-install · bootstrap ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
# 1) Ensure git is available
# ── Option 3: already running from inside the repo ───────────────────────────
# If setup.sh is sitting next to this script, we have everything we need.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd || echo "")"
if [ -f "${SCRIPT_DIR}/setup.sh" ]; then
echo " Running from local copy at $SCRIPT_DIR"
echo " (No git or internet needed)"
echo ""
# Copy to home so the install persists after the USB is removed
if [ "$SCRIPT_DIR" != "$DEST" ]; then
echo " Copying to $DEST for future use..."
cp -r "$SCRIPT_DIR" "$DEST" 2>/dev/null \
&& chown -R "${SUDO_USER:-$(id -un)}:" "$DEST" 2>/dev/null || true
echo ""
fi
exec bash "${SCRIPT_DIR}/setup.sh"
fi
# ── Options 1 & 2: clone from GitHub ─────────────────────────────────────────
if ! command -v git >/dev/null 2>&1; then
echo "Installing git..."
echo " Installing git..."
apt-get update -qq && apt-get install -y git
fi
# 2) Clone or update
# Build clone URL (with PAT if supplied)
CLONE_URL="$REPO_URL"
if [ -n "$PAT" ]; then
CLONE_URL="https://${PAT}@github.com/${REPO_URL#https://github.com/}"
fi
if [ -d "$DEST/.git" ]; then
echo "Repo already exists at $DEST — pulling latest..."
echo " Repo already exists at $DEST — pulling latest..."
git -C "$DEST" pull --ff-only || echo " (pull failed — continuing with existing version)"
else
echo "Cloning to $DEST ..."
git clone "$REPO_URL" "$DEST"
echo " Cloning to $DEST ..."
git clone "$CLONE_URL" "$DEST"
# Remove PAT from stored remote URL so it isn't saved in plain text
if [ -n "$PAT" ]; then
git -C "$DEST" remote set-url origin "$REPO_URL"
fi
fi
echo ""
echo "Launching setup..."
echo " Launching setup..."
echo ""
exec bash "$DEST/setup.sh"