Scope the compatibility bump's git identity to its own commit

`ci/bump-tested-up-to.sh` ran `git config user.name "compatibility check"`
before committing. That writes .git/config and outlives the script, so from
the first run onward every commit in that working copy is authored by
"compatibility check <noreply@localhost>" with no Co-Authored-By trailer —
including a release made by a person days later about something else.

git announces an identity it cannot FIND and says nothing about one that is
wrong, so the missing case is loud and this one is silent. Nothing fails,
nothing warns, and the author is only visible to somebody reading `git log`
for another reason. Measured across the family by the Nolimit Security
session: six misattributed hand commits in one sibling including two
releases, two in another, one in a third. This tree was clean — no local
identity, 0 misattributed — and one run of the script away.

The commit still signs itself as the robot, which is right: that one is not
a person's. It just does it with `git -c … commit`, which configures the
command and not the clone.

Guarded in ci/static.sh, because the fix is one line and reverting it would
be invisible for exactly as long as nobody reads an author field. Widened
past what was reported: the pattern accepts any scope flag, since --global
is the same fault one scope wider and reaches every repository on the box.

Proven with a full matrix rather than one trigger — no flag, --local,
--global and --system each go red with the named message and exit 1; a
commented mention, `git -c user.name=… commit`, `git config core.autocrlf`
and `git config --global core.pager` all stay green. The correct form being
a control matters: a check that flagged the fix would get one of the two
deleted. Five of those assertions are now in ci/selftest.sh (36 total), each
with a landing check that the plant is in the file before its verdict is
believed, and the passing line carries the script count — "every script is
clean" reads the same over zero files as over eleven.

ci/ ships nothing, so there is no version bump and no release here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kristianwind
2026-09-25 12:17:48 +02:00
co-authored by Claude Opus 5
parent f6ea46a93e
commit cc0aaf9272
3 changed files with 86 additions and 3 deletions
+8 -3
View File
@@ -60,10 +60,15 @@ done
git diff --quiet && { echo "Nothing actually changed on disk — check the sed patterns." >&2; exit 1; } git diff --quiet && { echo "Nothing actually changed on disk — check the sed patterns." >&2; exit 1; }
branch="compat/tested-up-to-$current_wp-wc-$current_wc" branch="compat/tested-up-to-$current_wp-wc-$current_wc"
git config user.name "compatibility check"
git config user.email "noreply@localhost"
git checkout -b "$branch" git checkout -b "$branch"
git commit -am "Tested against WordPress $current_wp and WooCommerce $current_wc # The identity is scoped to THIS commit with `git -c`, never written to the
# clone. `git config user.name` persists in .git/config, so every later commit
# in this working copy — a release days afterwards, by a person — would be
# authored by the robot with no Co-Authored-By trailer. git announces a
# MISSING identity and says nothing about a wrong one, so that is silent.
# Signing this one commit as the robot is right: it is not a person's.
git -c user.name="compatibility check" -c user.email="noreply@localhost" \
commit -am "Tested against WordPress $current_wp and WooCommerce $current_wc
$(printf '%s\n' "${changed[@]}") $(printf '%s\n' "${changed[@]}")
+48
View File
@@ -205,6 +205,54 @@ ann=$(ci_php ci/check-textdomain.php "$TEXT_DOMAIN" selftest-dotted 2>&1 \
&& ok "the annotated path exists on disk: $ann" \ && ok "the annotated path exists on disk: $ann" \
|| bad "the annotated path is not a file: '$ann'" || bad "the annotated path is not a file: '$ann'"
# ------------------------------------------------------- the clone's git identity
# 🔴 Grade 2 evidence: the exact line ci/bump-tested-up-to.sh carried until
# 2026-09-25, not an arbitrary `git config`. That line writes .git/config, so
# every later commit in the clone — a release, by a person — is authored by the
# robot with no trailer. Six such commits in one sibling plugin, two in
# another. git warns about an identity it cannot FIND and never about a wrong
# one, so nothing in the repository ever says so.
echo
echo "→ ci/static.sh must catch a ci/ script that configures the clone"
cd "$work/repo"
cp ci/build-zip.sh "$work/build-zip.orig"
for scope in '' '--local' '--global'; do
cp "$work/build-zip.orig" ci/build-zip.sh
line="git config ${scope:+$scope }user.name \"compatibility check\""
printf '%s\n' "$line" >> ci/build-zip.sh
# The plant must BE there before any verdict is believed. A `printf` that
# silently went somewhere else leaves the control state, and every assertion
# below then passes while proving nothing — a hollow probe wearing the
# costume of the most rigorous thing in the suite.
if [ "$(grep -cF "$line" ci/build-zip.sh)" -lt 1 ]; then
bad "could not stage the git-identity fixture for '${scope:-no flag}'"
continue
fi
id_out=$(./ci/static.sh 2>&1 || true)
if printf '%s' "$id_out" | grep -q 'sets a git identity that outlives it'; then
ok "flagged git config ${scope:-(no flag)} user.name"
else
bad "NOT FLAGGED: git config ${scope:-(no flag)} user.name — the clone keeps the robot's name"
fi
done
# The correct form must NOT fire, or the fix trips the check that exists to
# protect it and the next person deletes one of the two.
cp "$work/build-zip.orig" ci/build-zip.sh
printf '%s\n' 'git -c user.name="compatibility check" -c user.email=x commit -m y' >> ci/build-zip.sh
scoped_out=$(./ci/static.sh 2>&1 || true)
printf '%s' "$scoped_out" | grep -q 'sets a git identity that outlives it' \
&& bad "FALSE POSITIVE on 'git -c user.name=… commit' — that is the fix, not the fault" \
|| ok "ignored the scoped 'git -c … commit' form"
cp "$work/build-zip.orig" ci/build-zip.sh
# And the passing line must carry a number: "every script is clean" reads the
# same over zero files as over eleven.
clean_out=$(./ci/static.sh 2>&1 || true)
printf '%s' "$clean_out" | grep -qE "^ [0-9]+ scripts in ci/ leave the clone's git identity alone" \
&& ok "the git-identity check reports how many scripts it read" \
|| bad "the git-identity check printed no count — it cannot tell 11 scripts from 0"
# ------------------------------------------------------------------- plugin.conf # ------------------------------------------------------------------- plugin.conf
echo echo
echo "→ the floors must be required, not defaulted" echo "→ the floors must be required, not defaulted"
+30
View File
@@ -307,6 +307,36 @@ elif [ "$fails" = "$before" ]; then
echo " $secrets_scanned tracked files read, nothing that looks like a key or a private key" echo " $secrets_scanned tracked files read, nothing that looks like a key or a private key"
fi fi
ci_step "no ci/ script configures the clone it was handed"
# `git config user.name` writes .git/config and OUTLIVES the script. A helper
# that sets an identity before committing therefore renames every later commit
# in that working copy, including a release made by a person days afterwards
# and with no Co-Authored-By trailer. git announces an identity it cannot FIND
# and says nothing about one that is wrong, so the missing case is loud and
# this one is silent: nothing fails, nothing warns, and the author is only
# visible to somebody reading `git log` for another reason.
#
# ci/bump-tested-up-to.sh did this until it was scoped to `git -c … commit`,
# which still signs its own commit as the robot — correct, that one is not a
# person's — without touching the clone. Measured across the family: six
# misattributed hand commits in one sibling, two in another, including
# releases. This tree was clean and one run away.
#
# Any flag, not just --local: --global sets the whole machine's identity, which
# is the same fault one scope wider and reaches every repository on the box.
#
# The rule: a script may configure ITSELF, never the working copy it was
# handed. Reported by the Nolimit Security session 2026-09-25.
scripts_scanned=$(git ls-files 'ci/*.sh' | wc -l)
if [ "$scripts_scanned" -lt 1 ]; then
note_fail "The git-identity scan found no ci/*.sh files at all, so it proved nothing."
elif git ls-files -z 'ci/*.sh' \
| xargs -0 grep -nE '^[^#]*git config([[:space:]]+--[a-z-]+)*[[:space:]]+user\.'; then
note_fail "A ci/ script sets a git identity that outlives it. Scope it to the one commit with 'git -c user.name=… commit', which does not write .git/config."
else
echo " $scripts_scanned scripts in ci/ leave the clone's git identity alone"
fi
ci_step "no placeholders left in the plugin header" ci_step "no placeholders left in the plugin header"
# The header is the plugin's business card: wp-admin shows the author and the # The header is the plugin's business card: wp-admin shows the author and the
# links to whoever installs it, so a placeholder there survives for as long as # links to whoever installs it, so a placeholder there survives for as long as