#!/usr/bin/env bash # shellcheck disable=SC2030,SC2031 # Provider arms isolate PATH/credentials in subshells. # The commit whose CI was guarded must be the commit the provider atomically merges. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/pr-merge-head-pin}" SHA=0123456789abcdef0123456789abcdef01234567 make_fixture() { local name="$1" remote="$2" local root="$WORK_DIR/$name" local tools="$root/tools/git" mkdir -p "$tools" "$root/repo" cp "$SCRIPT_DIR/pr-merge.sh" "$tools/pr-merge.sh" cp "$SCRIPT_DIR/detect-platform.sh" "$tools/detect-platform.sh" git -C "$root/repo" init -q git -C "$root/repo" remote add origin "$remote" cat > "$tools/pr-metadata.sh" < "$tools/ci-queue-wait.sh" <<'SH' #!/usr/bin/env bash exit 0 SH chmod +x "$tools"/*.sh } rm -rf "$WORK_DIR" make_fixture gitea https://git.example.test/acme/widgets.git make_fixture github https://github.com/acme/widgets.git cat > "$WORK_DIR/gitea/curl" <<'SH' #!/usr/bin/env bash set -euo pipefail payload="" for ((i=1; i<=$#; i++)); do if [[ "${!i}" == "-d" ]]; then j=$((i + 1)) payload="${!j}" fi done printf '%s' "$payload" > "${MOSAIC_MERGE_PAYLOAD_LOG:?}" printf '200' SH chmod +x "$WORK_DIR/gitea/curl" set +e ( cd "$WORK_DIR/gitea/repo" export PATH="$WORK_DIR/gitea:$PATH" export GITEA_TOKEN=stub-token export GITEA_URL=https://git.example.test export MOSAIC_CREDENTIALS_FILE="$WORK_DIR/no-credentials.json" export MOSAIC_MERGE_PAYLOAD_LOG="$WORK_DIR/gitea-payload.json" env -u MOSAIC_GIT_IDENTITY "$WORK_DIR/gitea/tools/git/pr-merge.sh" -n 123 ) >"$WORK_DIR/gitea.out" 2>&1 gitea_rc=$? set -e if [[ "$gitea_rc" -ne 0 ]]; then echo "FAIL gitea-pin: merge fixture returned $gitea_rc" >&2 cat "$WORK_DIR/gitea.out" >&2 exit 1 fi python3 - "$WORK_DIR/gitea-payload.json" "$SHA" <<'PY' import json import sys payload = json.load(open(sys.argv[1], encoding="utf-8")) assert set(payload) <= {"Do", "head_commit_id", "delete_branch_after_merge"}, payload assert payload.get("Do") == "squash", payload assert payload.get("head_commit_id") == sys.argv[2], payload PY # A merge-gate verdict is commit-bound. A stale expected head must fail before merge. wrong_sha=ffffffffffffffffffffffffffffffffffffffff rm -f "$WORK_DIR/gitea-payload-stale.json" set +e ( cd "$WORK_DIR/gitea/repo" export PATH="$WORK_DIR/gitea:$PATH" export GITEA_TOKEN=stub-token export GITEA_URL=https://git.example.test export MOSAIC_CREDENTIALS_FILE="$WORK_DIR/no-credentials.json" export MOSAIC_MERGE_PAYLOAD_LOG="$WORK_DIR/gitea-payload-stale.json" env -u MOSAIC_GIT_IDENTITY "$WORK_DIR/gitea/tools/git/pr-merge.sh" -n 123 --expect-head "$wrong_sha" ) >"$WORK_DIR/gitea-stale.out" 2>&1 stale_rc=$? set -e if [[ "$stale_rc" -eq 0 ]] || [[ -e "$WORK_DIR/gitea-payload-stale.json" ]]; then echo "FAIL stale-verdict: moved head was not refused before provider merge" >&2 exit 1 fi # A merge-capable path cannot bypass the mandatory queue guard. The legacy # --skip-queue-guard option must be rejected before any provider merge call. cat > "$WORK_DIR/gitea/tools/git/ci-queue-wait.sh" <<'SH' #!/usr/bin/env bash exit 99 SH chmod +x "$WORK_DIR/gitea/tools/git/ci-queue-wait.sh" rm -f "$WORK_DIR/gitea-payload-bypass.json" set +e ( cd "$WORK_DIR/gitea/repo" export PATH="$WORK_DIR/gitea:$PATH" export GITEA_TOKEN=stub-token export GITEA_URL=https://git.example.test export MOSAIC_CREDENTIALS_FILE="$WORK_DIR/no-credentials.json" export MOSAIC_MERGE_PAYLOAD_LOG="$WORK_DIR/gitea-payload-bypass.json" env -u MOSAIC_GIT_IDENTITY "$WORK_DIR/gitea/tools/git/pr-merge.sh" -n 123 --skip-queue-guard ) >"$WORK_DIR/gitea-bypass.out" 2>&1 bypass_rc=$? set -e if [[ "$bypass_rc" -eq 0 ]] || [[ -e "$WORK_DIR/gitea-payload-bypass.json" ]]; then echo "FAIL merge-bypass: --skip-queue-guard reached the provider merge path" >&2 exit 1 fi # Dry-run is the only path that may omit the guard because it exits before the # provider merge dispatch. Prove the exit and absence of a merge payload. rm -f "$WORK_DIR/gitea-payload-dry-run.json" ( cd "$WORK_DIR/gitea/repo" export PATH="$WORK_DIR/gitea:$PATH" export GITEA_TOKEN=stub-token export GITEA_URL=https://git.example.test export MOSAIC_CREDENTIALS_FILE="$WORK_DIR/no-credentials.json" export MOSAIC_MERGE_PAYLOAD_LOG="$WORK_DIR/gitea-payload-dry-run.json" env -u MOSAIC_GIT_IDENTITY "$WORK_DIR/gitea/tools/git/pr-merge.sh" -n 123 --dry-run ) >"$WORK_DIR/gitea-dry-run.out" 2>&1 if [[ -e "$WORK_DIR/gitea-payload-dry-run.json" ]]; then echo "FAIL dry-run: non-merging preflight reached the provider merge path" >&2 exit 1 fi cat > "$WORK_DIR/github/gh" <<'SH' #!/usr/bin/env bash set -euo pipefail printf '%s\n' "$*" > "${MOSAIC_GH_MERGE_LOG:?}" SH chmod +x "$WORK_DIR/github/gh" ( cd "$WORK_DIR/github/repo" export PATH="$WORK_DIR/github:$PATH" export MOSAIC_GH_MERGE_LOG="$WORK_DIR/github-call.log" "$WORK_DIR/github/tools/git/pr-merge.sh" -n 123 ) >"$WORK_DIR/github.out" 2>&1 if ! grep -q -- "--match-head-commit $SHA" "$WORK_DIR/github-call.log"; then echo "FAIL github-pin: merge command omitted --match-head-commit $SHA" >&2 cat "$WORK_DIR/github-call.log" >&2 exit 1 fi echo "PR merge exact-head pin regression passed (Gitea + GitHub)"