Merge pull request #43 from kristianwind/scope-git-identity-to-its-own-commit
Scope the compatibility bump's git identity to its own commit
This commit is contained in:
@@ -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[@]}")
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user