Fix: Verify the initial Panama revision
This commit is contained in:
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
# Panama's front door: the one command a fresh Fedora machine needs.
|
# Panama's front door: the one command a fresh Fedora machine needs.
|
||||||
#
|
#
|
||||||
# bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot)
|
# Download this file from the documented commit URL, verify its documented
|
||||||
# bash <(curl -fsSL https://git.gbrown.org/gib/Panama/raw/branch/main/boot) --server
|
# SHA-256, then pass both immutable values as PANAMA_BOOT_REVISION and
|
||||||
|
# PANAMA_BOOT_SHA256 when invoking it.
|
||||||
#
|
#
|
||||||
# Deliberately dumb, because a copy of this script leaves the repository the
|
# Deliberately dumb, because a copy of this script leaves the repository the
|
||||||
# moment somebody curls it -- nothing here can be fixed by re-running
|
# moment somebody curls it -- nothing here can be fixed by re-running
|
||||||
@@ -17,9 +18,85 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [[ ! "${PANAMA_BOOT_REVISION:-}" =~ ^[0-9a-f]{40}$ ]]; then
|
||||||
|
echo "boot: PANAMA_BOOT_REVISION must be a full lowercase commit" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ ! "${PANAMA_BOOT_SHA256:-}" =~ ^[0-9a-f]{64}$ ]]; then
|
||||||
|
echo "boot: PANAMA_BOOT_SHA256 must be a lowercase SHA-256" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
actual_boot_sha="$(sha256sum "${BASH_SOURCE[0]}" | cut -d' ' -f1)"
|
||||||
|
if [[ "$actual_boot_sha" != "$PANAMA_BOOT_SHA256" ]]; then
|
||||||
|
echo "boot: downloaded boot file does not match PANAMA_BOOT_SHA256" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
REPO_URL="https://git.gbrown.org/gib/Panama.git"
|
REPO_URL="https://git.gbrown.org/gib/Panama.git"
|
||||||
PANAMA_PATH="${PANAMA_PATH:-$HOME/.local/share/Panama}"
|
PANAMA_PATH="${PANAMA_PATH:-$HOME/.local/share/Panama}"
|
||||||
export PANAMA_PATH
|
export PANAMA_PATH
|
||||||
|
BOOTSTRAP_USER=""
|
||||||
|
|
||||||
|
checkout_command() {
|
||||||
|
if [[ -n "$BOOTSTRAP_USER" ]]; then
|
||||||
|
runuser -u "$BOOTSTRAP_USER" -- "$@"
|
||||||
|
else
|
||||||
|
"$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_panama_checkout() {
|
||||||
|
local checkout="$1" actual_head checkout_status
|
||||||
|
|
||||||
|
if [[ -e "$checkout" && ! -d "$checkout/.git" ]]; then
|
||||||
|
printf 'boot: %s exists but is not a Panama Git checkout\n' "$checkout" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d "$checkout/.git" ]]; then
|
||||||
|
checkout_status="$(checkout_command git -C "$checkout" status --porcelain)" || {
|
||||||
|
printf 'boot: could not inspect the existing checkout at %s\n' "$checkout" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if [[ -n "$checkout_status" ]]; then
|
||||||
|
printf 'boot: existing checkout at %s has local changes\n' "$checkout" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Panama is already cloned at $checkout; fetching the verified revision"
|
||||||
|
checkout_command git -C "$checkout" fetch origin "$PANAMA_BOOT_REVISION" || return 1
|
||||||
|
if ! checkout_command git -C "$checkout" merge-base --is-ancestor \
|
||||||
|
HEAD "$PANAMA_BOOT_REVISION"; then
|
||||||
|
echo "boot: existing checkout cannot fast-forward to the verified revision" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
checkout_command git -C "$checkout" merge --ff-only "$PANAMA_BOOT_REVISION" || return 1
|
||||||
|
else
|
||||||
|
checkout_command mkdir -p "$(dirname "$checkout")" || return 1
|
||||||
|
checkout_command git init "$checkout" || return 1
|
||||||
|
checkout_command git -C "$checkout" remote add origin "$REPO_URL" || return 1
|
||||||
|
checkout_command git -C "$checkout" fetch --depth=1 origin \
|
||||||
|
"$PANAMA_BOOT_REVISION" || return 1
|
||||||
|
checkout_command git -C "$checkout" checkout --detach \
|
||||||
|
"$PANAMA_BOOT_REVISION" || return 1
|
||||||
|
|
||||||
|
actual_head="$(checkout_command git -C "$checkout" rev-parse 'HEAD^{commit}')" || return 1
|
||||||
|
if [[ "$actual_head" != "$PANAMA_BOOT_REVISION" ]]; then
|
||||||
|
echo "boot: fetched checkout does not match PANAMA_BOOT_REVISION" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
checkout_command git -C "$checkout" checkout -b main || return 1
|
||||||
|
checkout_command git -C "$checkout" config branch.main.remote origin || return 1
|
||||||
|
checkout_command git -C "$checkout" config branch.main.merge refs/heads/main || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
actual_head="$(checkout_command git -C "$checkout" rev-parse 'HEAD^{commit}')" || return 1
|
||||||
|
if [[ "$actual_head" != "$PANAMA_BOOT_REVISION" ]]; then
|
||||||
|
echo "boot: checkout HEAD does not match PANAMA_BOOT_REVISION" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
SERVER=0
|
SERVER=0
|
||||||
INSTALL_ARGS=()
|
INSTALL_ARGS=()
|
||||||
@@ -397,18 +474,11 @@ if [[ "$(id -u)" -eq 0 ]]; then
|
|||||||
dnf install -y git
|
dnf install -y git
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Cloned straight into the user's home and owned by them: this is the
|
# Create or advance the checkout as the target user. A root-owned .git in a
|
||||||
# checkout `panama update` will pull from for the life of the machine, and
|
# user's home would break every later update.
|
||||||
# a root-owned .git in a user's home is a wound that never heals.
|
|
||||||
PANAMA_PATH="$bootstrap_home/.local/share/Panama"
|
PANAMA_PATH="$bootstrap_home/.local/share/Panama"
|
||||||
if [[ -d "$PANAMA_PATH/.git" ]]; then
|
BOOTSTRAP_USER="$username"
|
||||||
echo "Panama is already cloned at $PANAMA_PATH; updating"
|
prepare_panama_checkout "$PANAMA_PATH"
|
||||||
runuser -u "$username" -- git -C "$PANAMA_PATH" pull --ff-only \
|
|
||||||
|| echo "Could not fast-forward; installing from the clone as it is" >&2
|
|
||||||
else
|
|
||||||
runuser -u "$username" -- mkdir -p "$bootstrap_home/.local/share"
|
|
||||||
runuser -u "$username" -- git clone "$REPO_URL" "$PANAMA_PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Handing off to install as $username"
|
echo "Handing off to install as $username"
|
||||||
exec runuser -u "$username" -- env PANAMA_PATH="$PANAMA_PATH" \
|
exec runuser -u "$username" -- env PANAMA_PATH="$PANAMA_PATH" \
|
||||||
@@ -422,19 +492,10 @@ if ! command -v git >/dev/null 2>&1; then
|
|||||||
sudo dnf install -y git
|
sudo dnf install -y git
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -d "$PANAMA_PATH/.git" ]]; then
|
prepare_panama_checkout "$PANAMA_PATH"
|
||||||
# An existing clone makes this the recovery command too. Only a fast-forward:
|
|
||||||
# local work is never rewritten, and a diverged clone still installs from
|
|
||||||
# what it has rather than stopping someone mid-repair.
|
|
||||||
echo "Panama is already cloned at $PANAMA_PATH; updating"
|
|
||||||
git -C "$PANAMA_PATH" pull --ff-only \
|
|
||||||
|| echo "Could not fast-forward; installing from the clone as it is" >&2
|
|
||||||
else
|
|
||||||
git clone "$REPO_URL" "$PANAMA_PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# `curl | bash` and `bash <(curl ...)` can leave stdin as the pipe, and the
|
# A shell invoked from automation can have a pipe as stdin, while the first
|
||||||
# first thing install runs is the interview, which has to be able to ask.
|
# thing install runs is the interview, which has to be able to ask.
|
||||||
# Reattach the terminal when there is one; without one the interview will say
|
# Reattach the terminal when there is one; without one the interview will say
|
||||||
# so itself.
|
# so itself.
|
||||||
# The probe actually opens /dev/tty rather than testing -r: a process with no
|
# The probe actually opens /dev/tty rather than testing -r: a process with no
|
||||||
|
|||||||
+210
-57
@@ -1,18 +1,9 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# The front door: `boot` is the script the README tells a fresh machine to
|
# `boot` is downloaded before the repository exists. It may hand off only
|
||||||
# curl, so it runs before anything else Panama ships -- including its own
|
# after both the downloaded script and the requested Git commit have been
|
||||||
# tests. What it must get right is small and worth pinning:
|
# verified. This fixture stubs Git and install inside a throwaway PANAMA_PATH;
|
||||||
#
|
# it never contacts the network or mutates the real checkout.
|
||||||
# * a machine without the clone gets one, from the documented URL, at
|
|
||||||
# PANAMA_PATH, and the install runs
|
|
||||||
# * a machine with the clone is not re-cloned -- the same command is the
|
|
||||||
# recovery command -- and a fast-forward failure does not stop the install
|
|
||||||
# * boot hands off to the clone's own install, with PANAMA_PATH exported,
|
|
||||||
# so a clone at a chosen location installs from that location
|
|
||||||
#
|
|
||||||
# Run against stub git and install in a throwaway PANAMA_PATH; nothing here
|
|
||||||
# touches the real clone or the network.
|
|
||||||
|
|
||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
|
|
||||||
@@ -28,13 +19,15 @@ work="$(mktemp -d)"
|
|||||||
trap 'rm -rf "$work"' EXIT
|
trap 'rm -rf "$work"' EXIT
|
||||||
|
|
||||||
calls="$work/calls"
|
calls="$work/calls"
|
||||||
|
state="$work/state"
|
||||||
stub_dir="$work/bin"
|
stub_dir="$work/bin"
|
||||||
clone_dir="$work/Panama"
|
clone_dir="$work/Panama"
|
||||||
mkdir -p "$stub_dir"
|
revision='0123456789abcdef0123456789abcdef01234567'
|
||||||
|
ancestor_revision='1111111111111111111111111111111111111111'
|
||||||
|
mismatched_revision='fedcba9876543210fedcba9876543210fedcba98'
|
||||||
|
boot_sha="$(sha256sum "$boot" | cut -d' ' -f1)"
|
||||||
|
mkdir -p "$stub_dir" "$state"
|
||||||
|
|
||||||
# The stub install records that it ran and what PANAMA_PATH it saw. The stub
|
|
||||||
# git records its arguments, and materializes a clone the way the real one
|
|
||||||
# would -- boot execs the clone's install, so the clone has to contain one.
|
|
||||||
cat >"$work/fake-install" <<STUB
|
cat >"$work/fake-install" <<STUB
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
printf 'install PANAMA_PATH=%s\n' "\${PANAMA_PATH:-unset}" >>"$calls"
|
printf 'install PANAMA_PATH=%s\n' "\${PANAMA_PATH:-unset}" >>"$calls"
|
||||||
@@ -44,56 +37,216 @@ chmod +x "$work/fake-install"
|
|||||||
cat >"$stub_dir/git" <<STUB
|
cat >"$stub_dir/git" <<STUB
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
printf 'git %s\n' "\$*" >>"$calls"
|
printf 'git %s\n' "\$*" >>"$calls"
|
||||||
if [[ "\$1" == "clone" ]]; then
|
mode="\$(<"$state/mode")"
|
||||||
mkdir -p "\$3/.git"
|
|
||||||
cp "$work/fake-install" "\$3/install"
|
case "\${1:-}" in
|
||||||
|
init)
|
||||||
|
[[ "\$#" -eq 2 && "\$2" == "$clone_dir" ]] || exit 97
|
||||||
|
mkdir -p "$clone_dir/.git"
|
||||||
|
;;
|
||||||
|
-C)
|
||||||
|
[[ "\${2:-}" == "$clone_dir" ]] || exit 97
|
||||||
|
case "\${3:-}" in
|
||||||
|
remote)
|
||||||
|
[[ "\$#" -eq 6 && "\$4" == add && "\$5" == origin \
|
||||||
|
&& "\$6" == https://git.gbrown.org/gib/Panama.git ]] || exit 97
|
||||||
|
;;
|
||||||
|
fetch)
|
||||||
|
if [[ "\${4:-}" == --depth=1 ]]; then
|
||||||
|
[[ "\$#" -eq 6 && "\$5" == origin && "\$6" == "$revision" ]] || exit 97
|
||||||
|
else
|
||||||
|
[[ "\$#" -eq 5 && "\$4" == origin && "\$5" == "$revision" ]] || exit 97
|
||||||
fi
|
fi
|
||||||
|
[[ "\$mode" != fetch-failure && "\$mode" != fresh-fetch-failure ]] || exit 42
|
||||||
|
;;
|
||||||
|
checkout)
|
||||||
|
if [[ "\${4:-}" == --detach ]]; then
|
||||||
|
[[ "\$#" -eq 5 && "\$5" == "$revision" ]] || exit 97
|
||||||
|
cp "$work/fake-install" "$clone_dir/install"
|
||||||
|
chmod +x "$clone_dir/install"
|
||||||
|
elif [[ "\${4:-}" == -b ]]; then
|
||||||
|
[[ "\$#" -eq 5 && "\$5" == main ]] || exit 97
|
||||||
|
else
|
||||||
|
exit 97
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
config)
|
||||||
|
case "\${4:-}:\${5:-}:\${6:-}" in
|
||||||
|
branch.main.remote:origin:|branch.main.merge:refs/heads/main:) ;;
|
||||||
|
*) exit 97 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
[[ "\$#" -eq 4 && "\$4" == --porcelain ]] || exit 97
|
||||||
|
cat "$state/status"
|
||||||
|
;;
|
||||||
|
merge-base)
|
||||||
|
[[ "\$#" -eq 6 && "\$4" == --is-ancestor && "\$5" == HEAD \
|
||||||
|
&& "\$6" == "$revision" ]] || exit 97
|
||||||
|
[[ "\$mode" != divergent ]] || exit 1
|
||||||
|
;;
|
||||||
|
merge)
|
||||||
|
[[ "\$#" -eq 5 && "\$4" == --ff-only && "\$5" == "$revision" ]] || exit 97
|
||||||
|
if [[ "\$mode" == existing-head-mismatch ]]; then
|
||||||
|
printf '%s\n' '$mismatched_revision' >"$state/head-revision"
|
||||||
|
else
|
||||||
|
printf '%s\n' '$revision' >"$state/head-revision"
|
||||||
|
fi
|
||||||
|
cp "$work/fake-install" "$clone_dir/install"
|
||||||
|
chmod +x "$clone_dir/install"
|
||||||
|
;;
|
||||||
|
rev-parse)
|
||||||
|
[[ "\$#" -eq 4 && "\$4" == 'HEAD^{commit}' ]] || exit 97
|
||||||
|
cat "$state/head-revision"
|
||||||
|
;;
|
||||||
|
*) exit 97 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*) exit 97 ;;
|
||||||
|
esac
|
||||||
STUB
|
STUB
|
||||||
chmod +x "$stub_dir/git"
|
chmod +x "$stub_dir/git"
|
||||||
|
|
||||||
run_boot() {
|
configure_case() {
|
||||||
|
local mode="$1" head_revision="${2:-$revision}" status="${3:-}"
|
||||||
|
rm -rf "$clone_dir"
|
||||||
: >"$calls"
|
: >"$calls"
|
||||||
PATH="$stub_dir:$PATH" PANAMA_PATH="$clone_dir" bash "$boot" </dev/null >/dev/null 2>&1
|
printf '%s\n' "$mode" >"$state/mode"
|
||||||
|
printf '%s\n' "$head_revision" >"$state/head-revision"
|
||||||
|
printf '%s' "$status" >"$state/status"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── A machine without the clone ──────────────────────────────────────────────
|
configure_existing_case() {
|
||||||
|
configure_case "$@"
|
||||||
|
mkdir -p "$clone_dir/.git"
|
||||||
|
cp "$work/fake-install" "$clone_dir/install"
|
||||||
|
chmod +x "$clone_dir/install"
|
||||||
|
}
|
||||||
|
|
||||||
run_boot || note 'boot failed on a machine without the clone'
|
run_boot() {
|
||||||
|
local supplied_revision="$1" supplied_sha="$2"
|
||||||
|
local -a env_args=(
|
||||||
|
"PATH=$stub_dir:$PATH"
|
||||||
|
"PANAMA_PATH=$clone_dir"
|
||||||
|
)
|
||||||
|
[[ "$supplied_revision" == UNSET ]] \
|
||||||
|
&& env_args+=(-u PANAMA_BOOT_REVISION) \
|
||||||
|
|| env_args+=("PANAMA_BOOT_REVISION=$supplied_revision")
|
||||||
|
[[ "$supplied_sha" == UNSET ]] \
|
||||||
|
&& env_args+=(-u PANAMA_BOOT_SHA256) \
|
||||||
|
|| env_args+=("PANAMA_BOOT_SHA256=$supplied_sha")
|
||||||
|
env "${env_args[@]}" bash "$boot" </dev/null >/dev/null 2>&1
|
||||||
|
run_status=$?
|
||||||
|
}
|
||||||
|
|
||||||
grep -q "git clone https://git.gbrown.org/gib/Panama.git $clone_dir" "$calls" \
|
assert_no_git_or_install() {
|
||||||
|| note 'boot does not clone the documented repository to PANAMA_PATH'
|
local case_name="$1"
|
||||||
grep -q "install PANAMA_PATH=$clone_dir" "$calls" \
|
if grep -qE '^(git|install) ' "$calls"; then
|
||||||
|| note 'boot does not hand off to the clone'\''s install with PANAMA_PATH exported'
|
note "$case_name reached Git or install"
|
||||||
|
|
||||||
# ── A machine that already has it ────────────────────────────────────────────
|
|
||||||
|
|
||||||
run_boot || note 'boot failed on a machine that already has the clone'
|
|
||||||
|
|
||||||
grep -q 'git clone' "$calls" \
|
|
||||||
&& note 'boot re-clones over an existing checkout'
|
|
||||||
grep -q 'git -C .* pull --ff-only' "$calls" \
|
|
||||||
|| note 'boot does not fast-forward an existing clone'
|
|
||||||
grep -q "install PANAMA_PATH=$clone_dir" "$calls" \
|
|
||||||
|| note 'boot does not run the install from an existing clone'
|
|
||||||
|
|
||||||
# ── A diverged clone still installs ──────────────────────────────────────────
|
|
||||||
#
|
|
||||||
# pull --ff-only refusing is normal life -- local commits, a rebase upstream.
|
|
||||||
# The command doubles as the repair path, so a refusal must be stepped over.
|
|
||||||
|
|
||||||
cat >"$stub_dir/git" <<'STUB'
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
[[ "$*" == *pull* ]] && exit 1
|
|
||||||
exit 0
|
|
||||||
STUB
|
|
||||||
chmod +x "$stub_dir/git"
|
|
||||||
|
|
||||||
: >"$calls"
|
|
||||||
if ! PATH="$stub_dir:$PATH" PANAMA_PATH="$clone_dir" bash "$boot" </dev/null >/dev/null 2>&1; then
|
|
||||||
note 'a clone that cannot fast-forward stops the install instead of proceeding'
|
|
||||||
fi
|
fi
|
||||||
grep -q "install PANAMA_PATH=$clone_dir" "$calls" \
|
}
|
||||||
|| note 'the install does not run when the fast-forward is refused'
|
|
||||||
|
assert_no_install_or_rewrite() {
|
||||||
|
local case_name="$1"
|
||||||
|
grep -q '^install ' "$calls" && note "$case_name reached install"
|
||||||
|
grep -qE '^git .* (reset|checkout -B|checkout -f)($| )' "$calls" \
|
||||||
|
&& note "$case_name rewrote the checkout"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Missing, malformed, or mismatched bootstrap inputs fail before Git.
|
||||||
|
input_cases=(
|
||||||
|
'missing revision|UNSET|BOOT_SHA'
|
||||||
|
'short revision|01234567|BOOT_SHA'
|
||||||
|
'uppercase revision|0123456789ABCDEF0123456789ABCDEF01234567|BOOT_SHA'
|
||||||
|
'missing digest|REVISION|UNSET'
|
||||||
|
'short digest|REVISION|01234567'
|
||||||
|
'uppercase digest|REVISION|AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
|
||||||
|
'mismatched digest|REVISION|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
||||||
|
)
|
||||||
|
|
||||||
|
for input_case in "${input_cases[@]}"; do
|
||||||
|
IFS='|' read -r name supplied_revision supplied_sha <<<"$input_case"
|
||||||
|
[[ "$supplied_revision" == REVISION ]] && supplied_revision="$revision"
|
||||||
|
[[ "$supplied_sha" == BOOT_SHA ]] && supplied_sha="$boot_sha"
|
||||||
|
configure_case validation-only
|
||||||
|
run_boot "$supplied_revision" "$supplied_sha"
|
||||||
|
(( run_status != 0 )) || note "$name was accepted"
|
||||||
|
assert_no_git_or_install "$name"
|
||||||
|
done
|
||||||
|
|
||||||
|
# A fresh install fetches only the requested commit, verifies checked-out HEAD,
|
||||||
|
# creates the tracked local main branch, and hands off.
|
||||||
|
configure_case fresh
|
||||||
|
run_boot "$revision" "$boot_sha"
|
||||||
|
(( run_status == 0 )) || note 'verified fresh bootstrap failed'
|
||||||
|
grep -qF "git init $clone_dir" "$calls" \
|
||||||
|
|| note 'fresh bootstrap did not initialize PANAMA_PATH'
|
||||||
|
grep -qF "git -C $clone_dir fetch --depth=1 origin $revision" "$calls" \
|
||||||
|
|| note 'fresh bootstrap did not fetch the exact revision'
|
||||||
|
grep -qF "git -C $clone_dir rev-parse HEAD^{commit}" "$calls" \
|
||||||
|
|| note 'fresh bootstrap did not resolve the checked-out commit'
|
||||||
|
grep -qF "git -C $clone_dir checkout -b main" "$calls" \
|
||||||
|
|| note 'fresh bootstrap did not create local main after verification'
|
||||||
|
grep -qF "git -C $clone_dir config branch.main.remote origin" "$calls" \
|
||||||
|
|| note 'fresh bootstrap did not configure main remote tracking'
|
||||||
|
grep -qF "git -C $clone_dir config branch.main.merge refs/heads/main" "$calls" \
|
||||||
|
|| note 'fresh bootstrap did not configure main merge tracking'
|
||||||
|
grep -qF "install PANAMA_PATH=$clone_dir" "$calls" \
|
||||||
|
|| note 'verified fresh bootstrap did not hand off with PANAMA_PATH'
|
||||||
|
grep -qE '^git (clone|.* pull)' "$calls" \
|
||||||
|
&& note 'fresh bootstrap used mutable clone or pull behavior'
|
||||||
|
|
||||||
|
# A fetched checkout whose HEAD does not equal the requested commit never
|
||||||
|
# creates the trusted branch or reaches install.
|
||||||
|
configure_case head-mismatch "$mismatched_revision"
|
||||||
|
run_boot "$revision" "$boot_sha"
|
||||||
|
(( run_status != 0 )) || note 'fresh HEAD mismatch returned success'
|
||||||
|
assert_no_install_or_rewrite 'fresh HEAD mismatch'
|
||||||
|
grep -qF "git -C $clone_dir checkout -b main" "$calls" \
|
||||||
|
&& note 'fresh HEAD mismatch created local main before equality passed'
|
||||||
|
|
||||||
|
# A clean existing ancestor is fetched and advanced with fast-forward only.
|
||||||
|
configure_existing_case existing "$ancestor_revision"
|
||||||
|
run_boot "$revision" "$boot_sha"
|
||||||
|
(( run_status == 0 )) || note 'clean ancestor bootstrap failed'
|
||||||
|
grep -qF "git -C $clone_dir status --porcelain" "$calls" \
|
||||||
|
|| note 'existing checkout cleanliness was not checked'
|
||||||
|
grep -qF "git -C $clone_dir fetch origin $revision" "$calls" \
|
||||||
|
|| note 'existing checkout did not fetch the exact revision'
|
||||||
|
grep -qF "git -C $clone_dir merge-base --is-ancestor HEAD $revision" "$calls" \
|
||||||
|
|| note 'existing checkout ancestry was not checked'
|
||||||
|
grep -qF "git -C $clone_dir merge --ff-only $revision" "$calls" \
|
||||||
|
|| note 'existing checkout was not advanced fast-forward-only'
|
||||||
|
grep -qF "install PANAMA_PATH=$clone_dir" "$calls" \
|
||||||
|
|| note 'verified existing checkout did not reach install'
|
||||||
|
grep -qE '^git .* (reset|pull)($| )' "$calls" \
|
||||||
|
&& note 'existing checkout used reset or pull instead of the exact revision'
|
||||||
|
|
||||||
|
# Dirty and divergent checkouts fail closed without rewriting or installing.
|
||||||
|
configure_existing_case dirty "$ancestor_revision" $' M boot\n'
|
||||||
|
run_boot "$revision" "$boot_sha"
|
||||||
|
(( run_status != 0 )) || note 'dirty checkout returned success'
|
||||||
|
grep -qF "git -C $clone_dir fetch origin $revision" "$calls" \
|
||||||
|
&& note 'dirty checkout fetched before refusing local work'
|
||||||
|
assert_no_install_or_rewrite 'dirty checkout'
|
||||||
|
|
||||||
|
configure_existing_case divergent "$ancestor_revision"
|
||||||
|
run_boot "$revision" "$boot_sha"
|
||||||
|
(( run_status != 0 )) || note 'divergent checkout returned success'
|
||||||
|
grep -qF "git -C $clone_dir merge --ff-only $revision" "$calls" \
|
||||||
|
&& note 'divergent checkout attempted a merge'
|
||||||
|
assert_no_install_or_rewrite 'divergent checkout'
|
||||||
|
|
||||||
|
# Fetch and post-fast-forward equality failures also stop before handoff.
|
||||||
|
configure_existing_case fetch-failure "$ancestor_revision"
|
||||||
|
run_boot "$revision" "$boot_sha"
|
||||||
|
(( run_status != 0 )) || note 'fetch failure returned success'
|
||||||
|
assert_no_install_or_rewrite 'fetch failure'
|
||||||
|
|
||||||
|
configure_existing_case existing-head-mismatch "$ancestor_revision"
|
||||||
|
run_boot "$revision" "$boot_sha"
|
||||||
|
(( run_status != 0 )) || note 'existing HEAD mismatch returned success'
|
||||||
|
assert_no_install_or_rewrite 'existing HEAD mismatch'
|
||||||
|
|
||||||
if (( ${#findings[@]} > 0 )); then
|
if (( ${#findings[@]} > 0 )); then
|
||||||
printf 'boot contract: %d finding(s)\n' "${#findings[@]}" >&2
|
printf 'boot contract: %d finding(s)\n' "${#findings[@]}" >&2
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ boot = sys.argv[1]
|
|||||||
work = Path(tempfile.mkdtemp())
|
work = Path(tempfile.mkdtemp())
|
||||||
atexit.register(shutil.rmtree, work, ignore_errors=True)
|
atexit.register(shutil.rmtree, work, ignore_errors=True)
|
||||||
findings: list[str] = []
|
findings: list[str] = []
|
||||||
|
BOOT_REVISION = "0123456789abcdef0123456789abcdef01234567"
|
||||||
|
BOOT_SHA256 = subprocess.run(
|
||||||
|
["sha256sum", boot], check=True, capture_output=True, text=True
|
||||||
|
).stdout.split()[0]
|
||||||
|
|
||||||
|
|
||||||
def note(message: str) -> None:
|
def note(message: str) -> None:
|
||||||
@@ -145,12 +149,42 @@ exec /usr/bin/ssh-keygen "$@"
|
|||||||
write_executable(stub_dir / "git", common + r'''
|
write_executable(stub_dir / "git", common + r'''
|
||||||
log git "$@"
|
log git "$@"
|
||||||
case "${1:-}" in
|
case "${1:-}" in
|
||||||
clone)
|
init)
|
||||||
mkdir -p "$3/.git"
|
[[ "$#" -eq 2 ]] || exit 97
|
||||||
cp "$PANAMA_BOOT_FIXTURE_ROOT/stub-install" "$3/install"
|
mkdir -p "$2/.git"
|
||||||
chmod +x "$3/install"
|
;;
|
||||||
|
-C)
|
||||||
|
case "${3:-}" in
|
||||||
|
remote)
|
||||||
|
[[ "$#" -eq 6 && "$4" == add && "$5" == origin \
|
||||||
|
&& "$6" == https://git.gbrown.org/gib/Panama.git ]] || exit 97
|
||||||
|
;;
|
||||||
|
fetch)
|
||||||
|
[[ "$#" -eq 6 && "$4" == --depth=1 && "$5" == origin \
|
||||||
|
&& "$6" == "$PANAMA_BOOT_REVISION" ]] || exit 97
|
||||||
|
;;
|
||||||
|
checkout)
|
||||||
|
if [[ "${4:-}" == --detach ]]; then
|
||||||
|
[[ "$#" -eq 5 && "$5" == "$PANAMA_BOOT_REVISION" ]] || exit 97
|
||||||
|
cp "$PANAMA_BOOT_FIXTURE_ROOT/stub-install" "$2/install"
|
||||||
|
chmod +x "$2/install"
|
||||||
|
else
|
||||||
|
[[ "$#" -eq 5 && "$4" == -b && "$5" == main ]] || exit 97
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
rev-parse)
|
||||||
|
[[ "$#" -eq 4 && "$4" == 'HEAD^{commit}' ]] || exit 97
|
||||||
|
printf '%s\n' "$PANAMA_BOOT_REVISION"
|
||||||
|
;;
|
||||||
|
config)
|
||||||
|
case "${4:-}:${5:-}:${6:-}" in
|
||||||
|
branch.main.remote:origin:|branch.main.merge:refs/heads/main:) ;;
|
||||||
|
*) exit 97 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*) exit 97 ;;
|
||||||
|
esac
|
||||||
;;
|
;;
|
||||||
-C) [[ "${3:-}" == pull && "${4:-}" == --ff-only ]] || exit 97 ;;
|
|
||||||
*) exit 97 ;;
|
*) exit 97 ;;
|
||||||
esac
|
esac
|
||||||
''')
|
''')
|
||||||
@@ -483,6 +517,8 @@ def run_case(
|
|||||||
**os.environ,
|
**os.environ,
|
||||||
"PATH": f"{stub_dir}:/usr/bin:/bin",
|
"PATH": f"{stub_dir}:/usr/bin:/bin",
|
||||||
"PANAMA_BOOT_FIXTURE_ROOT": str(fixture_root),
|
"PANAMA_BOOT_FIXTURE_ROOT": str(fixture_root),
|
||||||
|
"PANAMA_BOOT_REVISION": BOOT_REVISION,
|
||||||
|
"PANAMA_BOOT_SHA256": BOOT_SHA256,
|
||||||
"PANAMA_PATH": f"{fixture_root}/home/gib/.local/share/Panama",
|
"PANAMA_PATH": f"{fixture_root}/home/gib/.local/share/Panama",
|
||||||
"HOME": f"{fixture_root}/root",
|
"HOME": f"{fixture_root}/root",
|
||||||
}
|
}
|
||||||
@@ -586,6 +622,8 @@ guard_root.mkdir()
|
|||||||
guard_env = {
|
guard_env = {
|
||||||
**os.environ,
|
**os.environ,
|
||||||
"PANAMA_BOOT_FIXTURE_ROOT": str(guard_root),
|
"PANAMA_BOOT_FIXTURE_ROOT": str(guard_root),
|
||||||
|
"PANAMA_BOOT_REVISION": BOOT_REVISION,
|
||||||
|
"PANAMA_BOOT_SHA256": BOOT_SHA256,
|
||||||
"HOME": str(guard_root),
|
"HOME": str(guard_root),
|
||||||
}
|
}
|
||||||
if os.geteuid() == 0:
|
if os.geteuid() == 0:
|
||||||
|
|||||||
Reference in New Issue
Block a user