Read the force marker as part of the refspec, not of the branch
`git push origin +main` put the destination through the branch policy as "+main", which matched no entry, so the one spelling that escaped was the destructive one. `+refs/heads/main` escaped the same way, since the prefix also stopped the refs/heads/ strip from landing. One leading `+` now comes off before the destination is read. A `+` on a branch nothing protects is still an ordinary push, and the test says so - otherwise the strip could be doing the refusing rather than the policy.
This commit is contained in:
@@ -227,6 +227,11 @@ dejima_push_verdict() { # <repo-dir> <git argv...>
|
||||
fi
|
||||
local refspec
|
||||
for refspec in "${refspecs[@]}"; do
|
||||
# One leading `+` is the force marker, and it belongs to the refspec
|
||||
# rather than to the branch - so `git push origin +main` names main and
|
||||
# was compared as "+main", which matched no policy entry. The escaping
|
||||
# form was the destructive one.
|
||||
refspec="${refspec#+}"
|
||||
case "$refspec" in
|
||||
*:*) branch="${refspec##*:}" ;;
|
||||
HEAD) branch="$("$DEJIMA_GUARD_GIT" -C "$repo_dir" branch --show-current 2>/dev/null)" ;;
|
||||
@@ -475,6 +480,7 @@ _dejima_forge_path_verdict() {
|
||||
# value of a field flag - `-f query=mutation{...}` - rather than as
|
||||
# an argument of its own. Matched before the brace test below,
|
||||
# which a document would otherwise satisfy.
|
||||
|
||||
#
|
||||
# Both boundaries are anything that cannot continue an
|
||||
# identifier, rather than whitespace and a brace. GraphQL treats
|
||||
|
||||
+18
-2
@@ -3921,13 +3921,28 @@ _guard_repo() {
|
||||
# Each of these is the same push wearing different clothes. The hook this
|
||||
# supplements matched a regex over a command string and had to anticipate
|
||||
# the spelling; argv does not care.
|
||||
for form in "push origin main" "push origin HEAD:main" "push --repo=origin main" \
|
||||
"push --repo origin main" "push -o ci.skip origin main"; do
|
||||
#
|
||||
# `+` is the force marker and belongs to the refspec, not to the branch, so
|
||||
# the destination has to be read with it removed - `git push origin +main`
|
||||
# was compared as "+main" and matched no policy entry, which left the
|
||||
# force-push spelling as the one that went through.
|
||||
for form in "push origin main" "push origin HEAD:main" \
|
||||
"push --repo=origin main" "push --repo origin main" \
|
||||
"push -o ci.skip origin main" \
|
||||
"push origin +main" "push origin +refs/heads/main" \
|
||||
"push origin +feature:main" "push --force origin main" \
|
||||
"push --force-with-lease origin main" "push origin :main"; do
|
||||
# shellcheck disable=SC2086
|
||||
run _git_guard "$repo" $form
|
||||
[[ "$output" == *"aren't allowed in the sandbox"* ]] \
|
||||
|| { echo "not blocked: git $form -> $output"; return 1; }
|
||||
done
|
||||
|
||||
# A `+` on a branch that is not protected is still an ordinary push, so the
|
||||
# strip above cannot be doing the refusing.
|
||||
run _git_guard "$repo" push origin +feature
|
||||
[[ "$output" != *"Blocked by dejima"* ]] \
|
||||
|| { echo "a forced push to an unprotected branch was refused: $output"; return 1; }
|
||||
}
|
||||
|
||||
@test "the git guard leaves everything that is not a blocked push alone" {
|
||||
@@ -4119,6 +4134,7 @@ _guard_repo() {
|
||||
"git push" "git push origin" "git push origin HEAD" \
|
||||
"git push -o ci.skip origin main" "git push --push-option=x origin main" \
|
||||
"git push --repo origin main" "git push --repo=origin main" \
|
||||
"git push origin +main" \
|
||||
"git push --receive-pack /bin/true origin main" \
|
||||
"git push --all origin" "git push --mirror origin" \
|
||||
"git push origin feature main" \
|
||||
|
||||
Reference in New Issue
Block a user