From c611f06b50f7fecba7a4daa27713d505bf98d721 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 4 Sep 2026 16:47:23 +0100 Subject: [PATCH 1/3] fix(pins): refuse non-mainline propagation targets --- scripts/propagate-workflow-pins.sh | 77 +++++++++++++++++-- scripts/tests/propagate-workflow-pins-test.sh | 30 +++++++- 2 files changed, 100 insertions(+), 7 deletions(-) diff --git a/scripts/propagate-workflow-pins.sh b/scripts/propagate-workflow-pins.sh index 8455a0f19..57d752b1e 100755 --- a/scripts/propagate-workflow-pins.sh +++ b/scripts/propagate-workflow-pins.sh @@ -37,8 +37,9 @@ # PATH may be a single consumer repo (has .github/workflows) or a parent # directory of many repos. Defaults to the current directory. # --to target standards SHA to pin to. If omitted, resolved from -# (in order) $STANDARDS_TARGET_SHA, a local standards checkout -# ($STANDARDS_DIR or ~/standards), then `git ls-remote` HEAD. +# (in order) $STANDARDS_TARGET_SHA, the main ref of a local +# standards checkout ($STANDARDS_DIR or ~/standards), then the +# remote main ref. A feature-worktree HEAD is never selected. # # Output: tab-separated audit lines suitable for review. @@ -77,13 +78,22 @@ resolve_target() { if [ -n "$TARGET_SHA" ]; then printf '%s' "$TARGET_SHA"; return 0; fi local sd="${STANDARDS_DIR:-$HOME/standards}" - if git -C "$sd" rev-parse HEAD >/dev/null 2>&1; then - git -C "$sd" rev-parse HEAD; return 0 - fi + # The old implementation used HEAD. When invoked from a standards feature + # worktree, that propagated a PR-intermediate commit before it had landed on + # main. GitHub's contents API could read that commit, but cross-repository + # reusable workflows rejected it as `workflow was not found` (251 active + # workflow files / 70 repos in the 2026-09-04 incident). + local ref + for ref in refs/remotes/origin/main refs/heads/main; do + if git -C "$sd" rev-parse --verify "${ref}^{commit}" >/dev/null 2>&1; then + git -C "$sd" rev-parse "${ref}^{commit}" + return 0 + fi + done # Network fallback — the live standards HEAD. local remote - remote=$(git ls-remote https://github.com/hyperpolymath/standards.git HEAD 2>/dev/null | awk '{print $1}') + remote=$(git ls-remote https://github.com/hyperpolymath/standards.git refs/heads/main 2>/dev/null | awk '{print $1}') if [ -n "$remote" ]; then printf '%s' "$remote"; return 0; fi return 1 @@ -94,6 +104,61 @@ if ! TARGET_SHA="$(resolve_target)"; then exit 2 fi +# Prove that the proposed pin is a full commit SHA reachable from standards' +# default branch. Merely proving that `/commits/` exists is insufficient: +# a squash-merged PR leaves its intermediate commits addressable through the +# API but unusable as cross-repository reusable-workflow refs. +validate_target() { + [[ "$TARGET_SHA" =~ ^[0-9a-fA-F]{40}$ ]] || { + log "ERROR: target must be a full 40-character hexadecimal commit SHA: $TARGET_SHA" + return 1 + } + + local sd="${STANDARDS_DIR:-$HOME/standards}" ref head gd + if git -C "$sd" cat-file -e "${TARGET_SHA}^{commit}" >/dev/null 2>&1; then + for ref in refs/remotes/origin/main refs/heads/main; do + if head=$(git -C "$sd" rev-parse --verify "${ref}^{commit}" 2>/dev/null); then + if git -C "$sd" merge-base --is-ancestor "$TARGET_SHA" "$head"; then + return 0 + fi + + # A complete local graph gives a conclusive negative. A shallow or + # partial clone does not; let the server settle that case below. + gd=$(git -C "$sd" rev-parse --absolute-git-dir 2>/dev/null || true) + if [ -n "$gd" ] && [ ! -e "$gd/shallow" ] && + [ "$(git -C "$sd" config --get remote.origin.promisor 2>/dev/null || true)" != true ] && + [ -z "$(git -C "$sd" config --get remote.origin.partialclonefilter 2>/dev/null || true)" ]; then + log "ERROR: target ${TARGET_SHA} exists but is not reachable from local standards main (${head})." + return 1 + fi + break + fi + done + fi + + local api="${STANDARDS_REACHABILITY_API_BASE:-https://api.github.com}" + local -a auth=() + [ -n "${GITHUB_TOKEN:-}" ] && auth=(-H "Authorization: Bearer ${GITHUB_TOKEN}") + local body status + body=$(curl -fsS --max-time 20 \ + -H 'Accept: application/vnd.github+json' \ + "${auth[@]}" \ + "$api/repos/hyperpolymath/standards/compare/${TARGET_SHA}...main") || { + log "ERROR: could not prove target ${TARGET_SHA} is reachable from standards main; refusing propagation." + return 1 + } + status=$(printf '%s' "$body" | sed -n 's/.*"status"[[:space:]]*:[[:space:]]*"\([a-z]*\)".*/\1/p' | head -n1) + case "$status" in + identical|ahead) return 0 ;; + *) + log "ERROR: target ${TARGET_SHA} is not reachable from standards main (compare status: ${status:-unknown}); refusing propagation." + return 1 + ;; + esac +} + +validate_target || exit 2 + # --------------------------------------------------------------------------- # Per-file rewrite (the unit-testable core) # --------------------------------------------------------------------------- diff --git a/scripts/tests/propagate-workflow-pins-test.sh b/scripts/tests/propagate-workflow-pins-test.sh index 497d0a8f9..d27a4c74f 100755 --- a/scripts/tests/propagate-workflow-pins-test.sh +++ b/scripts/tests/propagate-workflow-pins-test.sh @@ -12,7 +12,25 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROP="$SCRIPT_DIR/../propagate-workflow-pins.sh" OLD="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -TARGET="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + +# A real local commit graph makes reachability part of every test. The +# propagation primitive must reject a SHA that merely exists on a feature +# branch: GitHub cannot resolve such a SHA as a cross-repo reusable workflow. +UPSTREAM="$TEST_DIR/standards" +git init -q -b main "$UPSTREAM" +git -C "$UPSTREAM" config user.email t@t +git -C "$UPSTREAM" config user.name t +touch "$UPSTREAM/reusable.yml" +git -C "$UPSTREAM" add reusable.yml +git -C "$UPSTREAM" commit -q -m main +TARGET=$(git -C "$UPSTREAM" rev-parse HEAD) +git -C "$UPSTREAM" checkout -q -b feature +touch "$UPSTREAM/feature-only" +git -C "$UPSTREAM" add feature-only +git -C "$UPSTREAM" commit -q -m feature +ORPHAN=$(git -C "$UPSTREAM" rev-parse HEAD) +git -C "$UPSTREAM" checkout -q main +export STANDARDS_DIR="$UPSTREAM" PASS=0; TOTAL=0 @@ -90,6 +108,16 @@ OUT=$(bash "$PROP" --to "$TARGET" "$ROOT") try "parent-dir mode sees repoA" contains repoA "$OUT" try "parent-dir mode sees repoB" contains repoB "$OUT" +# ── 8. Existing but non-mainline target is refused before any rewrite ─────── +R="$TEST_DIR/orphan"; mk_consumer "$R" +set +e +OUT=$(bash "$PROP" --fix --to "$ORPHAN" "$R" 2>&1) +RC=$? +set -e +try "feature-only target is rejected" test "$RC" -eq 2 +try "rejected target leaves consumer unchanged" file_has "$R/.github/workflows/governance.yml" "governance-reusable.yml@${OLD}" +try "rejection explains default-branch reachability" contains "not reachable" "$OUT" + echo "----------------------------------------" echo "$PASS/$TOTAL test cases passed." [ "$PASS" -eq "$TOTAL" ] || { echo "Some propagation tests FAILED."; exit 1; } From e143a15c56e1350e804b2a61053a540f95c22586 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:28:10 +0100 Subject: [PATCH 2/3] fix(ci): check every local standards main ref --- scripts/propagate-workflow-pins.sh | 27 +++++++++++-------- scripts/tests/propagate-workflow-pins-test.sh | 14 ++++++++++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/scripts/propagate-workflow-pins.sh b/scripts/propagate-workflow-pins.sh index 57d752b1e..1932809ae 100755 --- a/scripts/propagate-workflow-pins.sh +++ b/scripts/propagate-workflow-pins.sh @@ -115,27 +115,32 @@ validate_target() { } local sd="${STANDARDS_DIR:-$HOME/standards}" ref head gd + local local_main_seen=false if git -C "$sd" cat-file -e "${TARGET_SHA}^{commit}" >/dev/null 2>&1; then for ref in refs/remotes/origin/main refs/heads/main; do if head=$(git -C "$sd" rev-parse --verify "${ref}^{commit}" 2>/dev/null); then + local_main_seen=true if git -C "$sd" merge-base --is-ancestor "$TARGET_SHA" "$head"; then return 0 fi - - # A complete local graph gives a conclusive negative. A shallow or - # partial clone does not; let the server settle that case below. - gd=$(git -C "$sd" rev-parse --absolute-git-dir 2>/dev/null || true) - if [ -n "$gd" ] && [ ! -e "$gd/shallow" ] && - [ "$(git -C "$sd" config --get remote.origin.promisor 2>/dev/null || true)" != true ] && - [ -z "$(git -C "$sd" config --get remote.origin.partialclonefilter 2>/dev/null || true)" ]; then - log "ERROR: target ${TARGET_SHA} exists but is not reachable from local standards main (${head})." - return 1 - fi - break fi done + + # Only reject after every usable local main ref has been checked. A + # shallow or partial graph is not conclusive, so defer that case to the + # authoritative server comparison below. + gd=$(git -C "$sd" rev-parse --absolute-git-dir 2>/dev/null || true) + if [[ "$local_main_seen" == true && -n "$gd" && ! -e "$gd/shallow" ]] && + [[ "$(git -C "$sd" config --get remote.origin.promisor 2>/dev/null || true)" != true ]] && + [[ -z "$(git -C "$sd" config --get remote.origin.partialclonefilter 2>/dev/null || true)" ]]; then + log "ERROR: target ${TARGET_SHA} exists but is not reachable from any available local standards main ref." + return 1 + fi fi + # Neither usable local main ref proved reachability. Local refs can be stale, + # so only the authoritative server comparison may return a negative result. + local api="${STANDARDS_REACHABILITY_API_BASE:-https://api.github.com}" local -a auth=() [ -n "${GITHUB_TOKEN:-}" ] && auth=(-H "Authorization: Bearer ${GITHUB_TOKEN}") diff --git a/scripts/tests/propagate-workflow-pins-test.sh b/scripts/tests/propagate-workflow-pins-test.sh index d27a4c74f..153777493 100755 --- a/scripts/tests/propagate-workflow-pins-test.sh +++ b/scripts/tests/propagate-workflow-pins-test.sh @@ -118,6 +118,20 @@ try "feature-only target is rejected" test "$RC" -eq 2 try "rejected target leaves consumer unchanged" file_has "$R/.github/workflows/governance.yml" "governance-reusable.yml@${OLD}" try "rejection explains default-branch reachability" contains "not reachable" "$OUT" +# ── 9. A stale origin/main must not hide a newer local main ────────────────── +git -C "$UPSTREAM" update-ref refs/remotes/origin/main "$TARGET" +touch "$UPSTREAM/mainline-newer" +git -C "$UPSTREAM" add mainline-newer +git -C "$UPSTREAM" commit -q -m mainline-newer +NEWER_TARGET=$(git -C "$UPSTREAM" rev-parse HEAD) +R="$TEST_DIR/stale-origin"; mk_consumer "$R" +set +e +OUT=$(bash "$PROP" --to "$NEWER_TARGET" "$R" 2>&1) +RC=$? +set -e +try "newer local main target survives stale origin/main" test "$RC" -eq 0 +try "stale origin/main does not report unreachable" not_contains "not reachable" "$OUT" + echo "----------------------------------------" echo "$PASS/$TOTAL test cases passed." [ "$PASS" -eq "$TOTAL" ] || { echo "Some propagation tests FAILED."; exit 1; } From 302925e66777a597c8fe350c0d4d5e4230c97b3f Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 4 Sep 2026 18:56:08 +0100 Subject: [PATCH 3/3] fix(ci): detect shallow linked worktrees --- scripts/propagate-workflow-pins.sh | 6 ++--- scripts/tests/propagate-workflow-pins-test.sh | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/scripts/propagate-workflow-pins.sh b/scripts/propagate-workflow-pins.sh index 1932809ae..c27f72794 100755 --- a/scripts/propagate-workflow-pins.sh +++ b/scripts/propagate-workflow-pins.sh @@ -114,7 +114,7 @@ validate_target() { return 1 } - local sd="${STANDARDS_DIR:-$HOME/standards}" ref head gd + local sd="${STANDARDS_DIR:-$HOME/standards}" ref head shallow local local_main_seen=false if git -C "$sd" cat-file -e "${TARGET_SHA}^{commit}" >/dev/null 2>&1; then for ref in refs/remotes/origin/main refs/heads/main; do @@ -129,8 +129,8 @@ validate_target() { # Only reject after every usable local main ref has been checked. A # shallow or partial graph is not conclusive, so defer that case to the # authoritative server comparison below. - gd=$(git -C "$sd" rev-parse --absolute-git-dir 2>/dev/null || true) - if [[ "$local_main_seen" == true && -n "$gd" && ! -e "$gd/shallow" ]] && + shallow=$(git -C "$sd" rev-parse --is-shallow-repository 2>/dev/null || printf 'true') + if [[ "$local_main_seen" == true && "$shallow" != true ]] && [[ "$(git -C "$sd" config --get remote.origin.promisor 2>/dev/null || true)" != true ]] && [[ -z "$(git -C "$sd" config --get remote.origin.partialclonefilter 2>/dev/null || true)" ]]; then log "ERROR: target ${TARGET_SHA} exists but is not reachable from any available local standards main ref." diff --git a/scripts/tests/propagate-workflow-pins-test.sh b/scripts/tests/propagate-workflow-pins-test.sh index 153777493..977bf00c5 100755 --- a/scripts/tests/propagate-workflow-pins-test.sh +++ b/scripts/tests/propagate-workflow-pins-test.sh @@ -132,6 +132,32 @@ set -e try "newer local main target survives stale origin/main" test "$RC" -eq 0 try "stale origin/main does not report unreachable" not_contains "not reachable" "$OUT" +# ── 10. A linked worktree retains the shared clone's shallow status ──────────── +SHALLOW_REMOTE="$TEST_DIR/standards-remote.git" +SHALLOW_CLONE="$TEST_DIR/standards-shallow" +SHALLOW_WORKTREE="$TEST_DIR/standards-shallow-worktree" +FAKE_BIN="$TEST_DIR/fake-bin" +git init -q --bare "$SHALLOW_REMOTE" +git -C "$UPSTREAM" push -q "$SHALLOW_REMOTE" main +git -C "$SHALLOW_REMOTE" symbolic-ref HEAD refs/heads/main +git clone -q --depth 1 "file://$SHALLOW_REMOTE" "$SHALLOW_CLONE" +git -C "$SHALLOW_CLONE" fetch -q origin "$TARGET" +git -C "$SHALLOW_CLONE" worktree add -q -b reachability-test "$SHALLOW_WORKTREE" HEAD +mkdir -p "$FAKE_BIN" +cat > "$FAKE_BIN/curl" <<'EOF' +#!/usr/bin/env sh +printf '%s\n' '{"status":"ahead"}' +EOF +chmod +x "$FAKE_BIN/curl" +R="$TEST_DIR/shallow-consumer"; mk_consumer "$R" +set +e +OUT=$(STANDARDS_DIR="$SHALLOW_WORKTREE" PATH="$FAKE_BIN:$PATH" \ + bash "$PROP" --to "$TARGET" "$R" 2>&1) +RC=$? +set -e +try "linked shallow worktree defers to server reachability" test "$RC" -eq 0 +try "linked shallow worktree does not report unreachable" not_contains "not reachable" "$OUT" + echo "----------------------------------------" echo "$PASS/$TOTAL test cases passed." [ "$PASS" -eq "$TOTAL" ] || { echo "Some propagation tests FAILED."; exit 1; }