#!/usr/bin/env bash # Regression harness for #703: interactive issue creation and stale Tea-user fallback. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/issue-create-interactive-auth}" REPO_DIR="$WORK_DIR/repo" BIN_DIR="$WORK_DIR/bin" HOME_DIR="$WORK_DIR/home" LOG_FILE="$WORK_DIR/calls.log" CREDENTIALS_FILE="$WORK_DIR/credentials.json" rm -rf "$WORK_DIR" mkdir -p "$REPO_DIR" "$BIN_DIR" "$HOME_DIR" git -C "$REPO_DIR" init -q git -C "$REPO_DIR" remote add origin https://git.mosaicstack.dev/mosaicstack/stack.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. It then reads a REAL per-slot token from $HOME and returns it WITHOUT ever # consulting MOSAIC_CREDENTIALS_FILE, so the fixture credential below is silently # ignored and the suite runs against a production credential. An empty repo-local # value shadows the global one and reads back empty at rc=0. Measured: this suite # resolves a per-slot token without it. # # CONTAINMENT: the sandboxed HOME in run_wrapper(). 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. # # 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 "" cat > "$CREDENTIALS_FILE" <<'JSON' {"gitea":{"mosaicstack":{"url":"https://git.mosaicstack.dev","token":"test-token"}}} JSON cat > "$BIN_DIR/tea" <<'SH' #!/usr/bin/env bash set -euo pipefail if [[ "$*" == "login list --output json" ]]; then printf '%s\n' '[{"name":"mosaicstack","url":"https://git.mosaicstack.dev"}]' exit 0 fi if [[ "${1:-}" == "api" ]]; then if [[ "${MOSAIC_TEA_STALE_USER:-0}" == "1" ]]; then echo 'GetUserByName: stale configured user' >&2 exit 1 fi printf '%s\n' '{"login":"current-user"}' exit 0 fi printf 'tea %s\n' "$*" >> "$MOSAIC_TEST_LOG" exit 0 SH cat > "$BIN_DIR/curl" <<'SH' #!/usr/bin/env bash set -euo pipefail printf 'curl %s\n' "$*" >> "$MOSAIC_TEST_LOG" printf '%s\n' '{"number":703}' SH chmod +x "$BIN_DIR/tea" "$BIN_DIR/curl" run_wrapper() { ( cd "$REPO_DIR" PATH="$BIN_DIR:$PATH" \ HOME="$HOME_DIR" \ MOSAIC_CREDENTIALS_FILE="$CREDENTIALS_FILE" \ MOSAIC_TEST_LOG="$LOG_FILE" \ "$@" ) } : > "$LOG_FILE" printf 'Interactive title\nInteractive body\nlabel-a,label-b\nM1\n' | run_wrapper "$SCRIPT_DIR/issue-create.sh" -i >/dev/null grep -q -- 'tea issue create --repo mosaicstack/stack --login mosaicstack --title Interactive title --description Interactive body --labels label-a,label-b --milestone M1' "$LOG_FILE" # Explicit values take precedence in interactive mode: no title input is # supplied, but the wrapper still creates the issue with the explicit title. : > "$LOG_FILE" printf '\n\n\n' | run_wrapper "$SCRIPT_DIR/issue-create.sh" -i -t 'Explicit title' >/dev/null grep -q -- 'tea issue create --repo mosaicstack/stack --login mosaicstack --title Explicit title' "$LOG_FILE" : > "$LOG_FILE" run_wrapper env MOSAIC_TEA_STALE_USER=1 "$SCRIPT_DIR/issue-create.sh" -t 'Fallback title' -b 'Fallback body' >/dev/null 2>"$WORK_DIR/issue-stderr" grep -q -- 'curl .*https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues' "$LOG_FILE" grep -q -- 'Tea authenticated-user validation failed' "$WORK_DIR/issue-stderr" if grep -q -- 'tea issue create' "$LOG_FILE"; then echo 'FAIL: issue-create invoked Tea mutation after stale-user validation failed' >&2 exit 1 fi : > "$LOG_FILE" run_wrapper env MOSAIC_TEA_STALE_USER=1 "$SCRIPT_DIR/pr-create.sh" -t 'PR fallback' -H feature/wrapfix >/dev/null 2>"$WORK_DIR/pr-stderr" grep -q -- 'curl .*https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/pulls' "$LOG_FILE" grep -q -- 'Tea authenticated-user validation failed' "$WORK_DIR/pr-stderr" if grep -q -- 'tea pr create' "$LOG_FILE"; then echo 'FAIL: pr-create invoked Tea mutation after stale-user validation failed' >&2 exit 1 fi echo 'issue-create interactive/auth regression harness passed'