#!/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 " >&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"