Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9325f54fb | ||
|
|
ce6d735128 | ||
|
|
25b055f105 | ||
|
|
4f0d3e6e25 |
+185
@@ -0,0 +1,185 @@
|
|||||||
|
#!/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>] [-r owner/repo] [-H host]
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
# shellcheck source=detect-platform.sh
|
||||||
|
source "$SCRIPT_DIR/detect-platform.sh"
|
||||||
|
|
||||||
|
PR_NUMBER=""
|
||||||
|
TITLE=""
|
||||||
|
BODY=""
|
||||||
|
BASE_BRANCH=""
|
||||||
|
DRAFT_MODE=""
|
||||||
|
LOGIN_OVERRIDE=""
|
||||||
|
REPO_OVERRIDE=""
|
||||||
|
HOST_OVERRIDE=""
|
||||||
|
AUTH_CONFIG=""
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
[[ -z "$AUTH_CONFIG" ]] || rm -f -- "$AUTH_CONFIG"
|
||||||
|
}
|
||||||
|
terminate() {
|
||||||
|
local signal="$1"
|
||||||
|
trap - "$signal"
|
||||||
|
cleanup
|
||||||
|
kill -s "$signal" "$$"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
trap 'terminate HUP' HUP
|
||||||
|
trap 'terminate INT' INT
|
||||||
|
trap 'terminate TERM' TERM
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $(basename "$0") [OPTIONS]
|
||||||
|
|
||||||
|
Edit a pull request on the current repository (Gitea or GitHub).
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-n, --number NUMBER Pull request number (required)
|
||||||
|
-t, --title TITLE New title
|
||||||
|
-b, --body BODY New body/description
|
||||||
|
-B, --base BRANCH New base branch
|
||||||
|
--draft Mark the pull request as draft
|
||||||
|
--ready Mark the pull request ready for review
|
||||||
|
-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}"
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ;;
|
||||||
|
--draft)
|
||||||
|
[[ "$DRAFT_MODE" != "ready" ]] || { echo "Error: --draft and --ready are mutually exclusive" >&2; exit 1; }
|
||||||
|
DRAFT_MODE="draft"; shift ;;
|
||||||
|
--ready)
|
||||||
|
[[ "$DRAFT_MODE" != "draft" ]] || { echo "Error: --draft and --ready are mutually exclusive" >&2; exit 1; }
|
||||||
|
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
|
||||||
|
|
||||||
|
[[ -n "$PR_NUMBER" ]] || { echo "Error: Pull request number is required (-n)" >&2; exit 1; }
|
||||||
|
[[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || { echo "Error: Pull request number must be a positive integer" >&2; exit 1; }
|
||||||
|
if [[ -z "$TITLE" && -z "$BODY" && -z "$BASE_BRANCH" && -z "$DRAFT_MODE" ]]; then
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -n "$HOST_OVERRIDE" || -n "$REPO_OVERRIDE" ]]; then
|
||||||
|
PLATFORM="gitea"
|
||||||
|
else
|
||||||
|
PLATFORM=$(detect_platform)
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$PLATFORM" in
|
||||||
|
github)
|
||||||
|
[[ -z "$LOGIN_OVERRIDE" ]] || { echo "Error: --login is only valid for Gitea" >&2; exit 1; }
|
||||||
|
if [[ -n "$TITLE" || -n "$BODY" || -n "$BASE_BRANCH" ]]; then
|
||||||
|
CMD=(gh pr edit "$PR_NUMBER")
|
||||||
|
[[ -n "$TITLE" ]] && CMD+=(--title "$TITLE")
|
||||||
|
[[ -n "$BODY" ]] && CMD+=(--body "$BODY")
|
||||||
|
[[ -n "$BASE_BRANCH" ]] && CMD+=(--base "$BASE_BRANCH")
|
||||||
|
"${CMD[@]}"
|
||||||
|
fi
|
||||||
|
if [[ "$DRAFT_MODE" == "draft" ]]; then
|
||||||
|
gh pr ready "$PR_NUMBER" --undo
|
||||||
|
elif [[ "$DRAFT_MODE" == "ready" ]]; then
|
||||||
|
gh pr ready "$PR_NUMBER"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
gitea)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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"
|
||||||
|
# Resolve identity through the SAME private curl config used for the
|
||||||
|
# mutation. Tea login names are globally scoped and can be duplicated
|
||||||
|
# across hosts; a separate `tea api --login NAME` could validate another
|
||||||
|
# credential than this host-bound token.
|
||||||
|
AUTHENTICATED_USER=$(curl -fsS --config "$AUTH_CONFIG" -H "User-Agent: mosaic-pr-edit" "$API_BASE/user" \
|
||||||
|
| python3 -c 'import json,sys; value=json.load(sys.stdin).get("login"); print(value) if isinstance(value,str) and value else sys.exit(1)') || {
|
||||||
|
echo "Error: could not authenticate the host-bound credential for '$GITEA_LOGIN_NAME'" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
[[ "$AUTHENTICATED_USER" == "$IDENTITY" ]] || {
|
||||||
|
echo "Error: host-bound credential authenticates as '$AUTHENTICATED_USER', not MOSAIC_GIT_IDENTITY '$IDENTITY'" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
REPO_API="$API_BASE/repos/${REPO_SLUG}"
|
||||||
|
curl -fsS --config "$AUTH_CONFIG" -H "User-Agent: mosaic-pr-edit" "$REPO_API" >/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"
|
||||||
|
print(json.dumps(payload))
|
||||||
|
PY
|
||||||
|
)
|
||||||
|
curl -fsS --config "$AUTH_CONFIG" -X PATCH \
|
||||||
|
-H "User-Agent: mosaic-pr-edit" -H "Content-Type: application/json" \
|
||||||
|
-d "$PAYLOAD" "$REPO_API/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
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Regression harness for #701: -h/--help must exit 0, bad args must still exit nonzero.
|
# Regression harness for #701: -h/--help must exit 0, bad args must still exit nonzero.
|
||||||
#
|
#
|
||||||
# Covers the 7 wrappers whose usage() previously hard-coded `exit 1`, so every
|
# Covers wrappers whose usage() previously hard-coded `exit 1`, so every
|
||||||
# --help invocation exited nonzero and logged a phantom isError across fleet lanes.
|
# --help invocation exited nonzero and logged a phantom isError across fleet lanes.
|
||||||
# Asserts, per wrapper:
|
# Asserts, per wrapper:
|
||||||
# 1. `--help` exits 0 and prints usage.
|
# 1. `--help` exits 0 and prints usage.
|
||||||
@@ -18,6 +18,7 @@ WRAPPERS=(
|
|||||||
issue-list.sh
|
issue-list.sh
|
||||||
milestone-create.sh
|
milestone-create.sh
|
||||||
pr-create.sh
|
pr-create.sh
|
||||||
|
pr-edit.sh
|
||||||
pr-list.sh
|
pr-list.sh
|
||||||
pr-merge.sh
|
pr-merge.sh
|
||||||
)
|
)
|
||||||
@@ -47,7 +48,7 @@ for wrapper in "${WRAPPERS[@]}"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [[ "$fail" -eq 0 ]]; then
|
if [[ "$fail" -eq 0 ]]; then
|
||||||
echo "help-exit-code regression passed (7/7 wrappers)"
|
echo "help-exit-code regression passed (8/8 wrappers)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit "$fail"
|
exit "$fail"
|
||||||
|
|||||||
+160
@@ -0,0 +1,160 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Regression harness for secret-safe, identity-bound PR editing and explicit targets.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/pr-edit}"
|
||||||
|
REPO_DIR="$WORK_DIR/repo"; BIN_DIR="$WORK_DIR/bin"; HOME_DIR="$WORK_DIR/home"
|
||||||
|
XDG_DIR="$WORK_DIR/xdg"; LOG_FILE="$WORK_DIR/calls.log"
|
||||||
|
rm -rf "$WORK_DIR"; mkdir -p "$REPO_DIR" "$BIN_DIR" "$HOME_DIR" "$XDG_DIR/tea"
|
||||||
|
git -C "$REPO_DIR" init -q
|
||||||
|
git -C "$REPO_DIR" remote add origin https://git.uscllc.com/other/wrong-checkout.git
|
||||||
|
git -C "$REPO_DIR" config mosaic.gitIdentity ""
|
||||||
|
|
||||||
|
cat > "$XDG_DIR/tea/config.yml" <<'YAML'
|
||||||
|
logins:
|
||||||
|
- name: usc-coder3
|
||||||
|
url: https://git.uscllc.com
|
||||||
|
token: fixture-usc-token
|
||||||
|
- name: same-host-other
|
||||||
|
url: https://git.uscllc.com
|
||||||
|
token: fixture-other-token
|
||||||
|
- name: mosaic-coder3
|
||||||
|
url: https://git.mosaicstack.dev
|
||||||
|
token: fixture-mosaic-token
|
||||||
|
YAML
|
||||||
|
|
||||||
|
cat > "$BIN_DIR/tea" <<'SH'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
# Deliberately misleading duplicate-name response: the wrapper must never use
|
||||||
|
# tea for identity validation because its name lookup is not host-bound.
|
||||||
|
[[ "$*" == "api --login duplicate /user" ]] && { printf '{"login":"coder3"}\n'; exit 0; }
|
||||||
|
exit 1
|
||||||
|
SH
|
||||||
|
cat > "$BIN_DIR/curl" <<'SH'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
printf 'curl' >> "$MOSAIC_TEST_LOG"; printf ' <%s>' "$@" >> "$MOSAIC_TEST_LOG"; printf '\n' >> "$MOSAIC_TEST_LOG"
|
||||||
|
if [[ "${*: -1}" == */user ]]; then
|
||||||
|
printf '{"login":"%s"}\n' "${MOSAIC_STUB_AUTH_USER:-coder3}"
|
||||||
|
elif [[ "${*: -1}" == */repos/* && " $* " != *" -X PATCH "* ]]; then
|
||||||
|
[[ "${MOSAIC_STUB_SIGNAL:-}" == "TERM" ]] && { kill -TERM "$PPID"; sleep 1; }
|
||||||
|
[[ "${MOSAIC_STUB_SIGNAL:-}" == "INT" ]] && { kill -INT "$PPID"; sleep 1; }
|
||||||
|
printf '{"name":"repo"}\n'
|
||||||
|
else
|
||||||
|
printf '{"number":42,"draft":false}\n'
|
||||||
|
fi
|
||||||
|
SH
|
||||||
|
cat > "$BIN_DIR/gh" <<'SH'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
printf 'gh' >> "$MOSAIC_TEST_LOG"; printf ' <%s>' "$@" >> "$MOSAIC_TEST_LOG"; printf '\n' >> "$MOSAIC_TEST_LOG"
|
||||||
|
SH
|
||||||
|
chmod +x "$BIN_DIR/tea" "$BIN_DIR/curl" "$BIN_DIR/gh" "$SCRIPT_DIR/pr-edit.sh"
|
||||||
|
|
||||||
|
run_wrapper() {
|
||||||
|
(cd "$REPO_DIR"; PATH="$BIN_DIR:$PATH" HOME="$HOME_DIR" XDG_CONFIG_HOME="$XDG_DIR" \
|
||||||
|
MOSAIC_TEST_LOG="$LOG_FILE" "$SCRIPT_DIR/pr-edit.sh" "$@")
|
||||||
|
}
|
||||||
|
assert_no_secret() {
|
||||||
|
! grep -q 'fixture-.*-token' "$LOG_FILE" || { echo "Credential leaked into curl argv/log" >&2; exit 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
# The explicit target differs from CWD origin and must govern BOTH host and slug.
|
||||||
|
: > "$LOG_FILE"
|
||||||
|
# shellcheck disable=SC2016 # literal backticks prove argument-array body safety.
|
||||||
|
MOSAIC_GIT_IDENTITY=coder3 run_wrapper -n 42 --login mosaic-coder3 -r mosaicstack/stack \
|
||||||
|
-H git.mosaicstack.dev --title 'New title' --body 'Body with `literal` bytes' --base develop --draft >/dev/null
|
||||||
|
python3 - "$LOG_FILE" <<'PY'
|
||||||
|
import json, pathlib, sys
|
||||||
|
lines = pathlib.Path(sys.argv[1]).read_text().splitlines()
|
||||||
|
assert len(lines) == 3, lines
|
||||||
|
assert "https://git.mosaicstack.dev/api/v1/user" in lines[0], lines
|
||||||
|
assert "https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack" in lines[1], lines
|
||||||
|
assert "https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/pulls/42" in lines[2], lines
|
||||||
|
assert all("--config" in line for line in lines), lines
|
||||||
|
assert "Authorization:" not in "\n".join(lines), lines
|
||||||
|
payload = lines[2].split(" <-d> <", 1)[1].split("> <https://", 1)[0]
|
||||||
|
assert json.loads(payload) == {"title":"New title","body":"Body with `literal` bytes","base":"develop","draft":True}
|
||||||
|
PY
|
||||||
|
assert_no_secret
|
||||||
|
|
||||||
|
# Ready maps to false and still preflights before the write.
|
||||||
|
: > "$LOG_FILE"
|
||||||
|
MOSAIC_GIT_IDENTITY=coder3 run_wrapper -n 42 --login usc-coder3 -r USC/uconnect -H git.uscllc.com --ready >/dev/null
|
||||||
|
grep -q '"draft": false' "$LOG_FILE"; assert_no_secret
|
||||||
|
|
||||||
|
# Identity is mandatory; no ambient/first-host login can write.
|
||||||
|
: > "$LOG_FILE"
|
||||||
|
if run_wrapper -n 42 --login usc-coder3 --draft >/dev/null 2>&1; then echo "Unset identity wrote" >&2; exit 1; fi
|
||||||
|
[[ ! -s "$LOG_FILE" ]] || { echo "Unset identity reached curl" >&2; exit 1; }
|
||||||
|
|
||||||
|
# Explicit and ambient same-host wrong principals both refuse after identity
|
||||||
|
# lookup but before repo preflight/PATCH. The /user read is expected curl #1.
|
||||||
|
for mode in explicit ambient; do
|
||||||
|
: > "$LOG_FILE"
|
||||||
|
if [[ "$mode" == explicit ]]; then
|
||||||
|
cmd=(--login same-host-other)
|
||||||
|
else
|
||||||
|
cmd=(); export GITEA_LOGIN=same-host-other
|
||||||
|
fi
|
||||||
|
if MOSAIC_STUB_AUTH_USER=other MOSAIC_GIT_IDENTITY=coder3 run_wrapper -n 42 "${cmd[@]}" -r USC/uconnect -H git.uscllc.com --draft >/dev/null 2>&1; then
|
||||||
|
echo "$mode wrong identity wrote" >&2; exit 1
|
||||||
|
fi
|
||||||
|
unset GITEA_LOGIN
|
||||||
|
[[ "$(wc -l < "$LOG_FILE")" -eq 1 ]] || { echo "$mode wrong identity passed identity lookup" >&2; exit 1; }
|
||||||
|
! grep -q '/repos/' "$LOG_FILE" || { echo "$mode wrong identity reached repo preflight/PATCH" >&2; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# Set identity with no explicit/ambient login refuses rather than selecting first host login.
|
||||||
|
: > "$LOG_FILE"
|
||||||
|
if MOSAIC_GIT_IDENTITY=coder3 run_wrapper -n 42 -r USC/uconnect -H git.uscllc.com --draft >/dev/null 2>&1; then
|
||||||
|
echo "Missing login selected a principal" >&2; exit 1
|
||||||
|
fi
|
||||||
|
[[ ! -s "$LOG_FILE" ]] || { echo "Missing login reached curl" >&2; exit 1; }
|
||||||
|
|
||||||
|
# Split-credential probe for the duplicate-name cross-host seam: tea's
|
||||||
|
# name-only /user would report coder3, while the selected host-bound curl token
|
||||||
|
# reports other. The wrapper must trust only the latter handle used by PATCH.
|
||||||
|
: > "$LOG_FILE"
|
||||||
|
if MOSAIC_STUB_AUTH_USER=other MOSAIC_GIT_IDENTITY=coder3 run_wrapper -n 42 --login mosaic-coder3 \
|
||||||
|
-r mosaicstack/stack -H git.mosaicstack.dev --draft >/dev/null 2>&1; then
|
||||||
|
echo "Duplicate-name split credential reached PATCH" >&2; exit 1
|
||||||
|
fi
|
||||||
|
[[ "$(wc -l < "$LOG_FILE")" -eq 1 ]] || { echo "Duplicate-name identity mismatch passed /user" >&2; cat "$LOG_FILE" >&2; exit 1; }
|
||||||
|
! grep -q -- '-X> <PATCH' "$LOG_FILE" || { echo "Duplicate-name mismatch mutated" >&2; exit 1; }
|
||||||
|
|
||||||
|
# TERM and INT during repo preflight clean up, do not mutate, and return the
|
||||||
|
# signal status rather than swallowing termination into success.
|
||||||
|
for sig in TERM INT; do
|
||||||
|
: > "$LOG_FILE"
|
||||||
|
set +e
|
||||||
|
MOSAIC_STUB_SIGNAL="$sig" MOSAIC_GIT_IDENTITY=coder3 run_wrapper -n 42 --login usc-coder3 \
|
||||||
|
-r USC/uconnect -H git.uscllc.com --draft >/dev/null 2>&1
|
||||||
|
rc=$?
|
||||||
|
set -e
|
||||||
|
[[ "$rc" -ne 0 ]] || { echo "$sig was swallowed into success" >&2; exit 1; }
|
||||||
|
[[ "$rc" -eq 143 || "$rc" -eq 130 ]] || { echo "$sig returned unexpected status $rc" >&2; exit 1; }
|
||||||
|
! grep -q -- '-X> <PATCH' "$LOG_FILE" || { echo "$sig continued into PATCH" >&2; exit 1; }
|
||||||
|
assert_no_secret
|
||||||
|
done
|
||||||
|
|
||||||
|
# Cross-host credential fails before curl; explicit target preflight failure blocks PATCH.
|
||||||
|
: > "$LOG_FILE"
|
||||||
|
if MOSAIC_GIT_IDENTITY=coder3 run_wrapper -n 42 --login mosaic-coder3 -r USC/uconnect -H git.uscllc.com --draft >/dev/null 2>&1; then
|
||||||
|
echo "Cross-host login wrote" >&2; exit 1
|
||||||
|
fi
|
||||||
|
[[ ! -s "$LOG_FILE" ]] || { echo "Cross-host login reached curl" >&2; exit 1; }
|
||||||
|
|
||||||
|
if run_wrapper -n 42 --draft --ready >/dev/null 2>&1; then echo "Accepted conflicting modes" >&2; exit 1; fi
|
||||||
|
if run_wrapper -n 42 >/dev/null 2>&1; then echo "Accepted no-op edit" >&2; exit 1; fi
|
||||||
|
run_wrapper --help 2>&1 | grep -q '^Usage:'
|
||||||
|
|
||||||
|
# GitHub retains provider-native edit/readiness behavior.
|
||||||
|
git -C "$REPO_DIR" remote set-url origin https://github.com/acme/widgets.git
|
||||||
|
: > "$LOG_FILE"; run_wrapper -n 7 --title 'GitHub title' --draft >/dev/null
|
||||||
|
grep -q 'gh <pr> <edit> <7> <--title> <GitHub title>' "$LOG_FILE"
|
||||||
|
grep -q 'gh <pr> <ready> <7> <--undo>' "$LOG_FILE"
|
||||||
|
echo "PR edit regression harness passed"
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"lint": "eslint src",
|
"lint": "eslint src",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"test": "vitest run --passWithNoTests && pnpm run test:framework-shell",
|
"test": "vitest run --passWithNoTests && pnpm run test:framework-shell",
|
||||||
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && bash framework/tools/fleet/test-start-agent-session.sh && bash framework/systemd/user/test-fleet-units.sh && python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-ci-queue-wait-tristate.sh && bash framework/tools/git/test-ci-queue-wait-github-checks.sh && bash framework/tools/git/test-pr-merge-queue-branch.sh && bash framework/tools/git/test-pr-merge-head-pin.sh && bash framework/tools/git/test-pr-merge-message-field.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/git/test-explain-diagnostic-status-neutral.sh && bash framework/tools/git/test-detect-platform-outside-repo.sh && bash framework/tools/woodpecker/test-terminal-green-contract.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh"
|
"test:framework-shell": "bash framework/tools/quality/scripts/check-test-enumeration.sh && bash framework/tools/quality/scripts/test-check-test-enumeration.sh && bash framework/tools/fleet/test-start-agent-session.sh && bash framework/systemd/user/test-fleet-units.sh && python3 src/lease-broker/daemon_deadline_unittest.py && python3 src/lease-broker/normative_fragments_unittest.py && python3 src/lease-broker/receipt_challenge_unittest.py && python3 src/lease-broker/context_recovery_unittest.py && python3 src/lease-broker/recovery_runtime_unittest.py && python3 src/lease-broker/recovery_b1_adversarial_unittest.py && python3 src/lease-broker/framework_skill_portability_unittest.py && python3 src/mutator-gate/runtime_tools_unittest.py && python3 src/mutator-gate/runtime_launch_guard_unittest.py && python3 src/mutator-gate/version_coupling_unittest.py && python3 framework/tools/lease-broker/check-runtime-launches.py --root ../.. && bash framework/tools/codex/test-pr-diff-context.sh && bash framework/tools/qa/test-deps-preflight.sh && bash framework/tools/git/test-pr-edit.sh && bash framework/tools/git/test-pr-review-gitea-comment.sh && bash framework/tools/git/test-pr-review-repo-host-override.sh && bash framework/tools/git/test-ci-queue-wait-branch-absent.sh && bash framework/tools/git/test-ci-queue-wait-tristate.sh && bash framework/tools/git/test-ci-queue-wait-github-checks.sh && bash framework/tools/git/test-pr-merge-queue-branch.sh && bash framework/tools/git/test-pr-merge-head-pin.sh && bash framework/tools/git/test-pr-merge-message-field.sh && bash framework/tools/git/test-git-credential-mosaic.sh && bash framework/tools/git/test-gitea-token-identity.sh && bash framework/tools/git/test-explain-diagnostic-status-neutral.sh && bash framework/tools/git/test-detect-platform-outside-repo.sh && bash framework/tools/woodpecker/test-terminal-green-contract.sh && bash framework/tools/_scripts/test-install-ordering-guard.sh && bash framework/tools/tmux/agent-send.test.sh && bash framework/tools/wake/test-wake-store-ack.sh && bash framework/tools/wake/test-wake-store-enqueue-race.sh && bash framework/tools/wake/test-wake-digest-hmac.sh && bash framework/tools/wake/test-wake-digest-quarantine.sh && bash framework/tools/wake/test-wake-detector.sh && bash framework/tools/wake/test-wake-fn-oracle.sh && bash framework/tools/wake/test-wake-reconcile.sh && bash framework/tools/wake/test-wake-beacon.sh && bash framework/tools/wake/test-wake-preimage.sh && bash framework/tools/wake/test-wake-install.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mosaicstack/brain": "workspace:*",
|
"@mosaicstack/brain": "workspace:*",
|
||||||
|
|||||||
Reference in New Issue
Block a user