424 lines
18 KiB
Bash
Executable File
424 lines
18 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# `boot` is downloaded before the repository exists. It may hand off only
|
|
# after both the downloaded script and the requested Git commit have been
|
|
# verified. This fixture stubs Git and install inside a throwaway PANAMA_PATH;
|
|
# it never contacts the network or mutates the real checkout.
|
|
|
|
set -uo pipefail
|
|
|
|
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
boot="$repo_dir/boot"
|
|
|
|
findings=()
|
|
note() { findings+=("$1"); }
|
|
|
|
[[ -x "$boot" ]] || { printf 'boot contract: %s is not executable\n' "$boot" >&2; exit 1; }
|
|
|
|
# Git is the only package boot can install before the verified checkout exists.
|
|
# Both root-server and ordinary-user paths must exclude ambient third-party
|
|
# repositories while still allowing Fedora dependencies.
|
|
for git_install in \
|
|
'dnf install -y --repo=fedora --repo=updates --from-repo=fedora,updates git' \
|
|
'sudo dnf install -y --repo=fedora --repo=updates --from-repo=fedora,updates git'; do
|
|
grep -qF "$git_install" "$boot" \
|
|
|| note "boot omits reviewed Fedora source binding: $git_install"
|
|
done
|
|
|
|
work="$(mktemp -d)"
|
|
trap 'rm -rf "$work"' EXIT
|
|
|
|
calls="$work/calls"
|
|
state="$work/state"
|
|
stub_dir="$work/bin"
|
|
clone_dir="$work/Panama"
|
|
revision='0123456789abcdef0123456789abcdef01234567'
|
|
ancestor_revision='1111111111111111111111111111111111111111'
|
|
mismatched_revision='fedcba9876543210fedcba9876543210fedcba98'
|
|
boot_sha="$(sha256sum "$boot" | cut -d' ' -f1)"
|
|
mkdir -p "$stub_dir" "$state"
|
|
|
|
cat >"$work/fake-install" <<STUB
|
|
#!/usr/bin/env bash
|
|
printf 'install PANAMA_PATH=%s\n' "\${PANAMA_PATH:-unset}" >>"$calls"
|
|
STUB
|
|
chmod +x "$work/fake-install"
|
|
|
|
cat >"$stub_dir/git" <<STUB
|
|
#!/usr/bin/env bash
|
|
printf 'git %s\n' "\$*" >>"$calls"
|
|
mode="\$(<"$state/mode")"
|
|
|
|
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
|
|
[[ "\$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"
|
|
printf '%s\n' '$revision' >"$clone_dir/.git/HEAD"
|
|
elif [[ "\${4:-}" == -b ]]; then
|
|
[[ "\$#" -eq 5 && "\$5" == main ]] || exit 97
|
|
mkdir -p "$clone_dir/.git/refs/heads"
|
|
printf '%s\n' '$revision' >"$clone_dir/.git/refs/heads/main"
|
|
printf 'ref: refs/heads/main\n' >"$clone_dir/.git/HEAD"
|
|
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"
|
|
;;
|
|
ls-tree)
|
|
[[ "\$#" -eq 6 && "\$4" == -rz && "\$5" == --full-tree \
|
|
&& "\$6" == "$revision" ]] || exit 97
|
|
printf '100755 blob aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\tinstall\0'
|
|
;;
|
|
hash-object)
|
|
[[ "\$#" -eq 6 && "\$4" == --no-filters && "\$5" == -- \
|
|
&& "\$6" == install ]] || exit 97
|
|
printf '%s\n' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
;;
|
|
*) exit 97 ;;
|
|
esac
|
|
;;
|
|
*) exit 97 ;;
|
|
esac
|
|
STUB
|
|
chmod +x "$stub_dir/git"
|
|
|
|
configure_case() {
|
|
local mode="$1" head_revision="${2:-$revision}" status="${3:-}"
|
|
rm -rf "$clone_dir"
|
|
: >"$calls"
|
|
printf '%s\n' "$mode" >"$state/mode"
|
|
printf '%s\n' "$head_revision" >"$state/head-revision"
|
|
printf '%s' "$status" >"$state/status"
|
|
}
|
|
|
|
configure_existing_case() {
|
|
configure_case "$@"
|
|
mkdir -p "$clone_dir/.git"
|
|
cp "$work/fake-install" "$clone_dir/install"
|
|
chmod +x "$clone_dir/install"
|
|
}
|
|
|
|
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=$?
|
|
}
|
|
|
|
assert_no_git_or_install() {
|
|
local case_name="$1"
|
|
if grep -qE '^(git|install) ' "$calls"; then
|
|
note "$case_name reached Git or install"
|
|
fi
|
|
}
|
|
|
|
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 fresh fetch failure stops before any checked-out HEAD or executable
|
|
# handoff exists. The empty initialized Git directory is not a usable checkout.
|
|
configure_case fresh-fetch-failure
|
|
run_boot "$revision" "$boot_sha"
|
|
(( run_status != 0 )) || note 'fresh fetch failure returned success'
|
|
grep -qF "git -C $clone_dir fetch --depth=1 origin $revision" "$calls" \
|
|
|| note 'fresh fetch failure did not exercise the exact fetch'
|
|
assert_no_install_or_rewrite 'fresh fetch failure'
|
|
if grep -qE '^git .* (checkout|rev-parse)($| )' "$calls"; then
|
|
note 'fresh fetch failure reported or materialized a checked-out HEAD'
|
|
fi
|
|
if [[ -x "$clone_dir/install" || -e "$clone_dir/.git/HEAD" \
|
|
|| -e "$clone_dir/.git/refs/heads/main" ]]; then
|
|
note 'fresh fetch failure left a usable checkout'
|
|
fi
|
|
|
|
# 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'
|
|
|
|
# Git's porcelain status deliberately trusts index hints. The bootstrap cannot:
|
|
# these two flags can hide changed executable bytes while HEAD still names the
|
|
# reviewed commit. Exercise real Git so the contract cannot accidentally teach
|
|
# its adapter to expose state that Git itself hides.
|
|
real_git="$(command -v git)"
|
|
hidden_root="$work/hidden-index"
|
|
mkdir -p "$hidden_root/home"
|
|
"$real_git" init -q "$hidden_root/source"
|
|
"$real_git" -C "$hidden_root/source" config user.email contract@panama
|
|
"$real_git" -C "$hidden_root/source" config user.name contract
|
|
printf '#!/usr/bin/env bash\nexit 0\n' >"$hidden_root/source/install"
|
|
chmod +x "$hidden_root/source/install"
|
|
printf 'trusted target bytes\n' >"$hidden_root/source/target"
|
|
ln -s target "$hidden_root/source/trusted-link"
|
|
"$real_git" -C "$hidden_root/source" add install target trusted-link
|
|
"$real_git" -C "$hidden_root/source" commit -qm trusted
|
|
hidden_revision="$("$real_git" -C "$hidden_root/source" rev-parse HEAD)"
|
|
"$real_git" clone -q --bare "$hidden_root/source" "$hidden_root/origin.git"
|
|
|
|
# Exercise the exact boundary between checkout preparation and handoff. This
|
|
# test-only copy inserts a same-UID replacement after prepare returns; the
|
|
# production handoff must perform its complete comparison after that point.
|
|
post_prepare_checkout="$hidden_root/post-prepare-swap"
|
|
post_prepare_marker="$hidden_root/post-prepare-executed"
|
|
post_prepare_hook_marker="$hidden_root/post-prepare-hook-fired"
|
|
"$real_git" clone -q "$hidden_root/origin.git" "$post_prepare_checkout"
|
|
post_prepare_hook="$hidden_root/swap-install"
|
|
cat >"$post_prepare_hook" <<'HOOK'
|
|
#!/usr/bin/env bash
|
|
: >"$PANAMA_BOOT_POST_PREPARE_HOOK_MARKER"
|
|
printf '#!/usr/bin/env bash\nprintf "executed\\n" >%q\n' \
|
|
"$PANAMA_BOOT_POST_PREPARE_MARKER" >"$PANAMA_PATH/install"
|
|
chmod +x "$PANAMA_PATH/install"
|
|
HOOK
|
|
chmod +x "$post_prepare_hook"
|
|
hooked_boot="$hidden_root/boot-post-prepare-hook"
|
|
awk '
|
|
{
|
|
print
|
|
if ($0 == "prepare_panama_checkout \"$PANAMA_PATH\"") {
|
|
prepare_count++
|
|
if (prepare_count == 1) print "\"$PANAMA_BOOT_POST_PREPARE_FIXTURE\""
|
|
}
|
|
}
|
|
' "$boot" >"$hooked_boot"
|
|
hooked_boot_sha="$(sha256sum "$hooked_boot" | cut -d' ' -f1)"
|
|
post_prepare_status=0
|
|
HOME="$hidden_root/home" PANAMA_PATH="$post_prepare_checkout" \
|
|
PANAMA_BOOT_REVISION="$hidden_revision" PANAMA_BOOT_SHA256="$hooked_boot_sha" \
|
|
PANAMA_BOOT_POST_PREPARE_FIXTURE="$post_prepare_hook" \
|
|
PANAMA_BOOT_POST_PREPARE_MARKER="$post_prepare_marker" \
|
|
PANAMA_BOOT_POST_PREPARE_HOOK_MARKER="$post_prepare_hook_marker" \
|
|
bash "$hooked_boot" </dev/null >"$hidden_root/post-prepare.out" 2>&1 \
|
|
|| post_prepare_status=$?
|
|
[[ -e "$post_prepare_hook_marker" ]] \
|
|
|| note 'post-prepare replacement hook did not exercise the boundary'
|
|
(( post_prepare_status != 0 )) \
|
|
|| note 'post-prepare worktree replacement returned success'
|
|
[[ ! -e "$post_prepare_marker" ]] \
|
|
|| note 'post-prepare worktree replacement executed unreviewed install bytes'
|
|
|
|
# A valid tracked symlink must compare its link text with Git's 120000 blob;
|
|
# hashing the pathname would follow it and hash the target file instead.
|
|
symlink_checkout="$hidden_root/tracked-symlink"
|
|
"$real_git" clone -q "$hidden_root/origin.git" "$symlink_checkout"
|
|
symlink_status=0
|
|
HOME="$hidden_root/home" PANAMA_PATH="$symlink_checkout" \
|
|
PANAMA_BOOT_REVISION="$hidden_revision" PANAMA_BOOT_SHA256="$boot_sha" \
|
|
bash "$boot" </dev/null >"$hidden_root/tracked-symlink.out" 2>&1 \
|
|
|| symlink_status=$?
|
|
(( symlink_status == 0 )) \
|
|
|| note 'a checkout with a valid tracked symlink was rejected'
|
|
|
|
for hidden_flag in assume-unchanged skip-worktree; do
|
|
hidden_checkout="$hidden_root/$hidden_flag"
|
|
hidden_marker="$hidden_root/$hidden_flag-executed"
|
|
"$real_git" clone -q "$hidden_root/origin.git" "$hidden_checkout"
|
|
printf '#!/usr/bin/env bash\nprintf "executed\\n" >%q\n' "$hidden_marker" \
|
|
>"$hidden_checkout/install"
|
|
chmod +x "$hidden_checkout/install"
|
|
"$real_git" -C "$hidden_checkout" update-index "--$hidden_flag" install
|
|
[[ -z "$("$real_git" -C "$hidden_checkout" status --porcelain)" ]] \
|
|
|| note "$hidden_flag fixture was not hidden from porcelain status"
|
|
|
|
hidden_status=0
|
|
HOME="$hidden_root/home" PANAMA_PATH="$hidden_checkout" \
|
|
PANAMA_BOOT_REVISION="$hidden_revision" PANAMA_BOOT_SHA256="$boot_sha" \
|
|
bash "$boot" </dev/null >"$hidden_root/$hidden_flag.out" 2>&1 \
|
|
|| hidden_status=$?
|
|
(( hidden_status != 0 )) \
|
|
|| note "$hidden_flag modified checkout returned success"
|
|
[[ ! -e "$hidden_marker" ]] \
|
|
|| note "$hidden_flag modified checkout executed unreviewed install bytes"
|
|
done
|
|
|
|
# The same hidden-index state must not conceal a mode change or a different
|
|
# symlink target; both are part of the reviewed Git tree, not metadata hints.
|
|
for hidden_flag in assume-unchanged skip-worktree; do
|
|
for hidden_change in mode symlink-target; do
|
|
hidden_checkout="$hidden_root/$hidden_flag-$hidden_change"
|
|
"$real_git" clone -q "$hidden_root/origin.git" "$hidden_checkout"
|
|
case "$hidden_change" in
|
|
mode)
|
|
chmod -x "$hidden_checkout/install"
|
|
hidden_path=install
|
|
;;
|
|
symlink-target)
|
|
rm -- "$hidden_checkout/trusted-link"
|
|
ln -s untrusted-target "$hidden_checkout/trusted-link"
|
|
hidden_path=trusted-link
|
|
;;
|
|
esac
|
|
"$real_git" -C "$hidden_checkout" update-index "--$hidden_flag" "$hidden_path"
|
|
[[ -z "$("$real_git" -C "$hidden_checkout" status --porcelain)" ]] \
|
|
|| note "$hidden_flag $hidden_change fixture was not hidden from porcelain status"
|
|
|
|
hidden_status=0
|
|
HOME="$hidden_root/home" PANAMA_PATH="$hidden_checkout" \
|
|
PANAMA_BOOT_REVISION="$hidden_revision" PANAMA_BOOT_SHA256="$boot_sha" \
|
|
bash "$boot" </dev/null >"$hidden_root/$hidden_flag-$hidden_change.out" 2>&1 \
|
|
|| hidden_status=$?
|
|
(( hidden_status != 0 )) \
|
|
|| note "$hidden_flag concealed a tracked $hidden_change change"
|
|
done
|
|
done
|
|
|
|
if (( ${#findings[@]} > 0 )); then
|
|
printf 'boot contract: %d finding(s)\n' "${#findings[@]}" >&2
|
|
printf ' - %s\n' "${findings[@]}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
printf 'boot contract: PASS\n'
|