install report: first cut, generated by the helpers
Every run writes a timestamped install-report.md recording what was installed, changed, kept, skipped, started and run as root. Written for an adversarial read: the person who just ran a setup script off the internet hands it to an agent of their choosing and asks whether it did anything it should not have. Recorded by the HELPERS rather than by the sections. pkg_install and install_config report themselves, so anything installed or written through them appears whether or not a section author remembered — a section that has to remember is a section that will forget, and an incomplete report is worse than none because it reads as a full account. "Kept" is recorded as carefully as "changed". Leaving somebody's .zshrc alone is the claim a reviewer most wants substantiated, and it is invisible unless stated. Secrets are redacted at the moment of recording rather than filtered at render, so a credential never sits in memory formatted for printing. Verified against a POSTGRES_URL and an api_key/password pair. REPORT_FILE is passed through the sudo re-exec. It was not, first time, and the report silently vanished — the third variable this evening lost to env_reset. Unfinished on purpose, paused mid-task at the owner's request: machine-setup's 26 sections still only report through the two shared helpers, so the sections that change system state directly — systemd units, netplan, ufw, sshd drop-ins — are not yet recorded. That is the half a reviewer would care most about. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,7 @@ while [[ $# -gt 0 ]]; do
|
||||
done
|
||||
|
||||
# shellcheck source=officer-setup/lib/base.sh
|
||||
source "$SCRIPT_DIR/report.sh"
|
||||
source "$SCRIPT_DIR/officer-setup/lib/base.sh"
|
||||
# shellcheck source=officer-setup/lib/preflight.sh
|
||||
source "$SCRIPT_DIR/officer-setup/lib/preflight.sh"
|
||||
@@ -88,9 +89,12 @@ elif [[ "$EUID" -ne 0 ]]; then
|
||||
OFFICER_ROOT="${OFFICER_ROOT:-}" \
|
||||
SETUP_USERNAME="${SETUP_USERNAME:-}" \
|
||||
MACHINE_ROLE="${MACHINE_ROLE:-}" \
|
||||
REPORT_FILE="${REPORT_FILE:-}" \
|
||||
bash "$SCRIPT_DIR/officer-setup.sh" "$@"
|
||||
fi
|
||||
|
||||
trap report_flush EXIT
|
||||
|
||||
# ── what machine-setup already established ──
|
||||
echo ""
|
||||
if load_machine_answers; then
|
||||
@@ -214,6 +218,7 @@ fi
|
||||
#
|
||||
# Before the repository, because the repository is cloned into it.
|
||||
|
||||
report_section "Layout"
|
||||
step "Layout"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
@@ -257,6 +262,7 @@ fi
|
||||
# 3. Repository
|
||||
# =============================================================================
|
||||
|
||||
report_section "Repository"
|
||||
step "Repository"
|
||||
if ! skip; then
|
||||
PLATFORM_DIR="$(platform_dir)"
|
||||
@@ -329,6 +335,7 @@ fi
|
||||
# 4. Dependencies
|
||||
# =============================================================================
|
||||
|
||||
report_section "Dependencies"
|
||||
step "Dependencies"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
@@ -383,6 +390,7 @@ fi
|
||||
#
|
||||
# POSTGRES_URL is set here and written by the environment section below.
|
||||
|
||||
report_section "Database"
|
||||
step "Database"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
@@ -500,6 +508,7 @@ fi
|
||||
# 6. Environment
|
||||
# =============================================================================
|
||||
|
||||
report_section "Environment"
|
||||
step "Environment"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
@@ -545,6 +554,7 @@ if ! skip; then
|
||||
if confirm "Write it?"; then
|
||||
write_env
|
||||
ok "written, 0600, owned by ${USERNAME}"
|
||||
report_changed "wrote $(env_file) (0600, owner ${USERNAME}) — PORT, PUBLIC_URL, POSTGRES_URL. No secrets: every key lives in the secret store."
|
||||
[[ -f "$(env_file).before-officer-setup" ]] && echo " previous kept as $(env_file).before-officer-setup"
|
||||
SUMMARY+=("Environment: $(env_file)")
|
||||
else
|
||||
@@ -564,6 +574,7 @@ fi
|
||||
# races to create it, and an install that finishes without ever saying the words
|
||||
# "back this up" is one where nobody learns the file matters until it is gone.
|
||||
|
||||
report_section "Secrets"
|
||||
step "Secrets"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
@@ -583,6 +594,7 @@ if ! skip; then
|
||||
if confirm "Create it?"; then
|
||||
if bootstrap_secret_store; then
|
||||
ok "created, 0600, owned by ${USERNAME}"
|
||||
report_changed "created $(secret_store_path) (0600, dir 0700, owner ${USERNAME}) with keys for: jwt, headscale. Generated locally, never transmitted."
|
||||
echo ""
|
||||
warn "back up $(secret_store_path) — and keep it OUT of the backup that holds your database dump."
|
||||
echo " Losing it signs everyone out and makes every encrypted column in"
|
||||
@@ -607,6 +619,7 @@ fi
|
||||
# 8. Schema
|
||||
# =============================================================================
|
||||
|
||||
report_section "Schema"
|
||||
step "Schema"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
@@ -629,6 +642,7 @@ if ! skip; then
|
||||
if confirm "Push it?"; then
|
||||
if OUT="$(push_schema)"; then
|
||||
ok "schema applied"
|
||||
report_changed "applied ${SCHEMA_TABLES} tables to Postgres with 'bun db:push' (drizzle-kit; no migration files)"
|
||||
SUMMARY+=("Schema: ${SCHEMA_TABLES:-?} tables pushed")
|
||||
else
|
||||
warn "db:push failed"
|
||||
@@ -646,6 +660,7 @@ fi
|
||||
# 9. Build
|
||||
# =============================================================================
|
||||
|
||||
report_section "Build"
|
||||
step "Build"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
@@ -666,6 +681,7 @@ if ! skip; then
|
||||
elif confirm "Generate it?"; then
|
||||
if OUT="$(gen_index)"; then
|
||||
ok "$(gen_index_output)"
|
||||
report_changed "generated $(gen_index_output) from index.html, substituting PUBLIC_URL=${ENV_PUBLIC_URL}"
|
||||
SUMMARY+=("Build: index.gen.html for ${ENV_PUBLIC_URL}")
|
||||
else
|
||||
warn "gen:index failed"
|
||||
@@ -683,6 +699,7 @@ fi
|
||||
# 10. Services
|
||||
# =============================================================================
|
||||
|
||||
report_section "Services"
|
||||
step "Services"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
@@ -702,6 +719,7 @@ if ! skip; then
|
||||
if confirm "Write it and start them?"; then
|
||||
write_ecosystem
|
||||
ok "written — $(ecosystem_file)"
|
||||
report_changed "wrote $(ecosystem_file) — six pm2 apps: $(printf '%s ' "${CORE_PROCESSES[@]%%|*}")"
|
||||
|
||||
# Starting against a database that is not answering is not fatal — the server
|
||||
# waits and the agent retries forever — but it makes the Verify section below
|
||||
@@ -713,12 +731,14 @@ if ! skip; then
|
||||
|
||||
if OUT="$(pm2_start)"; then
|
||||
ok "processes started"
|
||||
report_started "pm2 startOrRestart: $(printf '%s ' "${CORE_PROCESSES[@]%%|*}")"
|
||||
pm2_save >/dev/null 2>&1 && ok "process list saved (survives a pm2 restart)"
|
||||
|
||||
echo ""
|
||||
if confirm "Start them on boot too?"; then
|
||||
if pm2_enable_startup; then
|
||||
ok "pm2 will resurrect them at boot"
|
||||
report_ran "pm2 startup systemd — installed a systemd unit so pm2 resurrects these at boot"
|
||||
SUMMARY+=("Services: 6 processes started, enabled at boot")
|
||||
else
|
||||
warn "could not enable the boot hook — run 'pm2 startup' yourself and follow it"
|
||||
@@ -743,6 +763,7 @@ fi
|
||||
# 11. Verify
|
||||
# =============================================================================
|
||||
|
||||
report_section "Verify"
|
||||
step "Verify"
|
||||
if ! skip; then
|
||||
echo ""
|
||||
@@ -791,3 +812,5 @@ fi
|
||||
echo ""
|
||||
echo -e "${BOLD} Pre-flight complete.${NC} The remaining sections are not built yet."
|
||||
echo ""
|
||||
|
||||
report_mark_complete
|
||||
|
||||
Reference in New Issue
Block a user