fix(git-tools): bind PR edits to acting identity (#1080)
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
coder3
2026-08-12 21:08:34 -05:00
parent 25b055f105
commit ce6d735128
2 changed files with 172 additions and 135 deletions
+92 -66
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# pr-edit.sh - Edit a pull request on GitHub or Gitea
# Usage: pr-edit.sh -n <pr_number> [-t <title>] [-b <body>] [-B <base>] [--draft|--ready] [--login <name>]
# Usage: pr-edit.sh -n <pr_number> [-t <title>] [-b <body>] [-B <base>] [--draft|--ready] [--login <name>] [-r owner/repo] [-H host]
set -euo pipefail
@@ -14,6 +14,14 @@ BODY=""
BASE_BRANCH=""
DRAFT_MODE=""
LOGIN_OVERRIDE=""
REPO_OVERRIDE=""
HOST_OVERRIDE=""
AUTH_CONFIG=""
cleanup() {
[[ -z "$AUTH_CONFIG" ]] || rm -f -- "$AUTH_CONFIG"
}
trap cleanup EXIT HUP INT TERM
usage() {
cat <<EOF
@@ -28,7 +36,9 @@ Options:
-B, --base BRANCH New base branch
--draft Mark the pull request as draft
--ready Mark the pull request ready for review
--login NAME Gitea tea login (must match the repository host)
-l, --login NAME Gitea login (must authenticate as MOSAIC_GIT_IDENTITY)
-r, --repo OWNER/REPO Explicit target repository
-H, --host HOST Explicit Gitea host (required with --repo off-host)
-h, --help Show this help message
EOF
exit "${1:-1}"
@@ -36,43 +46,21 @@ EOF
while [[ $# -gt 0 ]]; do
case "$1" in
-n|--number)
PR_NUMBER="${2:-}"
shift 2
;;
-t|--title)
TITLE="${2:-}"
shift 2
;;
-b|--body)
BODY="${2:-}"
shift 2
;;
-B|--base)
BASE_BRANCH="${2:-}"
shift 2
;;
-n|--number) PR_NUMBER="${2:-}"; shift 2 ;;
-t|--title) TITLE="${2:-}"; shift 2 ;;
-b|--body) BODY="${2:-}"; shift 2 ;;
-B|--base) BASE_BRANCH="${2:-}"; shift 2 ;;
--draft)
[[ "$DRAFT_MODE" != "ready" ]] || { echo "Error: --draft and --ready are mutually exclusive" >&2; exit 1; }
DRAFT_MODE="draft"
shift
;;
DRAFT_MODE="draft"; shift ;;
--ready)
[[ "$DRAFT_MODE" != "draft" ]] || { echo "Error: --draft and --ready are mutually exclusive" >&2; exit 1; }
DRAFT_MODE="ready"
shift
;;
--login)
LOGIN_OVERRIDE="${2:-}"
shift 2
;;
-h|--help)
usage 0
;;
*)
echo "Unknown option: $1" >&2
usage
;;
DRAFT_MODE="ready"; shift ;;
-l|--login) LOGIN_OVERRIDE="${2:-}"; shift 2 ;;
-r|--repo) REPO_OVERRIDE="${2:-}"; shift 2 ;;
-H|--host) HOST_OVERRIDE="${2:-}"; shift 2 ;;
-h|--help) usage 0 ;;
*) echo "Unknown option: $1" >&2; usage ;;
esac
done
@@ -82,8 +70,16 @@ if [[ -z "$TITLE" && -z "$BODY" && -z "$BASE_BRANCH" && -z "$DRAFT_MODE" ]]; the
echo "Error: At least one edit option is required" >&2
exit 1
fi
[[ -z "$REPO_OVERRIDE" || "$REPO_OVERRIDE" =~ ^[^/[:space:]]+/[^/[:space:]]+$ ]] || {
echo "Error: --repo must be OWNER/REPO" >&2
exit 1
}
PLATFORM=$(detect_platform)
if [[ -n "$HOST_OVERRIDE" || -n "$REPO_OVERRIDE" ]]; then
PLATFORM="gitea"
else
PLATFORM=$(detect_platform)
fi
case "$PLATFORM" in
github)
@@ -102,44 +98,74 @@ case "$PLATFORM" in
fi
;;
gitea)
HOST=$(get_remote_host) || { echo "Error: Could not resolve Gitea host from remote" >&2; exit 1; }
REPO_SLUG=$(get_repo_slug) || { echo "Error: Could not resolve Gitea repo slug from remote" >&2; exit 1; }
if [[ -n "$LOGIN_OVERRIDE" ]]; then
GITEA_LOGIN="$LOGIN_OVERRIDE"
else
GITEA_LOGIN=$(get_gitea_login) || { echo "Error: Could not resolve Gitea login for remote host" >&2; exit 1; }
fi
# Bind the credential to the explicitly selected login and repository host.
TOKEN=$(get_gitea_token_for_login "$GITEA_LOGIN" "$HOST") || {
echo "Error: Could not resolve token for Gitea login '$GITEA_LOGIN' on '$HOST'" >&2
IDENTITY="${MOSAIC_GIT_IDENTITY:-}"
[[ -n "$IDENTITY" ]] || {
echo "Error: MOSAIC_GIT_IDENTITY is required for a mutating Gitea operation" >&2
exit 1
}
HOST="${HOST_OVERRIDE:-}"
if [[ -z "$HOST" ]]; then
HOST=$(get_remote_host) || {
echo "Error: Could not resolve Gitea host; pass --host with --repo" >&2
exit 1
}
fi
HOST="${HOST#http://}"; HOST="${HOST#https://}"; HOST="${HOST%%/*}"
REPO_SLUG="${REPO_OVERRIDE:-}"
if [[ -z "$REPO_SLUG" ]]; then
REPO_SLUG=$(get_repo_slug) || { echo "Error: Could not resolve Gitea repo slug from remote" >&2; exit 1; }
fi
if [[ -n "$LOGIN_OVERRIDE" ]]; then
GITEA_LOGIN_NAME="$LOGIN_OVERRIDE"
elif [[ -n "${GITEA_LOGIN:-}" ]]; then
GITEA_LOGIN_NAME="$GITEA_LOGIN"
else
echo "Error: --login (or GITEA_LOGIN) is required; refusing host-first login selection" >&2
exit 1
fi
TOKEN=$(get_gitea_token_for_login "$GITEA_LOGIN_NAME" "$HOST") || {
echo "Error: login '$GITEA_LOGIN_NAME' is not configured for target host '$HOST'" >&2
exit 1
}
AUTHENTICATED_USER=$(get_gitea_authenticated_user "$GITEA_LOGIN_NAME") || {
echo "Error: could not authenticate Gitea login '$GITEA_LOGIN_NAME'" >&2
exit 1
}
[[ "$AUTHENTICATED_USER" == "$IDENTITY" ]] || {
echo "Error: Gitea login '$GITEA_LOGIN_NAME' authenticates as '$AUTHENTICATED_USER', not MOSAIC_GIT_IDENTITY '$IDENTITY'" >&2
exit 1
}
AUTH_CONFIG=$(gitea_write_auth_config "$TOKEN") || {
echo "Error: could not stage private Gitea authentication" >&2
exit 1
}
unset TOKEN
API_BASE="https://${HOST}/api/v1/repos/${REPO_SLUG}"
# Preflight the explicit host/repo pair before any mutation. This prevents
# a slug inferred from one checkout being combined with another host.
curl -fsS --config "$AUTH_CONFIG" -H "User-Agent: mosaic-pr-edit" "$API_BASE" >/dev/null || {
echo "Error: target repository preflight failed for https://${HOST}/${REPO_SLUG}" >&2
exit 1
}
PAYLOAD=$(TITLE="$TITLE" BODY="$BODY" BASE_BRANCH="$BASE_BRANCH" DRAFT_MODE="$DRAFT_MODE" python3 - <<'PY'
import json
import os
payload = {}
if os.environ["TITLE"]:
payload["title"] = os.environ["TITLE"]
if os.environ["BODY"]:
payload["body"] = os.environ["BODY"]
if os.environ["BASE_BRANCH"]:
payload["base"] = os.environ["BASE_BRANCH"]
if os.environ["DRAFT_MODE"]:
payload["draft"] = os.environ["DRAFT_MODE"] == "draft"
if os.environ["TITLE"]: payload["title"] = os.environ["TITLE"]
if os.environ["BODY"]: payload["body"] = os.environ["BODY"]
if os.environ["BASE_BRANCH"]: payload["base"] = os.environ["BASE_BRANCH"]
if os.environ["DRAFT_MODE"]: payload["draft"] = os.environ["DRAFT_MODE"] == "draft"
print(json.dumps(payload))
PY
)
curl -fsS -X PATCH \
-H "User-Agent: mosaic-pr-edit" \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
"https://${HOST}/api/v1/repos/${REPO_SLUG}/pulls/${PR_NUMBER}"
echo "Updated Gitea pull request #$PR_NUMBER using login '$GITEA_LOGIN'" >&2
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
curl -fsS --config "$AUTH_CONFIG" -X PATCH \
-H "User-Agent: mosaic-pr-edit" -H "Content-Type: application/json" \
-d "$PAYLOAD" "$API_BASE/pulls/${PR_NUMBER}"
echo "Updated Gitea pull request #$PR_NUMBER as '$AUTHENTICATED_USER'" >&2
;;
*) echo "Error: Could not detect git platform" >&2; exit 1 ;;
esac