#!/usr/bin/env bash

set -Eeuo pipefail
umask 077
export LANG=C

EXPECTED_HOSTNAME="sqjcnginx01"
EXPECTED_IPV4="10.2.203.102"
EXPECTED_OS="openEuler release 24.03 (LTS-SP1)"
PREFLIGHT_RUN_ID="q042-20260723T134134+0800-R1"
EXPECTED_BUILD_ATTEMPT_ID="B4"
PREFLIGHT_SCRIPT_SHA256="beb46e4c6c04bf3ca5e02fa70e8d7d405c0863140ab0a02add9742d1702a6f3f"
PREFLIGHT_RESULT_SHA256="7728a3d5457740be422698f0f48048eca227240866f166be7f3b9a41ef45d32d"
BUNDLE_ROOT="/opt/zhct-deploy"
PACKAGE_ROOT="${BUNDLE_ROOT}/packages"
EVIDENCE_DIR="/var/backups/zhct-q042/evidence/${PREFLIGHT_RUN_ID}"
BUILD_PARENT="/var/tmp/zhct-q042"
VIP_RE='10\.2\.203\.(115|116|117)'
MIN_FREE_BYTES=$((9 * 1024 * 1024 * 1024))
TARGET_UNITS=(
  nginx.service
  keepalived.service
  haproxy.service
  orchestrator.service
  sentinel5.service
  sentinel7.service
)
FORMAL_BINARIES=(
  /usr/local/nginx/sbin/nginx
  /usr/local/sbin/keepalived
  /usr/local/haproxy/sbin/haproxy
  /usr/local/orchestrator/orchestrator
  /opt/redis/5.0.14/bin/redis-sentinel
  /opt/redis/5.0.14/bin/redis-cli
  /opt/redis/7.2.14/bin/redis-sentinel
  /opt/redis/7.2.14/bin/redis-cli
  /usr/bin/orchestrator
  /usr/bin/orchestrator-client
)
FORMAL_UNIT_FILES=(
  /etc/systemd/system/nginx.service
  /etc/systemd/system/keepalived.service
  /etc/systemd/system/haproxy.service
  /usr/lib/systemd/system/orchestrator.service
  /etc/systemd/system/sentinel5.service
  /etc/systemd/system/sentinel7.service
)
FORMAL_RUNTIME_PATHS=(
  /etc/keepalived/keepalived.conf
  /etc/haproxy/haproxy.cfg
  /etc/orchestrator.conf.json
  /var/lib/redis-sentinel5/sentinel.conf
  /var/lib/redis-sentinel7/sentinel.conf
  /var/lib/orchestrator
  /var/log/orchestrator
  /etc/zhct/node.env
  /etc/zhct/secrets
)
SOURCE_ARCHIVES=(
  "nginx-1.26.3.tar.gz|69ee2b237744036e61d24b836668aad3040dda461fe6f570f1787eab570c75aa|nginx-1.26.3"
  "keepalived-2.3.4.tar.gz|6afd95ddb7d3e0d3b8b8e5b3a489144131b61a01b06d29e883d0c44acc8a36bf|keepalived-2.3.4"
  "haproxy-2.8.26.tar.gz|88c28dae25ea46672e66f8db0dadd1fb5920e06ee2415ceb9f281c256b537727|haproxy-2.8.26"
  "redis-5.0.14.tar.gz|3ea5024766d983249e80d4aa9457c897a9f079957d0fb1f35682df233f997f32|redis-5.0.14"
  "redis-7.2.14.tar.gz|21326da3f66c0aead4c8204c0ac52ff905337a77cadd169f75ac22835ea30025|redis-7.2.14"
)

die() {
  printf 'ERROR: %s\n' "$*" >&2
  exit 1
}

assert_units_quiescent() {
  local output=$1
  : >"${output}"
  local unit enabled active substate started
  for unit in "${TARGET_UNITS[@]}"; do
    enabled=$(systemctl is-enabled "${unit}" 2>/dev/null || true)
    active=$(systemctl show "${unit}" -p ActiveState --value)
    substate=$(systemctl show "${unit}" -p SubState --value)
    started=$(systemctl show "${unit}" -p ExecMainStartTimestampMonotonic --value)
    printf '%s\t%s\t%s\t%s\t%s\n' \
      "${unit}" "${enabled}" "${active}" "${substate}" "${started}" >>"${output}"
    [[ "${enabled}" == "disabled" ]] || die "unit is not disabled: ${unit}"
    [[ "${active}" == "inactive" ]] || die "unit is not inactive: ${unit}"
    [[ "${substate}" == "dead" ]] || die "unit is not dead: ${unit}"
    [[ "${started}" == "0" ]] || die "unit has a start timestamp: ${unit}"
  done
}

assert_formal_runtime_paths_absent() {
  local output=$1
  : >"${output}"
  local path
  for path in "${FORMAL_RUNTIME_PATHS[@]}"; do
    if [[ -e "${path}" || -L "${path}" ]]; then
      printf '%s\tPRESENT\n' "${path}" >>"${output}"
      die "formal runtime path exists during Q042 rebuild: ${path}"
    fi
    printf '%s\tABSENT\n' "${path}" >>"${output}"
  done
}

nearest_existing_path() {
  local path=$1
  while [[ ! -e "${path}" && ! -L "${path}" ]]; do
    [[ "${path}" != "/" ]] || die "cannot find an existing parent path"
    path=$(dirname -- "${path}")
  done
  realpath -e -- "${path}"
}

validate_archive() {
  local archive=$1
  python3 - "${archive}" <<'PY'
import pathlib
import posixpath
import sys
import tarfile

archive = sys.argv[1]

def reject(message: str) -> None:
    raise SystemExit(f"{archive}: {message}")

def normalized_inside(parts: tuple[str, ...]) -> bool:
    depth = 0
    for part in parts:
        if part in ("", "."):
            continue
        if part == "..":
            depth -= 1
            if depth < 0:
                return False
        else:
            depth += 1
    return True

with tarfile.open(archive, mode="r:gz") as tf:
    members = tf.getmembers()
    if not members:
        reject("archive is empty")
    for member in members:
        member_path = pathlib.PurePosixPath(member.name)
        if member_path.is_absolute() or not normalized_inside(member_path.parts):
            reject(f"unsafe member path: {member.name}")
        if member.isdev() or member.isfifo():
            reject(f"special file is forbidden: {member.name}")
        if member.issym():
            target = pathlib.PurePosixPath(member.linkname)
            combined = pathlib.PurePosixPath(
                posixpath.normpath(str(member_path.parent / target))
            )
            if target.is_absolute() or not normalized_inside(combined.parts):
                reject(f"unsafe symlink target: {member.name} -> {member.linkname}")
        if member.islnk():
            target = pathlib.PurePosixPath(member.linkname)
            if target.is_absolute() or not normalized_inside(target.parts):
                reject(f"unsafe hardlink target: {member.name} -> {member.linkname}")
PY
}

cleanup_build_root() {
  local rc=$?
  local failure_archive failure_archive_sha
  trap - EXIT
  if [[ -d "${BUILD_ROOT}" ]]; then
    if [[ "${rc}" -ne 0 ]]; then
      failure_archive="${ATTEMPT_DIR}/failure-artifacts.tar.gz"
      failure_archive_sha="${ATTEMPT_DIR}/failure-artifacts.sha256"
      printf 'exit_code=%s\n' "${rc}" >"${ATTEMPT_DIR}/failure.env"
      if tar -C "${BUILD_ROOT}" -czf "${failure_archive}" logs results &&
        tar -tzf "${failure_archive}" >/dev/null &&
        sha256sum "${failure_archive}" >"${failure_archive_sha}"; then
        :
      else
        rm -f -- "${failure_archive}" "${failure_archive_sha}"
        printf 'ERROR: failed to preserve build evidence; retaining %s\n' \
          "${BUILD_ROOT}" >&2
        printf 'preserved_build_root=%s\n' "${BUILD_ROOT}" \
          >"${ATTEMPT_DIR}/preserved-build-root.env"
        chmod 0700 "${BUILD_PARENT}" 2>/dev/null || true
        exit 1
      fi
    fi
    case "${BUILD_ROOT}" in
      /var/tmp/zhct-q042/q042-*)
        rm -rf -- "${BUILD_ROOT}"
        ;;
      *)
        printf 'ERROR: refusing to clean unexpected build root: %s\n' "${BUILD_ROOT}" >&2
        chmod 0700 "${BUILD_PARENT}" 2>/dev/null || true
        exit 1
        ;;
    esac
  fi
  chmod 0700 "${BUILD_PARENT}" 2>/dev/null || true
  exit "${rc}"
}

[[ "${EUID}" -eq 0 ]] || die "must run as root"
[[ $# -eq 2 && "$1" == "${PREFLIGHT_RUN_ID}" ]] || die "Q042 R1 run id mismatch"
BUILD_ATTEMPT_ID=$2
[[ "${BUILD_ATTEMPT_ID}" == "${EXPECTED_BUILD_ATTEMPT_ID}" ]] || \
  die "Q042 build attempt id mismatch"
BUILD_ROOT="${BUILD_PARENT}/${PREFLIGHT_RUN_ID}-${BUILD_ATTEMPT_ID}"
ATTEMPT_ROOT="${EVIDENCE_DIR}/offline-rebuild-attempts"
ATTEMPT_DIR="${ATTEMPT_ROOT}/${BUILD_ATTEMPT_ID}"
[[ "$(hostname -s)" == "${EXPECTED_HOSTNAME}" ]] || die "hostname mismatch"
[[ "$(tr -d '\r' </etc/openEuler-release)" == "${EXPECTED_OS}" ]] || die "OS mismatch"
[[ "$(uname -m)" == "x86_64" ]] || die "CPU architecture mismatch"
ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1 | \
  grep -Fxq "${EXPECTED_IPV4}" || die "expected IPv4 is not configured"

for command in awk bash cat chmod chown cmp curl cut date df dirname dnf find grep \
  hostname id install ip ldd ln make mkdir mount mv nproc python3 readlink realpath rm rpm \
  sed setpriv sha256sum sort ss systemctl tail tar tee timeout touch tr uname unshare wc; do
  command -v "${command}" >/dev/null 2>&1 || die "required command is missing: ${command}"
done

[[ -d "${EVIDENCE_DIR}" ]] || die "R1 preflight evidence directory is missing"
[[ ! -e "${EVIDENCE_DIR}/offline-rebuild-result.env" &&
  ! -L "${EVIDENCE_DIR}/offline-rebuild-result.env" ]] || \
  die "offline rebuild result already exists"
[[ "$(sha256sum "${EVIDENCE_DIR}/preflight-result.env" | awk '{print $1}')" == \
  "${PREFLIGHT_RESULT_SHA256}" ]] || die "R1 preflight result SHA256 mismatch"
grep -Fxq 'preflight_check=PASS' "${EVIDENCE_DIR}/preflight-result.env" || \
  die "R1 preflight is not PASS"
grep -Fxq 'offline_rebuild_execution=NOT_PERFORMED' \
  "${EVIDENCE_DIR}/preflight-result.env" || die "R1 preflight state mismatch"
[[ "$(sha256sum /root/q042-preflight-check-r1.sh | awk '{print $1}')" == \
  "${PREFLIGHT_SCRIPT_SHA256}" ]] || die "R1 preflight script SHA256 mismatch"

install -d -m 0700 -o root -g root "${ATTEMPT_ROOT}"
[[ -d "${ATTEMPT_ROOT}" && ! -L "${ATTEMPT_ROOT}" ]] || \
  die "Q042 attempt root is not a real directory"
mkdir -m 0700 "${ATTEMPT_DIR}" 2>/dev/null || \
  die "Q042 build attempt evidence already exists"
exec > >(tee "${ATTEMPT_DIR}/check.log") 2>&1
SELF_SHA256=$(sha256sum "$0" | awk '{print $1}')
printf 'offline_rebuild_script_sha256=%s\n' "${SELF_SHA256}"

install -d -m 0711 -o root -g root "${BUILD_PARENT}"
mkdir -m 0700 "${BUILD_ROOT}" 2>/dev/null || die "Q042 build root already exists"
trap cleanup_build_root EXIT
install -d -m 0700 -o root -g root \
  "${BUILD_ROOT}/src" "${BUILD_ROOT}/home" "${BUILD_ROOT}/tmp" \
  "${BUILD_ROOT}/cache" "${BUILD_ROOT}/logs" "${BUILD_ROOT}/results"

{
  for path in / /tmp /var/tmp /home /srv; do
    nearest_existing_path "${path}"
  done
  for path in "${FORMAL_BINARIES[@]}"; do
    realpath -e -- "${path}"
  done
  for path in "${FORMAL_UNIT_FILES[@]}"; do
    realpath -e -- "${path}"
  done
  realpath -e -- "${PACKAGE_ROOT}"
  for entry in "${SOURCE_ARCHIVES[@]}"; do
    IFS='|' read -r filename _ _ <<<"${entry}"
    realpath -e -- "${PACKAGE_ROOT}/${filename}"
  done
  for path in "${FORMAL_RUNTIME_PATHS[@]}"; do
    nearest_existing_path "${path}"
  done
} | sort -u >"${BUILD_ROOT}/protected-paths.txt"
[[ $(wc -l <"${BUILD_ROOT}/protected-paths.txt") -ge 10 ]] || \
  die "protected path inventory is unexpectedly small"

for entry in "${SOURCE_ARCHIVES[@]}"; do
  IFS='|' read -r filename expected_sha top_level <<<"${entry}"
  archive="${PACKAGE_ROOT}/${filename}"
  [[ -f "${archive}" ]] || die "source archive is missing: ${filename}"
  actual_sha=$(sha256sum "${archive}" | awk '{print $1}')
  [[ "${actual_sha}" == "${expected_sha}" ]] || die "source archive SHA256 mismatch: ${filename}"
  validate_archive "${archive}"
  tar -xzf "${archive}" --no-same-owner --no-same-permissions \
    --delay-directory-restore -C "${BUILD_ROOT}/src"
  [[ -d "${BUILD_ROOT}/src/${top_level}" ]] || \
    die "expected source top-level directory is missing: ${top_level}"
  printf '%s  %s\n' "${actual_sha}" "${filename}" \
    >>"${ATTEMPT_DIR}/source-sha256.txt"
done
[[ $(find "${BUILD_ROOT}/src" -mindepth 1 -maxdepth 1 -type d | wc -l) -eq 5 ]] || \
  die "unexpected source top-level directory count"

NOBODY_UID=$(id -u nobody)
NOBODY_GID=$(id -g nobody)
[[ "${NOBODY_UID}" == "65534" && "${NOBODY_GID}" == "65534" ]] || \
  die "nobody account identity mismatch"
chown -R "${NOBODY_UID}:${NOBODY_GID}" "${BUILD_ROOT}"

assert_units_quiescent "${ATTEMPT_DIR}/unit-state-before-rebuild.tsv"
ss -lntupH >"${ATTEMPT_DIR}/listeners-before-rebuild.txt"
ip -4 -br addr >"${ATTEMPT_DIR}/ipv4-before-rebuild.txt"
ip route show table all >"${ATTEMPT_DIR}/routes-before-rebuild.txt"
sha256sum "${FORMAL_BINARIES[@]}" >"${ATTEMPT_DIR}/formal-binaries-before-rebuild.sha256"
sha256sum "${FORMAL_UNIT_FILES[@]}" >"${ATTEMPT_DIR}/formal-unit-files-before-rebuild.sha256"
assert_formal_runtime_paths_absent "${ATTEMPT_DIR}/formal-runtime-paths-before-rebuild.tsv"
dnf_history_id_before=$(dnf history list | awk '$1 ~ /^[0-9]+$/ {print $1; exit}')
dnf_history_id_before=${dnf_history_id_before:-0}

target_ports=$(awk -F'\t' 'NR > 1 && $1 ~ /^[0-9]+$/ {
  ports[++count]=$1
} END {
  for (i=1; i<=count; i++) printf "%s%s", (i > 1 ? "|" : ""), ports[i]
}' "${BUNDLE_ROOT}/roles/nginx/manifests/ports.tsv")
[[ -z "$(ss -lntupH | grep -E ":(${target_ports})([[:space:]]|$)" || true)" ]] || \
  die "target port is listening before Q042 rebuild"
[[ -z "$(ip -o -4 addr show | grep -E "${VIP_RE}" || true)" ]] || \
  die "project VIP is announced before Q042 rebuild"

JOBS=$(nproc)
((JOBS > 4)) && JOBS=4
unshare --mount --net --pid --fork --mount-proc --propagation private bash -s -- \
  "${BUILD_ROOT}" "${NOBODY_UID}" "${NOBODY_GID}" "${JOBS}" <<'NS'
set -Eeuo pipefail
BUILD_ROOT=$1
NOBODY_UID=$2
NOBODY_GID=$3
JOBS=$4
mapfile -t PROTECTED_PATHS <"${BUILD_ROOT}/protected-paths.txt"
[[ "${#PROTECTED_PATHS[@]}" -ge 10 ]] || {
  printf 'protected path inventory is unexpectedly small in namespace\n' >&2
  exit 1
}

for path in "${PROTECTED_PATHS[@]}"; do
  mount --bind "${path}" "${path}"
  mount -o remount,bind,ro "${path}"
done
mount --bind "${BUILD_ROOT}" "${BUILD_ROOT}"
mount -o remount,bind,rw "${BUILD_ROOT}"

cat /proc/self/mountinfo >"${BUILD_ROOT}/results/mountinfo.txt"
{
  printf 'path\teffective_state\n'
  for path in "${PROTECTED_PATHS[@]}"; do
    effective_state=$(python3 - "${path}" <<'PY'
import os
import sys

print("ro" if os.statvfs(sys.argv[1]).f_flag & os.ST_RDONLY else "rw")
PY
)
    printf '%s\t%s\n' "${path}" "${effective_state}"
    if [[ "${effective_state}" != "ro" ]]; then
        printf 'protected path is not mounted read-only: %s\n' "${path}" >&2
        exit 1
    fi
  done
  build_effective_state=$(python3 - "${BUILD_ROOT}" <<'PY'
import os
import sys

print("ro" if os.statvfs(sys.argv[1]).f_flag & os.ST_RDONLY else "rw")
PY
)
  printf '%s\t%s\n' "${BUILD_ROOT}" "${build_effective_state}"
  [[ "${build_effective_state}" == "rw" ]] || {
    printf 'temporary build root is not writable in mount namespace\n' >&2
    exit 1
  }
} >"${BUILD_ROOT}/results/mount-isolation.tsv"
printf 'protected_mounts_readonly=PASS\ntemporary_build_mount_writable=PASS\n' \
  >"${BUILD_ROOT}/results/mount-isolation.env"

setpriv --reuid="${NOBODY_UID}" --regid="${NOBODY_GID}" --clear-groups \
  --no-new-privs --inh-caps=-all --ambient-caps=-all --bounding-set=-all \
  env -i \
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
    HOME="${BUILD_ROOT}/home" \
    TMPDIR="${BUILD_ROOT}/tmp" \
    XDG_CACHE_HOME="${BUILD_ROOT}/cache" \
    LANG=C \
    BUILD_ROOT="${BUILD_ROOT}" \
    JOBS="${JOBS}" \
  bash --noprofile --norc <<'BUILD'
set -Eeuo pipefail
umask 077

check_dynamic_links() {
  local binary=$1
  local output=$2
  ldd "${binary}" >"${output}" 2>&1
  ! grep -Fq 'not found' "${output}" || {
    printf 'missing runtime library for temporary binary: %s\n' "${binary}" >&2
    return 1
  }
}

{
  printf 'build_user_uid=%s\n' "$(id -u)"
  printf 'build_user_gid=%s\n' "$(id -g)"
  awk '
    /^NoNewPrivs:/ {print "no_new_privs=" $2}
    /^CapInh:/ {print "cap_inh=" $2}
    /^CapPrm:/ {print "cap_prm=" $2}
    /^CapEff:/ {print "cap_eff=" $2}
    /^CapBnd:/ {print "cap_bnd=" $2}
    /^CapAmb:/ {print "cap_amb=" $2}
  ' /proc/self/status
} >"${BUILD_ROOT}/results/build-identity.env"
grep -Fxq 'build_user_uid=65534' "${BUILD_ROOT}/results/build-identity.env"
grep -Fxq 'build_user_gid=65534' "${BUILD_ROOT}/results/build-identity.env"
grep -Fxq 'no_new_privs=1' "${BUILD_ROOT}/results/build-identity.env"
for capability_field in cap_inh cap_prm cap_eff cap_bnd cap_amb; do
  grep -Fxq "${capability_field}=0000000000000000" \
    "${BUILD_ROOT}/results/build-identity.env"
done
touch "${BUILD_ROOT}/results/nobody-write-probe"
rm -f -- "${BUILD_ROOT}/results/nobody-write-probe"

set +e
timeout 6 curl --noproxy "*" --connect-timeout 2 --max-time 4 -fsS \
  https://repo.openeuler.org/ >/dev/null 2>"${BUILD_ROOT}/results/network-negative-test.txt"
network_rc=$?
set -e
[[ "${network_rc}" -ne 0 ]] || {
  printf 'public network unexpectedly worked during offline rebuild\n' >&2
  exit 1
}
printf 'isolated_public_network=BLOCKED\nisolated_public_network_test_rc=%s\n' \
  "${network_rc}" >"${BUILD_ROOT}/results/network-isolation.env"

cd "${BUILD_ROOT}/src/nginx-1.26.3"
./configure \
  --prefix=/usr/local/nginx \
  --with-http_ssl_module \
  --with-http_v2_module \
  --with-http_realip_module \
  --with-http_stub_status_module \
  --with-threads >"${BUILD_ROOT}/logs/nginx-configure.log" 2>&1
make -j"${JOBS}" >"${BUILD_ROOT}/logs/nginx-make.log" 2>&1
objs/nginx -V >"${BUILD_ROOT}/results/nginx-version.txt" 2>&1
check_dynamic_links objs/nginx "${BUILD_ROOT}/results/nginx-ldd.txt"

cd "${BUILD_ROOT}/src/keepalived-2.3.4"
./configure --prefix=/usr/local --sysconfdir=/etc \
  >"${BUILD_ROOT}/logs/keepalived-configure.log" 2>&1
make -j"${JOBS}" >"${BUILD_ROOT}/logs/keepalived-make.log" 2>&1
keepalived_bin=keepalived/keepalived
[[ -f "${keepalived_bin}" && -x "${keepalived_bin}" ]] || {
  printf 'expected Keepalived binary is missing or not executable: %s\n' \
    "${keepalived_bin}" >&2
  exit 1
}
"${keepalived_bin}" --version >"${BUILD_ROOT}/results/keepalived-version.txt" 2>&1
printf '%s\n' "${keepalived_bin}" >"${BUILD_ROOT}/results/keepalived-binary-path.txt"
check_dynamic_links "${keepalived_bin}" "${BUILD_ROOT}/results/keepalived-ldd.txt"

cd "${BUILD_ROOT}/src/haproxy-2.8.26"
make -j"${JOBS}" TARGET=linux-glibc USE_OPENSSL=1 USE_PCRE2=1 USE_SYSTEMD=1 \
  >"${BUILD_ROOT}/logs/haproxy-make.log" 2>&1
./haproxy -vv >"${BUILD_ROOT}/results/haproxy-version.txt" 2>&1
check_dynamic_links ./haproxy "${BUILD_ROOT}/results/haproxy-ldd.txt"

cd "${BUILD_ROOT}/src/redis-5.0.14"
make -j"${JOBS}" >"${BUILD_ROOT}/logs/redis5-make.log" 2>&1
src/redis-sentinel --version >"${BUILD_ROOT}/results/redis5-sentinel-version.txt" 2>&1
src/redis-cli --version >"${BUILD_ROOT}/results/redis5-cli-version.txt" 2>&1
check_dynamic_links src/redis-sentinel "${BUILD_ROOT}/results/redis5-sentinel-ldd.txt"
check_dynamic_links src/redis-cli "${BUILD_ROOT}/results/redis5-cli-ldd.txt"

cd "${BUILD_ROOT}/src/redis-7.2.14"
make -j"${JOBS}" >"${BUILD_ROOT}/logs/redis7-make.log" 2>&1
src/redis-sentinel --version >"${BUILD_ROOT}/results/redis7-sentinel-version.txt" 2>&1
src/redis-cli --version >"${BUILD_ROOT}/results/redis7-cli-version.txt" 2>&1
check_dynamic_links src/redis-sentinel "${BUILD_ROOT}/results/redis7-sentinel-ldd.txt"
check_dynamic_links src/redis-cli "${BUILD_ROOT}/results/redis7-cli-ldd.txt"
BUILD
NS

grep -Fq 'nginx version: nginx/1.26.3' "${BUILD_ROOT}/results/nginx-version.txt" || \
  die "Nginx temporary version check failed"
grep -Fq 'Keepalived v2.3.4' "${BUILD_ROOT}/results/keepalived-version.txt" || \
  die "Keepalived temporary version check failed"
grep -Fq 'HAProxy version 2.8.26' "${BUILD_ROOT}/results/haproxy-version.txt" || \
  die "HAProxy temporary version check failed"
grep -Fq 'Redis server v=5.0.14' "${BUILD_ROOT}/results/redis5-sentinel-version.txt" || \
  die "Redis 5 Sentinel temporary version check failed"
grep -Fq 'redis-cli 5.0.14' "${BUILD_ROOT}/results/redis5-cli-version.txt" || \
  die "Redis 5 CLI temporary version check failed"
grep -Fq 'Redis server v=7.2.14' "${BUILD_ROOT}/results/redis7-sentinel-version.txt" || \
  die "Redis 7 Sentinel temporary version check failed"
grep -Fq 'redis-cli 7.2.14' "${BUILD_ROOT}/results/redis7-cli-version.txt" || \
  die "Redis 7 CLI temporary version check failed"
grep -Fxq 'protected_mounts_readonly=PASS' "${BUILD_ROOT}/results/mount-isolation.env" || \
  die "mount namespace isolation check failed"
grep -Fxq 'temporary_build_mount_writable=PASS' \
  "${BUILD_ROOT}/results/mount-isolation.env" || \
  die "temporary build mount write check failed"
grep -Fxq 'build_user_uid=65534' "${BUILD_ROOT}/results/build-identity.env" || \
  die "temporary build did not run as nobody"
grep -Fxq 'build_user_gid=65534' "${BUILD_ROOT}/results/build-identity.env" || \
  die "temporary build group is not nobody"
grep -Fxq 'no_new_privs=1' "${BUILD_ROOT}/results/build-identity.env" || \
  die "temporary build no-new-privs check failed"
for capability_field in cap_inh cap_prm cap_eff cap_bnd cap_amb; do
  grep -Fxq "${capability_field}=0000000000000000" \
    "${BUILD_ROOT}/results/build-identity.env" || \
    die "temporary build retained capability set: ${capability_field}"
done

tar -C "${BUILD_ROOT}" -czf \
  "${ATTEMPT_DIR}/build-artifacts.tar.gz" \
  logs results
offline_build_artifacts_sha256=$(sha256sum \
  "${ATTEMPT_DIR}/build-artifacts.tar.gz" | awk '{print $1}')
tar -tzf "${ATTEMPT_DIR}/build-artifacts.tar.gz" >/dev/null

rm -rf -- "${BUILD_ROOT}"
[[ ! -e "${BUILD_ROOT}" && ! -L "${BUILD_ROOT}" ]] || \
  die "Q042 temporary build root was not removed"
chmod 0700 "${BUILD_PARENT}"
trap - EXIT

assert_units_quiescent "${ATTEMPT_DIR}/unit-state-after-rebuild.tsv"
ss -lntupH >"${ATTEMPT_DIR}/listeners-after-rebuild.txt"
ip -4 -br addr >"${ATTEMPT_DIR}/ipv4-after-rebuild.txt"
ip route show table all >"${ATTEMPT_DIR}/routes-after-rebuild.txt"
sha256sum "${FORMAL_BINARIES[@]}" >"${ATTEMPT_DIR}/formal-binaries-after-rebuild.sha256"
sha256sum "${FORMAL_UNIT_FILES[@]}" >"${ATTEMPT_DIR}/formal-unit-files-after-rebuild.sha256"
assert_formal_runtime_paths_absent "${ATTEMPT_DIR}/formal-runtime-paths-after-rebuild.tsv"
dnf_history_id_after=$(dnf history list | awk '$1 ~ /^[0-9]+$/ {print $1; exit}')
dnf_history_id_after=${dnf_history_id_after:-0}

cmp "${ATTEMPT_DIR}/formal-binaries-before-rebuild.sha256" \
  "${ATTEMPT_DIR}/formal-binaries-after-rebuild.sha256" || \
  die "formal binary changed during Q042 rebuild"
cmp "${ATTEMPT_DIR}/formal-unit-files-before-rebuild.sha256" \
  "${ATTEMPT_DIR}/formal-unit-files-after-rebuild.sha256" || \
  die "formal systemd unit file changed during Q042 rebuild"
cmp "${ATTEMPT_DIR}/formal-runtime-paths-before-rebuild.tsv" \
  "${ATTEMPT_DIR}/formal-runtime-paths-after-rebuild.tsv" || \
  die "formal runtime path state changed during Q042 rebuild"
cmp "${ATTEMPT_DIR}/listeners-before-rebuild.txt" \
  "${ATTEMPT_DIR}/listeners-after-rebuild.txt" || \
  die "host listeners changed during Q042 rebuild"
cmp "${ATTEMPT_DIR}/ipv4-before-rebuild.txt" \
  "${ATTEMPT_DIR}/ipv4-after-rebuild.txt" || \
  die "host IPv4 configuration changed during Q042 rebuild"
cmp "${ATTEMPT_DIR}/routes-before-rebuild.txt" \
  "${ATTEMPT_DIR}/routes-after-rebuild.txt" || \
  die "host routes changed during Q042 rebuild"
[[ "${dnf_history_id_after}" == "${dnf_history_id_before}" ]] || \
  die "DNF history changed during Q042 rebuild"
[[ -z "$(ss -lntupH | grep -E ":(${target_ports})([[:space:]]|$)" || true)" ]] || \
  die "target port is listening after Q042 rebuild"
[[ -z "$(ip -o -4 addr show | grep -E "${VIP_RE}" || true)" ]] || \
  die "project VIP is announced after Q042 rebuild"
remaining_processes="${ATTEMPT_DIR}/remaining-build-processes.txt"
: >"${remaining_processes}"
for cmdline_file in /proc/[0-9]*/cmdline; do
  [[ -r "${cmdline_file}" ]] || continue
  command_line=$(tr '\0' ' ' <"${cmdline_file}" 2>/dev/null || true)
  if [[ "${command_line}" == *"${BUILD_ROOT}"* ]]; then
    printf '%s\t%s\n' "${cmdline_file}" "${command_line}" >>"${remaining_processes}"
  fi
done
[[ ! -s "${remaining_processes}" ]] || \
  die "temporary build process remains after Q042 rebuild"

root_available_bytes=$(df -B1 --output=avail / | tail -n 1 | tr -d ' ')
root_total_bytes=$(df -B1 --output=size / | tail -n 1 | tr -d ' ')
minimum_required_bytes=${MIN_FREE_BYTES}
if ((root_total_bytes / 5 > minimum_required_bytes)); then
  minimum_required_bytes=$((root_total_bytes / 5))
fi
((root_available_bytes >= minimum_required_bytes)) || die "root free space is below Q042 gate"

{
  printf 'captured_at=%s\n' "$(date --iso-8601=seconds)"
  printf 'run_id=%s\n' "${PREFLIGHT_RUN_ID}"
  printf 'build_attempt_id=%s\n' "${BUILD_ATTEMPT_ID}"
  printf 'offline_rebuild_script_sha256=%s\n' "${SELF_SHA256}"
  printf 'source_archive_count=5\n'
  printf 'source_archive_sha256_check=PASS\n'
  printf 'archive_path_and_link_safety=PASS\n'
  printf 'network_namespace_isolation=PASS\n'
  printf 'pid_namespace_cleanup=PASS\n'
  printf 'mount_namespace_protected_paths_readonly=PASS\n'
  printf 'temporary_build_uid=%s\n' "${NOBODY_UID}"
  printf 'temporary_build_gid=%s\n' "${NOBODY_GID}"
  printf 'temporary_build_no_new_privs=PASS\n'
  printf 'temporary_build_all_capability_sets_empty=PASS\n'
  printf 'nginx_1_26_3_offline_rebuild=PASS\n'
  printf 'keepalived_2_3_4_offline_rebuild=PASS\n'
  printf 'haproxy_2_8_26_offline_rebuild=PASS\n'
  printf 'redis_5_0_14_offline_rebuild=PASS\n'
  printf 'redis_7_2_14_offline_rebuild=PASS\n'
  printf 'temporary_binary_dynamic_links=PASS\n'
  printf 'formal_binary_immutability=PASS\n'
  printf 'formal_unit_file_immutability=PASS\n'
  printf 'formal_runtime_paths_immutability=PASS\n'
  printf 'host_listener_immutability=PASS\n'
  printf 'host_ipv4_immutability=PASS\n'
  printf 'host_route_immutability=PASS\n'
  printf 'dnf_history_id_before=%s\n' "${dnf_history_id_before}"
  printf 'dnf_history_id_after=%s\n' "${dnf_history_id_after}"
  printf 'target_units_quiescent=PASS\n'
  printf 'target_listener_count=0\n'
  printf 'vip_announcement_count=0\n'
  printf 'temporary_build_root_cleanup=PASS\n'
  printf 'offline_build_artifacts_sha256=%s\n' "${offline_build_artifacts_sha256}"
  printf 'root_available_bytes=%s\n' "${root_available_bytes}"
  printf 'minimum_required_bytes=%s\n' "${minimum_required_bytes}"
  printf 'offline_rebuild_check=PASS\n'
} >"${ATTEMPT_DIR}/offline-rebuild-result.env.tmp"

find "${ATTEMPT_DIR}" -type d -exec chmod 0700 {} +
find "${ATTEMPT_DIR}" -type f -exec chmod 0600 {} +
mv -T "${ATTEMPT_DIR}/offline-rebuild-result.env.tmp" \
  "${ATTEMPT_DIR}/offline-rebuild-result.env"
ln "${ATTEMPT_DIR}/offline-rebuild-result.env" \
  "${EVIDENCE_DIR}/offline-rebuild-result.env"
printf 'Q042_OFFLINE_REBUILD_OK\n'
cat "${ATTEMPT_DIR}/offline-rebuild-result.env"
