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

[ "$(id -un)" = "ops" ] || {
  echo "STOP: запускать на router-ops пользователем ops"
  exit 1
}

STEP="STEP_050M07R02_FIX_METADATA_AND_VALIDATE_REFERENCE"
PASS_DECISION="PASS_${STEP}"

TOKEN="e94a0859747d7b96f29c7fdafc2d0351ba603bb0a7e9e5a4"
PUBLIC_BASE="https://helena-background-beam-harry.trycloudflare.com/r/${TOKEN}"

ROOT="/opt/router-ops"
STATE_ROOT="${ROOT}/state"
PUBROOT="${ROOT}/public/r/${TOKEN}"

REFERENCE_ROOT="${PUBROOT}/vm101-reference"
SOURCE_CURRENT="${REFERENCE_ROOT}/current"

BUILD_TS="$(date -u +%Y%m%d-%H%M%S)"
REFERENCE_ID="${BUILD_TS}_vm101_reference_v1c"

PUBLIC_SNAPSHOT="${REFERENCE_ROOT}/snapshots/${REFERENCE_ID}"
PUBLIC_CURRENT="${REFERENCE_ROOT}/current"

STAGING_ROOT="${STATE_ROOT}/private-mirrors/vm101/reference-staging"
STAGING="${STAGING_ROOT}/${REFERENCE_ID}"

REPORT_SLUG="${BUILD_TS}_step050m07r02_fix_metadata_and_validate_reference"
REPORT_DIR="${PUBROOT}/${REPORT_SLUG}"

TRYCF_REPORT="${PUBLIC_BASE}/${REPORT_SLUG}/"
REPORT_TXT="${TRYCF_REPORT}report.txt"
FACTS_JSON="${TRYCF_REPORT}facts.json"

ARCHITECTURE_PLAN="${PUBLIC_BASE}/20260711-181158_local_architecture_plan_vm101_autonomous_hmn_recovery/"
XS_MAP="${PUBLIC_BASE}/20260711-120734_xs_map_audit_repair_publish/"
GLOBAL_PROJECT_PLAN="${PUBLIC_BASE}/20260711-123348_global_project_plan_wg_paid/"
VM101_REFERENCE="${PUBLIC_BASE}/vm101-reference/current/"
VM101_REFERENCE_SNAPSHOT="${PUBLIC_BASE}/vm101-reference/snapshots/${REFERENCE_ID}/"

CURRENT_STAGE="initialization"
LAST_SUCCESS="step_saved"

VM101_RC="NOT_RUN"
SOURCE_REFERENCE_ID="UNRESOLVED"
HOST_VALUE="UNRESOLVED"
BUSYBOX_VERSION="UNRESOLVED"
HEALTHY_SLOTS="0"
ROUTES_OK="false"
VALIDATION_OK="false"
SECRET_FINDINGS="UNKNOWN"

VM101_MODIFIED=false
PUBLIC_SNAPSHOT_PUBLISHED=false
PUBLIC_CURRENT_UPDATED=false

mkdir -p "$REPORT_DIR" "$STAGING_ROOT"

cp -a "$0" "$REPORT_DIR/step.sh"
chmod 600 "$REPORT_DIR/step.sh"

PROGRESS_LOG="$REPORT_DIR/progress.log"
: > "$PROGRESS_LOG"

stage() {
  CURRENT_STAGE="$1"

  echo
  echo ">>> [$1] $2" | tee -a "$PROGRESS_LOG"

  date -u '+    utc=%Y-%m-%dT%H:%M:%SZ' |
    tee -a "$PROGRESS_LOG"
}

mark_success() {
  LAST_SUCCESS="$1"
  echo "last_success=$LAST_SUCCESS" >> "$PROGRESS_LOG"
}

print_links() {
  echo
  echo "TRYCF_REPORT=$TRYCF_REPORT"
  echo "REPORT_TXT=$REPORT_TXT"
  echo "FACTS_JSON=$FACTS_JSON"
  echo "ARCHITECTURE_PLAN=$ARCHITECTURE_PLAN"
  echo "XS_MAP=$XS_MAP"
  echo "GLOBAL_PROJECT_PLAN=$GLOBAL_PROJECT_PLAN"
  echo "VM101_REFERENCE=$VM101_REFERENCE"
}

remote_vm101_script() {
  ssh \
    -o BatchMode=yes \
    -o ConnectTimeout=8 \
    -o ServerAliveInterval=20 \
    -o ServerAliveCountMax=6 \
    -o LogLevel=ERROR \
    pve-mgts \
    "ssh \
      -o BatchMode=yes \
      -o ConnectTimeout=8 \
      -o ServerAliveInterval=20 \
      -o ServerAliveCountMax=6 \
      -o StrictHostKeyChecking=no \
      -o UserKnownHostsFile=/dev/null \
      -o LogLevel=ERROR \
      -i /root/.ssh/pve_to_openwrt_mgts_ed25519 \
      root@10.71.100.2 \
      'sh -s'"
}

create_index() {
  cat > "$REPORT_DIR/index.html" <<EOF
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>${STEP}</title>
</head>
<body style="font-family:system-ui;max-width:1100px;margin:40px auto;padding:0 20px">
<h1>${STEP}</h1>

<ul>
<li><a href="report.txt">report.txt</a></li>
<li><a href="facts.json">facts.json</a></li>
<li><a href="assessment.json">assessment.json</a></li>
<li><a href="vm101-metadata.txt">vm101-metadata.txt</a></li>
<li><a href="validator-output.json">validator-output.json</a></li>
<li><a href="secret-scan.json">secret-scan.json</a></li>
<li><a href="sha256-check.txt">sha256-check.txt</a></li>
<li><a href="step.sh">step.sh</a></li>
</ul>

<h2>Reference</h2>
<ul>
<li><a href="${VM101_REFERENCE}">current</a></li>
<li><a href="${VM101_REFERENCE_SNAPSHOT}">immutable snapshot</a></li>
</ul>
</body>
</html>
EOF
}

write_stop() {
  local reason="$1"
  local rc="$2"
  local line="$3"

  cat > "$REPORT_DIR/report.txt" <<EOF
=== ${STEP} RESULT ===
step=${STEP}
decision=STOP_${STEP}_${reason}
step_execution=STOP
operation_result=REFERENCE_NOT_UPDATED
production_health=UNCHANGED
milestone_status=M07_IN_PROGRESS
all_ok=false

failure:
  rc=${rc}
  line=${line}
  stage=${CURRENT_STAGE}
  last_success=${LAST_SUCCESS}

metadata:
  source_reference_id=${SOURCE_REFERENCE_ID}
  host=${HOST_VALUE}
  busybox_version=${BUSYBOX_VERSION}

validation:
  validation_ok=${VALIDATION_OK}
  secret_findings=${SECRET_FINDINGS}

safety:
  vm101_read_only=true
  vm101_modified=${VM101_MODIFIED}
  public_snapshot_published=${PUBLIC_SNAPSHOT_PUBLISHED}
  public_current_updated=${PUBLIC_CURRENT_UPDATED}
  network_changed=false
  services_changed=false
  state_changed=false
  refresh_ran=false
  rebalance_ran=false

TRYCF_REPORT=${TRYCF_REPORT}
REPORT_TXT=${REPORT_TXT}
FACTS_JSON=${FACTS_JSON}
ARCHITECTURE_PLAN=${ARCHITECTURE_PLAN}
XS_MAP=${XS_MAP}
GLOBAL_PROJECT_PLAN=${GLOBAL_PROJECT_PLAN}
VM101_REFERENCE=${VM101_REFERENCE}
EOF

  python3 - \
    "$STEP" \
    "$reason" \
    "$rc" \
    "$line" \
    "$CURRENT_STAGE" \
    "$LAST_SUCCESS" \
    "$SOURCE_REFERENCE_ID" \
    "$HOST_VALUE" \
    "$BUSYBOX_VERSION" \
    "$VALIDATION_OK" \
    "$SECRET_FINDINGS" \
    "$PUBLIC_SNAPSHOT_PUBLISHED" \
    "$PUBLIC_CURRENT_UPDATED" \
    "$TRYCF_REPORT" \
    "$REPORT_TXT" \
    "$FACTS_JSON" \
    "$ARCHITECTURE_PLAN" \
    "$XS_MAP" \
    "$GLOBAL_PROJECT_PLAN" \
    "$VM101_REFERENCE" \
    > "$REPORT_DIR/facts.json" <<'PY'
import json
import sys

(
    step,
    reason,
    rc,
    line,
    stage,
    last_success,
    source_reference_id,
    host,
    busybox_version,
    validation_ok,
    secret_findings,
    snapshot_published,
    current_updated,
    report,
    report_txt,
    facts_json,
    architecture,
    xs_map,
    global_plan,
    vm101_reference,
) = sys.argv[1:]

print(json.dumps({
    "schema": "router-step-facts-v1",
    "step": step,
    "assessment": {
        "decision": f"STOP_{step}_{reason}",
        "step_execution": "STOP",
        "operation_result": "REFERENCE_NOT_UPDATED",
        "production_health": "UNCHANGED",
        "milestone_status": "M07_IN_PROGRESS",
        "all_ok": False,
        "failure": {
            "reason": reason,
            "rc": int(rc),
            "line": int(line),
            "stage": stage,
            "last_success": last_success,
        },
    },
    "metadata": {
        "source_reference_id": source_reference_id,
        "host": host,
        "busybox_version": busybox_version,
    },
    "validation": {
        "validation_ok": validation_ok == "true",
        "secret_findings": secret_findings,
    },
    "safety": {
        "vm101_read_only": True,
        "vm101_modified": False,
        "public_snapshot_published":
            snapshot_published == "true",
        "public_current_updated":
            current_updated == "true",
        "network_changed": False,
        "services_changed": False,
        "state_changed": False,
        "refresh_ran": False,
        "rebalance_ran": False,
    },
    "publish": {
        "trycf_report": report,
        "report_txt": report_txt,
        "facts_json": facts_json,
        "architecture_plan": architecture,
        "xs_map": xs_map,
        "global_project_plan": global_plan,
        "vm101_reference": vm101_reference,
    },
}, ensure_ascii=False, indent=2))
PY

  create_index

  find "$REPORT_DIR" \
    -type f \
    ! -name SHA256SUMS \
    -print0 |
    sort -z |
    xargs -0 sha256sum \
    > "$REPORT_DIR/SHA256SUMS"

  print_links
  exit "$rc"
}

fatal() {
  local reason="$1"
  local rc="${2:-1}"
  local line="${3:-$LINENO}"

  trap - ERR
  write_stop "$reason" "$rc" "$line"
}

trap 'rc=$?; fatal "UNEXPECTED_ERROR" "$rc" "$LINENO"' ERR

stage "01/07" "Проверяю текущий VM101 Reference"

for required in \
  "$SOURCE_CURRENT/index.html" \
  "$SOURCE_CURRENT/machine-profile.json" \
  "$SOURCE_CURRENT/machine-profile.md" \
  "$SOURCE_CURRENT/manifest.json" \
  "$SOURCE_CURRENT/runtime/current.json" \
  "$SOURCE_CURRENT/secret-scan.json" \
  "$SOURCE_CURRENT/SHA256SUMS"
do
  [ -s "$required" ] || {
    echo "MISSING_CURRENT_REFERENCE_FILE=$required"
    fatal "CURRENT_REFERENCE_INCOMPLETE" 2 "$LINENO"
  }
done

grep -Fq '"passed": true' \
  "$SOURCE_CURRENT/secret-scan.json" ||
  fatal "CURRENT_REFERENCE_SECRET_SCAN_NOT_PASS" 3 "$LINENO"

(
  cd "$SOURCE_CURRENT"
  sha256sum -c SHA256SUMS
) > "$REPORT_DIR/source-sha256-check.txt" 2>&1 ||
  fatal "CURRENT_REFERENCE_SHA256_FAILED" 4 "$LINENO"

SOURCE_REFERENCE_ID="$(
  python3 - "$SOURCE_CURRENT/manifest.json" <<'PY'
import json
import sys

with open(sys.argv[1], encoding="utf-8") as source:
    data = json.load(source)

print(data["reference_id"])
PY
)"

echo "source_reference_id=$SOURCE_REFERENCE_ID" |
  tee -a "$PROGRESS_LOG"

mark_success "current_reference_verified"

stage "02/07" "Снимаю исправленные metadata с VM101"

cat > "$REPORT_DIR/vm101-metadata.sh" <<'VM101'
#!/bin/sh
set -u

fact() {
  printf '__FACT__ %s=%s\n' "$1" "$2"
}

strict_iface() {
  iface="$1"
  attempt=1

  while [ "$attempt" -le 3 ]; do
    if ping \
      -I "$iface" \
      -c 1 \
      -W 3 \
      1.1.1.1 \
      >/dev/null 2>&1
    then
      return 0
    fi

    attempt=$((attempt + 1))
    sleep 1
  done

  return 1
}

routes_all() {
  for table in 201 202 203 204 205; do
    ip route show table "$table" 2>/dev/null |
      grep -q '^default ' ||
      return 1
  done

  return 0
}

HOST_VALUE="$(
  uci -q get system.@system[0].hostname \
    2>/dev/null ||
  true
)"

if [ -z "$HOST_VALUE" ] &&
   [ -r /proc/sys/kernel/hostname ]
then
  HOST_VALUE="$(
    cat /proc/sys/kernel/hostname 2>/dev/null ||
    true
  )"
fi

if [ -z "$HOST_VALUE" ]; then
  HOST_VALUE="$(
    uname -n 2>/dev/null ||
    true
  )"
fi

[ -n "$HOST_VALUE" ] ||
  HOST_VALUE="vm101"

BB_BIN="$(
  command -v busybox 2>/dev/null ||
  true
)"

[ -n "$BB_BIN" ] ||
  BB_BIN="/bin/busybox"

BB_VERSION="$(
  "$BB_BIN" 2>&1 |
    sed -n '1p' ||
  true
)"

case "$BB_VERSION" in
  BusyBox\ v*)
    ;;
  *)
    OPKG_VERSION="$(
      opkg status busybox 2>/dev/null |
        sed -n 's/^Version: //p' |
        head -n1 ||
      true
    )"

    if [ -n "$OPKG_VERSION" ]; then
      BB_VERSION="BusyBox ${OPKG_VERSION}"
    else
      BB_VERSION="BusyBox version unresolved"
    fi
    ;;
esac

fact host "$HOST_VALUE"
fact busybox_binary "$BB_BIN"
fact busybox_version "$BB_VERSION"
fact captured_utc "$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
fact runtime_cli "$(
  command -v amneziawg 2>/dev/null ||
  echo NOT_FOUND
)"

HEALTHY=0

for iface in vpn1 vpn2 vpn3 vpn4 vpn5; do
  if strict_iface "$iface"; then
    value=true
    HEALTHY=$((HEALTHY + 1))
  else
    value=false
  fi

  fact "strict.${iface}" "$value"
done

fact healthy_slots "$HEALTHY"

fact routes_201_205 "$(
  if routes_all; then
    echo true
  else
    echo false
  fi
)"

fact read_only true
fact vm101_modified false

echo "__TRACE__ stage=complete"
exit 0
VM101

chmod 600 "$REPORT_DIR/vm101-metadata.sh"
sh -n "$REPORT_DIR/vm101-metadata.sh"

if remote_vm101_script \
  < "$REPORT_DIR/vm101-metadata.sh" \
  > >(tee "$REPORT_DIR/vm101-metadata.txt") \
  2> >(tee "$REPORT_DIR/vm101-metadata.stderr" >&2)
then
  VM101_RC=0
else
  VM101_RC=$?
fi

[ "$VM101_RC" -eq 0 ] ||
  fatal "VM101_METADATA_READ_FAILED" "$VM101_RC" "$LINENO"

grep -Fq "__TRACE__ stage=complete" \
  "$REPORT_DIR/vm101-metadata.txt" ||
  fatal "VM101_METADATA_INCOMPLETE" 5 "$LINENO"

python3 - \
  "$REPORT_DIR/vm101-metadata.txt" \
  "$REPORT_DIR/metadata.json" <<'PY'
import json
import sys
from pathlib import Path

text = Path(sys.argv[1]).read_text(
    encoding="utf-8",
    errors="replace",
)

facts = {}

for line in text.splitlines():
    if not line.startswith("__FACT__ "):
        continue

    payload = line[len("__FACT__ "):]

    if "=" in payload:
        key, value = payload.split("=", 1)
        facts[key] = value

required = [
    "host",
    "busybox_binary",
    "busybox_version",
    "captured_utc",
    "runtime_cli",
    "healthy_slots",
    "routes_201_205",
]

missing = [
    key
    for key in required
    if not facts.get(key)
]

if missing:
    raise SystemExit(
        "missing metadata: " + ",".join(missing)
    )

result = {
    "host": facts["host"],
    "busybox_binary": facts["busybox_binary"],
    "busybox_version": facts["busybox_version"],
    "captured_utc": facts["captured_utc"],
    "runtime_cli": facts["runtime_cli"],
    "healthy_slots": int(facts["healthy_slots"]),
    "routes_201_205":
        facts["routes_201_205"] == "true",
    "strict": {
        iface:
            facts.get(f"strict.{iface}") == "true"
        for iface in [
            "vpn1",
            "vpn2",
            "vpn3",
            "vpn4",
            "vpn5",
        ]
    },
    "read_only":
        facts.get("read_only") == "true",
    "vm101_modified":
        facts.get("vm101_modified") == "true",
}

Path(sys.argv[2]).write_text(
    json.dumps(
        result,
        ensure_ascii=False,
        indent=2,
    ) + "\n",
    encoding="utf-8",
)
PY

HOST_VALUE="$(
  python3 - "$REPORT_DIR/metadata.json" <<'PY'
import json
import sys

data = json.load(open(sys.argv[1], encoding="utf-8"))
print(data["host"])
PY
)"

BUSYBOX_VERSION="$(
  python3 - "$REPORT_DIR/metadata.json" <<'PY'
import json
import sys

data = json.load(open(sys.argv[1], encoding="utf-8"))
print(data["busybox_version"])
PY
)"

HEALTHY_SLOTS="$(
  python3 - "$REPORT_DIR/metadata.json" <<'PY'
import json
import sys

data = json.load(open(sys.argv[1], encoding="utf-8"))
print(data["healthy_slots"])
PY
)"

ROUTES_OK="$(
  python3 - "$REPORT_DIR/metadata.json" <<'PY'
import json
import sys

data = json.load(open(sys.argv[1], encoding="utf-8"))
print("true" if data["routes_201_205"] else "false")
PY
)"

[ -n "$HOST_VALUE" ] ||
  fatal "HOSTNAME_STILL_EMPTY" 6 "$LINENO"

case "$BUSYBOX_VERSION" in
  BusyBox*)
    ;;
  *)
    fatal "BUSYBOX_VERSION_INVALID" 7 "$LINENO"
    ;;
esac

[ "$HEALTHY_SLOTS" = "5" ] ||
  fatal "PRODUCTION_HEALTH_NOT_5_OF_5" 8 "$LINENO"

[ "$ROUTES_OK" = "true" ] ||
  fatal "ROUTES_201_205_NOT_HEALTHY" 9 "$LINENO"

mark_success "correct_metadata_captured"

stage "03/07" "Строю новый immutable reference snapshot"

rm -rf "$STAGING"
mkdir -p "$STAGING"

cp -a "$SOURCE_CURRENT/." "$STAGING/"

rm -f "$STAGING/SHA256SUMS"

mkdir -p "$STAGING/tools" "$STAGING/docs"

python3 - \
  "$STAGING" \
  "$REPORT_DIR/metadata.json" \
  "$REFERENCE_ID" \
  "$SOURCE_REFERENCE_ID" <<'PY'
import json
import sys
from pathlib import Path

root = Path(sys.argv[1])
metadata_path = Path(sys.argv[2])
reference_id = sys.argv[3]
source_reference_id = sys.argv[4]

metadata = json.loads(
    metadata_path.read_text(encoding="utf-8")
)

profile_path = root / "machine-profile.json"
profile = json.loads(
    profile_path.read_text(encoding="utf-8")
)

profile["reference_id"] = reference_id
profile["source_reference_id"] = source_reference_id

profile.setdefault("identity", {})
profile["identity"]["host"] = metadata["host"]
profile["identity"]["busybox_version"] = (
    metadata["busybox_version"]
)

profile["metadata_correction"] = {
    "performed": True,
    "corrected_fields": [
        "identity.host",
        "identity.busybox_version",
    ],
    "source_reference_id": source_reference_id,
    "captured_utc": metadata["captured_utc"],
    "vm101_read_only": True,
}

profile.setdefault("runtime_health", {})
profile["runtime_health"]["healthy_slots"] = (
    metadata["healthy_slots"]
)
profile["runtime_health"]["routes_201_205"] = (
    metadata["routes_201_205"]
)
profile["runtime_health"]["strict"] = metadata["strict"]

profile_path.write_text(
    json.dumps(
        profile,
        ensure_ascii=False,
        indent=2,
    ) + "\n",
    encoding="utf-8",
)

manifest_path = root / "manifest.json"
manifest = json.loads(
    manifest_path.read_text(encoding="utf-8")
)

manifest["source_reference_id"] = source_reference_id
manifest["reference_id"] = reference_id
manifest["metadata_correction"] = {
    "performed": True,
    "host": metadata["host"],
    "busybox_version":
        metadata["busybox_version"],
    "captured_utc":
        metadata["captured_utc"],
}

manifest_path.write_text(
    json.dumps(
        manifest,
        ensure_ascii=False,
        indent=2,
    ) + "\n",
    encoding="utf-8",
)

runtime_path = root / "runtime" / "current.json"
runtime = json.loads(
    runtime_path.read_text(encoding="utf-8")
)

runtime["metadata_validation"] = {
    "host": metadata["host"],
    "busybox_version":
        metadata["busybox_version"],
    "captured_utc":
        metadata["captured_utc"],
    "healthy_slots":
        metadata["healthy_slots"],
    "routes_201_205":
        metadata["routes_201_205"],
    "strict":
        metadata["strict"],
}

runtime_path.write_text(
    json.dumps(
        runtime,
        ensure_ascii=False,
        indent=2,
    ) + "\n",
    encoding="utf-8",
)

profile_md = f"""# VM101 machine profile

Reference: {reference_id}
Source reference: {source_reference_id}

## Identity

- Host: {metadata['host']}
- Role: MGTS edge egress
- OS family: OpenWrt
- Shell: BusyBox ash
- BusyBox: {metadata['busybox_version']}
- System timezone: UTC
- Scheduled HMN refresh: 20 4 * * * UTC

## AmneziaWG

- Protocol: AmneziaWG
- Authoritative runtime CLI: {metadata['runtime_cli']}
- Interfaces: vpn1 through vpn5
- Runtime endpoint source: amneziawg show IFACE dump

## Routing

- Authoritative route tables: 201 through 205
- Table 200: optional legacy or bootstrap table
- Routes 201 through 205 healthy: {metadata['routes_201_205']}

## Runtime health

- Healthy VPN slots: {metadata['healthy_slots']}/5
- vpn1 strict: {metadata['strict']['vpn1']}
- vpn2 strict: {metadata['strict']['vpn2']}
- vpn3 strict: {metadata['strict']['vpn3']}
- vpn4 strict: {metadata['strict']['vpn4']}
- vpn5 strict: {metadata['strict']['vpn5']}

## Metadata correction

The host and BusyBox version were re-read from VM101 using a
BusyBox-compatible read-only probe. No production configuration was
changed.
"""

(root / "machine-profile.md").write_text(
    profile_md,
    encoding="utf-8",
)

(root / "generated-at.txt").write_text(
    metadata["captured_utc"] + "\n",
    encoding="utf-8",
)

validation_doc = """# VM101 Reference validation

The reference validator checks:

1. Required reference files exist.
2. The secret scan passed.
3. The machine profile has a non-empty host.
4. The BusyBox version begins with BusyBox.
5. The manifest matches every managed public file.
6. Managed public SHA256 values are correct.
7. The runtime snapshot contains five healthy VPN slots.
8. Route tables 201 through 205 are healthy.
9. The runtime CLI is /usr/bin/amneziawg.
10. Raw secret-bearing hashes are not exposed as public hashes.

Run on VM130:

    python3 tools/validate-reference.py /path/to/reference
"""

(root / "docs" / "reference-validation.md").write_text(
    validation_doc,
    encoding="utf-8",
)
PY

cat > "$STAGING/tools/validate-reference.py" <<'PY'
#!/usr/bin/env python3

import hashlib
import json
import sys
from pathlib import Path


def sha256(path: Path) -> str:
    digest = hashlib.sha256()

    with path.open("rb") as source:
        for chunk in iter(
            lambda: source.read(1024 * 1024),
            b"",
        ):
            digest.update(chunk)

    return digest.hexdigest()


def main() -> int:
    if len(sys.argv) != 2:
        print(
            "usage: validate-reference.py REFERENCE_ROOT",
            file=sys.stderr,
        )
        return 2

    root = Path(sys.argv[1]).resolve()

    required = [
        "index.html",
        "machine-profile.json",
        "machine-profile.md",
        "manifest.json",
        "secret-scan.json",
        "runtime/current.json",
        "methods/vm101-lib.sh",
        "docs/source-of-truth.md",
        "docs/known-failures.md",
        "docs/reference-validation.md",
    ]

    checks = {}
    errors = []

    for relative in required:
        path = root / relative
        present = path.is_file() and path.stat().st_size > 0
        checks[f"required:{relative}"] = present

        if not present:
            errors.append(
                f"required file missing: {relative}"
            )

    if errors:
        result = {
            "schema": "vm101-reference-validation-v1",
            "passed": False,
            "checks": checks,
            "errors": errors,
        }

        print(
            json.dumps(
                result,
                ensure_ascii=False,
                indent=2,
            )
        )
        return 1

    profile = json.loads(
        (root / "machine-profile.json").read_text(
            encoding="utf-8"
        )
    )

    manifest = json.loads(
        (root / "manifest.json").read_text(
            encoding="utf-8"
        )
    )

    secret_scan = json.loads(
        (root / "secret-scan.json").read_text(
            encoding="utf-8"
        )
    )

    runtime = json.loads(
        (root / "runtime/current.json").read_text(
            encoding="utf-8"
        )
    )

    host = str(
        profile.get("identity", {}).get("host", "")
    ).strip()

    busybox_version = str(
        profile.get("identity", {}).get(
            "busybox_version",
            "",
        )
    ).strip()

    checks["host_nonempty"] = bool(host)
    checks["busybox_version_valid"] = (
        busybox_version.startswith("BusyBox")
    )

    checks["secret_scan_passed"] = (
        secret_scan.get("passed") is True
        and secret_scan.get("finding_count") == 0
    )

    checks["runtime_cli_amneziawg"] = (
        profile.get("vpn", {}).get("runtime_cli")
        == "/usr/bin/amneziawg"
    )

    checks["runtime_healthy_5"] = (
        runtime.get("healthy_slots") == 5
    )

    checks["runtime_routes_201_205"] = (
        runtime.get("routes_201_205") is True
    )

    managed_files = manifest.get(
        "managed_files",
        [],
    )

    checks["managed_count_matches"] = (
        manifest.get("managed_file_count")
        == len(managed_files)
    )

    seen = set()

    for item in managed_files:
        relative = item.get("relative_path")
        public_hash = item.get("public_sha256")
        redactions = int(item.get("redactions", 0))

        if not relative:
            errors.append(
                "manifest item missing relative_path"
            )
            continue

        if relative in seen:
            errors.append(
                f"duplicate manifest path: {relative}"
            )
            continue

        seen.add(relative)

        path = root / "managed-files" / relative

        if not path.is_file():
            errors.append(
                f"managed file missing: {relative}"
            )
            continue

        actual_hash = sha256(path)

        if actual_hash != public_hash:
            errors.append(
                f"public hash mismatch: {relative}"
            )

        raw_hash = item.get("raw_sha256")

        if redactions > 0 and raw_hash != "PRIVATE_ONLY":
            errors.append(
                f"raw hash exposed for redacted file: {relative}"
            )

    actual_managed = {
        str(path.relative_to(root / "managed-files"))
        for path in (root / "managed-files").rglob("*")
        if path.is_file()
    }

    checks["manifest_covers_all_managed_files"] = (
        actual_managed == seen
    )

    if actual_managed != seen:
        missing_in_manifest = sorted(
            actual_managed - seen
        )

        missing_on_disk = sorted(
            seen - actual_managed
        )

        if missing_in_manifest:
            errors.append(
                "managed files absent from manifest: "
                + ",".join(missing_in_manifest)
            )

        if missing_on_disk:
            errors.append(
                "manifest files absent from disk: "
                + ",".join(missing_on_disk)
            )

    for name, value in checks.items():
        if not value:
            errors.append(
                f"failed check: {name}"
            )

    result = {
        "schema": "vm101-reference-validation-v1",
        "reference_id":
            manifest.get("reference_id"),
        "passed": not errors,
        "checks": checks,
        "errors": errors,
        "managed_file_count":
            len(managed_files),
    }

    print(
        json.dumps(
            result,
            ensure_ascii=False,
            indent=2,
        )
    )

    return 0 if not errors else 1


if __name__ == "__main__":
    raise SystemExit(main())
PY

chmod 755 "$STAGING/tools/validate-reference.py"

mark_success "corrected_reference_staged"

stage "04/07" "Повторяю secret scan и запускаю валидатор"

python3 - \
  "$STAGING" \
  "$REPORT_DIR/secret-scan.json" <<'PY'
import json
import re
import sys
from pathlib import Path

root = Path(sys.argv[1])
output = Path(sys.argv[2])

patterns = [
    (
        "private_pem",
        re.compile(
            r"-----BEGIN "
            r"(?:RSA |EC |OPENSSH )?"
            r"PRIVATE KEY-----",
            re.IGNORECASE,
        ),
    ),
    (
        "wireguard_private_value",
        re.compile(
            r"^\s*(?:PrivateKey|PresharedKey)"
            r"\s*=\s*(?!REDACTED\b)\S+",
            re.IGNORECASE,
        ),
    ),
    (
        "uci_private_value",
        re.compile(
            r"^\s*option\s+"
            r"(?:private_key|preshared_key|password|"
            r"token|secret|access_code)"
            r"\s+(?!['\"]?REDACTED['\"]?\s*$)\S+",
            re.IGNORECASE,
        ),
    ),
    (
        "authorization_header",
        re.compile(
            r"Authorization\s*:\s*"
            r"(?:Bearer|Basic)\s+"
            r"(?!REDACTED\b)\S+",
            re.IGNORECASE,
        ),
    ),
    (
        "credential_url",
        re.compile(
            r"[a-z][a-z0-9+.-]*://"
            r"[^/\s:@]+:[^/\s@]+@",
            re.IGNORECASE,
        ),
    ),
]

findings = []

for path in sorted(root.rglob("*")):
    if not path.is_file():
        continue

    if path.name in {
        "secret-scan.json",
        "validate-reference.py",
    }:
        continue

    try:
        text = path.read_text(
            encoding="utf-8",
            errors="strict",
        )
    except UnicodeDecodeError:
        findings.append({
            "file": str(path.relative_to(root)),
            "line": 0,
            "type": "non_utf8_file",
        })
        continue

    for number, line in enumerate(
        text.splitlines(),
        start=1,
    ):
        for finding_type, pattern in patterns:
            if pattern.search(line):
                findings.append({
                    "file":
                        str(path.relative_to(root)),
                    "line": number,
                    "type": finding_type,
                    "sample": line[:200],
                })

result = {
    "schema": "vm101-reference-secret-scan-v1",
    "passed": not findings,
    "finding_count": len(findings),
    "findings": findings,
}

payload = json.dumps(
    result,
    ensure_ascii=False,
    indent=2,
) + "\n"

(root / "secret-scan.json").write_text(
    payload,
    encoding="utf-8",
)

output.write_text(
    payload,
    encoding="utf-8",
)

if findings:
    raise SystemExit(40)
PY

SECRET_FINDINGS="$(
  python3 - "$REPORT_DIR/secret-scan.json" <<'PY'
import json
import sys

data = json.load(open(sys.argv[1], encoding="utf-8"))
print(data["finding_count"])
PY
)"

[ "$SECRET_FINDINGS" = "0" ] ||
  fatal "SECRET_SCAN_FAILED" 40 "$LINENO"

if python3 \
  "$STAGING/tools/validate-reference.py" \
  "$STAGING" \
  > "$REPORT_DIR/validator-output.json"
then
  VALIDATION_OK=true
else
  VALIDATION_OK=false
  fatal "REFERENCE_VALIDATION_FAILED" 41 "$LINENO"
fi

cp -a \
  "$REPORT_DIR/validator-output.json" \
  "$STAGING/reference-validation.json"

(
  cd "$STAGING"

  find . \
    -type f \
    ! -name SHA256SUMS \
    -print0 |
    sort -z |
    xargs -0 sha256sum \
    > SHA256SUMS

  sha256sum -c SHA256SUMS
) > "$REPORT_DIR/sha256-check.txt" 2>&1 ||
  fatal "STAGED_SHA256_FAILED" 42 "$LINENO"

mark_success "reference_validated"

stage "05/07" "Публикую immutable snapshot и обновляю current"

[ ! -e "$PUBLIC_SNAPSHOT" ] ||
  fatal "SNAPSHOT_ALREADY_EXISTS" 43 "$LINENO"

PUBLIC_TMP="${PUBLIC_SNAPSHOT}.new.$$"
CURRENT_NEW="${REFERENCE_ROOT}/current.new.$$"
CURRENT_OLD="${REFERENCE_ROOT}/current.old.$$"

rm -rf \
  "$PUBLIC_TMP" \
  "$CURRENT_NEW" \
  "$CURRENT_OLD"

cp -a "$STAGING" "$PUBLIC_TMP"
chmod -R a+rX "$PUBLIC_TMP"

mv "$PUBLIC_TMP" "$PUBLIC_SNAPSHOT"
PUBLIC_SNAPSHOT_PUBLISHED=true

cp -a "$PUBLIC_SNAPSHOT" "$CURRENT_NEW"

if [ -e "$PUBLIC_CURRENT" ]; then
  mv "$PUBLIC_CURRENT" "$CURRENT_OLD"
fi

mv "$CURRENT_NEW" "$PUBLIC_CURRENT"
rm -rf "$CURRENT_OLD"

PUBLIC_CURRENT_UPDATED=true

mark_success "snapshot_and_current_published"

stage "06/07" "Обновляю history и локальные project links"

python3 - \
  "$REFERENCE_ROOT" \
  "$REFERENCE_ID" \
  "$SOURCE_REFERENCE_ID" \
  "$VM101_REFERENCE" \
  "$VM101_REFERENCE_SNAPSHOT" \
  "$BUILD_TS" <<'PY'
import html
import json
import sys
from pathlib import Path

(
    root_arg,
    reference_id,
    source_reference_id,
    current_url,
    snapshot_url,
    build_ts,
) = sys.argv[1:]

root = Path(root_arg)
history_path = root / "history.json"

if history_path.exists():
    history = json.loads(
        history_path.read_text(
            encoding="utf-8"
        )
    )
else:
    history = {
        "schema": "vm101-reference-history-v1",
        "snapshots": [],
    }

history["current"] = reference_id

existing = {
    item.get("reference_id")
    for item in history.get("snapshots", [])
}

if reference_id not in existing:
    history.setdefault("snapshots", []).append({
        "reference_id": reference_id,
        "source_reference_id":
            source_reference_id,
        "generated_at_compact_utc":
            build_ts,
        "snapshot_url":
            snapshot_url,
        "change":
            "metadata correction and validator",
    })

history["snapshots"] = sorted(
    history["snapshots"],
    key=lambda item: item["reference_id"],
    reverse=True,
)

history_path.write_text(
    json.dumps(
        history,
        ensure_ascii=False,
        indent=2,
    ) + "\n",
    encoding="utf-8",
)

items = []

for item in history["snapshots"]:
    items.append(
        '<li><a href="'
        + html.escape(item["snapshot_url"])
        + '">'
        + html.escape(item["reference_id"])
        + "</a></li>"
    )

index = f"""<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>VM101 Reference</title>
</head>
<body style="font-family:system-ui;max-width:1100px;margin:40px auto;padding:0 20px">
<h1>VM101 Reference</h1>

<p><a href="{html.escape(current_url)}"><strong>Current reference</strong></a></p>

<h2>Immutable snapshots</h2>
<ul>
{''.join(items)}
</ul>

<p><a href="history.json">history.json</a></p>
</body>
</html>
"""

(root / "index.html").write_text(
    index,
    encoding="utf-8",
)
PY

chmod -R a+rX "$REFERENCE_ROOT"

cat > "$STATE_ROOT/current-vm101-reference.env" <<EOF
VM101_REFERENCE_ID=${REFERENCE_ID}
VM101_REFERENCE=${VM101_REFERENCE}
VM101_REFERENCE_SNAPSHOT=${VM101_REFERENCE_SNAPSHOT}
VM101_REFERENCE_MANIFEST=${VM101_REFERENCE}manifest.json
VM101_REFERENCE_GENERATED_AT_UTC=${BUILD_TS}
VM101_REFERENCE_SOURCE_ID=${SOURCE_REFERENCE_ID}
EOF

chmod 600 "$STATE_ROOT/current-vm101-reference.env"

python3 - \
  "$STATE_ROOT/current-project-links.env" \
  "$VM101_REFERENCE" <<'PY'
import sys
from pathlib import Path

path = Path(sys.argv[1])
reference = sys.argv[2]

lines = []

if path.exists():
    lines = path.read_text(
        encoding="utf-8",
        errors="replace",
    ).splitlines()

lines = [
    line
    for line in lines
    if not line.startswith("VM101_REFERENCE=")
]

lines.append(
    f"VM101_REFERENCE={reference}"
)

path.write_text(
    "\n".join(lines) + "\n",
    encoding="utf-8",
)
PY

chmod 600 "$STATE_ROOT/current-project-links.env"

mark_success "history_and_links_updated"

stage "07/07" "Формирую итоговый PASS"

(
  cd "$PUBLIC_CURRENT"
  sha256sum -c SHA256SUMS
) > "$REPORT_DIR/current-sha256-check.txt" 2>&1 ||
  fatal "PUBLISHED_CURRENT_SHA256_FAILED" 44 "$LINENO"

python3 \
  "$PUBLIC_CURRENT/tools/validate-reference.py" \
  "$PUBLIC_CURRENT" \
  > "$REPORT_DIR/current-validator-output.json" ||
  fatal "PUBLISHED_CURRENT_VALIDATION_FAILED" 45 "$LINENO"

MANAGED_COUNT="$(
  python3 - "$PUBLIC_CURRENT/manifest.json" <<'PY'
import json
import sys

data = json.load(open(sys.argv[1], encoding="utf-8"))
print(data["managed_file_count"])
PY
)"

MANIFEST_SHA="$(
  sha256sum "$PUBLIC_CURRENT/manifest.json" |
    cut -d' ' -f1
)"

python3 - \
  "$STEP" \
  "$REFERENCE_ID" \
  "$SOURCE_REFERENCE_ID" \
  "$HOST_VALUE" \
  "$BUSYBOX_VERSION" \
  "$HEALTHY_SLOTS" \
  "$ROUTES_OK" \
  "$MANAGED_COUNT" \
  "$SECRET_FINDINGS" \
  "$MANIFEST_SHA" \
  "$VM101_REFERENCE" \
  "$VM101_REFERENCE_SNAPSHOT" \
  > "$REPORT_DIR/assessment.json" <<'PY'
import json
import sys

(
    step,
    reference_id,
    source_reference_id,
    host,
    busybox_version,
    healthy_slots,
    routes_ok,
    managed_count,
    secret_findings,
    manifest_sha,
    current_url,
    snapshot_url,
) = sys.argv[1:]

print(json.dumps({
    "schema": "vm101-reference-assessment-v1",
    "decision":
        f"PASS_{step}",
    "step_execution": "PASS",
    "operation_result":
        "REFERENCE_METADATA_FIXED_AND_VALIDATED",
    "production_health": "HEALTHY",
    "milestone_status": "M07_IN_PROGRESS",
    "all_ok": True,
    "reference": {
        "reference_id": reference_id,
        "source_reference_id":
            source_reference_id,
        "current_url": current_url,
        "snapshot_url": snapshot_url,
        "manifest_sha256": manifest_sha,
        "managed_file_count":
            int(managed_count),
    },
    "metadata": {
        "host": host,
        "busybox_version":
            busybox_version,
        "corrected": True,
    },
    "validation": {
        "validator_installed": True,
        "validator_passed": True,
        "secret_findings":
            int(secret_findings),
        "sha256_passed": True,
    },
    "runtime": {
        "healthy_slots":
            int(healthy_slots),
        "routes_201_205":
            routes_ok == "true",
    },
    "safety": {
        "vm101_read_only": True,
        "vm101_modified": False,
        "network_changed": False,
        "services_changed": False,
        "state_changed": False,
        "refresh_ran": False,
        "rebalance_ran": False,
    },
    "next_step":
        "BUILD_CANONICAL_REPLACEMENT_FILES_FROM_REFERENCE",
}, ensure_ascii=False, indent=2))
PY

cat > "$REPORT_DIR/report.txt" <<EOF
=== ${STEP} RESULT ===
step=${STEP}
decision=${PASS_DECISION}
step_execution=PASS
operation_result=REFERENCE_METADATA_FIXED_AND_VALIDATED
production_health=HEALTHY
milestone_status=M07_IN_PROGRESS
all_ok=true

reference:
  reference_id=${REFERENCE_ID}
  source_reference_id=${SOURCE_REFERENCE_ID}
  public_current=${VM101_REFERENCE}
  public_snapshot=${VM101_REFERENCE_SNAPSHOT}
  manifest_sha256=${MANIFEST_SHA}
  managed_files=${MANAGED_COUNT}

metadata:
  host=${HOST_VALUE}
  busybox_version=${BUSYBOX_VERSION}
  corrected=true

validation:
  validator_installed=true
  validator_passed=true
  secret_findings=${SECRET_FINDINGS}
  sha256_passed=true

runtime:
  healthy_slots=${HEALTHY_SLOTS}
  routes_201_205=${ROUTES_OK}

safety:
  vm101_read_only=true
  vm101_modified=false
  network_changed=false
  services_changed=false
  state_changed=false
  refresh_ran=false
  rebalance_ran=false

plan:
  current_milestone=M07
  milestone_completed=false

next_step:
  BUILD_CANONICAL_REPLACEMENT_FILES_FROM_REFERENCE

TRYCF_REPORT=${TRYCF_REPORT}
REPORT_TXT=${REPORT_TXT}
FACTS_JSON=${FACTS_JSON}
ARCHITECTURE_PLAN=${ARCHITECTURE_PLAN}
XS_MAP=${XS_MAP}
GLOBAL_PROJECT_PLAN=${GLOBAL_PROJECT_PLAN}
VM101_REFERENCE=${VM101_REFERENCE}
EOF

python3 - \
  "$REPORT_DIR/assessment.json" \
  "$STEP" \
  "$BUILD_TS" \
  "$TRYCF_REPORT" \
  "$REPORT_TXT" \
  "$FACTS_JSON" \
  "$ARCHITECTURE_PLAN" \
  "$XS_MAP" \
  "$GLOBAL_PROJECT_PLAN" \
  "$VM101_REFERENCE" \
  > "$REPORT_DIR/facts.json" <<'PY'
import json
import sys

(
    assessment_path,
    step,
    generated_at,
    report,
    report_txt,
    facts_json,
    architecture,
    xs_map,
    global_plan,
    vm101_reference,
) = sys.argv[1:]

assessment = json.load(
    open(assessment_path, encoding="utf-8")
)

print(json.dumps({
    "schema": "router-step-facts-v1",
    "step": step,
    "generated_at_utc": generated_at,
    "assessment": assessment,
    "safety": assessment["safety"],
    "plan": {
        "current_milestone": "M07",
        "milestone_completed": False,
    },
    "next_step":
        "BUILD_CANONICAL_REPLACEMENT_FILES_FROM_REFERENCE",
    "publish": {
        "trycf_report": report,
        "report_txt": report_txt,
        "facts_json": facts_json,
        "architecture_plan": architecture,
        "xs_map": xs_map,
        "global_project_plan": global_plan,
        "vm101_reference": vm101_reference,
    },
}, ensure_ascii=False, indent=2))
PY

create_index

find "$REPORT_DIR" \
  -type f \
  ! -name SHA256SUMS \
  -print0 |
  sort -z |
  xargs -0 sha256sum \
  > "$REPORT_DIR/SHA256SUMS"

trap - ERR

echo "decision=$PASS_DECISION"
echo "step_execution=PASS"
echo "operation_result=REFERENCE_METADATA_FIXED_AND_VALIDATED"
echo "production_health=HEALTHY"
echo "reference_id=$REFERENCE_ID"
echo "source_reference_id=$SOURCE_REFERENCE_ID"
echo "host=$HOST_VALUE"
echo "busybox_version=$BUSYBOX_VERSION"
echo "validator_passed=true"
echo "secret_findings=$SECRET_FINDINGS"
echo "healthy_slots=$HEALTHY_SLOTS"
echo "routes_201_205=$ROUTES_OK"
echo "vm101_modified=false"

print_links
