officer-setup section 2: the repository

Clones from ssh://git@gitea.officer.dev:2222/officerdev/platform.git, or uses the
checkout already at $OFFICER_ROOT/platform.

Cloned as the account, never as root. A repository owned by root is one the owner
cannot pull, cannot commit in, and whose node_modules they cannot write — and
every later section in this script writes into that directory as them.

Three things it refuses to do quietly:

  It does not repoint an existing remote. This checkout points at
  gitea.pastilhas.dev rather than the new gitea.officer.dev; that is reported
  with the command to change it, because where somebody's work pushes to is
  their decision.

  It does not pull over uncommitted changes. A dirty tree means the pull is
  skipped and said so, rather than failing halfway or burying the work.

  It pulls with --ff-only, so a failure means the branch has diverged rather
  than that the network was down, and the message says which.

SSH reachability is checked before the clone, not after. An ssh URL with no
usable key does not fail cleanly: git prompts for a password nobody is there to
type, or stops on host-key verification. BatchMode turns both into an immediate
answer, and the check reads the server's response rather than the exit code —
Gitea greets a successful authentication and then exits 1, so exit status alone
reports success as failure.

When the key is missing it offers the https form of the same URL, which works
without a key if the repository is readable anonymously, and otherwise stops and
says to add the key. Verified against the new host: ssh authentication from this
account already works.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 21:48:35 +00:00
co-authored by Claude Opus 5
parent b724e3ffbe
commit a5a8cd4e9c
2 changed files with 168 additions and 2 deletions
+106 -2
View File
@@ -40,6 +40,8 @@ done
source "$SCRIPT_DIR/officer-setup/lib/base.sh"
# shellcheck source=officer-setup/lib/preflight.sh
source "$SCRIPT_DIR/officer-setup/lib/preflight.sh"
# shellcheck source=officer-setup/lib/repo.sh
source "$SCRIPT_DIR/officer-setup/lib/repo.sh"
trap 'echo ""; echo -e "${RED}╔══════════════════════════════════════════════════╗${NC}"; echo -e "${RED}║ OFFICER SETUP FAILED${NC}"; echo -e "${RED}║ Step: ${CURRENT_STEP:-unknown}${NC}"; echo -e "${RED}║ Line: $LINENO${NC}"; echo -e "${RED}║ Command: $BASH_COMMAND${NC}"; echo -e "${RED}╚══════════════════════════════════════════════════╝${NC}"' ERR
@@ -153,11 +155,113 @@ else
echo " steps are remembered and skipped."
fi
# =============================================================================
# 2. Repository
# =============================================================================
step "Repository"
if ! skip; then
PLATFORM_DIR="$(platform_dir)"
echo ""
info "Repository — where the platform's code lives"
echo " path: ${PLATFORM_DIR}"
if repo_exists; then
echo " remote: $(repo_remote)"
echo " branch: $(repo_branch)"
echo " working: $(repo_is_dirty && echo 'has uncommitted changes' || echo 'clean')"
# Reported, never silently corrected. Repointing somebody's remote is a
# decision about where their work goes, and this script is not entitled to
# make it quietly.
if [[ -n "$(repo_remote)" && "$(repo_remote)" != "$OFFICER_REPO" ]]; then
echo ""
warn "this checkout points somewhere other than ${OFFICER_REPO}"
echo " Left alone. To move it:"
echo " git -C ${PLATFORM_DIR} remote set-url origin ${OFFICER_REPO}"
fi
if repo_is_dirty; then
echo ""
echo " not pulling — there are uncommitted changes here, and a pull"
echo " would either fail or bury them"
SUMMARY+=("Repository: present at ${PLATFORM_DIR}, left alone (uncommitted changes)")
elif confirm "Pull the latest changes?"; then
if pull_repo; then
ok "up to date on $(repo_branch)"
SUMMARY+=("Repository: pulled, on $(repo_branch)")
else
# --ff-only, so this means the branch has diverged rather than that the
# network failed. Saying which matters.
warn "could not fast-forward — the local branch has diverged from the remote"
ERRORS+=("Repository: pull refused, branch diverged")
SUMMARY+=("Repository: present, pull refused (diverged)")
fi
else
SUMMARY+=("Repository: present at ${PLATFORM_DIR}")
fi
else
echo " nothing there yet"
echo ""
info "Clone from ${OFFICER_REPO}?"
echo " Cloned as ${USERNAME}, not as root — a repository owned by root is"
echo " one you cannot pull, commit in, or install into."
CLONE_URL="$OFFICER_REPO"
# Checked before cloning. An ssh URL with no usable key does not fail
# cleanly: git prompts for a password nobody is there to type, or stops on
# host-key verification.
if [[ "$CLONE_URL" == ssh://* ]] && ! repo_ssh_ok "$CLONE_URL"; then
echo ""
warn "${USERNAME} cannot authenticate to $(repo_ssh_host "$CLONE_URL") over ssh"
echo " Either add that account's public key to the git server, or clone"
echo " over https instead — which works without a key if the repository"
echo " is readable anonymously."
echo ""
echo " [1] https — $(repo_https_url "$CLONE_URL")"
echo " [2] ssh anyway — will fail if the key is genuinely missing"
echo " [3] stop here, and add the key first"
echo ""
REPO_PICK=""
while [[ -z "$REPO_PICK" ]]; do
if ! read -rp " Which one? (1/2/3) [1]: " REPO_CHOICE; then
echo ""
fail "No answer."
fi
case "${REPO_CHOICE:-1}" in
1)
CLONE_URL="$(repo_https_url "$CLONE_URL")"
REPO_PICK=go
;;
2) REPO_PICK=go ;;
3) fail "Stopped. Add ${USERNAME}'s public key to the git server and run this again." ;;
*) warn "Pick 1, 2 or 3." ;;
esac
done
fi
if confirm "Clone it now?"; then
if clone_repo "$CLONE_URL"; then
ok "cloned to ${PLATFORM_DIR} on $(repo_branch)"
SUMMARY+=("Repository: cloned from ${CLONE_URL}")
else
warn "the clone did not complete"
ERRORS+=("Repository: clone failed")
fail "Nothing below can run without the repository."
fi
else
fail "Nothing below can run without the repository."
fi
fi
step_ok
fi
# =============================================================================
# NOT BUILT YET
# =============================================================================
#
# 2 Repository clone or locate the platform at $OFFICER_ROOT/platform
# 3 Dependencies bun install
# 4 Database Postgres in docker, or one you already run
# 5 Environment .env