#!/usr/bin/env bash # verify-clean-clone.sh -- prove the COMMITTED artifact runs, from a clean clone. # # ================== THIS FILE IS THE SECOND VERSION. THE FIRST HAD B1. ======== # B1 was: the delivered scripts were committed mode 100644, so the artifact # returned 126 Permission denied for anyone who cloned it. Two of us ran 32/32 # because our local working copies had the exec bit set by hand at creation. # # I wrote v1 of this file to prevent exactly that. V1 COPIED THE WORKING-TREE # FILES INTO A SCRATCH REPOSITORY AND ASSERTED THE SCRATCH REPOSITORY'S INDEX. # cp preserves the local exec bit, so `git add` in the scratch repo recorded # 100755 NO MATTER WHAT THE REAL REPOSITORY STORED. Reviewer reproduction: # git update-index --chmod=-x push-guard.sh test-push-guard.sh # ./verify-clean-clone.sh -> EXIT 0, "CLEAN CLONE: suite ran and passed" # while the real index read 100644 -- the precise contaminated state B1 was. # # THE CONTROL FOR THE DEFECT INHERITED THE DEFECT, BECAUSE IT MEASURED A COPY # INSTEAD OF THE SUBJECT. cp LAUNDERS MODE. # # Both of v1's mechanisms were right -- assert the INDEX not the disk, execute # DIRECTLY not via `bash script`. They were applied to the wrong repository. # So v2 changes what is measured, not how: # * mode is read from the SOURCE repository's COMMITTED TREE (git ls-tree), # which no local chmod can influence; # * the tree under test is produced by CLONING THAT COMMIT, so every mode # comes out of the object store rather than off my filesystem. # There is no cp anywhere in this file, and that is deliberate. # # It also REFUSES rather than passes when the artifacts are untracked: an # artifact that is not committed has no mode to verify, and a verifier that # silently succeeds on nothing is the vacuous-absence failure all over again. set -euo pipefail readonly EX_FAIL=1 readonly EX_USAGE=64 REPO="" REV="HEAD" die() { printf 'usage error: %s\n' "$1" >&2; exit "$EX_USAGE"; } while (( $# )); do case "$1" in --repo) REPO="${2:-}"; shift 2 ;; --rev) REV="${2:-}"; shift 2 ;; *) die "unknown argument: $1" ;; esac done HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" [[ -n "$REPO" ]] || REPO="$HERE" ARTIFACTS=(push-guard.sh test-push-guard.sh verify-clean-clone.sh mutate-push-guard.sh) SUITE="test-push-guard.sh" # --- the subject must be a real repository, or there is nothing to verify ----- if ! ROOT="$(git -C "$REPO" rev-parse --show-toplevel 2>/dev/null)"; then printf 'REFUSING: %s is not inside a git repository.\n' "$REPO" >&2 printf 'This verifier checks the COMMITTED mode of the artifact. An uncommitted\n' >&2 printf 'artifact has no committed mode, and passing here would prove nothing.\n' >&2 exit "$EX_FAIL" fi if ! REV_SHA="$(git -C "$ROOT" rev-parse --verify --quiet "${REV}^{commit}")"; then printf 'REFUSING: %s does not resolve to a commit in %s\n' "$REV" "$ROOT" >&2 exit "$EX_FAIL" fi printf '=== subject ===\n' printf ' repo %s\n rev %s (%s)\n\n' "$ROOT" "$REV" "$REV_SHA" # --- 1. MODE, FROM THE COMMITTED TREE OF THE SUBJECT ------------------------- # git ls-tree reports what the COMMIT records. Nothing on my filesystem can # move this number -- which is the whole point, and what v1 got wrong. printf '=== committed modes (git ls-tree %s) ===\n' "$REV" rc=0 for f in "${ARTIFACTS[@]}"; do entry="$(git -C "$ROOT" ls-tree "$REV_SHA" -- "$f")" if [[ -z "$entry" ]]; then printf ' FAIL %s is NOT TRACKED at %s -- nothing committed to verify\n' "$f" "$REV" rc=1; continue fi mode="${entry%% *}"; rest="${entry#* }"; type="${rest%% *}" if [[ "$type" != blob ]]; then printf ' FAIL %s is a %s at %s, not a regular file\n' "$f" "$type" "$REV" rc=1; continue fi case "$mode" in 100755) printf ' ok %s committed %s\n' "$f" "$mode" ;; 120000) printf ' FAIL %s is a SYMLINK (%s) -- the reviewed blob is a path, not the code\n' "$f" "$mode"; rc=1 ;; *) printf ' FAIL %s committed %s, needs 100755\n' "$f" "$mode" printf ' fix with: git update-index --chmod=+x %s && commit\n' "$f" rc=1 ;; esac done if (( rc != 0 )); then printf '\nREFUSING TO CONTINUE: the COMMITTED modes are wrong, whatever the disk says.\n' printf 'A clone of this commit would exit 126 for the next person.\n' exit "$EX_FAIL" fi # --- 2. RUN FROM A CLONE OF THAT COMMIT -------------------------------------- # Cloning materialises every file from the object store, so the modes on disk # are the COMMITTED modes by construction. No cp, no local state, nothing this # machine can contribute. WORK="$(mktemp -d)" trap 'rm -rf "$WORK"' EXIT printf '\n=== cloning %s (no local mode bits survive this) ===\n' "$REV_SHA" git clone -q --no-local --no-hardlinks "$ROOT" "$WORK/clone" git -C "$WORK/clone" -c advice.detachedHead=false checkout -q "$REV_SHA" for f in "${ARTIFACTS[@]}"; do printf ' clone disk mode: %s %s\n' "$(stat -c '%a' "$WORK/clone/$f")" "$f" done printf '\n=== executing DIRECTLY (./%s), not via "bash %s" ===\n' "$SUITE" "$SUITE" # Invoking the interpreter explicitly masks a missing exec bit completely -- it # is how the original green was obtained. Direct execution is the thing under # test, so the mode has to be real for this line to succeed. cd "$WORK/clone" if ! "./$SUITE"; then printf '\nCLEAN-CLONE RUN FAILED.\n' exit "$EX_FAIL" fi printf '\n=== CLEAN CLONE: the COMMITTED artifact ran and passed ===\n'