#!/usr/bin/env bash
#clear
#export PS4='\e[90m+${LINENO} in ${#BASH_SOURCE[@]}>${FUNCNAME[0]}:${BASH_SOURCE[@]##*/} \e[0m'
#set -x
TEST_CATEGORY=core

level=$1
if [ -z "$level" ]; then
  level=1
else 
  # remove the level parameter
  shift
fi
echo "starting: ${BASH_SOURCE[@]##*/} <LOG_LEVEL=$1>"

#echo "sourcing init"
source this
source test.suite

log.level $level

competionArray=(once config list file ite)
source oo

test.ossh() 
{
((TEST_COUNTER++))
console.log "


Test 0: ossh \"$*\"
===================================================================="
ossh.start "$@"
console.log "RETURN: $RETURN_VALUE  Result: $RESULT 
===================================================================="
}

test.case - "ossh test start" \
   ossh usage
expect 0 "*" "Test start"

source ossh

### test.method

# ============================================================================
# Test ossh.config.create - user@host parsing (bug fix #1)
# ============================================================================

test.case $level "ossh.config.create parses user@host correctly" \
  ossh.config.create test@testhost

# Verify Host line uses hostname only (not user@host)
HOST_LINE=$(grep "^Host " "$CONFIG_PATH/result.txt" 2>/dev/null | head -1)
if echo "$HOST_LINE" | grep -q "^Host testhost$"; then
  expect.pass "Host line is 'Host testhost' (no @ symbol)"
else
  expect.fail "Host line should be 'Host testhost', got: $HOST_LINE"
fi

test.case $level "ossh.config.create parses User from user@host" \
  ossh.config.create test@testhost

USER_LINE=$(grep "User " "$CONFIG_PATH/result.txt" 2>/dev/null | head -1)
if echo "$USER_LINE" | grep -q "User test$"; then
  expect.pass "User parsed as 'test'"
else
  expect.fail "User should be 'test', got: $USER_LINE"
fi

test.case $level "ossh.config.create parses HostName from user@host" \
  ossh.config.create test@testhost

HOSTNAME_LINE=$(grep "HostName " "$CONFIG_PATH/result.txt" 2>/dev/null | head -1)
if echo "$HOSTNAME_LINE" | grep -q "HostName testhost$"; then
  expect.pass "HostName parsed as 'testhost'"
else
  expect.fail "HostName should be 'testhost', got: $HOSTNAME_LINE"
fi

# ============================================================================
# Test private.config.create sets RESULT via create.result (bug fix #4)
# ============================================================================

test.case $level "config.create sets RESULT via create.result" \
  ossh.config.create test@testhost

if [ -n "$RESULT" ] && [ "$RESULT" = "testhost" ]; then
  expect.pass "RESULT set to 'testhost'"
else
  expect.fail "RESULT should be 'testhost', got: '$RESULT'"
fi

# ============================================================================
# Test ossh.config.save.last - writes clean entry (bug fix #2, #3)
# ============================================================================

# Use a temp file to avoid polluting real ~/.ssh/config
TEST_SSH_CONFIG=$(mktemp /tmp/test.ossh.config.XXXXXX)

# First, create a config entry
ossh.config.create test@testhost

test.case $level "ossh.config.save.last writes clean entry to file" \
  ossh.config.save.last "$TEST_SSH_CONFIG"

if grep -q "^Host testhost$" "$TEST_SSH_CONFIG" 2>/dev/null; then
  expect.pass "config.save.last wrote 'Host testhost' to file"
else
  expect.fail "config.save.last should write 'Host testhost' to file"
fi

# ============================================================================
# Test ossh.config.save.last - duplicate detection (bug fix #3)
# ============================================================================

# config.save.last was already called once above, so calling again should detect duplicate
test.case $level "ossh.config.save.last detects duplicate Host entry" \
  ossh.config.save.last "$TEST_SSH_CONFIG"

if [ "$RETURN_VALUE" -eq 1 ]; then
  expect.pass "config.save.last returned 1 for duplicate Host"
else
  expect.fail "config.save.last should return 1 for duplicate, got: $RETURN_VALUE"
fi

# Verify only one entry exists (no duplicate appended)
ENTRY_COUNT=$(grep -c "^Host testhost$" "$TEST_SSH_CONFIG" 2>/dev/null)
test.case $level "config.save.last did not append duplicate entry" \
  echo "$ENTRY_COUNT"

if [ "$ENTRY_COUNT" -eq 1 ]; then
  expect.pass "only 1 'Host testhost' entry in file"
else
  expect.fail "should have exactly 1 entry, found: $ENTRY_COUNT"
fi

# ============================================================================
# Cleanup
# ============================================================================

rm -f "$TEST_SSH_CONFIG" 2>/dev/null

# ============================================================================
# Test ossh.known.hosts.remove - requires host parameter
# ============================================================================

test.case $level "ossh.known.hosts.remove requires host parameter" \
  ossh.known.hosts.remove

if [ "$RETURN_VALUE" -eq 1 ]; then
  expect.pass "returns 1 when no host given"
else
  expect.fail "should return 1 when no host given, got: $RETURN_VALUE"
fi

# ============================================================================
# Test ossh.known.hosts.remove - function exists
# ============================================================================

test.case $level "ossh.known.hosts.remove is defined" \
  type ossh.known.hosts.remove

if type ossh.known.hosts.remove 2>/dev/null | grep -q "function"; then
  expect.pass "ossh.known.hosts.remove is a function"
else
  expect.fail "ossh.known.hosts.remove should be a function after sourcing ossh"
fi

# ============================================================================
# Test ossh.known.hosts.remove - handles missing known_hosts gracefully
# ============================================================================

TEST_HOME_BACKUP="$HOME"
TEST_TMP_HOME=$(mktemp -d /tmp/test.ossh.home.XXXXXX)
HOME="$TEST_TMP_HOME"

test.case $level "ossh.known.hosts.remove handles missing known_hosts" \
  ossh.known.hosts.remove testhost 8022

if [ "$RETURN_VALUE" -eq 0 ]; then
  expect.pass "returns 0 when no known_hosts file exists"
else
  expect.fail "should return 0 gracefully, got: $RETURN_VALUE"
fi

HOME="$TEST_HOME_BACKUP"
rm -rf "$TEST_TMP_HOME" 2>/dev/null

# ============================================================================
# Test ossh.known.hosts.remove.completion exists
# ============================================================================

if type ossh.known.hosts.remove.completion >/dev/null 2>&1; then
  expect.pass "ossh.known.hosts.remove.completion is defined"
else
  expect.fail "ossh.known.hosts.remove.completion should be defined"
fi

# ============================================================================
# Test ossh.install.user.remote - function exists (new feature)
# ============================================================================

test.case $level "ossh.install.user.remote is defined" \
  type ossh.install.user.remote

if type ossh.install.user.remote 2>/dev/null | grep -q "function"; then
  expect.pass "ossh.install.user.remote is a function"
else
  expect.fail "ossh.install.user.remote should be a function after sourcing ossh"
fi

# ============================================================================
# Test ossh.install.user.remote - requires sshConfigHost parameter
# ============================================================================

test.case $level "ossh.install.user.remote requires sshConfigHost" \
  ossh.install.user.remote

if [ "$RETURN_VALUE" -eq 1 ]; then
  expect.pass "returns 1 when no sshConfigHost given"
else
  expect.fail "should return 1 when no sshConfigHost given, got: $RETURN_VALUE"
fi

# ============================================================================
# Test ossh.install.user.remote - requires user parameter
# ============================================================================

test.case $level "ossh.install.user.remote requires user parameter" \
  ossh.install.user.remote testhost

if [ "$RETURN_VALUE" -eq 1 ]; then
  expect.pass "returns 1 when no user given"
else
  expect.fail "should return 1 when no user given, got: $RETURN_VALUE"
fi

# ============================================================================
# Test ossh.install.user.remote - code quality / pattern tests (CRIT-7)
# ============================================================================

# Extract function body once for all pattern tests
FUNC_START=$(grep -n '^ossh\.install\.user\.remote()' "$OOSH_DIR/ossh" | head -1 | cut -d: -f1)
FUNC_END=$(awk "NR>$FUNC_START && /^[a-zA-Z].*()/ {print NR; exit}" "$OOSH_DIR/ossh")
FUNC_BODY=$(sed -n "${FUNC_START},${FUNC_END}p" "$OOSH_DIR/ossh")

# ----------------------------------------------------------------------------
test.case $level "T-REMOTE-1: install.user.remote uses getent for Linux home detection" \
  echo "$FUNC_BODY"

if echo "$FUNC_BODY" | grep -q "getent passwd"; then
  expect.pass "function uses getent passwd for Linux home detection"
else
  expect.fail "function should use getent passwd for Linux home detection"
fi

# ----------------------------------------------------------------------------
test.case $level "T-REMOTE-2: install.user.remote has dscl fallback for macOS" \
  echo "$FUNC_BODY"

if echo "$FUNC_BODY" | grep -q "dscl"; then
  expect.pass "function has dscl fallback for macOS"
else
  expect.fail "function should have dscl fallback for macOS"
fi

# ----------------------------------------------------------------------------
test.case $level "T-REMOTE-3: install.user.remote uses portable sed pattern" \
  echo "$FUNC_BODY"

if echo "$FUNC_BODY" | grep -q "sed -i ''"; then
  expect.fail "function uses macOS-only 'sed -i \\x27\\x27' — should use platform-aware pattern"
else
  expect.pass "function does not use macOS-only sed -i pattern"
fi

# ----------------------------------------------------------------------------
# After the refactor that collapses ossh.install.user.remote onto
# user.oosh.install, dseditgroup/usermod, ln -s and git safe.directory
# are no longer expected in the ossh body — they live in user.oosh.install
# (via its .groups.{darwin,linux} helpers and main body). These tests now
# target the canonical location.
USER_INSTALL_START=$(grep -n '^user\.oosh\.install()' "$OOSH_DIR/user" | head -1 | cut -d: -f1)
USER_INSTALL_END=$(awk "NR>$USER_INSTALL_START && /^[a-zA-Z].*()/ {print NR; exit}" "$OOSH_DIR/user")
USER_INSTALL_BLOCK=$(sed -n "${USER_INSTALL_START},${USER_INSTALL_END}p" "$OOSH_DIR/user")
# Also include the private helpers that user.oosh.install dispatches to via os.check
USER_GROUPS_BLOCK=$(grep -E "^private\.user\.oosh\.install\.groups\." "$OOSH_DIR/user" | head -5)
USER_HELPERS_BLOCK=$(awk '/^private\.user\.oosh\.install\./{flag=1} flag; /^}/ && flag{flag=0}' "$OOSH_DIR/user")

test.case $level "T-REMOTE-4: user.oosh.install handles both dseditgroup and usermod" \
  echo "combined"

if echo "$USER_INSTALL_BLOCK $USER_HELPERS_BLOCK" | grep -q "dseditgroup" \
   && echo "$USER_INSTALL_BLOCK $USER_HELPERS_BLOCK" | grep -qE "usermod|user\.group\.add"; then
  expect.pass "user.oosh.install (with helpers) handles both dseditgroup (macOS) and Linux group mgmt"
else
  expect.fail "user.oosh.install should handle both dseditgroup and usermod/user.group.add for group management"
fi

# ----------------------------------------------------------------------------
test.case $level "T-REMOTE-5: user.oosh.install creates symlinks (not copies)" \
  echo "$USER_INSTALL_BLOCK"

if echo "$USER_INSTALL_BLOCK" | grep -q "ln -s"; then
  expect.pass "user.oosh.install uses ln -s to create symlinks"
else
  expect.fail "user.oosh.install should use ln -s for symlinks, not cp"
fi

# ----------------------------------------------------------------------------
test.case $level "T-REMOTE-6: user.oosh.install adds git safe.directory" \
  echo "$USER_INSTALL_BLOCK"

if echo "$USER_INSTALL_BLOCK" | grep -q "safe\.directory"; then
  expect.pass "user.oosh.install adds git safe.directory for shared oosh repo"
else
  expect.fail "user.oosh.install should add git safe.directory for cross-user shared repo"
fi

# ----------------------------------------------------------------------------
test.case $level "T-REMOTE-7: ossh.install.user.remote delegates to user.oosh.install" \
  echo "$FUNC_BODY"

# Match the invocation ` oosh.install <args>` (preceded by anything that
# closes a command name — space, ", ', \"). Covers both the dispatcher form
# `user oosh.install` and the absolute-path form `"$sharedOosh/user" oosh.install`.
if echo "$FUNC_BODY" | grep -qE "[^a-zA-Z]oosh\.install[ 	]"; then
  expect.pass "ossh.install.user.remote delegates via 'user oosh.install'"
else
  expect.fail "ossh.install.user.remote should delegate to 'user oosh.install' over SSH"
fi

# ============================================================================
# Test Darwin-specific portability patterns in the install pipeline (MED-7).
# F3 (the /root → $HOME sed templating) lived in ossh.install.continue.local
# until commit «state-machine fail-loud Phase 1»; it now lives in oo's state 31
# body (right after `config save`). Aggregate both files so the test still
# verifies the portable-sed invariant regardless of which file owns it.
# ============================================================================

INSTALL_PIPELINE_FULL="$(cat "$OOSH_DIR/ossh" "$OOSH_DIR/oo" 2>/dev/null)"

# ----------------------------------------------------------------------------
test.case $level "T-DARWIN-1: portable sed-i pattern uses uname check" \
  echo "(install pipeline aggregated)"

if echo "$INSTALL_PIPELINE_FULL" | grep -q 'uname -s.*Darwin'; then
  expect.pass "install pipeline uses uname -s check for Darwin-specific sed -i handling"
else
  expect.fail "install pipeline (oo or ossh) should use uname -s to detect Darwin for portable sed -i"
fi

# ----------------------------------------------------------------------------
test.case $level "T-DARWIN-2: root home detection handles both Linux and macOS" \
  echo "(install pipeline aggregated)"

# The code should use $HOME (dynamic) rather than hardcoding /root or /var/root
if echo "$INSTALL_PIPELINE_FULL" | grep -qE '_?rootHome="\$HOME"'; then
  expect.pass "root home detection uses \$HOME (works on both Linux /root and macOS /var/root)"
else
  expect.fail "root home detection should use \$HOME for portability across Linux and macOS"
fi

# ============================================================================
# Test Summary
# ============================================================================

# ============================================================================
# Shared SSH config tests — fixture-based
# ============================================================================
SHARED_FIXTURE="/tmp/test.ossh.shared.$$"
SHARED_DIR="$SHARED_FIXTURE/shared_ssh"

# Phase 3 of the .ssh/ correctness plan: github access flows through
# ~/.ssh/ids/ssh.developking/id_rsa, not a standalone deploy key. The
# shared-create primitive no longer touches any deploy key file.

# ============================================================================
# T-SHARED-1: ossh.config.shared.github.create creates directory and config
# ============================================================================
test.ossh.shared.create() {
  ossh.config.shared.github.create "$SHARED_DIR" >/dev/null 2>&1
  local rc=$?

  if [ $rc -eq 0 ] && [ -d "$SHARED_DIR" ] && [ -f "$SHARED_DIR/config" ]; then
    create.result 0 "dir and config created"
  else
    create.result 1 "rc=$rc dir=$([ -d "$SHARED_DIR" ] && echo yes || echo no) config=$([ -f "$SHARED_DIR/config" ] && echo yes || echo no)"
  fi
}
test.case - "T-SHARED-1: config.shared.github.create creates directory and config" \
  test.ossh.shared.create
expect 0 "dir and config created" "ossh.config.shared.github.create creates shared SSH directory and config"

# ============================================================================
# T-SHARED-2: ossh.config.shared.github.create is idempotent
# ============================================================================
test.ossh.shared.idempotent() {
  # Run twice
  ossh.config.shared.github.create "$SHARED_DIR" >/dev/null 2>&1
  ossh.config.shared.github.create "$SHARED_DIR" >/dev/null 2>&1
  local rc=$?

  # Count Host github.com entries — should be exactly 1
  local count
  count=$(grep -c "^Host github.com$" "$SHARED_DIR/config" 2>/dev/null)

  if [ $rc -eq 0 ] && [ "$count" -eq 1 ]; then
    create.result 0 "idempotent ($count entry)"
  else
    create.result 1 "rc=$rc count=$count"
  fi
}
test.case - "T-SHARED-2: config.shared.github.create is idempotent" \
  test.ossh.shared.idempotent
expect 0 "idempotent (1 entry)" "ossh.config.shared.github.create does not duplicate on re-run"

# ============================================================================
# T-SHARED-3: ossh.config.shared.github.create sets correct permissions
# ============================================================================
test.ossh.shared.permissions() {
  local dirPerms
  dirPerms=$(stat -c "%a" "$SHARED_DIR" 2>/dev/null || stat -f "%Lp" "$SHARED_DIR" 2>/dev/null)
  local configPerms
  configPerms=$(stat -c "%a" "$SHARED_DIR/config" 2>/dev/null || stat -f "%Lp" "$SHARED_DIR/config" 2>/dev/null)

  # Standalone deploy key file should NOT exist anymore
  local hasLegacyKey="no"
  [ -e "$SHARED_DIR/2cuGitHub" ] && hasLegacyKey="yes"

  if [ "$dirPerms" = "700" ] && [ "$configPerms" = "600" ] && [ "$hasLegacyKey" = "no" ]; then
    create.result 0 "permissions correct, no legacy 2cuGitHub"
  else
    create.result 1 "dir=$dirPerms config=$configPerms legacyKey=$hasLegacyKey"
  fi
}
test.case - "T-SHARED-3: config.shared.github.create sets correct perms, no legacy key" \
  test.ossh.shared.permissions
expect 0 "permissions correct, no legacy 2cuGitHub" "directory 700, config 600, no standalone 2cuGitHub file"

# ============================================================================
# T-SHARED-6: shared config contains Host github.com with developking IdentityFile
# ============================================================================
test.ossh.shared.validConfig() {
  if ! grep -q "^Host github.com$" "$SHARED_DIR/config" 2>/dev/null; then
    create.result 1 "Host github.com not found in config"
    return
  fi
  # Extract the github.com block and check IdentityFile.
  local ghBlock
  ghBlock=$(awk '
    /^Host github.com$/ {found=1; next}
    found && /^Host / {found=0}
    found {print}
  ' "$SHARED_DIR/config")
  if echo "$ghBlock" | grep -Fq "IdentityFile ~/.ssh/ids/ssh.developking/id_rsa"; then
    create.result 0 "github.com block uses developking id_rsa"
  else
    create.result 1 "github.com block has wrong IdentityFile"
  fi
}
test.case - "T-SHARED-6: shared config has Host github.com via ids/ssh.developking/id_rsa" \
  test.ossh.shared.validConfig
expect 0 "github.com block uses developking id_rsa" "shared config's github.com Host points at developking key"

# ============================================================================
# T-SHARED-4: ossh.config.shared.link creates symlink for user
# ============================================================================
test.ossh.shared.link.symlink() {
  local testUserHome="$SHARED_FIXTURE/home_testuser"
  mkdir -p "$testUserHome/.ssh"

  # Override HOME to simulate the target user
  local SAVE_HOME="$HOME"
  HOME="$testUserHome"

  # Call link with explicit user path simulation
  # We test the logic by calling directly with the shared dir
  if [ ! -e "$testUserHome/.ssh/config" ]; then
    ln -s "$SHARED_DIR/config" "$testUserHome/.ssh/config"
  fi

  HOME="$SAVE_HOME"

  if [ -L "$testUserHome/.ssh/config" ]; then
    local target
    target=$(readlink "$testUserHome/.ssh/config")
    if [ "$target" = "$SHARED_DIR/config" ]; then
      create.result 0 "symlink created"
    else
      create.result 1 "symlink target=$target expected=$SHARED_DIR/config"
    fi
  else
    create.result 1 "not a symlink"
  fi
}
test.case - "T-SHARED-4: config.shared.link creates symlink" \
  test.ossh.shared.link.symlink
expect 0 "symlink created" "ossh.config.shared.link creates symlink to shared config"

# ============================================================================
# T-SHARED-5: appending Host github.com block preserves pre-existing config
# ============================================================================
test.ossh.shared.link.append() {
  local testUserHome="$SHARED_FIXTURE/home_existinguser"
  mkdir -p "$testUserHome/.ssh"
  # Create a pre-existing config with different content
  echo "Host myserver" > "$testUserHome/.ssh/config"
  echo " User admin" >> "$testUserHome/.ssh/config"

  # Simulate the per-user-link path: append the github.com block from
  # the shared config if not already present.
  if ! grep -q "^Host github.com$" "$testUserHome/.ssh/config" 2>/dev/null; then
    awk '
      /^Host github.com$/ {found=1; print; next}
      found && /^Host / {found=0}
      found {print}
    ' "$SHARED_DIR/config" >> "$testUserHome/.ssh/config"
  fi

  # Verify original content preserved AND github.com added
  local hasOriginal=false
  local hasGithub=false
  grep -q "^Host myserver$" "$testUserHome/.ssh/config" 2>/dev/null && hasOriginal=true
  grep -q "^Host github.com$" "$testUserHome/.ssh/config" 2>/dev/null && hasGithub=true

  if [ "$hasOriginal" = "true" ] && [ "$hasGithub" = "true" ]; then
    create.result 0 "appended without overwrite"
  else
    create.result 1 "original=$hasOriginal github=$hasGithub"
  fi
}
test.case - "T-SHARED-5: github.com append preserves pre-existing user config" \
  test.ossh.shared.link.append
expect 0 "appended without overwrite" "existing config preserved, Host github.com appended"

# Cleanup shared fixture
rm -rf "$SHARED_FIXTURE" 2>/dev/null

# ============================================================================
# T-PROXYJUMP-1: config.create with proxyJump includes ProxyJump line
# ============================================================================
test.case $level "config.create with proxyJump includes ProxyJump line" \
  ossh.config.create testProxyHost test@localhost:22 proxyJump jumphost

RESULT_CONTENT=$(cat $CONFIG_PATH/result.txt 2>/dev/null)
if echo "$RESULT_CONTENT" | grep -q "ProxyJump jumphost"; then
  expect.pass "ProxyJump jumphost found in config"
else
  expect.fail "ProxyJump line missing, got: $RESULT_CONTENT"
fi

# ============================================================================
# T-PROXYJUMP-2: config.create without proxyJump omits ProxyJump line
# ============================================================================
test.case $level "config.create without proxyJump omits ProxyJump line" \
  ossh.config.create testNoProxy test@localhost:22

RESULT_CONTENT=$(cat $CONFIG_PATH/result.txt 2>/dev/null)
if echo "$RESULT_CONTENT" | grep -q "ProxyJump"; then
  expect.fail "ProxyJump should not appear when param not given"
else
  expect.pass "no ProxyJump in config without param"
fi

# ─────────────────────────────────────────────────────────────────────────────
# T-HARDEN-* : ossh.harden.* methods exist, signatures right, orchestrator
# chains in order and doesn't silently invoke .sshd.allowusers. Pattern
# mirrors T-REMOTE-* — grep the function body, not runtime behaviour.
# ─────────────────────────────────────────────────────────────────────────────
for m in harden harden.packages harden.unattended.upgrades harden.fail2ban harden.firewall harden.sshd harden.sshd.allowusers; do
  test.case $level "T-HARDEN-DEF-$m: ossh.$m is defined" \
    type ossh.$m
  if [ "$RETURN_VALUE" -eq 0 ]; then
    expect.pass "ossh.$m is a function"
  else
    expect.fail "ossh.$m not defined"
  fi
done

# T-HARDEN-ORDER: orchestrator calls the five sub-methods in the documented order
HARDEN_BODY=$(declare -f ossh.harden 2>/dev/null)
test.case $level "T-HARDEN-ORDER: ossh.harden invokes sub-methods in order" \
  echo "$HARDEN_BODY"
if echo "$HARDEN_BODY" | awk '
    /ossh\.harden\.packages /            {p=NR}
    /ossh\.harden\.unattended\.upgrades/ {u=NR}
    /ossh\.harden\.fail2ban/             {f=NR}
    /ossh\.harden\.firewall/             {w=NR}
    /ossh\.harden\.sshd /                {s=NR}
    END {exit !(p<u && u<f && f<w && w<s)}
'; then
  expect.pass "orchestrator chains packages -> unattended -> fail2ban -> firewall -> sshd"
else
  expect.fail "sub-method call order in ossh.harden does not match the documented sequence"
fi

# T-HARDEN-NO-ALLOWUSERS: orchestrator must NOT call the AllowUsers sub-method
test.case $level "T-HARDEN-NO-ALLOWUSERS: orchestrator does not silently call .sshd.allowusers" \
  echo "$HARDEN_BODY"
if ! echo "$HARDEN_BODY" | grep -q "ossh\.harden\.sshd\.allowusers"; then
  expect.pass "ossh.harden does not silently call .sshd.allowusers"
else
  expect.fail "ossh.harden references .sshd.allowusers - it must stay opt-in to avoid lockouts"
fi

# T-HARDEN-PREFLIGHT: every top-level harden method calls private.ossh.harden.preflight
for m in harden harden.packages harden.unattended.upgrades harden.fail2ban harden.firewall harden.sshd harden.sshd.allowusers; do
  BODY=$(declare -f ossh.$m 2>/dev/null)
  test.case $level "T-HARDEN-PREFLIGHT-$m: ossh.$m calls preflight" \
    echo "$BODY"
  if echo "$BODY" | grep -q "private\.ossh\.harden\.preflight"; then
    expect.pass "ossh.$m gates entry on preflight"
  else
    expect.fail "ossh.$m bypasses preflight - would risk lockouts or non-Linux targets"
  fi
done

# T-HARDEN-ALLOWUSERS-EMPTY: .sshd.allowusers refuses to run without users
ALLOW_BODY=$(declare -f ossh.harden.sshd.allowusers 2>/dev/null)
test.case $level "T-HARDEN-ALLOWUSERS-EMPTY: .sshd.allowusers rejects empty user list" \
  echo "$ALLOW_BODY"
if echo "$ALLOW_BODY" | grep -q "refusing to run"; then
  expect.pass ".sshd.allowusers refuses to run with empty users arg"
else
  expect.fail ".sshd.allowusers must refuse empty users (else it locks everyone out)"
fi

# ─────────────────────────────────────────────────────────────────────────────
# T-BRANCH-SHORT-* : this.git.branch.short strips the four known ref prefixes
# and the rev-parse sites all delegate to it.
# ─────────────────────────────────────────────────────────────────────────────
BRANCH_BODY=$(declare -f this.git.branch.short 2>/dev/null)
test.case $level "T-BRANCH-SHORT-EXISTS: this.git.branch.short is defined" \
  type this.git.branch.short
if [ "$RETURN_VALUE" -eq 0 ]; then
  expect.pass "this.git.branch.short is a function"
else
  expect.fail "this.git.branch.short not defined"
fi

for prefix in "refs/heads/" "refs/remotes/origin/" "heads/origin/" "origin/"; do
  test.case $level "T-BRANCH-SHORT-STRIP-$prefix: body strips '$prefix' prefix" \
    echo "$BRANCH_BODY"
  if echo "$BRANCH_BODY" | grep -qF "\${b#$prefix}"; then
    expect.pass "body strips $prefix"
  else
    expect.fail "body does not strip $prefix - polluted branch names will leak through"
  fi
done

# T-BRANCH-SHORT-CALLER-*: every caller-side rev-parse site delegates to the helper
for pair in "ossh:449" "ossh:510" "ossh:720" "oo:1233" "user:701" "promote:437" "promote:556"; do
  file="${pair%:*}"
  test.case $level "T-BRANCH-SHORT-CALLER-$pair: $file uses this.git.branch.short" \
    echo "(grep below)"
  if grep -q "this\.git\.branch\.short" "$OOSH_DIR/$file" 2>/dev/null; then
    expect.pass "$file references this.git.branch.short"
  else
    expect.fail "$file has a rev-parse that wasn't migrated to this.git.branch.short"
  fi
done

# T-BRANCH-SHORT-REMOTE-*: init/oosh and oo sanitise OOSH_BRANCH
for file in init/oosh oo; do
  test.case $level "T-BRANCH-SHORT-REMOTE-$file: $file strips OOSH_BRANCH prefixes" \
    echo "(grep below)"
  if grep -qE "OOSH_BRANCH=.*OOSH_BRANCH#(heads/origin/|origin/)" "$OOSH_DIR/$file" 2>/dev/null; then
    expect.pass "$file has defence-in-depth OOSH_BRANCH stripping"
  else
    expect.fail "$file does not sanitise OOSH_BRANCH - a polluted caller will still break the worktree add"
  fi
done

# ─────────────────────────────────────────────────────────────────────────────
# T-GITHUB-SEED : Phase 3 of the .ssh/ correctness plan replaced the
# deploy_keys/2cuGitHub seeding flow with a single `ossh.config.shared.seed.github`
# helper. ossh.install.finish.local invokes it once (not branched). The shared
# config carries `Host github.com` whose IdentityFile is
# ~/.ssh/ids/ssh.developking/id_rsa — placed by osshLayout.role.developking
# on every user during install (no per-runner key transfer needed).
# ─────────────────────────────────────────────────────────────────────────────
FINISH_BODY=$(declare -f ossh.install.finish.local \
                          ossh.config.shared.seed.github 2>/dev/null)

test.case $level "T-GITHUB-SEED-CALLED: finish.local invokes ossh.config.shared.seed.github" \
  echo "$FINISH_BODY"
if echo "$FINISH_BODY" | grep -q "ossh.config.shared.seed.github"; then
  expect.pass "finish.local calls seed.github (single entry point, no deploy-key branching)"
else
  expect.fail "finish.local doesn't call ossh.config.shared.seed.github — Phase 3 wiring missing"
fi

test.case $level "T-GITHUB-SEED-NO-DEPLOY-KEY-BRANCH: finish.local no longer branches on deploy_keys/2cuGitHub" \
  echo "$FINISH_BODY"
if echo "$FINISH_BODY" | grep -qE "deploy_keys/2cuGitHub"; then
  expect.fail "finish.local still references deploy_keys/2cuGitHub — Phase 3 retired this flow"
else
  expect.pass "finish.local has no deploy_keys/2cuGitHub branching"
fi

test.case $level "T-GITHUB-SEED-DELEGATES-TO-CREATE: seed.github delegates to ossh.config.shared.github.create on remote" \
  echo "(grep)"
SEED_GITHUB_BODY=$(declare -f ossh.config.shared.seed.github 2>/dev/null)
# The body invokes the remote ossh as `sudo -E $(command -v ossh) config.shared.github.create`.
# Match the unique config.shared.github.create token; the `$(command -v ossh) ` shell
# substitution puts a `)` between "ossh" and the space, so a tighter pattern like
# `ossh +config\.shared\.github\.create` does NOT match. Use the suffix only.
if echo "$SEED_GITHUB_BODY" | grep -qE 'config\.shared\.github\.create'; then
  expect.pass "seed.github delegates to remote ossh config.shared.github.create"
else
  expect.fail "seed.github doesn't delegate to ossh.config.shared.github.create — install loses GitHub access for non-root users"
fi

# T-SHARED-SSH-COPY: the extracted helper exists and both caller-side and
# developking-fallback paths delegate to it (DRY — single source of truth
# for the per-user copy+chown loop).
test.case $level "T-SHARED-SSH-COPY-EXISTS: private.ossh.shared.ssh.copy.to.all is defined" \
  type private.ossh.shared.ssh.copy.to.all
if [ "$RETURN_VALUE" -eq 0 ]; then
  expect.pass "private.ossh.shared.ssh.copy.to.all is a function"
else
  expect.fail "private.ossh.shared.ssh.copy.to.all not defined"
fi

test.case $level "T-SHARED-SSH-COPY-CALLSITES: finish.local invokes the helper at least once" \
  echo "$FINISH_BODY"
# After the F8 refactor (commit 706950f) the propagate call is now made
# UNCONDITIONALLY ONCE in finish.local, regardless of which seeding path
# (caller-side or developking-fallback) ran. That's an even tighter DRY than
# "called from both branches" — single call site after either branch returns.
if echo "$FINISH_BODY" | grep -q "private\\.ossh\\.shared\\.ssh\\.copy\\.to\\.all"; then
  expect.pass "finish.local invokes the per-user-propagate helper"
else
  expect.fail "finish.local does not call private.ossh.shared.ssh.copy.to.all — propagation broken"
fi

# ─────────────────────────────────────────────────────────────────────────────
# T-SEED-GITHUB : Phase 3 collapsed the two-branch seeding flow into a single
# ossh.config.shared.seed.github helper. It carries a skip-when-seeded probe
# (idempotent re-runs) and delegates to the remote ossh.config.shared.github.create.
# The legacy seed.from.local.deploy.key + seed.fallback are kept only as
# deprecated shims that warn and forward to seed.github.
# ─────────────────────────────────────────────────────────────────────────────

test.case $level "T-SEED-GITHUB-EXISTS: ossh.config.shared.seed.github is defined" \
  type ossh.config.shared.seed.github
if [ "$RETURN_VALUE" -eq 0 ]; then
  expect.pass "ossh.config.shared.seed.github is a function"
else
  expect.fail "ossh.config.shared.seed.github not defined — Phase 3 wiring missing"
fi

SEED_GITHUB_BODY=$(declare -f ossh.config.shared.seed.github 2>/dev/null)
test.case $level "T-SEED-GITHUB-PROBE: seed.github has skip-when-seeded probe (Host github.com check)" \
  echo "(grep below)"
if echo "$SEED_GITHUB_BODY" | grep -qE 'grep -q "?\^Host github\\?\.com'; then
  expect.pass "seed.github skips when Host github.com already in shared config"
else
  expect.fail "seed.github missing skip-when-seeded probe — re-runs would re-append the github block"
fi

test.case $level "T-SEED-LEGACY-DEPRECATED: seed.from.local.deploy.key is a deprecated shim that forwards to seed.github" \
  echo "(grep)"
LEGACY_LOCAL_BODY=$(declare -f ossh.config.shared.seed.from.local.deploy.key 2>/dev/null)
if echo "$LEGACY_LOCAL_BODY" | grep -qE 'deprecated' && echo "$LEGACY_LOCAL_BODY" | grep -qE 'ossh\.config\.shared\.seed\.github'; then
  expect.pass "seed.from.local.deploy.key is a deprecation shim forwarding to seed.github"
else
  expect.fail "seed.from.local.deploy.key not a deprecation shim — Phase 3 retirement incomplete"
fi

test.case $level "T-SEED-FALLBACK-DEPRECATED: seed.fallback is a deprecated shim that forwards to seed.github" \
  echo "(grep)"
LEGACY_FALLBACK_BODY=$(declare -f ossh.config.shared.seed.fallback 2>/dev/null)
if echo "$LEGACY_FALLBACK_BODY" | grep -qE 'deprecated' && echo "$LEGACY_FALLBACK_BODY" | grep -qE 'ossh\.config\.shared\.seed\.github'; then
  expect.pass "seed.fallback is a deprecation shim forwarding to seed.github"
else
  expect.fail "seed.fallback not a deprecation shim — Phase 3 retirement incomplete"
fi

# ─────────────────────────────────────────────────────────────────────────────
# T-INIT-* : init/oosh is the thin bootstrap that hands off to
# ossh install.continue.local (the mature state-machine entrypoint).
# No more sh→bash re-exec scaffolding, no more oosh_install_remote /
# oosh_check_all_pm / etc. — those were all eliminated by declaring
# bash 4+ and git as explicit prereqs.
# ─────────────────────────────────────────────────────────────────────────────
INIT_CONTENT=$(cat "$OOSH_DIR/init/oosh" 2>/dev/null)

test.case $level "T-INIT-HANDS-OFF-TO-CONTINUE-LOCAL: init/oosh hands off to ossh install.continue.local" \
  echo "(grep below)"
if printf "%s" "$INIT_CONTENT" | grep -qE '"\$OOSH_DIR/this" +call +ossh +install\.continue\.local'; then
  expect.pass "init/oosh hands off to ossh install.continue.local"
else
  expect.fail "init/oosh missing handoff to install.continue.local — install path broken"
fi

test.case $level "T-INIT-THIN-BOOTSTRAP: init/oosh no longer contains old sh→bash scaffolding" \
  echo "(grep below)"
if printf "%s" "$INIT_CONTENT" | grep -qE 'oosh_install_remote|oosh_check_all_pm|oosh_parse_shellps|oosh_setup_env|oosh_status'; then
  expect.fail "init/oosh still contains old bootstrap scaffolding (oosh_* functions)"
else
  expect.pass "init/oosh is the thin bootstrap (old scaffolding removed)"
fi

# T-INIT-README-USES-SH-C : init/oosh is now POSIX sh, so the README
# install one-liners advertise `sh -c "$(curl/wget/fetch …)"`. The earlier
# `bash -c` requirement existed because of a bash-only re-exec chain that
# the sh migration eliminated.
README_CONTENT=$(cat "$OOSH_DIR/README.md" 2>/dev/null)
test.case $level "T-INIT-README-USES-SH-C: install one-liners in README use sh -c (init/oosh is POSIX sh)" \
  echo "(grep below)"
if printf "%s" "$README_CONTENT" \
   | grep -v '^> ' \
   | grep -qE '(^| )sh -c[[:space:]]+"\$\((curl|wget|fetch) '; then
  expect.pass "README install one-liners use sh -c"
else
  expect.fail "README install one-liners are missing the sh -c form — init/oosh is sh-clean now and the README should reflect that"
fi

# ─────────────────────────────────────────────────────────────────────────────
# T-GITHUB-SETUP-* : Phase 3 — ossh.config.shared.github.create emits
# `Host github.com` whose IdentityFile is ~/.ssh/ids/ssh.developking/id_rsa.
# state 31 in oo invokes it (curl-install path); finish.local invokes
# seed.github which delegates to it on the remote.
# ─────────────────────────────────────────────────────────────────────────────
SHARED_GITHUB_CREATE_BODY=$(declare -f ossh.config.shared.github.create 2>/dev/null)
test.case $level "T-GITHUB-SETUP-EMITS-HOST-GITHUB: shared.github.create emits Host github.com block" \
  echo "(grep below)"
if printf "%s" "$SHARED_GITHUB_CREATE_BODY" | grep -qE 'Host github\.com'; then
  expect.pass "shared.github.create body contains Host github.com block"
else
  expect.fail "shared.github.create doesn't emit Host github.com — Phase 3 incomplete"
fi

test.case $level "T-GITHUB-SETUP-USES-DEVELOPKING: IdentityFile points at ids/ssh.developking/id_rsa" \
  echo "(grep below)"
if printf "%s" "$SHARED_GITHUB_CREATE_BODY" | grep -qE 'ids/ssh\.developking/id_rsa'; then
  expect.pass "shared.github.create uses ~/.ssh/ids/ssh.developking/id_rsa"
else
  expect.fail "shared.github.create doesn't reference ids/ssh.developking/id_rsa — github won't authenticate"
fi

STATE_CONTENT=$(cat "$OOSH_DIR/oo" 2>/dev/null)
test.case $level "T-GITHUB-SETUP-FROM-STATE31: oo state 31 invokes ossh.config.shared.github.create" \
  echo "(grep below)"
if printf "%s" "$STATE_CONTENT" | grep -qE 'ossh[[:space:]]+config\.shared\.github\.create'; then
  expect.pass "state 31 body delegates to ossh.config.shared.github.create"
else
  expect.fail "state 31 doesn't call ossh.config.shared.github.create — curl install path has no GitHub setup"
fi

test.case $level "T-GITHUB-SETUP-FROM-FINISH: seed.github delegates to ossh config.shared.github.create" \
  echo "(grep below)"
SEED_GH_BODY=$(declare -f ossh.config.shared.seed.github 2>/dev/null)
# Same caveat as T-GITHUB-SEED-DELEGATES-TO-CREATE above — `$(command -v ossh)`
# shell substitution puts a `)` between "ossh" and the space, so match by the
# unique config.shared.github.create suffix only.
if printf "%s" "$SEED_GH_BODY" | grep -qE 'config\.shared\.github\.create'; then
  expect.pass "seed.github delegates to ossh config.shared.github.create on the remote"
else
  expect.fail "seed.github doesn't delegate to ossh config.shared.github.create — install loses GitHub access for non-root users"
fi

# ─────────────────────────────────────────────────────────────────────────────
# T-OSSH-PREREQS-* : the remote prereq-install primitives exist and each has
# the completion functions that completion.audit demands. Catches the same
# class of drift the completion audit catches, but proactively in the ossh
# suite itself so a broken wiring fails fast.
# ─────────────────────────────────────────────────────────────────────────────
test.case $level "T-OSSH-PREREQS-PRIMITIVES-PRESENT: ossh.pm.discover / ossh.cmd / ossh.prereqs.install all exist" \
  echo "(grep)"
_osshMissing=""
for m in ossh.pm.discover ossh.cmd ossh.prereqs.install; do
  grep -qE "^${m//./\\.}\(\)" "$OOSH_DIR/ossh" || _osshMissing+="$m "
done
if [ -z "$_osshMissing" ]; then
  expect.pass "all three ossh prereq primitives defined"
else
  expect.fail "missing: $_osshMissing"
fi

test.case $level "T-OSSH-PREREQS-COMPLETION: each new ossh.* method has its completion functions" \
  echo "(grep)"
_osshCompMissing=""
grep -qE '^ossh\.pm\.discover\.completion\.sshConfigHost'      "$OOSH_DIR/ossh" || _osshCompMissing+="pm.discover.sshConfigHost "
grep -qE '^ossh\.cmd\.completion\.sshConfigHost'               "$OOSH_DIR/ossh" || _osshCompMissing+="cmd.sshConfigHost "
grep -qE '^ossh\.cmd\.completion\.pkg'                          "$OOSH_DIR/ossh" || _osshCompMissing+="cmd.pkg "
grep -qE '^ossh\.prereqs\.install\.completion\.sshConfigHost'  "$OOSH_DIR/ossh" || _osshCompMissing+="prereqs.install.sshConfigHost "
if [ -z "$_osshCompMissing" ]; then
  expect.pass "all completion functions present"
else
  expect.fail "missing completion: $_osshCompMissing"
fi

# T-OSSH-PREREQS-THIN-WRAPPER : ossh.prereqs.install is now a thin SCP+run
# wrapper that ships init/oosh to the host and lets it self-install. The
# platform install logic (apk-extras, busybox-suid, brew-bash + paths.d,
# Homebrew bootstrap) all moved into init/oosh's POSIX-sh prelude — single
# source of truth. Anti-regression for re-fattening this function.
# The matching coverage for the platform install logic now lives in
# test/test.install (T-INIT-INSTALL-* assertions against the init/oosh body).
test.case $level "T-OSSH-PREREQS-THIN-WRAPPER: ossh.prereqs.install is an SCP+run wrapper around init/oosh" \
  echo "(grep)"
PREREQS_BODY=$(declare -f ossh.prereqs.install 2>/dev/null)
if printf "%s" "$PREREQS_BODY" | grep -qE 'scp .*init/oosh' \
   && printf "%s" "$PREREQS_BODY" | grep -qE 'private\.ossh\.ssh.*bash'; then
  expect.pass "ossh.prereqs.install delivers init/oosh via scp and invokes it remotely under bash"
else
  expect.fail "ossh.prereqs.install body has drifted from the thin SCP+run wrapper — single-source-of-truth for platform install lives in init/oosh's prelude"
fi

# T-OSSH-PREREQS-NO-PLATFORM-LOGIC : the platform install logic explicitly
# moved OUT of ossh.prereqs.install. Catch a re-fattening regression early.
test.case $level "T-OSSH-PREREQS-NO-PLATFORM-LOGIC: ossh.prereqs.install no longer contains platform install logic" \
  echo "(grep)"
PREREQS_BODY=$(declare -f ossh.prereqs.install 2>/dev/null)
if printf "%s" "$PREREQS_BODY" | grep -qE '/etc/paths\.d/oosh-homebrew|chmod u\+s /bin/busybox|NONINTERACTIVE=1.*Homebrew/install|bash shadow util-linux'; then
  expect.fail "ossh.prereqs.install body has re-absorbed platform install logic that belongs in init/oosh's prelude"
else
  expect.pass "ossh.prereqs.install no longer contains platform install logic (lives in init/oosh)"
fi

# T-OSSH-CMD-PREFLIGHT-NOT-SILENCED : ossh.cmd's apt-get update preflight must
# NOT redirect stdout/stderr — that hides sudo password prompts on remotes
# without NOPASSWD configured, leaving the install to hang silently.
# Pre-5ecd118 the preflight was silenced and `ossh install` hung on bob's box;
# this guard catches future regressions to the silencing.
test.case $level "T-OSSH-CMD-PREFLIGHT-NOT-SILENCED: ossh.cmd apt-get update doesn't redirect stdout/stderr" \
  echo "(grep)"
CMD_BODY=$(declare -f ossh.cmd 2>/dev/null)
if printf "%s" "$CMD_BODY" | grep -qE 'apt-get\* *\)' \
   && ! printf "%s" "$CMD_BODY" | grep -qE 'apt-get update.*>/dev/null|apt-get update.*2>&1'; then
  expect.pass "ossh.cmd apt-get update preflight runs without output redirects"
else
  expect.fail "ossh.cmd apt-get update is silenced — sudo password prompts will hang on remotes without NOPASSWD"
fi

# ============================================================================
# ossh folder.fix + rights.fix (Phase A/B)
# ============================================================================

# T-RIGHTS-FIX-ALIAS-EXISTS: post-rename, ossh.rights.fix is a defined function
# (and ossh.fix.rights is gone).
test.case $level "T-RIGHTS-FIX-ALIAS-EXISTS: ossh.rights.fix defined; ossh.fix.rights removed" \
  echo "(type)"
if declare -f ossh.rights.fix >/dev/null 2>&1 && ! declare -f ossh.fix.rights >/dev/null 2>&1; then
  expect.pass "rename complete"
else
  expect.fail "ossh.rights.fix missing or ossh.fix.rights still defined"
fi

# T-RIGHTS-FIX-IS-THIN-ALIAS: the renamed body should delegate to
# private.osshLayout.perms.tighten — not carry its own chmod logic.
test.case $level "T-RIGHTS-FIX-IS-THIN-ALIAS: ossh.rights.fix body calls private.osshLayout.perms.tighten" \
  echo "(grep declare -f)"
RIGHTS_BODY=$(declare -f ossh.rights.fix 2>/dev/null)
if printf "%s" "$RIGHTS_BODY" | grep -q 'private.osshLayout.perms.tighten'; then
  expect.pass "delegates to perms.tighten"
else
  expect.fail "body does NOT call private.osshLayout.perms.tighten — alias incomplete"
fi

# T-FOLDER-FIX-FUNCTION-EXISTS: ossh.folder.fix defined + all 3 completion helpers.
test.case $level "T-FOLDER-FIX-FUNCTION-EXISTS: ossh.folder.fix + completions defined" \
  echo "(type)"
if declare -f ossh.folder.fix >/dev/null 2>&1 \
   && declare -f ossh.folder.fix.completion.installerEmail >/dev/null 2>&1 \
   && declare -f ossh.folder.fix.completion.sshDir >/dev/null 2>&1 \
   && declare -f ossh.folder.fix.completion.mode >/dev/null 2>&1; then
  expect.pass "function + all completion helpers defined"
else
  expect.fail "ossh.folder.fix or one of its completion helpers is missing"
fi

# T-FOLDER-FIX-REJECTS-UNKNOWN-MODE: unknown mode keyword → error.log + return 1.
test.case $level "T-FOLDER-FIX-REJECTS-UNKNOWN-MODE: unknown mode returns 1" \
  echo "(invoke)"
ossh.folder.fix "" /tmp/test.no.such.path.$$ bogus_mode_xyz >/dev/null 2>&1
if [ "$?" -ne 0 ]; then
  expect.pass "unknown mode rejected"
else
  expect.fail "unknown mode silently accepted"
fi

# T-FOLDER-FIX-PRUNE-REMOVES-KNOWN-STALE: private.ossh.folder.fix.prune removes
# only the documented legacy artifact patterns.
test.ossh.foldFixPrunesStale() {
  local fixture="/tmp/test.folder.fix.prune.$(id -u).$$"
  mkdir -p "$fixture/no_deploy_keys"
  touch "$fixture/2cuGitHub" "$fixture/2cuGitHub.pub"
  touch "$fixture/config.bak.20260101-120000"
  touch "$fixture/id_ed25519.previous" "$fixture/id_ed25519.pub.previous"
  touch "$fixture/known_hosts.old"
  touch "$fixture/something.old"
  private.ossh.folder.fix.prune "$fixture" >/dev/null 2>&1
  if [ -f "$fixture/2cuGitHub" ] || [ -f "$fixture/config.bak.20260101-120000" ] \
     || [ -f "$fixture/id_ed25519.previous" ] || [ -f "$fixture/known_hosts.old" ] \
     || [ -d "$fixture/no_deploy_keys" ]; then
    create.result 1 "some known-stale artifact survived: $(ls $fixture)"
  else
    create.result 0 "all known-stale removed"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case $level "T-FOLDER-FIX-PRUNE-REMOVES-KNOWN-STALE: removes 2cuGitHub, .bak.*, .previous, .old, no_deploy_keys" \
  test.ossh.foldFixPrunesStale
expect 0 "all known-stale removed" "private.ossh.folder.fix.prune deletes documented legacy artifact patterns"

# T-FOLDER-FIX-PRUNE-KEEPS-USER-STATE: never touch authorized_keys, id_rsa,
# or anything the user might rely on for SSH-in or legacy-server access.
test.ossh.foldFixPruneKeepsUserState() {
  local fixture="/tmp/test.folder.fix.prune.keep.$(id -u).$$"
  mkdir -p "$fixture"
  touch "$fixture/authorized_keys" "$fixture/id_rsa" "$fixture/id_rsa.pub"
  touch "$fixture/config"
  private.ossh.folder.fix.prune "$fixture" >/dev/null 2>&1
  if [ -f "$fixture/authorized_keys" ] && [ -f "$fixture/id_rsa" ] \
     && [ -f "$fixture/id_rsa.pub" ] && [ -f "$fixture/config" ]; then
    create.result 0 "user state preserved"
  else
    create.result 1 "prune destroyed user state: $(ls $fixture)"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case $level "T-FOLDER-FIX-PRUNE-KEEPS-USER-STATE: authorized_keys / id_rsa / config preserved" \
  test.ossh.foldFixPruneKeepsUserState
expect 0 "user state preserved" "private.ossh.folder.fix.prune never deletes user-authored files"

# T-FOLDER-FIX-CHECK-FUNCTION-EXISTS: ossh.folder.fix.check defined + completion.
test.case $level "T-FOLDER-FIX-CHECK-FUNCTION-EXISTS: ossh.folder.fix.check + completion defined" \
  echo "(type)"
if declare -f ossh.folder.fix.check >/dev/null 2>&1 \
   && declare -f ossh.folder.fix.check.completion.sshDir >/dev/null 2>&1; then
  expect.pass "function + completion defined"
else
  expect.fail "ossh.folder.fix.check or its completion is missing"
fi

# T-FOLDER-FIX-CHECK-IS-READONLY: seed a broken state and verify check
# doesn't mutate anything. We compute a recursive hash before + after.
test.ossh.foldFixCheckReadonly() {
  local fixture="/tmp/test.folder.fix.check.$(id -u).$$"
  mkdir -p "$fixture/private_key"
  echo dummy > "$fixture/id_ed25519"
  chmod 777 "$fixture/id_ed25519"        # bad perms — drift
  ln -s ../id_ed25519 "$fixture/private_key/test.private_key"  # forbidden symlink
  chmod 755 "$fixture"                   # wrong dir perms
  local before
  before=$(find "$fixture" -printf '%p %m %y\n' 2>/dev/null | sort | sha256sum)
  ossh.folder.fix.check "$fixture" >/dev/null 2>&1
  local after
  after=$(find "$fixture" -printf '%p %m %y\n' 2>/dev/null | sort | sha256sum)
  if [ "$before" = "$after" ]; then
    create.result 0 "no mutation"
  else
    create.result 1 "check mutated state: $(diff <(echo "$before") <(echo "$after"))"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case $level "T-FOLDER-FIX-CHECK-IS-READONLY: ossh.folder.fix.check does not mutate the tree" \
  test.ossh.foldFixCheckReadonly
expect 0 "no mutation" "ossh.folder.fix.check is strictly read-only"

# T-FOLDER-FIX-CHECK-RETURNS-ZERO-ON-DRIFT: per the design, check always
# returns 0 (reports findings via warn.log) so it can be used in pipelines.
test.case $level "T-FOLDER-FIX-CHECK-RETURNS-ZERO-ON-DRIFT: returns 0 even when drift detected" \
  echo "(invoke)"
test.ossh.foldFixCheckRcZero() {
  local fixture="/tmp/test.folder.fix.check.rc.$(id -u).$$"
  mkdir -p "$fixture/private_key"
  echo dummy > "$fixture/id_ed25519"
  chmod 777 "$fixture/id_ed25519"
  ln -s ../id_ed25519 "$fixture/private_key/test.private_key"
  ossh.folder.fix.check "$fixture" >/dev/null 2>&1
  local rc=$?
  rm -rf "$fixture" 2>/dev/null
  if [ "$rc" -eq 0 ]; then
    create.result 0 "rc=0 with drift"
  else
    create.result 1 "rc=$rc"
  fi
}
test.ossh.foldFixCheckRcZero
expect 0 "rc=0 with drift" "check returns 0 even when drift detected"

# T-FOLDER-FIX-CONFIG-NORMALIZE-WODA: normalises absolute IdentityFile paths in WODA Host blocks
# to the portable ~/.ssh/id_ed25519 form.
test.ossh.foldFixConfigNormalizeWoda() {
  local fixture="/tmp/test.folder.fix.cfg.woda.$(id -u).$$"
  mkdir -p "$fixture"
  cat > "$fixture/config" <<'EOF'
Host WODA.test
 User root
 Port 22
 HostName 178.254.18.182
 IdentityFile /home/test/.ssh/id_ed25519

Host other
 IdentityFile /should/stay/absolute
EOF
  private.ossh.folder.fix.config.normalize "$fixture" >/dev/null 2>&1
  if grep -q "^ IdentityFile ~/.ssh/id_ed25519\$" "$fixture/config" \
     && grep -q "^ IdentityFile /should/stay/absolute\$" "$fixture/config"; then
    create.result 0 "WODA portable, non-WODA unchanged"
  else
    create.result 1 "wrong content: $(cat $fixture/config)"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case $level "T-FOLDER-FIX-CONFIG-NORMALIZE-WODA: WODA IdentityFile rewritten to portable; non-WODA untouched" \
  test.ossh.foldFixConfigNormalizeWoda
expect 0 "WODA portable, non-WODA unchanged" "private.ossh.folder.fix.config.normalize fixes WODA portability without touching other Host blocks"

# T-FOLDER-FIX-CONFIG-NORMALIZE-GITHUB: adds Host github.com block when missing.
test.ossh.foldFixConfigAddGithub() {
  local fixture="/tmp/test.folder.fix.cfg.github.$(id -u).$$"
  mkdir -p "$fixture"
  echo "# empty config" > "$fixture/config"
  private.ossh.folder.fix.config.normalize "$fixture" >/dev/null 2>&1
  if grep -q "^Host github.com\$" "$fixture/config" \
     && grep -q "^ IdentityFile ~/.ssh/ids/ssh.developking/id_rsa\$" "$fixture/config"; then
    create.result 0 "Host github.com added with canonical IdentityFile"
  else
    create.result 1 "wrong content: $(cat $fixture/config)"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case $level "T-FOLDER-FIX-CONFIG-NORMALIZE-GITHUB: Host github.com block added if missing" \
  test.ossh.foldFixConfigAddGithub
expect 0 "Host github.com added with canonical IdentityFile" "config.normalize ensures Host github.com is present"

# T-FOLDER-FIX-CONFIG-STRIP-LEGACY: strict-only helper removes the Host 2cuGitHub block.
test.ossh.foldFixConfigStripLegacy() {
  local fixture="/tmp/test.folder.fix.cfg.legacy.$(id -u).$$"
  mkdir -p "$fixture"
  cat > "$fixture/config" <<'EOF'
Host 2cuGitHub
 User git
 IdentityFile ~/.ssh/2cuGitHub

Host keep.me
 IdentityFile ~/.ssh/id_ed25519
EOF
  private.ossh.folder.fix.config.strip.legacy "$fixture" >/dev/null 2>&1
  if ! grep -q "^Host 2cuGitHub\$" "$fixture/config" \
     && grep -q "^Host keep.me\$" "$fixture/config"; then
    create.result 0 "2cuGitHub block removed, keep.me preserved"
  else
    create.result 1 "wrong content: $(cat $fixture/config)"
  fi
  rm -rf "$fixture" 2>/dev/null
}
test.case $level "T-FOLDER-FIX-CONFIG-STRIP-LEGACY: Host 2cuGitHub removed; other blocks preserved" \
  test.ossh.foldFixConfigStripLegacy
expect 0 "2cuGitHub block removed, keep.me preserved" "config.strip.legacy removes Host 2cuGitHub block only"

# T-FOLDER-FIX-SCAN-GIT-REMOTES: pre-flight scan helper exists and runs without error
# even when nothing matches. (Full integration testing would need a real git repo
# fixture under $HOME — too invasive for unit tests.)
test.case $level "T-FOLDER-FIX-SCAN-GIT-REMOTES: function defined + returns 0 when no matches" \
  echo "(invoke)"
if declare -f private.ossh.folder.fix.scan.git.remotes >/dev/null 2>&1; then
  private.ossh.folder.fix.scan.git.remotes nonexistent_alias_xyz_zzz >/dev/null 2>&1
  if [ $? -eq 0 ]; then
    expect.pass "scan helper defined and returns 0 on no-match"
  else
    expect.fail "scan helper returned non-zero on no-match"
  fi
else
  expect.fail "private.ossh.folder.fix.scan.git.remotes not defined"
fi

test.suite.save.results
