scripts/install.sh — one command for both halves
`bun setup` runs it. Machine setup first, then officer setup, stopping if the first does not finish rather than running the second against a machine that is not ready. They stay two scripts because they answer two different questions and are worth running apart — a machine you already trust needs only the second, one you are rebuilding needs only the first. --machine-only and --officer-only say so directly, and both halves remain runnable by path. Privileges are checked here, before anything is done, because the two systems want opposite things: Linux needs root for apt, systemd, useradd, netplan and ufw and for creating directories owned by the service account; macOS must NOT be root, since Homebrew refuses to run as one. Each script already enforces its own rule, so this is only about failing early instead of halfway. officer-setup.sh gained the same OS-aware check. It required root unconditionally, which on macOS would have failed immediately after machine-setup — which must run as the user — and for no reason: there the account running it IS the owner, so there is nothing to chown and nothing to drop privileges to. Arguments are parsed before privileges, so --help works without sudo and an unknown option is rejected before anybody is asked for a password. It did not, first time round. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -25,7 +25,7 @@
|
||||
"format": "{ git diff --name-only HEAD -- 'src/**/*.ts' 'src/**/*.tsx'; git ls-files --others --exclude-standard -- 'src/**/*.ts' 'src/**/*.tsx'; } | xargs -r prettier --write",
|
||||
"format:all": "prettier --write \"src/**/*.{ts,tsx}\"",
|
||||
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
|
||||
"setup": "bash scripts/setup/officer-setup.sh"
|
||||
"setup": "bash scripts/install.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.2.41",
|
||||
|
||||
Executable
+103
@@ -0,0 +1,103 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Officer — install
|
||||
# =============================================================================
|
||||
#
|
||||
# One command, blank machine to running platform. It runs the two halves in
|
||||
# order and does nothing else itself:
|
||||
#
|
||||
# setup/machine-setup/machine-setup.sh a usable machine — packages, tailnet,
|
||||
# runtimes, docker, shell
|
||||
# setup/officer-setup.sh the platform on top of it — repo,
|
||||
# dependencies, postgres, .env, secret
|
||||
# store, schema, build, pm2
|
||||
#
|
||||
# They stay two scripts because they answer two different questions and are worth
|
||||
# running separately: a machine you already trust needs only the second, and a
|
||||
# machine you are rebuilding needs only the first. This is the wrapper for the
|
||||
# case where you want both, which is most first runs.
|
||||
#
|
||||
# Both are re-runnable. Each remembers the steps it finished and skips them, so
|
||||
# stopping halfway and coming back costs nothing.
|
||||
#
|
||||
# ── Privileges ──
|
||||
#
|
||||
# Linux needs root: apt, systemd units, useradd, netplan, ufw, and creating
|
||||
# directories owned by the service account. macOS must NOT be root: Homebrew
|
||||
# refuses to run as one, and there is nothing to chown because the account
|
||||
# running this IS the owner. Both scripts enforce that themselves; this checks
|
||||
# first so the failure arrives before anything has been done.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MACHINE="$SCRIPT_DIR/setup/machine-setup/machine-setup.sh"
|
||||
OFFICER="$SCRIPT_DIR/setup/officer-setup.sh"
|
||||
|
||||
BOLD='\033[1m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
say() { echo -e "$*"; }
|
||||
die() {
|
||||
echo -e "${YELLOW}error:${NC} $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
[[ -r "$MACHINE" ]] || die "missing $MACHINE"
|
||||
[[ -r "$OFFICER" ]] || die "missing $OFFICER"
|
||||
|
||||
# Which halves to run. Both by default.
|
||||
RUN_MACHINE=true
|
||||
RUN_OFFICER=true
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--machine-only) RUN_OFFICER=false ;;
|
||||
--officer-only) RUN_MACHINE=false ;;
|
||||
-h | --help)
|
||||
say "usage: install.sh [--machine-only | --officer-only]"
|
||||
say ""
|
||||
say " no flags both halves, machine first"
|
||||
say " --machine-only stop after the machine is provisioned"
|
||||
say " --officer-only the platform only, on a machine you already trust"
|
||||
exit 0
|
||||
;;
|
||||
*) die "unknown option: $arg" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
KERNEL="$(uname -s)"
|
||||
case "$KERNEL" in
|
||||
Darwin)
|
||||
[[ "$EUID" -eq 0 ]] && die "do not run this with sudo on macOS — Homebrew refuses to run as root. Run it as yourself."
|
||||
;;
|
||||
Linux)
|
||||
[[ "$EUID" -ne 0 ]] && die "please run as root: sudo ./scripts/install.sh"
|
||||
;;
|
||||
*) die "unsupported system: $KERNEL. Officer installs on Linux and macOS." ;;
|
||||
esac
|
||||
|
||||
say ""
|
||||
say "${BOLD}Officer install${NC}"
|
||||
say " system: $KERNEL"
|
||||
$RUN_MACHINE && say " 1/2 machine setup"
|
||||
$RUN_OFFICER && say " $($RUN_MACHINE && echo 2/2 || echo 1/1) officer setup"
|
||||
say ""
|
||||
say " Either half can be run on its own later:"
|
||||
say " scripts/setup/machine-setup/machine-setup.sh"
|
||||
say " scripts/setup/officer-setup.sh"
|
||||
say ""
|
||||
|
||||
# Not `set -e`'s job: a half that exits non-zero should say which half, and stop
|
||||
# before the next one starts on a machine that is not ready for it.
|
||||
if $RUN_MACHINE; then
|
||||
bash "$MACHINE" || die "machine setup did not finish — fix what it reported, then run this again"
|
||||
fi
|
||||
|
||||
if $RUN_OFFICER; then
|
||||
bash "$OFFICER" || die "officer setup did not finish — fix what it reported, then run this again"
|
||||
fi
|
||||
|
||||
say ""
|
||||
say "${GREEN}Done.${NC}"
|
||||
@@ -66,7 +66,17 @@ echo -e "${BOLD}╔════════════════════
|
||||
echo -e "${BOLD}║ Officer Setup ║${NC}"
|
||||
echo -e "${BOLD}╚══════════════════════════════════════════════════╝${NC}"
|
||||
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
# root on Linux, NOT root on macOS — the same split machine-setup makes, for the
|
||||
# same reason. On Linux this creates directories owned by another account and
|
||||
# drops privileges with `sudo -u`. On macOS the account running the script IS the
|
||||
# owner, so there is nothing to chown and nothing to drop to — and Homebrew, which
|
||||
# machine-setup ran just before this, refuses to run as root at all.
|
||||
OFFICER_OS="$(uname -s)"
|
||||
if [[ "$OFFICER_OS" == "Darwin" ]]; then
|
||||
if [[ "$EUID" -eq 0 ]]; then
|
||||
fail "Do not run this with sudo on macOS — run it as yourself."
|
||||
fi
|
||||
elif [[ "$EUID" -ne 0 ]]; then
|
||||
fail "Please run as root: sudo ./officer-setup.sh"
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user