From: Plom Heller Date: Wed, 23 Sep 2026 06:58:28 +0000 (+0200) Subject: Fix install_server.sh putting repo where user can't find or link into it. X-Git-Url: https://plomlompom.com/repos/%7B%7B%20web_path%20%7D%7D/booking/static/error?a=commitdiff_plain;ds=inline;p=confplom Fix install_server.sh putting repo where user can't find or link into it. --- diff --git a/CLAUDE.md b/CLAUDE.md index 6c18632..be6a695 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -89,7 +89,7 @@ root, so all of it is present on every target. - First login on a new remote server: triggered by `install_server.sh`. - Both first-login scripts can be rerun by hand later (e.g. `/data/confplom/scripts/start_root_t490s.sh`, or - `~/confplom/scripts/start_root_server.sh`); so can `start_user.sh`. + `/opt/confplom/scripts/start_root_server.sh`); so can `start_user.sh`. There is no test runner. For logic changes prefer a dry read-through plus `sh -n`/`shellcheck -s dash`; never execute the scripts against real block @@ -427,11 +427,22 @@ Run from the admin's workstation; one argument, `server` (`LOGIN="root@${SERVER}"`). Targets a server assumed reachable over SSH as root (e.g. a provider-handed fresh VM); together with `start_root_server.sh` it exists to lock that root access back down. `check_tools scp ssh ssh-keygen -tar`. Constants: `FNAME_REPO_TAR=repo.tar`; +tar`. Constants: `FNAME_REPO_TAR=repo.tar`; `PATH_OPT=/opt`; `OPTS_SSH_NEW_HOST="-o StrictHostKeyChecking=accept-new"` on every `scp`/`ssh` (a first-ever connection would otherwise block on a prompt); -`PATH_REPO_PARENT`; `RELPATH_SETUP_SCRIPT` (remote path to -`start_root_server.sh`, built from `DIRNAME_REPO`/`DIRNAME_SCRIPTS`). +`PATH_REPO_PARENT`; `PATH_REMOTE_REPO` (`/opt/`) and +`PATH_SETUP_SCRIPT` (remote path to `start_root_server.sh`, built from it and +`DIRNAME_SCRIPTS`). + +**Why `/opt`:** the landed repo must be readable by the unprivileged user +too, since `start_user.sh` runs as that account and `link_home` symlinks its +home into the repo — root's `~` would be unreachable for both. `/opt` is +FHS's place for a self-contained add-on tree keeping its own internal layout +(as opposed to `/usr/local`'s `bin`/`share` split); `/srv` is for data the +host *serves*, which this checkout isn't (`PATH_GIT_BASE` is); a server-side +`/data` would suggest a shared LV that doesn't exist there. The local track +keeps `/data/` because there it genuinely is shared across +installs. 1. `mktemp --directory` locally; `tar cf` the whole repo checkout (same "whole repo, not just `scripts/`" principle as `setup_luksvg.sh`). @@ -441,13 +452,19 @@ tar`. Constants: `FNAME_REPO_TAR=repo.tar`; `ssh-keygen -R` on a nonexistent file exits non-zero, which would abort under errexit on a from-scratch admin account. 3. `scp` the tar to `${LOGIN}:~`; remove the local temp dir. -4. `ssh` in to `tar xf --no-same-owner` (lands at `~/`). The - flag matters: GNU `tar` as root defaults to `--same-owner`, which would - restore the *workstation's* numeric UID onto files under `/root`; that - silent mismatch would otherwise make any later root-run `git` operation - against that tree refuse it as "dubious ownership". Then `ssh -t` - (pseudo-tty, since the script ends prompting for a password) to run - `./${RELPATH_SETUP_SCRIPT}`. +4. `ssh` in to `tar xf -C /opt --no-same-owner` (lands at + `${PATH_REMOTE_REPO}`), then remove the uploaded tar. The flag matters: + GNU `tar` as root defaults to `--same-owner`, which would restore the + *workstation's* numeric UID onto the files; that silent mismatch would + otherwise make any later root-run `git` operation against that tree + refuse it as "dubious ownership". (Root-owned, the tree is still readable + by the user as long as the checkout's modes are the usual 644/755, which + GNU `tar` as root preserves.) Then `ssh -t` (pseudo-tty, since the script + ends prompting for a password) to run `${PATH_SETUP_SCRIPT}`. + +Not rerunnable once `start_root_server.sh` got as far as disabling root SSH; +before that (e.g. an `apt-get` failure), a rerun just unpacks over the +existing tree. No `YES!` gate: nothing here is destructive; the point of no easy return (locking root SSH) happens on the remote end inside `start_root_server.sh`. @@ -456,8 +473,8 @@ No `YES!` gate: nothing here is destructive; the point of no easy return `start_root_t490s.sh`, `start_root_server.sh`, `start_user.sh` live in `scripts/` only so they ride along on the `data` LV / the pushed tar. They -run *inside* a target, invoked by absolute or `~`-relative path (e.g. -`/data/confplom/scripts/...`, `~/confplom/scripts/...`), never against the +run *inside* a target, invoked by absolute path (e.g. +`/data/confplom/scripts/...`, `/opt/confplom/scripts/...`), never against the rescue environment's LUKS/LVM state; that's why `_lib.sh`'s `cd` and `${PATH_REPO}` matter more for them than for the LUKS-facing scripts. They use only narration, basics, `PATH_REPO`, `link_home` and `start_root`. @@ -723,7 +740,7 @@ in `.profile.d/` with bare names, sourced by the loop line in `~/.profile`. resolves the real path before computing `sys.path[0]`, so `from lib.argparsing import ArgParser` loads *this repo's own* `home/user/.local/bin/lib/` (`/data/confplom/...` locally, - `~/confplom/...` remotely), never the symlinked copy `link_home` places + `/opt/confplom/...` remotely), never the symlinked copy `link_home` places under `~/.local/bin/lib/`. Harmless (identical content) but worth knowing. `status.py` reaches the same directory explicitly by appending `Path(__file__).resolve().parents[2] / '.local' / 'bin' / 'lib'` to @@ -752,6 +769,6 @@ in `.profile.d/` with bare names, sourced by the loop line in `~/.profile`. - Line length 80 columns; wrap with backslash-newline (inside double-quoted strings it's elided rather than becoming a literal newline) or, where it reads as clearly, factor the long expression into a named constant first - (as `install_server.sh` does with `RELPATH_SETUP_SCRIPT`). + (as `install_server.sh` does with `PATH_SETUP_SCRIPT`). - New `mount` calls in the LUKS/VG-facing scripts must go through `mount_privately` (see "Shared library"). diff --git a/scripts/install_server.sh b/scripts/install_server.sh index ac52aa7..3f2b902 100755 --- a/scripts/install_server.sh +++ b/scripts/install_server.sh @@ -11,10 +11,12 @@ include usage # constants we might want to change at some point FNAME_REPO_TAR=repo.tar +PATH_OPT=/opt # constants derived from changeables PATH_REPO_PARENT=$(dirname "${PATH_REPO}") -RELPATH_SETUP_SCRIPT="${DIRNAME_REPO}/${DIRNAME_SCRIPTS}/start_root_server.sh" +PATH_REMOTE_REPO="${PATH_OPT}/${DIRNAME_REPO}" +PATH_SETUP_SCRIPT="${PATH_REMOTE_REPO}/${DIRNAME_SCRIPTS}/start_root_server.sh" # inputs to confirm usage $# "server" @@ -36,8 +38,10 @@ msg 'Uploading repo tar to server …' scp ${OPTS_SSH_NEW_HOST} "${PATH_REPO_TAR}" "${LOGIN}:~" rm -rf "${PATH_TEMP}" -msg 'Unpacking repo and running setup script …' +msg 'Unpacking repo to %s and running setup script …' "${PATH_REMOTE_REPO}" # --no-same-owner owns the files to root, preventing "dubious ownership" for # any later git operation against this tree (by hand, or a future script)! -ssh ${OPTS_SSH_NEW_HOST} "${LOGIN}" tar xf "${FNAME_REPO_TAR}" --no-same-owner -ssh -t ${OPTS_SSH_NEW_HOST} "${LOGIN}" "./${RELPATH_SETUP_SCRIPT}" +ssh ${OPTS_SSH_NEW_HOST} "${LOGIN}" \ + "tar xf ${FNAME_REPO_TAR} -C ${PATH_OPT} --no-same-owner" \ + "&& rm ${FNAME_REPO_TAR}" +ssh -t ${OPTS_SSH_NEW_HOST} "${LOGIN}" "${PATH_SETUP_SCRIPT}"