#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

BASE="${ROUTER_OPS_BASE:-/opt/router-ops}"
ROOT="${BUNDLE_ROOT:?}"
RUN_DIR="${ROUTER_DETACHED_RUN_DIR:?}"
CHILD_RESULT="${ROUTER_DETACHED_CHILD_RESULT:?}"
INCOMING="${ROUTER_STEP_INCOMING:-/home/ops/incoming}"
SELFTEST="${ROUTER_EXACT_WORKER_SELFTEST:-false}"

STEP=STEP_050M07P26C1_R02_WIREGUARD_CONFIG_QR_REVOKE_REISSUE_SURFACE
VM121_BASE_COMMIT=13f7b33bb28ffa87b3e0294082de1ed5d438f8c2
VM121_BASE_TREE=57adc457e616133842dca65534deff139f9fd835
VM121_BASE_COUNT=50
VM100_PUBLIC_URL=https://reports.secret-studio.ru/latest/20260816-094040_vm100_git_source_8c5d11b7e4b1/
VM101_PUBLIC_URL=https://reports.secret-studio.ru/latest/20260816-094047_vm101_git_source_94a1c5627bac/
VM121_PUBLIC_URL=https://reports.secret-studio.ru/latest/20260817-082613_vm121_git_source_13f7b33bb28f/
P25_REPORT_URL=https://reports.secret-studio.ru/latest/20260817-071459_step050m07p25_r02_controlled_synthetic_wireguard_domain_v2_e2e/
P26_REPORT_URL=https://reports.secret-studio.ru/latest/20260817-082619_step050m07p26_r03_invite_magic_link_secure_session_mvp/
LOCAL_PLAN_URL=https://reports.secret-studio.ru/latest/20260719-080444_local_architecture_plan_vm101_autonomous_hmn_recovery_r19/
GLOBAL_PLAN_URL=https://reports.secret-studio.ru/latest/20260802-105248_global_project_plan_wg_paid_after_r20qw/
ACCESS_MAP_URL=https://reports.secret-studio.ru/latest/20260812-153301_access_map_canonical_current/

CURRENT="$RUN_DIR/workflow-current.txt"
EVENTS="$RUN_DIR/workflow-events.tsv"
EVIDENCE="$RUN_DIR/evidence"
REPORT="$RUN_DIR/report"
PAYLOAD="$RUN_DIR/public-payload"
FINAL_ENV="$RUN_DIR/final-publication.env"
TARGET_DIR="$RUN_DIR/target"
mkdir -p "$EVIDENCE" "$REPORT" "$PAYLOAD" "$TARGET_DIR" "$INCOMING"
chmod 700 "$EVIDENCE" "$REPORT" "$PAYLOAD" "$TARGET_DIR"

source "$BASE/lib/router-step-workflow.sh"
source <("$BASE/bin/router-release-contract" env --root "$ROOT")
router_step_workflow_init "$CURRENT" "$EVENTS" preflight backup apply isolated_test machine_close postcheck report_publish archive

CORE_CHANGE_COMPLETE=false
CORE_CHANGE_REPEATED=false
SOURCE_CHANGED=false
SOURCE_APPLIED=false
BACKUP_READY=false
LIVE_DATABASE_WRITTEN=false
ISOLATED_DATABASE_WRITTEN=false
DATABASE_SCHEMA_CHANGED=false
EXTERNAL_ONBOARDING_ACTIVE=false
LIVE_ENV_UNCHANGED=unknown
ISOLATED_DB_CLEANUP_STATUS=not_started
BACKUP_DIR=unknown
STOP_DETAIL=unknown
STOP_HANDLED=false
STEP_REPORT_URL=unknown
LATEST_ARCHIVE=not_created
LATEST_ARCHIVE_SHA256=unknown
XS_MAP_URL=unknown
VM121_COMMIT="$VM121_BASE_COMMIT"
VM121_TREE="$VM121_BASE_TREE"
VM121_COUNT="$VM121_BASE_COUNT"
REMOTE_PKG=unknown
REMOTE_TEST=unknown
PRE_ENV_SHA=unknown
POST_ENV_SHA=unknown
BACKEND_STARTED_BEFORE=unknown
BACKEND_STARTED_AFTER=unknown

last_field() {
  local key="$1" file="$2"
  awk -F= -v k="$key" '$1==k{v=substr($0,index($0,"=")+1)} END{print v}' "$file"
}

write_child() {
  local result="$1" rc="$2" tmp="${CHILD_RESULT}.tmp.$$"
  {
    echo "RESULT=$result"
    echo "WORKER_RC=$rc"
    echo "CORE_CHANGE_COMPLETE=$CORE_CHANGE_COMPLETE"
    echo "CORE_CHANGE_REPEATED=false"
    echo "SOURCE_CHANGED=$SOURCE_CHANGED"
    echo "LIVE_DATABASE_WRITTEN=false"
    echo "ISOLATED_DATABASE_WRITTEN=$ISOLATED_DATABASE_WRITTEN"
    echo "DATABASE_SCHEMA_CHANGED=false"
    echo "EXTERNAL_ONBOARDING_ACTIVE=false"
    echo "ISOLATED_DB_CLEANUP_STATUS=$ISOLATED_DB_CLEANUP_STATUS"
    echo "BACKUP_DIR=$BACKUP_DIR"
    echo "VM121_COMMIT=$VM121_COMMIT"
    echo "VM121_TREE=$VM121_TREE"
    echo "VM121_FILE_COUNT=$VM121_COUNT"
    echo "VM121_PUBLIC_URL=$VM121_PUBLIC_URL"
    echo "STEP_REPORT_URL=$STEP_REPORT_URL"
    echo "LATEST_ARCHIVE=$LATEST_ARCHIVE"
    echo "LATEST_ARCHIVE_SHA256=$LATEST_ARCHIVE_SHA256"
  } > "$tmp"
  chmod 600 "$tmp"
  mv "$tmp" "$CHILD_RESULT"
}

archive_latest() {
  local log="$EVIDENCE/archive.log"
  router_step_archive_latest_python "$BASE" "$INCOMING" "$(date -u +%Y%m%d-%H%M%S)" | tee "$log"
  LATEST_ARCHIVE="$(last_field LATEST_ARCHIVE "$log")"
  LATEST_ARCHIVE_SHA256="$(last_field LATEST_ARCHIVE_SHA256 "$log")"
}

resolve_xs_map() {
  local f=/opt/router-ops/inventory/XS_MAP_CURRENT.md u=''
  if [[ -r "$f" ]]; then
    u="$(grep -Eo 'https://reports\.secret-studio\.ru/[^[:space:]`)]+' "$f" 2>/dev/null | tail -n1 || true)"
  fi
  [[ -n "$u" ]] && XS_MAP_URL="$u" || XS_MAP_URL=unknown
}

cleanup_remote() {
  [[ "$SELFTEST" == false ]] || return 0
  set +e
  if [[ "$REMOTE_TEST" != unknown ]]; then
    ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 "docker exec wgaccess-backend rm -f /tmp/p26c1_profile_surface_test.py >/dev/null 2>&1 || true; rm -f '$REMOTE_TEST'" >/dev/null 2>&1 || true
  fi
  if [[ "$REMOTE_PKG" != unknown ]]; then
    ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 "rm -f '$REMOTE_PKG'" >/dev/null 2>&1 || true
  fi
  set -e
}

rollback_now() {
  [ "$BACKUP_READY" = true ] || return 0
  [[ "$CORE_CHANGE_COMPLETE" == false ]] || return 0
  set +e
  ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 /bin/bash -s -- "$BACKUP_DIR" > "$EVIDENCE/rollback.txt" 2>&1 <<'VM121_ROLLBACK'
set -Eeuo pipefail
BACKUP_DIR="${1:?}"
ARCHIVE="$BACKUP_DIR/source-before.tar.gz"
test -f "$ARCHIVE"
rm -f /opt/wg-access/backend/app/services/profile_delivery.py
tar -xzf "$ARCHIVE" -C /
cd /opt/wg-access
docker compose up -d --force-recreate backend >/dev/null
for i in $(seq 1 120); do
  if curl -fsS --max-time 3 http://127.0.0.1:18080/health >/dev/null 2>&1 && curl -fsS --max-time 3 http://127.0.0.1:18080/health/db >/dev/null 2>&1; then
    echo BACKEND_RECOVERY_HEALTH=PASS
    exit 0
  fi
  sleep 1
  [[ "$i" -lt 120 ]]
done
echo BACKEND_RECOVERY_HEALTH=FAIL
exit 1
VM121_ROLLBACK
  local rrc=$?
  if [[ "$rrc" -eq 0 ]]; then
    SOURCE_CHANGED=false
    SOURCE_APPLIED=false
  fi
  set -e
  return "$rrc"
}

write_stop_report() {
  local rc="$1" line="$2" command="$3"
  cat > "$REPORT/report.txt" <<EOFSTOP
RESULT=STOP_P26C1_WIREGUARD_CONFIG_QR_REVOKE_REISSUE_SURFACE
REVISION=R02
STOP_RC=$rc
STOP_LINE=$line
STOP_DETAIL=$STOP_DETAIL
CORE_CHANGE_COMPLETE=$CORE_CHANGE_COMPLETE
CORE_CHANGE_REPEATED=false
SOURCE_CHANGED=$SOURCE_CHANGED
LIVE_DATABASE_WRITTEN=false
ISOLATED_DATABASE_WRITTEN=$ISOLATED_DATABASE_WRITTEN
DATABASE_SCHEMA_CHANGED=false
ISOLATED_DB_CLEANUP_STATUS=$ISOLATED_DB_CLEANUP_STATUS
BACKUP_DIR=$BACKUP_DIR
EXTERNAL_ONBOARDING_ACTIVE=false
VM121_COMMIT=$VM121_COMMIT
VM121_TREE=$VM121_TREE
VM121_FILE_COUNT=$VM121_COUNT
VM121_PUBLIC_URL=$VM121_PUBLIC_URL
P26_REPORT_URL=$P26_REPORT_URL
ACCESS_MAP_URL=$ACCESS_MAP_URL
NEXT_ACTION=inspect retained evidence; if CORE_CHANGE_COMPLETE=true continue post-core without restoring accepted source
EOFSTOP
  printf 'STOP_COMMAND=%q\n' "$command" >> "$REPORT/report.txt"
  cp "$REPORT/report.txt" "$REPORT/verify.txt"
  cp "$ROOT/scripts/run-step.sh" "$REPORT/executed-step.sh"
  cp "$ROOT/release-info.json" "$REPORT/release-info.json"
  cp "$ROOT/rollback/README.md" "$REPORT/rollback.txt"
  for f in pre-vm121-source.txt pre-vm121-source-validation.txt pre-vm121-live.txt pre-source-sha.txt backup.txt apply.txt generation.txt production-gate.txt profile-surface-e2e.txt production-after-isolated.txt machine-close.txt post-vm121-source.txt post-vm121-source-validation.txt post-vm121-live.txt rollback.txt; do
    [[ ! -f "$EVIDENCE/$f" ]] || cp "$EVIDENCE/$f" "$REPORT/$f"
  done
}

stop_handler() {
  local rc="$1" line="$2" command="$3"
  trap - ERR
  [[ "$STOP_HANDLED" == false ]] || return "$rc"
  STOP_HANDLED=true
  if [[ "$CORE_CHANGE_COMPLETE" == false && "$BACKUP_READY" == true ]]; then
    rollback_now || true
  fi
  cleanup_remote
  resolve_xs_map
  write_stop_report "$rc" "$line" "$command"
  set +e
  if [[ "$SELFTEST" == false ]]; then
    local args=()
    while IFS= read -r f; do args+=("$f" "$(basename "$f")"); done < <(find "$REPORT" -maxdepth 1 -type f -print | LC_ALL=C sort)
    router_step_publish_payload step050m07p26c1_r02_wireguard_config_qr_revoke_reissue_surface_stop \
      "$REPORT" "$PAYLOAD" "$CURRENT" "$EVENTS" "$FINAL_ENV" "${args[@]}" >/dev/null 2>&1 || true
    [[ -f "$FINAL_ENV" ]] && STEP_REPORT_URL="$(last_field PUBLIC_URL "$FINAL_ENV")"
    archive_latest >/dev/null 2>&1 || true
  fi
  set -e
  write_child STOP_P26C1_WIREGUARD_CONFIG_QR_REVOKE_REISSUE_SURFACE "$rc"
  return "$rc"
}
trap 'rc=$?; stop_handler "$rc" "$LINENO" "$BASH_COMMAND"; exit "$rc"' ERR

selftest_worker() {
  local pkg="$ROOT/$ROUTER_RELEASE_TARGET_PACKAGE_PATH" sha
  sha="$(sha256sum "$pkg" | awk '{print $1}')"
  [[ "$sha" == "$ROUTER_RELEASE_TARGET_PACKAGE_SHA256" ]]
  tar -tzf "$pkg" > "$TARGET_DIR/package-list.txt"
  for rel in \
    opt/wg-access/.env.example \
    opt/wg-access/docker-compose.yml \
    opt/wg-access/backend/app/config.py \
    opt/wg-access/backend/app/api/auth_v2.py \
    opt/wg-access/backend/app/services/profile_delivery.py; do
    grep -Fqx "$rel" "$TARGET_DIR/package-list.txt"
  done
  [[ "$(wc -l < "$TARGET_DIR/package-list.txt")" -eq 5 ]]
  mkdir -p "$TARGET_DIR/extract"
  tar -xzf "$pkg" -C "$TARGET_DIR/extract"
  python3 -m py_compile \
    "$TARGET_DIR/extract/opt/wg-access/backend/app/config.py" \
    "$TARGET_DIR/extract/opt/wg-access/backend/app/api/auth_v2.py" \
    "$TARGET_DIR/extract/opt/wg-access/backend/app/services/profile_delivery.py"
  python3 - "$ROOT/payload/p26c1_profile_surface_test.py" <<'PYCOMPILE'
from pathlib import Path
import sys
p=Path(sys.argv[1]); compile(p.read_bytes(), str(p), 'exec')
PYCOMPILE
  grep -Fq 'TRANSITION_DIR="$(mktemp -d /tmp/p26c1-r02-runtime-transition.XXXXXX)"' "$ROOT/install.sh"
  ! grep -Eq 'TRANSITION="/tmp/' "$ROOT/install.sh"
  grep -Fq 'LIVE_DATABASE_WRITTEN=false' "$ROOT/scripts/run-step.sh"
  grep -Fq 'ISOLATED_DATABASE_GUARD=PASS' "$ROOT/payload/p26c1_profile_surface_test.py"
  echo RESULT=PASS_P26C1_R02_EXACT_WORKER_SELFTEST
  write_child PASS_P26C1_R02_EXACT_WORKER_SELFTEST 0
}

if [[ "$SELFTEST" == true ]]; then
  selftest_worker
  trap - ERR
  exit 0
fi

collect_vm121_live() {
  local outfile="$1"
  ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 /bin/bash -s > "$outfile" 2>&1 <<'VM121_LIVE'
set -Eeuo pipefail
curl -fsS --max-time 5 http://127.0.0.1:18080/health >/dev/null
curl -fsS --max-time 5 http://127.0.0.1:18080/health/db >/dev/null
PG=wgaccess-postgres
U="$(docker exec "$PG" sh -lc 'printf %s "$POSTGRES_USER"')"
D="$(docker exec "$PG" sh -lc 'printf %s "$POSTGRES_DB"')"
Q(){ docker exec "$PG" psql -v ON_ERROR_STOP=1 -U "$U" -d "$D" -Atqc "$1"; }
echo BACKEND_HEALTH=PASS
echo "ALEMBIC_VERSION=$(Q 'SELECT version_num FROM alembic_version')"
echo "USER_ROWS=$(Q 'SELECT count(*) FROM users')"
echo "PLAN_ROWS=$(Q 'SELECT count(*) FROM plans')"
echo "ACCESS_GRANT_ROWS=$(Q 'SELECT count(*) FROM access_grants')"
echo "AUTH_SESSION_ROWS=$(Q 'SELECT count(*) FROM auth_sessions')"
echo "AUDIT_EVENT_ROWS=$(Q 'SELECT count(*) FROM audit_events')"
echo "CONNECTION_PROFILE_ROWS=$(Q 'SELECT count(*) FROM connection_profiles')"
echo "PEER_CREDENTIAL_ROWS=$(Q 'SELECT count(*) FROM peer_credentials')"
echo "PROVISIONING_JOB_ROWS=$(Q 'SELECT count(*) FROM provisioning_jobs')"
echo "LIVE_ENV_SHA256=$(sha256sum /opt/wg-access/.env | awk '{print $1}')"
echo "BACKEND_STARTED_AT=$(docker inspect -f '{{.State.StartedAt}}' wgaccess-backend)"
for unit in wg-access-agent.path wg-access-agent.timer wg-access-agent.service; do
  key="$(echo "$unit" | tr 'a-z.-' 'A-Z__')"
  echo "${key}_ACTIVE=$(systemctl is-active "$unit" 2>/dev/null || true)"
  echo "${key}_ENABLED=$(systemctl is-enabled "$unit" 2>/dev/null || true)"
done
docker exec -i wgaccess-backend python - <<'PY'
import json, urllib.request
from app.config import settings
print('EXTERNAL_ONBOARDING_ACTIVE='+str(bool(settings.external_onboarding_active)).lower())
with urllib.request.urlopen('http://127.0.0.1:8000/openapi.json', timeout=5) as r:
    doc=json.load(r)
paths=doc.get('paths',{})
v2=sorted(p for p in paths if p.startswith('/v2/'))
print('V2_ROUTE_COUNT='+str(len(v2)))
for p in v2: print('V2_ROUTE='+p)
PY
VM121_LIVE
}

assert_prod_zero() {
  local file="$1"
  [[ "$(last_field ALEMBIC_VERSION "$file")" == 0004_profile_provisioning ]]
  for key in USER_ROWS PLAN_ROWS ACCESS_GRANT_ROWS AUTH_SESSION_ROWS AUDIT_EVENT_ROWS CONNECTION_PROFILE_ROWS PEER_CREDENTIAL_ROWS PROVISIONING_JOB_ROWS; do
    [[ "$(last_field "$key" "$file")" == 0 ]]
  done
}

assert_agent_inactive() {
  local file="$1"
  [[ "$(last_field WG_ACCESS_AGENT_PATH_ACTIVE "$file")" == inactive ]]
  [[ "$(last_field WG_ACCESS_AGENT_PATH_ENABLED "$file")" == disabled ]]
  [[ "$(last_field WG_ACCESS_AGENT_TIMER_ACTIVE "$file")" == inactive ]]
  [[ "$(last_field WG_ACCESS_AGENT_TIMER_ENABLED "$file")" == disabled ]]
  [[ "$(last_field WG_ACCESS_AGENT_SERVICE_ACTIVE "$file")" == inactive ]]
}

router_step_phase_begin preflight
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 /usr/local/sbin/router-vm121-git-publish.sh --check > "$EVIDENCE/pre-vm121-source.txt" 2>&1
"$ROOT/scripts/source-check-validate.sh" "$EVIDENCE/pre-vm121-source.txt" vm121 "$VM121_BASE_COMMIT" "$VM121_BASE_TREE" "$VM121_BASE_COUNT" > "$EVIDENCE/pre-vm121-source-validation.txt" || { STOP_DETAIL=pre_vm121_source; false; }
collect_vm121_live "$EVIDENCE/pre-vm121-live.txt" || { STOP_DETAIL=pre_vm121_live; false; }
assert_prod_zero "$EVIDENCE/pre-vm121-live.txt" || { STOP_DETAIL=pre_prod_state_not_zero; false; }
assert_agent_inactive "$EVIDENCE/pre-vm121-live.txt" || { STOP_DETAIL=pre_agent_not_inactive; false; }
[[ "$(last_field EXTERNAL_ONBOARDING_ACTIVE "$EVIDENCE/pre-vm121-live.txt")" == false ]] || { STOP_DETAIL=pre_external_onboarding_enabled; false; }
[[ "$(last_field V2_ROUTE_COUNT "$EVIDENCE/pre-vm121-live.txt")" == 6 ]] || { STOP_DETAIL=pre_v2_route_count; false; }
PRE_ENV_SHA="$(last_field LIVE_ENV_SHA256 "$EVIDENCE/pre-vm121-live.txt")"
BACKEND_STARTED_BEFORE="$(last_field BACKEND_STARTED_AT "$EVIDENCE/pre-vm121-live.txt")"
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 'sha256sum -c -' < "$ROOT/reference/pre-source.sha256" > "$EVIDENCE/pre-source-sha.txt" 2>&1 || { STOP_DETAIL=pre_source_file_hash; false; }
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 'test ! -e /opt/wg-access/backend/app/services/profile_delivery.py' || { STOP_DETAIL=pre_profile_delivery_already_present; false; }
PKG="$ROOT/$ROUTER_RELEASE_TARGET_PACKAGE_PATH"
ACTUAL_PKG_SHA="$(sha256sum "$PKG" | awk '{print $1}')"
[[ "$ACTUAL_PKG_SHA" == "$ROUTER_RELEASE_TARGET_PACKAGE_SHA256" ]] || { STOP_DETAIL=target_package_sha; false; }
tar -tzf "$PKG" > "$EVIDENCE/target-package-list.txt"
[[ "$(wc -l < "$EVIDENCE/target-package-list.txt")" -eq 5 ]] || { STOP_DETAIL=target_package_member_count; false; }
router_step_phase_complete preflight exact_vm121_source_prod_zero_agent_inactive_and_candidate_verified

router_step_phase_begin backup
token="$(basename "$RUN_DIR" | tr -cd 'A-Za-z0-9._-')"
BACKUP_DIR="/root/router-ops-backups/p26c1-r02-$token"
REMOTE_PKG="/root/router-step-p26c1-r02-$token.tar.gz"
REMOTE_TEST="/root/router-step-p26c1-r02-$token-profile-test.py"
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 /bin/bash -s -- "$BACKUP_DIR" > "$EVIDENCE/backup.txt" 2>&1 <<'VM121_BACKUP'
set -Eeuo pipefail
B="${1:?}"
install -d -m 0700 "$B"
tar -czf "$B/source-before.tar.gz" -C / \
  opt/wg-access/.env.example \
  opt/wg-access/docker-compose.yml \
  opt/wg-access/backend/app/config.py \
  opt/wg-access/backend/app/api/auth_v2.py
chmod 600 "$B/source-before.tar.gz"
sha256sum "$B/source-before.tar.gz" > "$B/source-before.tar.gz.sha256"
chmod 600 "$B/source-before.tar.gz.sha256"
echo "BACKUP_DIR=$B"
echo SOURCE_BACKUP_PRESENT=true
VM121_BACKUP
BACKUP_READY=true
router_step_phase_complete backup exact_source_backup_created

router_step_phase_begin apply
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 "umask 077; cat > '$REMOTE_PKG'" < "$PKG" || { STOP_DETAIL=remote_package_transfer; false; }
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 "umask 077; cat > '$REMOTE_TEST'" < "$ROOT/payload/p26c1_profile_surface_test.py" || { STOP_DETAIL=remote_test_transfer; false; }
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 /bin/bash -s -- "$REMOTE_PKG" "$ROUTER_RELEASE_TARGET_PACKAGE_SHA256" > "$EVIDENCE/apply.txt" 2>&1 <<'VM121_APPLY'
set -Eeuo pipefail
PKG="${1:?}"
EXPECTED_PACKAGE_SHA="${2:?}"
ACTUAL="$(sha256sum "$PKG" | awk '{print $1}')"
[[ "$ACTUAL" == "$EXPECTED_PACKAGE_SHA" ]]
LIST="$(mktemp)"
STAGE="$(mktemp -d /root/p26c1-r02-source-stage.XXXXXX)"
trap 'rm -f "$LIST" "$LIST.expected"; rm -rf "$STAGE"' EXIT
tar -tzf "$PKG" > "$LIST"
cat > "$LIST.expected" <<'EOF_LIST'
opt/wg-access/.env.example
opt/wg-access/backend/app/api/auth_v2.py
opt/wg-access/backend/app/config.py
opt/wg-access/backend/app/services/profile_delivery.py
opt/wg-access/docker-compose.yml
EOF_LIST
LC_ALL=C sort -o "$LIST" "$LIST"
LC_ALL=C sort -o "$LIST.expected" "$LIST.expected"
cmp -s "$LIST" "$LIST.expected"
tar -xzf "$PKG" -C "$STAGE"
python3 -m py_compile \
  "$STAGE/opt/wg-access/backend/app/config.py" \
  "$STAGE/opt/wg-access/backend/app/api/auth_v2.py" \
  "$STAGE/opt/wg-access/backend/app/services/profile_delivery.py"
docker stop wgaccess-backend >/dev/null
install -m 0644 "$STAGE/opt/wg-access/.env.example" /opt/wg-access/.env.example
install -m 0644 "$STAGE/opt/wg-access/docker-compose.yml" /opt/wg-access/docker-compose.yml
install -m 0644 "$STAGE/opt/wg-access/backend/app/config.py" /opt/wg-access/backend/app/config.py
install -m 0644 "$STAGE/opt/wg-access/backend/app/api/auth_v2.py" /opt/wg-access/backend/app/api/auth_v2.py
install -m 0644 "$STAGE/opt/wg-access/backend/app/services/profile_delivery.py" /opt/wg-access/backend/app/services/profile_delivery.py
cd /opt/wg-access
docker compose up -d --force-recreate backend >/dev/null
for i in $(seq 1 180); do
  if curl -fsS --max-time 3 http://127.0.0.1:18080/health >/dev/null 2>&1 && curl -fsS --max-time 3 http://127.0.0.1:18080/health/db >/dev/null 2>&1; then break; fi
  sleep 1
  [[ "$i" -lt 180 ]]
done
docker exec wgaccess-backend python -c 'import qrcode; import app.services.profile_delivery; print("QRCODE_RUNTIME_IMPORT=PASS")'
docker exec wgaccess-backend python -m py_compile /app/app/config.py /app/app/api/auth_v2.py /app/app/services/profile_delivery.py
echo "BACKEND_STARTED_AT=$(docker inspect -f '{{.State.StartedAt}}' wgaccess-backend)"
echo TARGET_PACKAGE_SHA_MATCH=true
echo SOURCE_APPLY=PASS
VM121_APPLY
SOURCE_APPLIED=true
SOURCE_CHANGED=true
BACKEND_STARTED_AFTER="$(last_field BACKEND_STARTED_AT "$EVIDENCE/apply.txt")"
[[ -n "$BACKEND_STARTED_AFTER" && "$BACKEND_STARTED_AFTER" != "$BACKEND_STARTED_BEFORE" ]] || { STOP_DETAIL=backend_generation_not_changed; false; }
{
  echo "BACKEND_STARTED_BEFORE=$BACKEND_STARTED_BEFORE"
  echo "BACKEND_STARTED_AFTER=$BACKEND_STARTED_AFTER"
  echo BACKEND_GENERATION_CHANGED=true
} > "$EVIDENCE/generation.txt"
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 /bin/bash -s > "$EVIDENCE/production-gate.txt" 2>&1 <<'VM121_GATE'
set -Eeuo pipefail
EXT="$(docker exec wgaccess-backend python -c 'from app.config import settings; print(str(settings.external_onboarding_active).lower())')"
echo "EXTERNAL_ONBOARDING_ACTIVE=$EXT"
[[ "$EXT" == false ]]
CODE="$(curl -sS --max-time 5 -o /tmp/p26c1-prod-gate-body.$$ -w '%{http_code}' -H 'Content-Type: application/json' -d '{"email":"closed@example.com"}' http://127.0.0.1:18080/v2/auth/login/request)"
rm -f /tmp/p26c1-prod-gate-body.$$
echo "PUBLIC_LOGIN_WHILE_DISABLED_HTTP=$CODE"
[[ "$CODE" == 404 ]]
echo PRODUCTION_EXTERNAL_GATE=PASS
VM121_GATE
router_step_phase_complete apply candidate_source_installed_backend_recreated_qrcode_runtime_healthy_external_closed

router_step_phase_begin isolated_test
TEMP_DB="p26c1_$(date -u +%Y%m%d%H%M%S)_$RANDOM"
set +e
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 /bin/bash -s -- "$REMOTE_TEST" "$TEMP_DB" > "$EVIDENCE/profile-surface-e2e.txt" 2>&1 <<'VM121_ISOLATED'
set -Eeuo pipefail
REMOTE_TEST="${1:?}"
TEMP_DB="${2:?}"
[[ "$TEMP_DB" == p26c1_* ]]
U="$(docker exec wgaccess-postgres sh -lc 'printf %s "$POSTGRES_USER"')"
cleanup(){
  set +e
  docker exec wgaccess-backend rm -f /tmp/p26c1_profile_surface_test.py >/dev/null 2>&1 || true
  docker exec wgaccess-postgres dropdb --if-exists -U "$U" "$TEMP_DB" >/dev/null 2>&1
  rc=$?
  set -e
  if [[ "$rc" -eq 0 ]]; then echo ISOLATED_TEST_DB_DROPPED=true; else echo ISOLATED_TEST_DB_DROPPED=false; fi
}
trap cleanup EXIT
docker exec wgaccess-postgres createdb -U "$U" "$TEMP_DB"
docker cp "$REMOTE_TEST" wgaccess-backend:/tmp/p26c1_profile_surface_test.py >/dev/null
docker exec -e TEMP_DB="$TEMP_DB" wgaccess-backend sh -lc '
  set -Eeuo pipefail
  export DATABASE_URL="$(python - <<"PY"
import os
from sqlalchemy.engine import make_url
u=make_url(os.environ["DATABASE_URL"])
print(u.set(database=os.environ["TEMP_DB"]).render_as_string(hide_password=False))
PY
)"
  cd /app
  alembic upgrade head >/dev/null
  PYTHONPATH=/app python /tmp/p26c1_profile_surface_test.py
'
VM121_ISOLATED
ISOLATED_TEST_RC=$?
set -e
if grep -Fqx 'ISOLATED_DATABASE_MUTATION_STARTED=true' "$EVIDENCE/profile-surface-e2e.txt"; then
  ISOLATED_DATABASE_WRITTEN=true
fi
if grep -Fqx 'ISOLATED_TEST_DB_DROPPED=true' "$EVIDENCE/profile-surface-e2e.txt"; then
  ISOLATED_DB_CLEANUP_STATUS=PASS
else
  ISOLATED_DB_CLEANUP_STATUS=FAIL
fi
if [[ "$ISOLATED_TEST_RC" -ne 0 ]]; then
  STOP_DETAIL=profile_surface_e2e
  false
fi
[[ "$ISOLATED_DB_CLEANUP_STATUS" == PASS ]] || { STOP_DETAIL=isolated_db_cleanup; false; }
for kv in \
  'RESULT=PASS_P26C1_PROFILE_SURFACE_E2E' \
  'ISOLATED_DATABASE_GUARD=PASS' \
  'PROFILE_LIST_REQUIRES_SESSION=true' \
  'PROFILE_CREATE_CSRF_REQUIRED=true' \
  'CROSS_USER_GRANT_REJECTED=true' \
  'PROFILE_CREATE_AUTHORIZED=true' \
  'PROFILE_TUNNEL_RESERVED=true' \
  'CONFIG_BLOCKED_BEFORE_ACTIVE=true' \
  'CONFIG_NO_STORE=PASS' \
  'QR_SVG_NO_STORE=PASS' \
  'CROSS_USER_CONFIG_DENIED=true' \
  'REVOKE_CSRF_REQUIRED=true' \
  'REVOKE_HOLDS_TUNNEL_UNTIL_ACK=true' \
  'REVOKE_ACK_RELEASES_AND_REVOKES=true' \
  'REISSUE_NEW_PROVISION_INTENT=true' \
  'REISSUE_CREDENTIAL_REVISION_ROTATED=true' \
  'JOB_PAYLOAD_SECRET_FIELDS_ABSENT=true' \
  'REISSUE_CONFIG_CHANGED=true' \
  'REISSUE_CONFIG_NO_STORE=PASS' \
  'PROFILE_SURFACE_AUDIT_COVERAGE=PASS' \
  'RAW_CONFIG_ABSENT_FROM_AUDIT=true' \
  'SYNTHETIC_PROFILE_ROWS_CLEAN=true' \
  'SYNTHETIC_CREDENTIAL_ROWS_CLEAN=true' \
  'SYNTHETIC_JOB_ROWS_CLEAN=true' \
  'SYNTHETIC_AUTH_ROWS_CLEAN=true'; do
  grep -Fqx "$kv" "$EVIDENCE/profile-surface-e2e.txt" || { STOP_DETAIL="profile_surface_${kv%%=*}"; false; }
done
collect_vm121_live "$EVIDENCE/production-after-isolated.txt" || { STOP_DETAIL=production_after_isolated_live; false; }
assert_prod_zero "$EVIDENCE/production-after-isolated.txt" || { STOP_DETAIL=production_db_changed_by_isolated_test; false; }
assert_agent_inactive "$EVIDENCE/production-after-isolated.txt" || { STOP_DETAIL=agent_changed_by_isolated_test; false; }
[[ "$(last_field EXTERNAL_ONBOARDING_ACTIVE "$EVIDENCE/production-after-isolated.txt")" == false ]] || { STOP_DETAIL=external_onboarding_changed; false; }
CORE_CHANGE_COMPLETE=true
router_step_phase_complete isolated_test profile_surface_security_semantics_proven_on_fail_closed_temporary_database_production_untouched

router_step_phase_begin machine_close
"$BASE/bin/router-machine-close-safe" vm121 "$STEP: authenticated WG config QR revoke reissue surface" > "$EVIDENCE/machine-close.txt" 2>&1 || { STOP_DETAIL=vm121_machine_close; false; }
grep -Fqx 'RESULT=PASS_ROUTER_MACHINE_CLOSE' "$EVIDENCE/machine-close.txt" || { STOP_DETAIL=vm121_machine_close_result; false; }
VM121_COMMIT="$(last_field COMMIT "$EVIDENCE/machine-close.txt")"
VM121_TREE="$(last_field TREE "$EVIDENCE/machine-close.txt")"
VM121_COUNT="$(last_field GIT_FILE_COUNT "$EVIDENCE/machine-close.txt")"
VM121_PUBLIC_URL="$(last_field VM121_PUBLIC_URL "$EVIDENCE/machine-close.txt")"
[[ "$VM121_COMMIT" =~ ^[0-9a-f]{40}$ ]]
[[ "$VM121_TREE" =~ ^[0-9a-f]{40}$ ]]
[[ "$VM121_COUNT" == 51 ]] || { STOP_DETAIL=vm121_new_file_count; false; }
[[ "$VM121_PUBLIC_URL" == https://reports.secret-studio.ru/latest/* ]]
router_step_phase_complete machine_close vm121_source_committed_and_published

router_step_phase_begin postcheck
ssh -T -o BatchMode=yes -o ConnectTimeout=20 vm121 /usr/local/sbin/router-vm121-git-publish.sh --check > "$EVIDENCE/post-vm121-source.txt" 2>&1
"$ROOT/scripts/source-check-validate.sh" "$EVIDENCE/post-vm121-source.txt" vm121 "$VM121_COMMIT" "$VM121_TREE" "$VM121_COUNT" > "$EVIDENCE/post-vm121-source-validation.txt" || { STOP_DETAIL=post_vm121_source; false; }
collect_vm121_live "$EVIDENCE/post-vm121-live.txt" || { STOP_DETAIL=post_vm121_live; false; }
assert_prod_zero "$EVIDENCE/post-vm121-live.txt" || { STOP_DETAIL=post_prod_state_not_zero; false; }
assert_agent_inactive "$EVIDENCE/post-vm121-live.txt" || { STOP_DETAIL=post_agent_not_inactive; false; }
[[ "$(last_field V2_ROUTE_COUNT "$EVIDENCE/post-vm121-live.txt")" == 11 ]] || { STOP_DETAIL=post_v2_route_count; false; }
[[ "$(last_field EXTERNAL_ONBOARDING_ACTIVE "$EVIDENCE/post-vm121-live.txt")" == false ]] || { STOP_DETAIL=post_external_onboarding_enabled; false; }
POST_ENV_SHA="$(last_field LIVE_ENV_SHA256 "$EVIDENCE/post-vm121-live.txt")"
[[ "$POST_ENV_SHA" == "$PRE_ENV_SHA" ]] || { STOP_DETAIL=live_env_changed; false; }
LIVE_ENV_UNCHANGED=true
cleanup_remote
router_step_phase_complete postcheck clean_source_production_db_zero_agent_inactive_env_unchanged_external_closed

router_step_phase_begin report_publish
resolve_xs_map
cat > "$REPORT/report.txt" <<EOFREPORT
RESULT=PASS_P26C1_WIREGUARD_CONFIG_QR_REVOKE_REISSUE_SURFACE
REVISION=R02
CORE_CHANGE_COMPLETE=true
CORE_CHANGE_REPEATED=false
SOURCE_CHANGED=true
LIVE_DATABASE_WRITTEN=false
ISOLATED_DATABASE_WRITTEN=true
DATABASE_SCHEMA_CHANGED=false
ALEMBIC_VERSION=0004_profile_provisioning
VM121_ONLY_CHANGE=true
VM100_MUTATED=false
VM101_MUTATED=false
PROVISIONING_SOURCE_CHANGED=false
PROFILE_CREATE_AUTHORIZATION=PASS
PROFILE_OWNERSHIP_ISOLATION=PASS
CONFIG_NO_STORE=PASS
QR_NO_STORE=PASS
QR_CONTENT_SECURITY_POLICY=PASS
RAW_CONFIG_PUBLICATION=false
RAW_CONFIG_AUDIT_LEAK=false
REVOKE_HOLDS_RESERVATION_UNTIL_ACK=PASS
REVOKE_ACK_REVOKES_CREDENTIAL=PASS
REISSUE_CREDENTIAL_ROTATION=PASS
REISSUE_CONFIG_CHANGED=PASS
JOB_PAYLOAD_SECRET_FIELDS_ABSENT=PASS
PROFILE_SURFACE_AUDIT_COVERAGE=PASS
ISOLATED_DATABASE_FAIL_CLOSED_GUARD=PASS
ISOLATED_DB_CLEANUP_STATUS=PASS
PRODUCTION_DATABASE_UNCHANGED=true
LIVE_ENV_UNCHANGED=$LIVE_ENV_UNCHANGED
EXTERNAL_ONBOARDING_ACTIVE=false
CONFIG_QR_IMPLEMENTED=true
PUBLIC_CONFIG_QR_ACTIVE=false
EXTERNAL_CLIENT_HANDSHAKE_PROVEN=false
SMTP_TLS_DELIVERY_ACTIVE=false
BACKEND_GENERATION_CHANGED=true
BACKUP_DIR=$BACKUP_DIR
VM100_PUBLIC_URL=$VM100_PUBLIC_URL
VM101_PUBLIC_URL=$VM101_PUBLIC_URL
VM121_COMMIT=$VM121_COMMIT
VM121_TREE=$VM121_TREE
VM121_FILE_COUNT=$VM121_COUNT
VM121_PUBLIC_URL=$VM121_PUBLIC_URL
P25_REPORT_URL=$P25_REPORT_URL
P26_REPORT_URL=$P26_REPORT_URL
LOCAL_PLAN_URL=$LOCAL_PLAN_URL
GLOBAL_PLAN_URL=$GLOBAL_PLAN_URL
ACCESS_MAP_URL=$ACCESS_MAP_URL
XS_MAP_URL=$XS_MAP_URL
RUNTIME_IMPACT=true
COPY_VERIFY=PASS
NEXT_ACTION=P26C2 controlled live external WireGuard proof through authenticated config surface: real lifecycle, handshake/data-plane, revoke, reissue, new handshake, teardown
EOFREPORT
cp "$REPORT/report.txt" "$REPORT/verify.txt"
cp "$ROOT/scripts/run-step.sh" "$REPORT/executed-step.sh"
cp "$ROOT/release-info.json" "$REPORT/release-info.json"
cp "$ROOT/rollback/README.md" "$REPORT/rollback.txt"
for f in pre-vm121-source-validation.txt pre-vm121-live.txt pre-source-sha.txt backup.txt apply.txt generation.txt production-gate.txt profile-surface-e2e.txt production-after-isolated.txt machine-close.txt post-vm121-source-validation.txt post-vm121-live.txt; do cp "$EVIDENCE/$f" "$REPORT/$f"; done
python3 - "$REPORT/facts.json" "$VM121_COMMIT" "$VM121_TREE" "$VM121_COUNT" "$VM121_PUBLIC_URL" "$BACKUP_DIR" <<'PYFACTS'
import json,sys
out,commit,tree,count,url,backup=sys.argv[1:]
facts={
 "schema":"wg-paid-p26c1-r02-facts-v1",
 "result":"PASS_P26C1_WIREGUARD_CONFIG_QR_REVOKE_REISSUE_SURFACE",
 "revision":"R02",
 "vm121_only_change":True,
 "source_changed":True,
 "live_database_written":False,
 "isolated_database_written":True,
 "database_schema_changed":False,
 "alembic_version":"0004_profile_provisioning",
 "profile_ownership_authorization":"PASS",
 "config_no_store":"PASS",
 "qr_no_store":"PASS",
 "revoke_reissue_semantics":"PASS",
 "raw_config_publication":False,
 "raw_config_audit_leak":False,
 "production_database_unchanged":True,
 "isolated_database_cleanup":"PASS",
 "live_env_unchanged":True,
 "external_onboarding_active":False,
 "config_qr_implemented":True,
 "public_config_qr_active":False,
 "external_client_handshake_proven":False,
 "smtp_tls_delivery_active":False,
 "vm121_commit":commit,"vm121_tree":tree,"vm121_file_count":int(count),"vm121_public_url":url,"backup_dir":backup,
}
with open(out,'w',encoding='utf-8') as f: json.dump(facts,f,indent=2,sort_keys=True); f.write('\n')
PYFACTS
args=()
while IFS= read -r f; do args+=("$f" "$(basename "$f")"); done < <(find "$REPORT" -maxdepth 1 -type f -print | LC_ALL=C sort)
router_step_publish_payload step050m07p26c1_r02_wireguard_config_qr_revoke_reissue_surface \
  "$REPORT" "$PAYLOAD" "$CURRENT" "$EVENTS" "$FINAL_ENV" "${args[@]}"
STEP_REPORT_URL="$(last_field PUBLIC_URL "$FINAL_ENV")"
router_step_phase_complete report_publish report_facts_and_exact_worker_published

router_step_phase_begin archive
archive_latest
router_step_phase_complete archive latest_archived
STOP_DETAIL=none
write_child PASS_P26C1_WIREGUARD_CONFIG_QR_REVOKE_REISSUE_SURFACE 0
trap - ERR
exit 0
