296 lines
9.8 KiB
Bash
Executable File
296 lines
9.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Regression harness for Gitea PR metadata normalization.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/pr-metadata-gitea}"
|
|
REPO_DIR="$WORK_DIR/repo"
|
|
FIXTURE_DIR="$WORK_DIR/fixtures"
|
|
STUB_DIR="$WORK_DIR/stubs"
|
|
HOME_DIR="$WORK_DIR/home"
|
|
CREDENTIALS_FILE="$WORK_DIR/credentials.json"
|
|
|
|
rm -rf "$WORK_DIR"
|
|
mkdir -p "$REPO_DIR" "$FIXTURE_DIR" "$STUB_DIR" "$HOME_DIR"
|
|
|
|
git -C "$REPO_DIR" init -q
|
|
git -C "$REPO_DIR" remote add origin https://git.uscllc.com/USC/uconnect.git
|
|
# HERMETICITY (#1007) — TWO mechanisms with DIFFERENT jobs; do not conflate them.
|
|
#
|
|
# OPERATIVE: the empty repo-local `mosaic.gitIdentity` below. get_gitea_token()
|
|
# step 0 resolves a per-agent identity from `git config --get mosaic.gitIdentity`,
|
|
# which on a provisioned agent seat is set GLOBALLY and so leaks into this fresh
|
|
# repo. Step 0 runs BEFORE the credential loader AND before the GITEA_TOKEN env
|
|
# check, so the `GITEA_TOKEN="stub-token"` set in the run helpers below is
|
|
# silently overridden and a REAL per-slot token from $HOME is what reaches curl.
|
|
# Measured on a provisioned seat before this pin: both stub-curl calls carried
|
|
# the real token in argv. An empty repo-local value shadows the global one and
|
|
# reads back empty at rc=0.
|
|
#
|
|
# CONTAINMENT: the sandboxed HOME in the three run helpers below. It only has to
|
|
# bound a failure that the pin should already have prevented.
|
|
#
|
|
# NOTE FOR ANYONE AUDITING THIS SUITE: the sandboxed HOME is containment, NOT an
|
|
# assay. Running a suite under a decoy HOME to test for this defect REMOVES the
|
|
# trigger — ~/.gitconfig is where the global identity lives, so step 0 is skipped
|
|
# by construction and every suite reads clean however vulnerable it is. To measure,
|
|
# REPLICATE a seat (a decoy HOME whose .gitconfig sets mosaic.gitIdentity, with no
|
|
# per-slot token) so step 0 reaches its fail-loud branch. See
|
|
# test-gitea-token-identity.sh for the stronger `env -i HOME=…` form used where a
|
|
# suite's whole subject IS identity resolution.
|
|
#
|
|
# Note the env-var route does NOT work: detect-platform.sh reads
|
|
# "${MOSAIC_GIT_IDENTITY:-}", and `:-` treats set-but-empty identically to unset.
|
|
git -C "$REPO_DIR" config mosaic.gitIdentity ""
|
|
|
|
# The pin above removes step 0, but this suite has a SECOND, independent
|
|
# dependency on operator state, and closing only the first would leave the suite
|
|
# red on any hermetic environment. The `GITEA_TOKEN="stub-token"` /
|
|
# `GITEA_URL="https://git.example.test"` pair the run helpers set is INERT: step 2
|
|
# of get_gitea_token accepts GITEA_TOKEN only when GITEA_URL matches the remote
|
|
# host, and this repo's origin is git.uscllc.com, so that pair can never satisfy
|
|
# it. Before this fixture the only credential that could reach the authenticated
|
|
# curl branch was a REAL one — from step 0 on an agent seat, or from step 1
|
|
# reading the operator's own ~/.config/mosaic/credentials.json. That is why the
|
|
# "curl success path" case passed: not because the stub credential worked, but
|
|
# because a production credential was available.
|
|
#
|
|
# A fixture is used rather than relying on the sandboxed HOME making step 1 find
|
|
# nothing: a test that passes because production configuration is ABSENT fails
|
|
# the moment it is present. Step 1 now resolves deterministically to a value that
|
|
# is a fixture on every machine.
|
|
cat > "$CREDENTIALS_FILE" <<'JSON'
|
|
{
|
|
"gitea": {
|
|
"usc": {
|
|
"url": "https://git.uscllc.com",
|
|
"token": "stub-token"
|
|
}
|
|
}
|
|
}
|
|
JSON
|
|
|
|
cat > "$FIXTURE_DIR/gitea-standard.json" <<'JSON'
|
|
{
|
|
"number": 1905,
|
|
"title": "Smoke gate fix",
|
|
"state": "open",
|
|
"user": {"login": "edith"},
|
|
"head": {"ref": "edith/t_39ce717c-authentik-smoke-gate"},
|
|
"base": {"ref": "main"},
|
|
"labels": [{"name": "ci"}],
|
|
"assignees": [{"login": "edith"}],
|
|
"html_url": "https://git.uscllc.com/USC/uconnect/pulls/1905"
|
|
}
|
|
JSON
|
|
|
|
cat > "$FIXTURE_DIR/gitea-fallback.json" <<'JSON'
|
|
{
|
|
"number": 1908,
|
|
"title": "Fallback branch fields",
|
|
"state": "open",
|
|
"user": {"login": "edith"},
|
|
"head_branch": "fix/fallback-head",
|
|
"base_branch": "main",
|
|
"html_url": "https://git.uscllc.com/USC/uconnect/pulls/1908"
|
|
}
|
|
JSON
|
|
|
|
cat > "$FIXTURE_DIR/gitea-refs-pull-label.json" <<'JSON'
|
|
{
|
|
"number": 1908,
|
|
"title": "Closed merged PR with synthetic pull ref",
|
|
"state": "closed",
|
|
"user": {"login": "edith"},
|
|
"head": {"ref": "refs/pull/1908/head", "label": "fix/t_23fa9e1d-portal-health-backend"},
|
|
"base": {"ref": "main"},
|
|
"html_url": "https://git.uscllc.com/USC/uconnect/pulls/1908"
|
|
}
|
|
JSON
|
|
|
|
cat > "$FIXTURE_DIR/gitea-error.json" <<'JSON'
|
|
{"message": "user does not exist [uid: 0, name: ]", "url": "https://git.uscllc.com/api/swagger"}
|
|
JSON
|
|
|
|
cat > "$STUB_DIR/curl" <<'SH'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
output_file=""
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-o)
|
|
output_file="$2"
|
|
shift 2
|
|
;;
|
|
-w|-H|-u)
|
|
shift 2
|
|
;;
|
|
-s|-S|-sS)
|
|
shift
|
|
;;
|
|
*)
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$output_file" ]]; then
|
|
echo "curl stub expected -o <output_file>" >&2
|
|
exit 2
|
|
fi
|
|
|
|
case "${MOSAIC_STUB_CURL_MODE:-success}" in
|
|
success)
|
|
cat > "$output_file" <<'JSON'
|
|
{
|
|
"number": 1910,
|
|
"title": "Live curl path",
|
|
"state": "open",
|
|
"user": {"login": "edith"},
|
|
"head": {"ref": "fix/live-curl-path"},
|
|
"base": {"ref": "main"},
|
|
"html_url": "https://git.example.test/acme/widgets/pulls/1910"
|
|
}
|
|
JSON
|
|
printf '200'
|
|
;;
|
|
cat-fails-after-2xx)
|
|
rm -f -- "$output_file"
|
|
ln -s /nonexistent/pr-metadata-body "$output_file"
|
|
printf '200'
|
|
;;
|
|
*)
|
|
echo "unknown MOSAIC_STUB_CURL_MODE=${MOSAIC_STUB_CURL_MODE:-}" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
SH
|
|
chmod +x "$STUB_DIR/curl"
|
|
|
|
assert_tmpdir_empty() {
|
|
local tmpdir="$1" leftover
|
|
leftover=$(find "$tmpdir" -mindepth 1 -print -quit)
|
|
if [[ -n "$leftover" ]]; then
|
|
echo "Expected tmpfile cleanup, found leftover: $leftover" >&2
|
|
find "$tmpdir" -mindepth 1 -maxdepth 1 -ls >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
run_curl_success_case() {
|
|
local tmpdir="$WORK_DIR/tmp-success" stderr_file="$WORK_DIR/curl-success.stderr"
|
|
local output status
|
|
mkdir -p "$tmpdir"
|
|
|
|
set +e
|
|
output=$(cd "$REPO_DIR" && \
|
|
PATH="$STUB_DIR:$PATH" \
|
|
HOME="$HOME_DIR" \
|
|
MOSAIC_CREDENTIALS_FILE="$CREDENTIALS_FILE" \
|
|
TMPDIR="$tmpdir" \
|
|
GITEA_TOKEN="stub-token" \
|
|
GITEA_URL="https://git.example.test" \
|
|
MOSAIC_STUB_CURL_MODE="success" \
|
|
"$SCRIPT_DIR/pr-metadata.sh" -n 1910 2>"$stderr_file")
|
|
status=$?
|
|
set -e
|
|
|
|
if [[ "$status" -ne 0 ]]; then
|
|
echo "Expected curl success path to pass, got status $status" >&2
|
|
cat "$stderr_file" >&2
|
|
exit 1
|
|
fi
|
|
if grep -q "unbound variable" "$stderr_file"; then
|
|
echo "curl success path emitted unbound-variable cleanup noise" >&2
|
|
cat "$stderr_file" >&2
|
|
exit 1
|
|
fi
|
|
assert_tmpdir_empty "$tmpdir"
|
|
|
|
PR_METADATA_OUTPUT="$output" python3 - <<'PY'
|
|
import json
|
|
import os
|
|
|
|
data = json.loads(os.environ["PR_METADATA_OUTPUT"])
|
|
assert data["number"] == 1910, data
|
|
assert data["baseRefName"] == "main", data
|
|
assert data["headRefName"] == "fix/live-curl-path", data
|
|
PY
|
|
}
|
|
|
|
run_curl_early_exit_cleanup_case() {
|
|
local tmpdir="$WORK_DIR/tmp-early-exit" stderr_file="$WORK_DIR/curl-early-exit.stderr"
|
|
local output status
|
|
mkdir -p "$tmpdir"
|
|
|
|
set +e
|
|
output=$(cd "$REPO_DIR" && \
|
|
PATH="$STUB_DIR:$PATH" \
|
|
HOME="$HOME_DIR" \
|
|
MOSAIC_CREDENTIALS_FILE="$CREDENTIALS_FILE" \
|
|
TMPDIR="$tmpdir" \
|
|
GITEA_TOKEN="stub-token" \
|
|
GITEA_URL="https://git.example.test" \
|
|
MOSAIC_STUB_CURL_MODE="cat-fails-after-2xx" \
|
|
"$SCRIPT_DIR/pr-metadata.sh" -n 1910 2>"$stderr_file")
|
|
status=$?
|
|
set -e
|
|
|
|
if [[ "$status" -eq 0 ]]; then
|
|
echo "Expected unreadable 2xx body path to fail" >&2
|
|
printf '%s\n' "$output" >&2
|
|
exit 1
|
|
fi
|
|
if grep -q "unbound variable" "$stderr_file"; then
|
|
echo "curl early-exit path emitted unbound-variable cleanup noise" >&2
|
|
cat "$stderr_file" >&2
|
|
exit 1
|
|
fi
|
|
if ! grep -q "No such file or directory" "$stderr_file"; then
|
|
echo "Expected body-read failure from broken symlink path" >&2
|
|
cat "$stderr_file" >&2
|
|
exit 1
|
|
fi
|
|
if grep -q "Gitea API returned non-JSON" "$stderr_file"; then
|
|
echo "curl helper masked body-read failure as later JSON parsing failure" >&2
|
|
cat "$stderr_file" >&2
|
|
exit 1
|
|
fi
|
|
assert_tmpdir_empty "$tmpdir"
|
|
}
|
|
|
|
run_case() {
|
|
local fixture="$1" expected_number="$2" expected_head="$3"
|
|
local output
|
|
output=$(cd "$REPO_DIR" && HOME="$HOME_DIR" MOSAIC_CREDENTIALS_FILE="$CREDENTIALS_FILE" \
|
|
MOSAIC_GITEA_PR_METADATA_RAW_FILE="$fixture" "$SCRIPT_DIR/pr-metadata.sh" -n "$expected_number")
|
|
PR_METADATA_OUTPUT="$output" python3 - "$expected_number" "$expected_head" <<'PY'
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
data = json.loads(os.environ["PR_METADATA_OUTPUT"])
|
|
expected_number = int(sys.argv[1])
|
|
expected_head = sys.argv[2]
|
|
assert data["number"] == expected_number, data
|
|
assert data["baseRefName"] == "main", data
|
|
assert data["headRefName"] == expected_head, data
|
|
PY
|
|
}
|
|
|
|
run_case "$FIXTURE_DIR/gitea-standard.json" 1905 edith/t_39ce717c-authentik-smoke-gate
|
|
run_case "$FIXTURE_DIR/gitea-fallback.json" 1908 fix/fallback-head
|
|
run_case "$FIXTURE_DIR/gitea-refs-pull-label.json" 1908 fix/t_23fa9e1d-portal-health-backend
|
|
run_curl_success_case
|
|
run_curl_early_exit_cleanup_case
|
|
|
|
if cd "$REPO_DIR" && MOSAIC_GITEA_PR_METADATA_RAW_FILE="$FIXTURE_DIR/gitea-error.json" "$SCRIPT_DIR/pr-metadata.sh" -n 1909 >/dev/null 2>"$WORK_DIR/error.log"; then
|
|
echo "Expected API error fixture to fail" >&2
|
|
exit 1
|
|
fi
|
|
grep -q "Gitea API error" "$WORK_DIR/error.log"
|
|
|
|
echo "Gitea PR metadata regression harness passed"
|