#!/usr/bin/env bash
# Regression harness for host-specific Gitea tea login resolution.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WORK_DIR="${MOSAIC_TEST_WORK_DIR:-$PWD/.mosaic-test-work/gitea-login-resolution}"
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.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. It then reads a REAL per-slot token from $HOME and returns it WITHOUT ever
# consulting MOSAIC_CREDENTIALS_FILE, so the fixture credentials below are silently
# ignored. This suite is the one where the consequence is not subtle: it FAILS
# outright on a provisioned seat (rc=1 bare, rc=0 with $HOME sandboxed, one
# variable changed) and passes everywhere else, including CI, which has no
# per-agent token to leak.
#
# CONTAINMENT: the sandboxed HOME in the four 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.
#
# 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": "mosaic-token"
    },
    "usc": {
      "url": "https://git.uscllc.com",
      "token": "usc-token"
    }
  }
}
JSON

cat > "$BIN_DIR/tea" <<'SH'
#!/usr/bin/env bash
set -euo pipefail

if [[ "$*" == "login list --output json" ]]; then
    cat <<'JSON'
[
  {"name":"evil-usc","url":"https://evilgit.uscllc.com","user":"bad.actor"},
  {"name":"usc","url":"https://git.uscllc.com","user":"ci-bot"}
]
JSON
    exit 0
fi

if [[ "${1:-}" == "api" ]]; then
    printf '%s\n' '{"login":"ci-bot"}'
    exit 0
fi

printf 'tea %s\n' "$*" >> "$MOSAIC_TEST_LOG"
if [[ "${MOSAIC_TEA_FAIL_PR_CREATE:-}" == "1" && "$*" == pr\ create* ]]; then
    echo 'GetUserByName: simulated stale login failure' >&2
    exit 1
fi
exit 0
SH

cat > "$BIN_DIR/curl" <<'SH'
#!/usr/bin/env bash
set -euo pipefail

printf 'curl %s\n' "$*" >> "$MOSAIC_TEST_LOG"
url="${*: -1}"
case "$url" in
    */pulls/*.diff)
        printf 'diff --git a/file b/file\n'
        ;;
    */pulls/*)
        printf '{"head":{"sha":"abc123"}}'
        ;;
    */commits/*/status)
        printf '{"state":"success","statuses":[{"context":"ci/mock","status":"success"}]}'
        ;;
    # Repo roots: the pr-create API fallback resolves its base from the forge
    # default_branch (T51-P2 WP5a). Exact-suffix matches so the /pulls POST
    # endpoint (no trailing path) still falls through to the catch-all.
    */api/v1/repos/USC/uconnect)
        printf '{"default_branch":"main"}'
        ;;
    */api/v1/repos/mosaicstack/stack)
        printf '{"default_branch":"next"}'
        ;;
    *)
        printf '{}'
        ;;
esac
SH

chmod +x "$BIN_DIR/tea" "$BIN_DIR/curl"

run_in_repo() {
    (
        # HERMETICITY, second half (#1356). The empty repo-local `mosaic.gitIdentity`
        # above pins the git-config route into identity resolution. It does NOT pin
        # the environment route, and MOSAIC_GIT_IDENTITY is checked FIRST — so on any
        # provisioned seat, where the launcher exports it, this suite failed before
        # any change: rc=1 as-is, rc=0 under `env -u MOSAIC_GIT_IDENTITY`, one
        # variable. A suite that cannot run on a seat cannot guard this code for the
        # agents that actually run it.
        #
        # Unset rather than set empty: an empty MOSAIC_GIT_IDENTITY and an absent one
        # take different branches in resolve_git_identity(), and the case under test
        # is "no identity at all".
        cd "$REPO_DIR"
        env -u MOSAIC_GIT_IDENTITY \
        PATH="${_SANDBOX_BIN:-$BIN_DIR}:$PATH" \
        HOME="$HOME_DIR" \
        MOSAIC_CREDENTIALS_FILE="$CREDENTIALS_FILE" \
        MOSAIC_TEST_LOG="$LOG_FILE" \
        "$@"
    )
}

usc_login=$(run_in_repo bash -c '
    export GITEA_LOGIN=mosaicstack
    export GITEA_URL=https://git.mosaicstack.dev
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login
')
if [[ "$usc_login" != "usc" ]]; then
    echo "Expected USC host to resolve tea login 'usc' despite stale mosaicstack env; got '$usc_login'" >&2
    exit 1
fi

usc_login_with_usc_url=$(run_in_repo bash -c '
    export GITEA_LOGIN=mosaicstack
    export GITEA_URL=https://git.uscllc.com
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login
')
if [[ "$usc_login_with_usc_url" != "usc" ]]; then
    echo "Expected USC host to reject stale GITEA_LOGIN even when GITEA_URL matches USC; got '$usc_login_with_usc_url'" >&2
    exit 1
fi

usc_login_without_url=$(run_in_repo bash -c '
    export GITEA_LOGIN=mosaicstack
    unset GITEA_URL
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login
')
if [[ "$usc_login_without_url" != "usc" ]]; then
    echo "Expected USC host to ignore unmatched GITEA_LOGIN without URL; got '$usc_login_without_url'" >&2
    exit 1
fi

git -C "$REPO_DIR" remote set-url origin https://hermes:token@git.uscllc.com/USC/uconnect.git
embedded_host=$(run_in_repo bash -c '
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_remote_host
')
if [[ "$embedded_host" != "git.uscllc.com" ]]; then
    echo "Expected credential-bearing remote host to strip userinfo; got '$embedded_host'" >&2
    exit 1
fi
git -C "$REPO_DIR" remote set-url origin https://git.uscllc.com/USC/uconnect.git

override_login=$(run_in_repo bash -c '
    export GITEA_LOGIN=usc
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_repo_override
')
if [[ "$override_login" != "usc" ]]; then
    echo "Expected --repo override path to honor explicit GITEA_LOGIN; got '$override_login'" >&2
    exit 1
fi

git -C "$REPO_DIR" remote set-url origin https://git.mosaicstack.dev/mosaicstack/stack.git
: > "$LOG_FILE"
run_in_repo env GITEA_LOGIN=usc "$SCRIPT_DIR/issue-list.sh" --repo USC/uconnect -n 1
grep -q -- 'tea issues list --repo USC/uconnect --login usc' "$LOG_FILE"
git -C "$REPO_DIR" remote set-url origin https://git.uscllc.com/USC/uconnect.git

: > "$LOG_FILE"
run_in_repo "$SCRIPT_DIR/issue-close.sh" -i 42
grep -q -- 'tea issue close 42 --repo USC/uconnect --login usc' "$LOG_FILE"
if grep -q -- '--login mosaicstack' "$LOG_FILE"; then
    echo "issue-close.sh used hardcoded mosaicstack login on USC host" >&2
    exit 1
fi

: > "$LOG_FILE"
run_in_repo "$SCRIPT_DIR/milestone-list.sh"
grep -q -- 'tea milestone list --repo USC/uconnect --login usc' "$LOG_FILE"

: > "$LOG_FILE"
run_in_repo "$SCRIPT_DIR/milestone-create.sh" -t "0.2.0" -d "USC milestone"
grep -q -- 'tea milestones create --title 0.2.0 --description USC milestone --repo USC/uconnect --login usc' "$LOG_FILE"

: > "$LOG_FILE"
run_in_repo "$SCRIPT_DIR/milestone-close.sh" -t "0.2.0"
grep -q -- 'tea milestone close 0.2.0 --repo USC/uconnect --login usc' "$LOG_FILE"

if command -v pwsh >/dev/null 2>&1; then
    : > "$LOG_FILE"
    run_in_repo pwsh -NoProfile -File "$SCRIPT_DIR/issue-list.ps1" -Limit 1
    grep -q -- 'tea issues list --state open --limit 1 --repo USC/uconnect --login usc' "$LOG_FILE"

    : > "$LOG_FILE"
    run_in_repo pwsh -NoProfile -File "$SCRIPT_DIR/issue-create.ps1" -Title "PowerShell issue"
    grep -q -- 'tea issue create --title PowerShell issue --repo USC/uconnect --login usc' "$LOG_FILE"

    : > "$LOG_FILE"
    run_in_repo pwsh -NoProfile -File "$SCRIPT_DIR/pr-list.ps1" -Limit 1
    grep -q -- 'tea pr list --state open --limit 1 --repo USC/uconnect --login usc' "$LOG_FILE"

    : > "$LOG_FILE"
    run_in_repo pwsh -NoProfile -File "$SCRIPT_DIR/pr-create.ps1" -Title "PowerShell PR"
    grep -q -- 'tea pr create --title PowerShell PR --head master --repo USC/uconnect --login usc' "$LOG_FILE"

    : > "$LOG_FILE"
    run_in_repo pwsh -NoProfile -File "$SCRIPT_DIR/pr-merge.ps1" -Number 42 -SkipQueueGuard
    grep -q -- 'tea pr merge 42 --style squash --repo USC/uconnect --login usc' "$LOG_FILE"

    : > "$LOG_FILE"
    run_in_repo pwsh -NoProfile -File "$SCRIPT_DIR/milestone-create.ps1" -List
    grep -q -- 'tea milestones list --repo USC/uconnect --login usc' "$LOG_FILE"
fi

: > "$LOG_FILE"
if run_in_repo "$SCRIPT_DIR/pr-diff.sh" --repo USC/uconnect -n 7 >/dev/null 2>&1; then
    echo "Expected pr-diff.sh --repo without host to fail loud" >&2
    exit 1
fi
if grep -q -- 'git.mosaicstack.dev/api/v1/repos/USC/uconnect' "$LOG_FILE"; then
    echo "pr-diff.sh --repo defaulted API host to git.mosaicstack.dev" >&2
    exit 1
fi

: > "$LOG_FILE"
run_in_repo env GITEA_URL=https://git.uscllc.com "$SCRIPT_DIR/pr-diff.sh" --repo USC/uconnect -n 7 >/dev/null
grep -q -- 'curl .*https://git.uscllc.com/api/v1/repos/USC/uconnect/pulls/7.diff' "$LOG_FILE"

: > "$LOG_FILE"
run_in_repo "$SCRIPT_DIR/pr-ci-wait.sh" --repo USC/uconnect --host git.uscllc.com -n 9 -t 2 -i 1
grep -q -- 'curl .*https://git.uscllc.com/api/v1/repos/USC/uconnect/pulls/9' "$LOG_FILE"
grep -q -- 'curl .*https://git.uscllc.com/api/v1/repos/USC/uconnect/commits/abc123/status' "$LOG_FILE"

: > "$LOG_FILE"
run_in_repo env MOSAIC_TEA_FAIL_PR_CREATE=1 GITEA_TOKEN=usc-token GITEA_URL=https://git.uscllc.com "$SCRIPT_DIR/pr-create.sh" -t "USC API fallback" -H feature/pr-create
grep -q -- 'tea pr create --repo USC/uconnect --login usc --title USC API fallback --head feature/pr-create' "$LOG_FILE"
grep -q -- 'curl .*Authorization: token usc-token .*https://git.uscllc.com/api/v1/repos/USC/uconnect/pulls' "$LOG_FILE"
if grep -q -- 'git.mosaicstack.dev/api/v1/repos/USC/uconnect/pulls' "$LOG_FILE"; then
    echo "pr-create.sh API fallback defaulted USC repo to git.mosaicstack.dev" >&2
    exit 1
fi

git -C "$REPO_DIR" remote set-url origin https://git.mosaicstack.dev/mosaicstack/stack.git
: > "$LOG_FILE"
run_in_repo env GITEA_TOKEN=mosaic-token GITEA_URL=https://git.mosaicstack.dev "$SCRIPT_DIR/issue-close.sh" -i 536
grep -q -- 'curl .*https://git.mosaicstack.dev/api/v1/repos/mosaicstack/stack/issues/536' "$LOG_FILE"
if grep -q -- 'tea issue close 536 .*--login mosaicstack' "$LOG_FILE"; then
    echo "issue-close.sh invented a mosaicstack tea login instead of using API fallback" >&2
    exit 1
fi

# ---------------------------------------------------------------------------
# #560: loud diagnostic + host-derived login for BOTH instances + override-wins
# ---------------------------------------------------------------------------

# Loud diagnostic: a host with no matching tea login must emit an actionable
# error to stderr (the previous behavior was a SILENT failure). The original
# mock defines only usc/evil-usc logins, so mosaicstack resolution fails here.
git -C "$REPO_DIR" remote set-url origin https://git.mosaicstack.dev/mosaicstack/stack.git
diag_stderr=$(run_in_repo bash -c '
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_host git.mosaicstack.dev
' 2>&1 1>/dev/null || true)
if ! grep -q "no Gitea tea login matches host 'git.mosaicstack.dev'" <<<"$diag_stderr"; then
    echo "Expected loud diagnostic naming the unresolved host; got: $diag_stderr" >&2
    exit 1
fi
if ! grep -q "Available tea logins:" <<<"$diag_stderr"; then
    echo "Expected diagnostic to list available tea logins; got: $diag_stderr" >&2
    exit 1
fi

# Both-instance host derivation + override-wins, using a mock that DOES define a
# mosaicstack login. Scoped to this section so the API-fallback assertions above
# (which rely on mosaicstack having NO tea login) remain valid.
BIN_DIR2="$WORK_DIR/bin2"
mkdir -p "$BIN_DIR2"
cp "$BIN_DIR/curl" "$BIN_DIR2/curl"
cat > "$BIN_DIR2/tea" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
if [[ "$*" == "login list --output json" ]]; then
    cat <<'JSON'
[
  {"name":"mosaicstack","url":"https://git.mosaicstack.dev","user":"ci-bot"},
  {"name":"usc","url":"https://git.uscllc.com","user":"ci-bot"}
]
JSON
    exit 0
fi
printf 'tea %s\n' "$*" >> "$MOSAIC_TEST_LOG"
exit 0
SH
chmod +x "$BIN_DIR2/tea"

run_in_repo2() {
    # Same sandbox as run_in_repo, different mock tea (BIN_DIR2 defines a
    # mosaicstack login). This MUST delegate rather than re-implement: it was a
    # copy once, and the copy silently missed the MOSAIC_GIT_IDENTITY unset, so
    # the suite kept failing on a seat after run_in_repo was already fixed.
    _SANDBOX_BIN="$BIN_DIR2" run_in_repo "$@"
}

git -C "$REPO_DIR" remote set-url origin https://git.mosaicstack.dev/mosaicstack/stack.git
mosaic_login=$(run_in_repo2 bash -c 'source "'"$SCRIPT_DIR"'/detect-platform.sh"; get_gitea_login')
if [[ "$mosaic_login" != "mosaicstack" ]]; then
    echo "Expected mosaicstack origin to derive login 'mosaicstack'; got '$mosaic_login'" >&2
    exit 1
fi

git -C "$REPO_DIR" remote set-url origin https://git.uscllc.com/USC/uconnect.git
usc_login_derived=$(run_in_repo2 bash -c 'source "'"$SCRIPT_DIR"'/detect-platform.sh"; get_gitea_login')
if [[ "$usc_login_derived" != "usc" ]]; then
    echo "Expected usc origin to derive login 'usc'; got '$usc_login_derived'" >&2
    exit 1
fi

# Explicit GITEA_LOGIN override is honored when it matches the host.
git -C "$REPO_DIR" remote set-url origin https://git.mosaicstack.dev/mosaicstack/stack.git
override_wins=$(run_in_repo2 bash -c 'export GITEA_LOGIN=mosaicstack; source "'"$SCRIPT_DIR"'/detect-platform.sh"; get_gitea_login')
if [[ "$override_wins" != "mosaicstack" ]]; then
    echo "Expected valid GITEA_LOGIN override to win on mosaicstack host; got '$override_wins'" >&2
    exit 1
fi
git -C "$REPO_DIR" remote set-url origin https://git.uscllc.com/USC/uconnect.git

# ---------------------------------------------------------------------------
# #1356: the git-identity ladder. A seat declares who it is (MOSAIC_GIT_IDENTITY
# or `git config mosaic.gitIdentity`); resolution must use THAT seat's login and
# must REFUSE to borrow another one when it is absent. Silently borrowing
# satisfies gate 16 mechanically (a review exists) while violating it (the
# reviewer and the author are the same actor under two names).
#
# BIN_DIR3 mocks a tea that holds a canonical per-seat login, which is what a
# projected seat looks like. BIN_DIR2 (mosaicstack only) is reused as the
# "seat has no login" case — no third mock needed for the negative branch.
# ---------------------------------------------------------------------------
BIN_DIR3="$WORK_DIR/bin3"
mkdir -p "$BIN_DIR3"
cp "$BIN_DIR/curl" "$BIN_DIR3/curl"
cat > "$BIN_DIR3/tea" <<'SH'
#!/usr/bin/env bash
set -euo pipefail
if [[ "$*" == "login list --output json" ]]; then
    cat <<'JSON'
[
  {"name":"mosaicstack","url":"https://git.mosaicstack.dev","user":"ci-bot"},
  {"name":"mosaicstack-testseat","url":"https://git.mosaicstack.dev","user":"testseat"},
  {"name":"usc","url":"https://git.uscllc.com","user":"ci-bot"}
]
JSON
    exit 0
fi
printf 'tea %s\n' "$*" >> "$MOSAIC_TEST_LOG"
exit 0
SH
chmod +x "$BIN_DIR3/tea"

run_in_repo3() { _SANDBOX_BIN="$BIN_DIR3" run_in_repo "$@"; }

git -C "$REPO_DIR" remote set-url origin https://git.mosaicstack.dev/mosaicstack/stack.git

# Branch 1 (host path): identity set, canonical login PRESENT -> that login wins
# over the shared `mosaicstack` one, which is what host-matching alone would pick.
ladder_hit=$(run_in_repo3 env MOSAIC_GIT_IDENTITY=testseat bash -c '
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_host git.mosaicstack.dev
')
if [[ "$ladder_hit" != "mosaicstack-testseat" ]]; then
    echo "Expected identity ladder to select 'mosaicstack-testseat'; got '$ladder_hit'" >&2
    exit 1
fi

# CONTROL for branch 1: the same mock, no identity, must still resolve by host.
# Without this, branch 1 passing proves nothing about the ladder specifically --
# it would also pass if the code just picked the last matching login.
ladder_none=$(run_in_repo3 bash -c '
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_host git.mosaicstack.dev
')
if [[ "$ladder_none" != "mosaicstack" ]]; then
    echo "Expected no-identity host resolution to stay 'mosaicstack'; got '$ladder_none'" >&2
    exit 1
fi

# Branch 2 (host path): identity set, canonical login ABSENT -> fail closed with a
# named error. Two assertions, and they are not the same one twice: rc!=0 proves
# it refused, and the ABSENCE of any login on stdout proves it did not borrow the
# `mosaicstack` login that is sitting right there matching the host.
ladder_err=$(run_in_repo2 env MOSAIC_GIT_IDENTITY=testseat bash -c '
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_host git.mosaicstack.dev
' 2>&1 1>/dev/null || true)
ladder_out=$(run_in_repo2 env MOSAIC_GIT_IDENTITY=testseat bash -c '
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_host git.mosaicstack.dev
' 2>/dev/null || true)
if [[ -n "$ladder_out" ]]; then
    echo "Identity ladder BORROWED login '$ladder_out' instead of failing closed" >&2
    exit 1
fi
if ! grep -q "mosaicstack-testseat" <<<"$ladder_err"; then
    echo "Expected the error to name the login it wanted; got: $ladder_err" >&2
    exit 1
fi

# Branch 3: `git config mosaic.gitIdentity` is the second rung and must work when
# the environment variable is absent -- a seat may be configured either way.
git -C "$REPO_DIR" config mosaic.gitIdentity testseat
ladder_gitcfg=$(run_in_repo3 bash -c '
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_host git.mosaicstack.dev
')
git -C "$REPO_DIR" config --unset mosaic.gitIdentity || true
if [[ "$ladder_gitcfg" != "mosaicstack-testseat" ]]; then
    echo "Expected git-config identity rung to select 'mosaicstack-testseat'; got '$ladder_gitcfg'" >&2
    exit 1
fi

# Branch 4 (--repo override path): same rule, owner-derived instead of host-derived.
override_ladder=$(run_in_repo3 env MOSAIC_GIT_IDENTITY=testseat bash -c '
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_repo_override mosaicstack/stack
')
if [[ "$override_ladder" != "mosaicstack-testseat" ]]; then
    echo "Expected --repo override ladder to select 'mosaicstack-testseat'; got '$override_ladder'" >&2
    exit 1
fi

# Branch 5: explicit GITEA_LOGIN outranks the ladder. An operator naming a login
# by hand is a deliberate act, not an accident to be second-guessed.
override_explicit=$(run_in_repo3 env MOSAIC_GIT_IDENTITY=testseat GITEA_LOGIN=mosaicstack bash -c '
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_repo_override mosaicstack/stack
')
if [[ "$override_explicit" != "mosaicstack" ]]; then
    echo "Expected explicit GITEA_LOGIN to outrank the identity ladder; got '$override_explicit'" >&2
    exit 1
fi

# Branch 6 (#1357 S1): with tea ABSENT from PATH, the override path must say tea is
# missing, not "no tea login named X exists" (a cause that was never checked) and
# not the seat-logins.sh advice, which cannot be followed without tea.
NOTEA_BIN="$WORK_DIR/notea-bin"; mkdir -p "$NOTEA_BIN"
for t in bash git python3 sed grep cat mktemp dirname basename readlink env sort head tr cut; do
    _p="$(command -v "$t" 2>/dev/null || true)"; [[ -n "$_p" ]] && ln -sf "$_p" "$NOTEA_BIN/$t"
done
override_notea_rc=0
override_notea_err=$(cd "$REPO_DIR" && env -u GITEA_LOGIN \
    PATH="$NOTEA_BIN" HOME="$HOME_DIR" MOSAIC_GIT_IDENTITY=testseat \
    bash -c '
    command -v tea >/dev/null 2>&1 && { echo "SETUP: tea still on PATH"; exit 99; }
    source "'"$SCRIPT_DIR"'/detect-platform.sh"
    get_gitea_login_for_repo_override mosaicstack/stack
' 2>&1 >/dev/null) || override_notea_rc=$?
if [[ "$override_notea_rc" != 1 ]]; then
    echo "Expected --repo override path to fail (rc=1) with tea absent; got rc=$override_notea_rc: $override_notea_err" >&2
    exit 1
fi
if ! grep -q 'tea is not installed' <<<"$override_notea_err"; then
    echo "Expected --repo override path to name tea as absent; got: $override_notea_err" >&2
    exit 1
fi
if grep -q 'has no tea login\|seat-logins.sh' <<<"$override_notea_err"; then
    echo "Override path diagnosed a missing LOGIN while tea itself is absent: $override_notea_err" >&2
    exit 1
fi

git -C "$REPO_DIR" remote set-url origin https://git.uscllc.com/USC/uconnect.git


# ---------------------------------------------------------------------------
# #865 Blocker 1 & 2: get_gitea_token_for_login must resolve the SAME token as
# PyYAML would (or fail closed identically) even when PyYAML is ABSENT, and must
# bind the credential to the repo host's scheme + host + EFFECTIVE PORT — not the
# hostname alone. These fixtures probe the ImportError-dispatched line-parser
# fallback under FORCED PyYAML absence with adversarial YAML shapes, asserting it
# NEVER misattributes a token from a nested sub-map or a mis-indented line, strips
# inline comments like PyYAML, fails closed where PyYAML errors, and rejects a
# port mismatch while accepting an exact / default-port match. When PyYAML is
# available the same fixtures also assert the PyYAML path agrees (equivalence).
# ---------------------------------------------------------------------------
FIXTURE_XDG="$WORK_DIR/tokenfix"
NOYAML_DIR="$WORK_DIR/noyaml"
mkdir -p "$FIXTURE_XDG/tea" "$NOYAML_DIR"
# A shadow `yaml` module that raises ImportError, forcing the fallback path.
printf 'raise ImportError("forced-absent for #865 fallback regression")\n' > "$NOYAML_DIR/yaml.py"
if python3 -c 'import yaml' >/dev/null 2>&1; then HAVE_PYYAML=true; else HAVE_PYYAML=false; fi
# Confirm the shim really does force ImportError, so the fallback is exercised.
if python3 -c 'import yaml' >/dev/null 2>&1; then
    if PYTHONPATH="$NOYAML_DIR" python3 -c 'import yaml' >/dev/null 2>&1; then
        echo "FAIL: PyYAML-absence shim did not force ImportError (fallback not exercised)" >&2
        exit 1
    fi
fi

write_fixture() { printf '%s' "$1" > "$FIXTURE_XDG/tea/config.yml"; }

# Resolve a token via the FORCED-fallback path (PyYAML shimmed to ImportError).
token_fallback() {
    (
        cd "$REPO_DIR"
        HOME="$HOME_DIR" XDG_CONFIG_HOME="$FIXTURE_XDG" PYTHONPATH="$NOYAML_DIR" bash -c '
            source "'"$SCRIPT_DIR"'/detect-platform.sh"
            get_gitea_token_for_login "$1" "$2"
        ' _ "$1" "$2"
    ) 2>/dev/null || true
}

# Resolve a token via the normal path (uses PyYAML when installed).
token_pyyaml() {
    (
        cd "$REPO_DIR"
        HOME="$HOME_DIR" XDG_CONFIG_HOME="$FIXTURE_XDG" bash -c '
            source "'"$SCRIPT_DIR"'/detect-platform.sh"
            get_gitea_token_for_login "$1" "$2"
        ' _ "$1" "$2"
    ) 2>/dev/null || true
}

assert_token() {
    local desc="$1" expected="$2" login="$3" host="$4" got
    got=$(token_fallback "$login" "$host")
    if [[ "$got" != "$expected" ]]; then
        echo "FAIL fallback [$desc]: expected [$expected] got [$got]" >&2
        exit 1
    fi
    if [[ "$HAVE_PYYAML" == true ]]; then
        got=$(token_pyyaml "$login" "$host")
        if [[ "$got" != "$expected" ]]; then
            echo "FAIL pyyaml [$desc]: expected [$expected] got [$got]" >&2
            exit 1
        fi
    fi
}

# 1. Plain, well-formed entry resolves its token.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: TOK_PLAIN
'
assert_token "plain scalar" "TOK_PLAIN" primary git.example

# 2. A token nested inside a deeper SUB-MAP must NOT attach to the entry — PyYAML
#    resolves the entry's own token to None here, so the fallback must too.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    extra:
      token: TOK_NESTED_ATTACKER
  - name: other
    url: https://git.example
    token: TOK_OTHER
'
assert_token "nested sub-map token is not attributed" "" primary git.example
assert_token "sibling entry still resolves its own token" "TOK_OTHER" other git.example

# 3. A MIS-INDENTED token line (deeper than the entry's fields) must not attach;
#    PyYAML errors on this shape, so both fail closed.
write_fixture 'logins:
  - name: primary
    url: https://git.example
      token: TOK_MISINDENT
'
assert_token "mis-indented token fails closed" "" primary git.example

# 4. A trailing inline comment on a scalar is stripped, exactly as PyYAML does.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: TOK_INLINE  # trailing note
'
assert_token "inline comment stripped" "TOK_INLINE" primary git.example

# 5. A PyYAML-fail-closed case: tab indentation. PyYAML raises a scanner error;
#    the fallback resolves no token. Both fail closed identically.
write_fixture "$(printf 'logins:\n  - name: primary\n    url: https://git.example\n\ttoken: TOK_TAB\n')"
assert_token "tab-indent fails closed like PyYAML" "" primary git.example

# 6. Host binding is scheme + host + EFFECTIVE PORT, not hostname alone.
write_fixture 'logins:
  - name: ported
    url: https://git.example:8443
    token: TOK_PORTED
'
assert_token "explicit port exact match accepted" "TOK_PORTED" ported git.example:8443
assert_token "portless repo host rejects :8443 login" "" ported git.example
assert_token "wrong explicit port rejected" "" ported git.example:9443

# 7. An implicit (portless) login URL equals the scheme's explicit default port.
write_fixture 'logins:
  - name: defported
    url: https://git.example
    token: TOK_DEFPORT
'
assert_token "implicit https vs explicit :443 match" "TOK_DEFPORT" defported git.example:443
assert_token "implicit https vs :8443 rejected" "" defported git.example:8443

# 8. An UNQUOTED token whose raw text PyYAML's implicit resolver types as a
#    NON-string (int / null / bool / float) must fail closed: PyYAML yields a
#    non-str value that _accept rejects, so the fallback must NOT surface the
#    stringified scalar as a credential. Each raw form fails closed IDENTICALLY
#    to PyYAML (a prior residual emitted "12345"/"null"/"true"/etc. here).
assert_nonstring_token_fails_closed() {
    local desc="$1" raw="$2"
    write_fixture "logins:
  - name: primary
    url: https://git.example
    token: ${raw}
"
    assert_token "$desc" "" primary git.example
}
assert_nonstring_token_fails_closed "unquoted int token fails closed" "12345"
assert_nonstring_token_fails_closed "unquoted null token fails closed" "null"
assert_nonstring_token_fails_closed "unquoted tilde-null token fails closed" "~"
assert_nonstring_token_fails_closed "unquoted yes(bool) token fails closed" "yes"
assert_nonstring_token_fails_closed "unquoted true(bool) token fails closed" "true"
assert_nonstring_token_fails_closed "unquoted float token fails closed" "3.14"

# 9. A QUOTED scalar is ALWAYS a string, even when its contents look like a
#    non-string implicit form. The quotes force str typing in PyYAML, so the
#    fallback must accept the literal (quote-stripped) contents as the token.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: "12345"
'
assert_token "double-quoted digit token is a literal string" "12345" primary git.example
write_fixture "logins:
  - name: primary
    url: https://git.example
    token: 'abc'
"
assert_token "single-quoted token is a literal string" "abc" primary git.example

# assert_fallback_fails_closed: the forced-fallback path MUST resolve no token
# (fail closed). Used for STRUCTURAL cases where PyYAML would resolve a DIFFERENT
# token (e.g. duplicate-key last-wins) — the fallback must never surface the
# wrong/stale token, so it fails closed instead; when PyYAML is present we also
# confirm it really does resolve a (divergent) token, proving the fallback is the
# strictly-more-conservative side and the case is a genuine fail-open guard.
assert_fallback_fails_closed() {
    local desc="$1" login="$2" host="$3" got
    got=$(token_fallback "$login" "$host")
    if [[ -n "$got" ]]; then
        echo "FAIL fallback [$desc]: expected fail-closed, got a token" >&2
        exit 1
    fi
    if [[ "$HAVE_PYYAML" == true ]]; then
        got=$(token_pyyaml "$login" "$host")
        if [[ -z "$got" ]]; then
            echo "FAIL [$desc]: expected PyYAML to resolve a divergent token" >&2
            exit 1
        fi
    fi
}

# 10. tea's REAL on-disk shape: the `logins:` block SEQUENCE items sit at the
#     SAME indentation as the key (dash at column 0), with extra scalar fields.
#     The recognizer must resolve this exactly like PyYAML (regression guard so
#     the stricter whole-document recognizer does not fail closed on real input).
write_fixture 'logins:
- name: primary
  url: https://git.example
  token: TOK_REAL
  default: false
  ssh_host: ""
- name: other
  url: https://other.example
  token: TOK_REAL_OTHER
preferences:
  editor: false
  flags: null
'
assert_token "tea dash-at-column-0 real shape resolves" "TOK_REAL" primary git.example
assert_token "tea real shape sibling resolves own token" "TOK_REAL_OTHER" other other.example

# 11. NESTED-SHADOW: a nested `logins:` (NOT at root scope) must not be mistaken
#     for the real root logins. The recognizer parses whole-document structure,
#     so it selects the ROOT logins token exactly as PyYAML does — never the
#     nested attacker token. (A prior line scan matched the FIRST logins at ANY
#     indent and returned ATTACKER.)
write_fixture 'outer:
  logins:
    - name: primary
      url: https://git.example
      token: ATTACKER_NESTED
logins:
  - name: primary
    url: https://git.example
    token: ROOT_TOK
'
assert_token "nested logins shadow selects ROOT token" "ROOT_TOK" primary git.example

# 12. BLOCK-SCALAR-SHADOW: text inside a YAML literal/folded block ( | or > ) is
#     an OPAQUE scalar to PyYAML (so `logins` is a string, not a list) and must
#     not be scanned as live logins entries. Both fail closed.
write_fixture 'logins: |
  - name: primary
    url: https://git.example
    token: ATTACKER_BLOCK
'
assert_token "block-scalar logins value fails closed" "" primary git.example
# A folded/literal block scalar anywhere is outside the recognizer's subset, so
# the fallback fails closed (conservative) even though PyYAML can still resolve
# the real root token past the opaque scalar. Fail-closed is the safe side.
write_fixture 'note: >
  logins:
    - name: primary
      token: ATTACKER_FOLDED
logins:
  - name: primary
    url: https://git.example
    token: ROOT_OK
'
assert_fallback_fails_closed "folded block scalar present fails closed" primary git.example

# 13. DUPLICATE-ROOT / DUPLICATE-FIELD: a duplicated `logins:` root key (PyYAML
#     last-wins) or a duplicated field within a login must fail closed rather
#     than take the FIRST (stale) value. PyYAML resolves the LAST; the fallback
#     refuses to guess.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: FIRST_DUP
logins:
  - name: primary
    url: https://git.example
    token: LAST_DUP
'
assert_fallback_fails_closed "duplicate root logins key fails closed" primary git.example
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: FIRST_FIELD
    token: SECOND_FIELD
'
assert_fallback_fails_closed "duplicate token field fails closed" primary git.example

# 14. MALFORMED-AFTER-VALID: a syntax error LATER in the file makes PyYAML reject
#     the WHOLE document; the recognizer must too (not emit the earlier token).
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: TOK_PLAIN
broken: a: b: c
'
assert_token "malformed line after valid login fails closed" "" primary git.example
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: TOK_PLAIN
broken: [unclosed
'
assert_token "unclosed flow after valid login fails closed" "" primary git.example

# 15. EXTRA-DOCUMENT: a multi-document file (--- separator, or ... end marker)
#     makes PyYAML safe_load reject multi-document input; the recognizer fails
#     closed on ANY document marker rather than emit the first doc's token.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: TOK_PLAIN
---
logins:
  - name: primary
    url: https://git.example
    token: SECOND_DOC
'
assert_token "second document (--- separator) fails closed" "" primary git.example
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: TOK_PLAIN
...
trailing: 1
'
assert_token "end marker then more content fails closed" "" primary git.example

# 16. CONSTRUCTOR-VALIDITY / INVALID-INDICATOR: a plain scalar can match a typed
#     implicit resolver (int/float/timestamp) yet be NON-constructible, or begin
#     with an indicator a plain scalar may not start with. PyYAML then RAISES on
#     the WHOLE document (constructor error / scanner error) and yields NO token,
#     so the fallback must ALSO fail closed for the whole document -- even though
#     the (unrelated) malformed key sits alongside an otherwise-valid logins
#     block whose token is itself well-formed. A prior residual proved STRUCTURE
#     and implicit TYPE but not constructor validity, so it ignored the malformed
#     key and still emitted the valid login token (fail-open in the dangerous
#     direction). assert_both_fail_closed asserts fallback == PyYAML == no token.
assert_both_fail_closed() {
    local desc="$1" login="$2" host="$3" got
    got=$(token_fallback "$login" "$host")
    if [[ -n "$got" ]]; then
        echo "FAIL fallback [$desc]: expected fail-closed, got a token" >&2
        exit 1
    fi
    if [[ "$HAVE_PYYAML" == true ]]; then
        got=$(token_pyyaml "$login" "$host")
        if [[ -n "$got" ]]; then
            echo "FAIL pyyaml [$desc]: expected PyYAML to also fail closed (raise/no token), got a token" >&2
            exit 1
        fi
    fi
}

# write_bad_key_fixture: an unrelated root key carrying $1 as its plain scalar,
# followed by an otherwise-valid logins block whose token is well-formed.
write_bad_key_fixture() {
    write_fixture "bad: $1
logins:
  - name: primary
    url: https://git.example
    token: TOK_PLAIN
"
}

# Non-constructible TIMESTAMP-tagged scalars: match the resolver, but the
# calendar field is out of range so PyYAML's datetime construction raises.
write_bad_key_fixture '2023-99-99'          # month 99 / day 99 invalid
assert_both_fail_closed "bad-date 2023-99-99 fails closed like PyYAML" primary git.example
write_bad_key_fixture '2023-13-01'          # month 13 invalid
assert_both_fail_closed "bad-month 2023-13-01 fails closed like PyYAML" primary git.example
write_bad_key_fixture '2023-01-15T25:00:00' # hour 25 invalid
assert_both_fail_closed "bad-hour timestamp fails closed like PyYAML" primary git.example

# Non-constructible INT-tagged scalars: match the int resolver, but the radix
# body is empty after underscore removal so int(base) raises.
write_bad_key_fixture '0b_'
assert_both_fail_closed "empty-binary 0b_ fails closed like PyYAML" primary git.example
write_bad_key_fixture '0x_'
assert_both_fail_closed "empty-hex 0x_ fails closed like PyYAML" primary git.example
write_bad_key_fixture '0x__'
assert_both_fail_closed "empty-hex 0x__ (multi-underscore) fails closed" primary git.example

# Invalid plain-scalar INDICATOR forms: a plain scalar may not begin with '%'
# (directive) or ',' (flow) -- PyYAML raises a scanner/parser error on the whole
# document, so the fallback fails closed on the leading indicator.
write_bad_key_fixture '%broken'
assert_both_fail_closed "leading-%% directive indicator fails closed" primary git.example
write_bad_key_fixture ',bad'
assert_both_fail_closed "leading-comma flow indicator fails closed" primary git.example
# Bare block indicators in a value position ('-'/'- ', '?'/'? ', ':'/': '):
# PyYAML raises a scanner error on the whole document, so the fallback must fail
# closed rather than accept the indicator as a plain-scalar string.
write_bad_key_fixture '-'
assert_both_fail_closed "bare dash (seq indicator) fails closed" primary git.example
write_bad_key_fixture '- x'
assert_both_fail_closed "dash-space (seq entry) fails closed" primary git.example
write_bad_key_fixture '? key'
assert_both_fail_closed "question-space (complex key) fails closed" primary git.example
# ...but an indicator NOT followed by whitespace is a valid plain scalar string,
# so the token still resolves (no over-broad fail-close).
write_bad_key_fixture '-x'
assert_token "dash-not-space is a plain string, token resolves" "TOK_PLAIN" primary git.example
write_bad_key_fixture ':x'
assert_token "colon-not-space is a plain string, token resolves" "TOK_PLAIN" primary git.example

# NOT over-broad: a genuinely CONSTRUCTIBLE typed scalar (or a look-alike PyYAML
# keeps as a plain string) leaves the document valid, so BOTH still resolve the
# login token -- the fix must not fail closed on these.
write_bad_key_fixture '2023-01-15'
assert_token "valid date unrelated key still resolves token" "TOK_PLAIN" primary git.example
write_bad_key_fixture '2023-01-15 10:00:00'
assert_token "valid datetime unrelated key still resolves token" "TOK_PLAIN" primary git.example
# '0o_' is NOT matched by PyYAML's int resolver (YAML 1.1 octal is 0[0-7]+, not
# 0o...), so PyYAML keeps it a STRING and resolves the token; the fallback must
# agree (no spurious fail-close).
write_bad_key_fixture '0o_'
assert_token "0o_ is a plain string in PyYAML, token still resolves" "TOK_PLAIN" primary git.example
# '4.e8' matches the fallback's (superset) float pattern but PyYAML keeps it a
# string; either way it is constructible, so the token still resolves in both.
write_bad_key_fixture '4.e8'
assert_token "4.e8 float look-alike still resolves token" "TOK_PLAIN" primary git.example
# A valid radix int as an unrelated key must not fail closed.
write_bad_key_fixture '0x1f'
assert_token "valid hex int unrelated key still resolves token" "TOK_PLAIN" primary git.example

# 17. TAB / SCANNER PARITY: PyYAML raises a ScannerError on a tab used anywhere
#     outside a quoted scalar -- leading, trailing, or embedded in a plain value,
#     immediately after a key colon, before a key colon, or as indentation -- and
#     yields NO token, accepting tabs ONLY inside single/double-quoted scalars
#     (where the tab is preserved as string content). A prior fallback swallowed
#     those tabs (via .strip()/.rstrip() normalization and [ \t] key separators)
#     and still emitted the login token -- a fail-open in the dangerous direction.
#     The recognizer now fails CLOSED for the whole document on any tab PyYAML
#     rejects, while preserving the tabs PyYAML keeps (inside quotes). All tab
#     positions were verified empirically against PyYAML 6.0.3 (ScannerError for
#     each rejected position; string-preserved for quoted inner tabs).
TAB=$'\t'
# Fail-close: a tab in a plain value position (trailing / leading / embedded).
write_bad_key_fixture "l4o${TAB}"
assert_both_fail_closed "trailing tab in plain value fails closed" primary git.example
write_bad_key_fixture "${TAB}9"
assert_both_fail_closed "leading tab in plain value fails closed" primary git.example
write_bad_key_fixture "a${TAB}b"
assert_both_fail_closed "embedded tab in plain value fails closed" primary git.example
# Fail-close: a tab immediately after the key colon (no separating space).
write_fixture "bad:${TAB}9
logins:
  - name: primary
    url: https://git.example
    token: TOK_PLAIN
"
assert_both_fail_closed "tab immediately after key colon fails closed" primary git.example
# Fail-close: a tab used as indentation (before a sequence dash).
write_fixture "logins:
${TAB}- name: primary
    url: https://git.example
    token: TOK_PLAIN
"
assert_both_fail_closed "tab used as indentation fails closed" primary git.example
# Fail-close: a tab trailing a sequence-mapping field value.
write_fixture "logins:
  - name: primary
    url: https://git.example
    token: TOK_PLAIN${TAB}
"
assert_both_fail_closed "tab trailing a seq field value fails closed" primary git.example
# NOT over-broad: a tab strictly INSIDE a quoted scalar is valid YAML (PyYAML
# keeps it as string content), so the document parses and the login token still
# resolves in BOTH paths -- double-quoted and single-quoted.
write_bad_key_fixture "\"a${TAB}b\""
assert_token "tab inside a double-quoted value still resolves token" "TOK_PLAIN" primary git.example
write_bad_key_fixture "'a${TAB}b'"
assert_token "tab inside a single-quoted value still resolves token" "TOK_PLAIN" primary git.example
# ...and a quoted token value carrying an inner tab resolves to the exact string
# (tab preserved), identical to PyYAML's construction.
write_fixture "logins:
  - name: primary
    url: https://git.example
    token: \"T${TAB}OK\"
"
assert_token "quoted token with inner tab resolves verbatim" "T${TAB}OK" primary git.example

# 18. CONTROL-CHARACTER FAIL-CLOSE (#865 round-9 blocker 1): PyYAML's Reader
#     scans the ENTIRE raw document stream (not merely scalar contents, and NOT
#     scoped by quoting) for bytes outside its printable set and raises
#     ReaderError -- a WHOLE-DOCUMENT reject -- the instant one is found,
#     regardless of where it sits: an unrelated field's plain scalar, inside a
#     double- or single-quoted scalar, or a comment. Verified empirically against
#     real installed PyYAML 6.0.3 (see detect-platform.sh's _FORBIDDEN_CONTROL
#     comment): every C0 control byte {0x00-0x08, 0x0B, 0x0C, 0x0E-0x1F} plus DEL
#     (0x7F) rejects in ALL THREE contexts (plain / double-quoted / single-quoted);
#     only TAB(0x09), LF(0x0A), CR(0x0D) are accepted among the low byte range
#     (TAB has its own narrower, position-aware coverage in section 17 above; LF/CR
#     are line separators). A prior fallback ONLY guarded tabs and emitted the
#     login token from documents PyYAML rejects over an UNRELATED field's control
#     byte -- a dangerous fail-open (credential emission from a document PyYAML
#     refuses). write_control_char_fixture writes the raw byte directly via
#     printf's octal escape (never through a bash string/variable, which cannot
#     hold an embedded NUL) so 0x00 is exercised faithfully alongside the rest.
write_control_char_fixture() {
    local octal="$1" quote="${2:-}"
    {
        if [[ -n "$quote" ]]; then
            printf 'bad: %sx' "$quote"
            # shellcheck disable=SC2059 # deliberate: $octal supplies printf's
            # own \NNN octal escape so the raw control byte reaches the file
            # directly, never passing through a bash string (which truncates
            # at an embedded NUL and so cannot represent byte 0x00 otherwise).
            printf "\\${octal}"
            printf 'y%s\n' "$quote"
        else
            printf 'bad: x'
            # shellcheck disable=SC2059 # deliberate: $octal supplies printf's
            # own \NNN octal escape so the raw control byte reaches the file
            # directly, never passing through a bash string (which truncates
            # at an embedded NUL and so cannot represent byte 0x00 otherwise).
            printf "\\${octal}"
            printf 'y\n'
        fi
        printf 'logins:\n  - name: primary\n    url: https://git.example\n    token: TOK_PLAIN\n'
    } > "$FIXTURE_XDG/tea/config.yml"
}

# Plain (unquoted) unrelated-field placement: the full empirically-confirmed
# forbidden C0/DEL set.
for octal in 000 001 002 003 004 005 006 007 010 013 014 \
             016 017 020 021 022 023 024 025 026 027 \
             030 031 032 033 034 035 036 037 177; do
    write_control_char_fixture "$octal"
    assert_both_fail_closed "control byte \\$octal in unrelated plain field fails closed" primary git.example
done

# Inside-quote variants (double and single) for the six bytes called out
# explicitly in the round-9 blocker report: 0x00,0x01,0x07,0x0e,0x1f,0x7f.
for octal in 000 001 007 016 037 177; do
    write_control_char_fixture "$octal" '"'
    assert_both_fail_closed "control byte \\$octal inside double-quoted unrelated field fails closed" primary git.example
    write_control_char_fixture "$octal" "'"
    assert_both_fail_closed "control byte \\$octal inside single-quoted unrelated field fails closed" primary git.example
done

# Same forbidden byte inside a comment line -- PyYAML's Reader check is
# stream-wide, so it rejects here too, not merely inside live scalar content.
{
    printf '# note'
    printf '\007'
    printf 'here\nlogins:\n  - name: primary\n    url: https://git.example\n    token: TOK_PLAIN\n'
} > "$FIXTURE_XDG/tea/config.yml"
assert_both_fail_closed "control byte in a comment line fails closed" primary git.example

# NOT over-broad: TAB/LF/CR remain accepted where PyYAML already accepts them
# (covered by section 17's tab fixtures and the ordinary newline-delimited
# fixtures used throughout this file), so no additional assertion is needed
# here beyond confirming the forbidden-control guard does not fire on them.

# 19. UNSIGNED-EXPONENT FLOAT OVER-REJECTION (#865 round-9 blocker 2): PyYAML
#     6.0.3's implicit float resolver requires an EXPLICIT SIGN on the exponent
#     ([eE][-+][0-9]+); an unsigned exponent is NOT matched, so PyYAML resolves
#     the scalar as a plain STRING, not a float. A prior fallback's float
#     recognizer accepted an OPTIONAL sign ([eE][-+]?[0-9]+), over-matching these
#     spellings as floats and dropping the token PyYAML would emit verbatim
#     (over-rejection). Verified empirically against real PyYAML 6.0.3.
for form in '1.0e10' '+1.0e10' '-1.0e10' '1.0E10' '.5e10' '4.e8'; do
    write_fixture "logins:
  - name: primary
    url: https://git.example
    token: ${form}
"
    assert_token "unsigned-exponent form '$form' is a PyYAML string, token resolves" "$form" primary git.example
done

# Parity guard: a genuine SIGNED-exponent float is still typed as a non-string
# float by PyYAML and must still fail closed (not regress into over-acceptance).
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: 1.0e+10
'
assert_token "signed-exponent genuine float still fails closed" "" primary git.example
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: 1.0e-10
'
assert_token "signed-exponent (negative) genuine float still fails closed" "" primary git.example

# 20. RESIDUAL OVER-REJECTION found via round-9 differential fuzzing (folded into
#     this round, not split off): a plain scalar starting with "?" NOT followed by
#     whitespace (e.g. "?x") is a valid PyYAML string -- only a bare "?" or "? "
#     (question mark followed by space/EOL) opens a complex mapping key and is
#     illegal in a value position. A prior blanket-reject set treated EVERY
#     leading "?" as illegal, over-rejecting a token PyYAML accepts verbatim.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: ?x
'
assert_token "question-mark-not-space is a plain string, token resolves" "?x" primary git.example

# 21. PRINTABLE-BOUNDARY FAIL-CLOSE (#865 round-10 blocker 1): the round-9 guard
#     used a hand-rolled C0/DEL subset that MISSED code points PyYAML's Reader
#     also rejects -- the C1 block (U+0080-0084, U+0086-009F) and the BMP
#     noncharacters U+FFFE/U+FFFF -- so the fallback still emitted the token from
#     documents PyYAML rejects whole (fail-open). The guard now uses PyYAML
#     6.0.3's EXACT Reader.NON_PRINTABLE character class (see detect-platform.sh
#     _FORBIDDEN_CONTROL). Verified empirically against real PyYAML 6.0.3:
#     PRINTABLE = {0x09,0x0A,0x0D, 0x20-0x7E, 0x85(NEL), 0xA0-0xD7FF,
#     0xE000-0xFFFD, 0x10000-0x10FFFF}; everything else fails the whole document
#     closed. write_codepoint_fixture emits a chosen Unicode code point's real
#     UTF-8 bytes (via python3, since bash strings cannot faithfully carry many
#     of these) into a selectable position, then the login block follows.
write_codepoint_fixture() {
    # $1 = hex code point (e.g. 0x80); $2 = position: field|comment|token|nelterm
    CP_HEX="$1" CP_POS="$2" python3 - "$FIXTURE_XDG/tea/config.yml" <<'PY'
import sys
cp = int(__import__("os").environ["CP_HEX"], 16)
pos = __import__("os").environ["CP_POS"]
ch = chr(cp)
head = "logins:\n  - name: primary\n    url: https://git.example\n    token: TOK_PLAIN\n"
if pos == "field":
    doc = head + "other: x" + ch + "y\n"
elif pos == "comment":
    doc = head + "# note x" + ch + "y here\n"
elif pos == "token":
    doc = "logins:\n  - name: primary\n    url: https://git.example\n    token: T" + ch + "K\n"
elif pos == "nelterm":
    # NEL (U+0085) used as the line terminator throughout: PyYAML treats it as a
    # line break (printable, NOT a ReaderError) and resolves the token; the
    # fallback's _split_logical_lines splits on NEL identically OUTSIDE a quote
    # -> parity, token resolves. (Round 23 covers NEL/LS/PS INSIDE a quote, where
    # PyYAML folds rather than breaks and a naive splitlines() would over-split.)
    doc = ("logins:" + ch + "  - name: primary" + ch
           + "    url: https://git.example" + ch + "    token: TOK_NEL" + ch)
else:
    raise SystemExit("bad pos")
with open(sys.argv[1], "w", encoding="utf-8") as f:
    f.write(doc)
PY
}

# C1-block + BMP-noncharacter code points fail the WHOLE document closed in an
# unrelated field and in a comment, exactly as PyYAML's ReaderError does.
for cphex in 0x80 0x81 0x84 0x86 0x9f 0xfffe 0xffff; do
    write_codepoint_fixture "$cphex" field
    assert_both_fail_closed "code point $cphex in unrelated field fails closed" primary git.example
    write_codepoint_fixture "$cphex" comment
    assert_both_fail_closed "code point $cphex in a comment fails closed" primary git.example
done

# NOT over-broad: printable code points PyYAML ACCEPTS must still resolve the
# token in BOTH paths -- NEL(0x85) as a line separator, U+00A0 (NBSP) inside a
# value, and an astral code point (U+1F600) inside the token value.
write_codepoint_fixture 0x85 nelterm
assert_token "NEL (U+0085) line-terminator resolves token" "TOK_NEL" primary git.example
write_codepoint_fixture 0xa0 field
assert_token "U+00A0 in unrelated value still resolves token" "TOK_PLAIN" primary git.example
write_codepoint_fixture 0x1f600 token
assert_token "astral U+1F600 inside token resolves verbatim" "$(printf 'T\360\237\230\200K')" primary git.example

# 22. INTERNAL-INDICATOR OVER-REJECTION (#865 round-10 blocker 2): the round-9
#     recognizer blanket-rejected any plain scalar CONTAINING a flow indicator
#     ([]{}*&!), but in BLOCK context PyYAML treats ',[]{}' as ordinary content
#     and treats '!&*#...' as significant ONLY at the FIRST non-space char. So an
#     INTERNAL indicator is legal plain-string content and PyYAML emits the token
#     verbatim; the fallback dropped it (over-rejection). Verified empirically
#     against real PyYAML 6.0.3. The fix removes the blanket internal scan while
#     the leading-char guard and the ' #'/': '/trailing-':' guards keep the
#     fail-OPEN direction shut.
for tv in 'a!b' 'a,b' 'a[b' 'a]b' 'a{b' 'a}b' 'a&b' 'a*b' 'a[b]c' 'a{b}c' 'a,b,c' 'a#b' 'a:b'; do
    write_fixture "logins:
  - name: primary
    url: https://git.example
    token: ${tv}
"
    assert_token "internal-indicator token '$tv' resolves verbatim" "$tv" primary git.example
done

# Fail-OPEN direction stays shut: a LEADING indicator, a ' #' comment tail, an
# internal ': ' (colon-space) inline map, and a trailing ':' each make PyYAML
# resolve NO usable string token (tag/flow/anchor reject or None, comment strip,
# or a mapping), so BOTH must fail closed. (Leading tag/anchor/flow are the
# documented, round-9-approved structural fail-closed class; kept intact here.)
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: !x
'
assert_both_fail_closed "leading '!' tag token fails closed" primary git.example
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: [a]
'
assert_both_fail_closed "leading '[' flow-seq token fails closed" primary git.example
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: a # trailing comment
'
# ' #' comment tail: PyYAML strips the comment -> token is the string 'a', which
# still resolves. This is the NOT-over-broad boundary partner of the guard.
assert_token "space-hash comment tail strips to plain token" "a" primary git.example
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: a: b
'
assert_both_fail_closed "internal colon-space (inline map) token fails closed" primary git.example
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: ab:
'
assert_both_fail_closed "trailing colon (map indicator) token fails closed" primary git.example

# 23. EMBEDDED LINE-BREAK INSIDE A QUOTED SCALAR (#865 round-11 blocker A): the
#     round-10 fallback split the raw document with str.splitlines(), which breaks
#     at NEL(U+0085), LS(U+2028) and PS(U+2029) -- code points that are PRINTABLE
#     to PyYAML's Reader. Inside a flow (quoted) scalar PyYAML does NOT break at
#     these: it LINE-FOLDS a double/single-quoted scalar (NEL/LF/CR -> a single
#     space; LS/PS -> the char verbatim), so it resolves ONE token, while
#     splitlines() cut the value mid-quote and failed the whole document closed
#     (over-rejection). The fallback now uses _split_logical_lines, which
#     reproduces PyYAML's flow-folding. Verified empirically vs real PyYAML 6.0.3.
#     write_break_fixture emits a chosen break code point in a selectable context.
write_break_fixture() {
    # $1 = hex code point of the break; $2 = context: dq|sq|plain|comment|dq2
    CP_HEX="$1" Q_STYLE="$2" python3 - "$FIXTURE_XDG/tea/config.yml" <<'PY'
import sys, os
cp = int(os.environ["CP_HEX"], 16)
q = os.environ["Q_STYLE"]
ch = chr(cp)
head = "logins:\n  - name: primary\n    url: https://git.example\n    token: "
if q == "dq":
    doc = head + '"tok' + ch + 'en"'
elif q == "sq":
    doc = head + "'tok" + ch + "en'"
elif q == "plain":
    doc = head + "tok" + ch + "en"
elif q == "dq2":
    # blank line inside a quoted scalar: PyYAML folds a two-break run to a literal
    # newline, which the recognizer's key regex cannot carry -> endorsed
    # fail-closed over-reject (see assert_fallback_fails_closed below).
    doc = head + '"tok' + ch + ch + 'en"'
elif q == "comment":
    doc = ("logins:\n  - name: primary\n    url: https://git.example\n"
           "    token: TOK_PLAIN\n# c" + ch + "x")
else:
    raise SystemExit("bad q")
with open(sys.argv[1], "w", encoding="utf-8") as f:
    f.write(doc + "\n")
PY
}

# NEL folds to a single space inside double- AND single-quoted scalars: the token
# resolves identically in both paths (fallback no longer over-splits).
write_break_fixture 0x85 dq
assert_token "NEL inside double-quote folds to space, token resolves" "tok en" primary git.example
write_break_fixture 0x85 sq
assert_token "NEL inside single-quote folds to space, token resolves" "tok en" primary git.example
# LS(U+2028)/PS(U+2029) are preserved VERBATIM by PyYAML's flow fold (they are
# not \n-class breaks); the fallback must surface them byte-for-byte.
write_break_fixture 0x2028 dq
assert_token "LS inside double-quote is verbatim" "$(printf 'tok\342\200\250en')" primary git.example
write_break_fixture 0x2028 sq
assert_token "LS inside single-quote is verbatim" "$(printf 'tok\342\200\250en')" primary git.example
write_break_fixture 0x2029 dq
assert_token "PS inside double-quote is verbatim" "$(printf 'tok\342\200\251en')" primary git.example

# Direction-sensitivity: the SAME code points UNQUOTED (a plain scalar) or in a
# COMMENT make PyYAML raise a scanner error, so both paths must fail closed. The
# fold rule applies ONLY inside a quoted scalar.
write_break_fixture 0x85 plain
assert_token "NEL in an unquoted plain scalar fails closed" "" primary git.example
write_break_fixture 0x2028 plain
assert_token "LS in an unquoted plain scalar fails closed" "" primary git.example
write_break_fixture 0x85 comment
assert_token "NEL in a comment fails closed" "" primary git.example

# Endorsed fail-closed over-reject: a blank line inside a quoted scalar folds to a
# literal newline that the recognizer cannot carry -- PyYAML resolves a
# (newline-bearing) token, the fallback fails closed (strictly safer).
write_break_fixture 0x85 dq2
assert_fallback_fails_closed "blank-line-in-quote (NEL run) fails closed" primary git.example

# 24. LEADING NON-SPECIFIC TAG / ANCHOR PROPERTY (#865 round-11 blocker B, revised
#     in round 12): the round-10 recognizer blanket-rejected any scalar beginning
#     with '!' or '&'. Round 11 taught it to strip a transparent NON-SPECIFIC tag
#     ('! ' bang + SPACE) and a transparent plain ANCHOR ('&name ') so '! x' /
#     '&a x' resolve the STRING 'x', matching PyYAML. Round 12 discovered that the
#     anchor half of that was a HIGH fail-open: PyYAML's Composer tracks anchor
#     NAMES in a document-scoped registry and raises ComposerError ("found
#     duplicate anchor") the instant the SAME name is declared on a SECOND node
#     ANYWHERE in the document (even an unrelated one) -- the fallback's
#     per-scalar-only view has no such registry and would emit the later token.
#     Round 12's fix: reject EVERY '&'-anchor property, unconditionally. The
#     transparent NON-SPECIFIC TAG behavior ('! x' -> 'x') is unchanged and still
#     verified below; only the anchor half now fails closed (deliberate
#     conservative over-reject, verified safe both ways against real PyYAML 6.0.3).
for pair in '! x=x' '! x y=x y' '! "q"=q' "! 'q'=q"; do
    tv="${pair%%=*}"; want="${pair#*=}"
    write_fixture "logins:
  - name: primary
    url: https://git.example
    token: ${tv}
"
    assert_token "tag property token '$tv' resolves node string" "$want" primary git.example
done

# Fail-OPEN direction stays shut. '!x' (bang + NON-space) is a tag HANDLE ->
# ConstructorError; '!foo x'/'* a'/'! !x' raise; a property over a NON-string node
# ('! 123'/'! true'/'! null') types non-str -> no usable token. All fail closed in
# BOTH paths.
for tv in '!x' '!foo x' '* a' '! !x' '! 123' '! true' '! null' '&a &b x'; do
    write_fixture "logins:
  - name: primary
    url: https://git.example
    token: ${tv}
"
    assert_token "non-resolving property token '$tv' fails closed" "" primary git.example
done

# Round 12: a SINGLE, non-duplicated '&a x' is valid YAML that real PyYAML
# resolves to the string 'x' (round-11 behavior, and still true of the oracle).
# The fallback now rejects it anyway -- a deliberate, endorsed CONSERVATIVE
# over-reject (see the round-12 comment block above): fail-closed can only cost
# an emitted token PyYAML would have allowed, never emit one PyYAML rejects, and
# a per-scalar recognizer cannot safely prove document-wide anchor-name
# uniqueness. assert_fallback_fails_closed also confirms PyYAML really does
# resolve a token here, proving this is a genuine (safe-direction) divergence
# and not an accidental parity loss.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: &a x
'
assert_fallback_fails_closed "round-12: single non-duplicated anchor '&a x' now fails closed (conservative over-reject; PyYAML resolves x)" primary git.example
# Same over-reject for the combined tag+anchor forms round 11 used to resolve.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: ! &b x
'
assert_fallback_fails_closed "round-12: '! &b x' (tag+anchor) now fails closed (conservative over-reject)" primary git.example
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: &b ! x
'
assert_fallback_fails_closed "round-12: '&b ! x' (anchor+tag) now fails closed (conservative over-reject)" primary git.example

# Endorsed fail-closed over-reject: an EXPLICIT tag ('!!str x', verbose
# '!<tag:yaml.org,2002:str> x') forces a string PyYAML resolves, but the fallback
# recognizes only the transparent non-specific tag and fails closed (safer).
for tv in '!!str x' '!<tag:yaml.org,2002:str> x'; do
    write_fixture "logins:
  - name: primary
    url: https://git.example
    token: ${tv}
"
    assert_fallback_fails_closed "explicit-tag token '$tv' fails closed" primary git.example
done

# 25. #865 round 12 HIGH fail-open closure: DUPLICATE ANCHOR NAME across separate
#     nodes. Real PyYAML's Composer tracks anchor names in a DOCUMENT-SCOPED
#     registry and raises ComposerError ("found duplicate anchor ... first
#     occurrence") the instant the SAME anchor name is declared a second time
#     ANYWHERE in the document -- failing the WHOLE document closed, no token,
#     regardless of how far the duplicate sits from the logins block. The round-11
#     fallback tracked anchors only WITHIN a single scalar's `_strip_properties`
#     call, so it had no visibility into a duplicate declared on an unrelated
#     node and would still emit the (later) token: fail-open. The round-12 fix
#     (reject every '&'-anchor property, unconditionally -- see section 24 above)
#     closes this as a strict superset: since NO anchor is ever accepted, a
#     duplicate anchor can never slip through. These cases exercise that
#     document-wide duplicate-anchor invariant specifically (as opposed to
#     section 24's single-anchor-on-the-token-field cases) and pair each fallback
#     assertion with confirmation that real PyYAML also fails closed here (via
#     ComposerError), proving this was a genuine fail-open, not a hypothetical.
write_fixture 'first: &same one
second: &same two
logins:
  - name: primary
    url: https://git.example
    token: TOK_DUP_ROOT
'
assert_both_fail_closed "round-12: duplicate anchor name on two unrelated root nodes fails closed" primary git.example

write_fixture 'outer:
  nested: &dup x
dup_root: &dup y
logins:
  - name: primary
    url: https://git.example
    token: TOK_DUP_NESTED
'
assert_both_fail_closed "round-12: duplicate anchor name across a nested node and a root node fails closed" primary git.example

write_fixture 'first: &dup one
logins:
  - name: primary
    url: https://git.example
    token: &dup TOK_DUP_TOKEN_NODE
'
assert_both_fail_closed "round-12: anchor name declared earlier and repeated on the token-bearing node fails closed" primary git.example

# Regression guard: the non-specific TAG half of section 24 ('! x' -> 'x') is
# UNCHANGED by the round-12 anchor fix and must still resolve.
write_fixture 'logins:
  - name: primary
    url: https://git.example
    token: ! x
'
assert_token "round-12 regression: '! x' (tag, no anchor) still resolves 'x'" "x" primary git.example

echo "Gitea login resolution regression harness passed"
