#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
export LC_ALL=C

EXPECTED_HOSTNAME=sqjcredis01
EXPECTED_IPV4=10.2.203.112
EXPECTED_OS='openEuler release 24.03 (LTS-SP1)'
EXPECTED_PERCONA_FINGERPRINT='4D1B B29D 63D9 8E42 2B21 13B1 9334 A25F 8507 EFA5'
BUNDLE_ROOT=${BUNDLE_ROOT:-/opt/zhct-deploy}
EVIDENCE_DIR=${EVIDENCE_DIR:-}
PACKAGE_ROOT="${BUNDLE_ROOT}/packages"
RPM_ROOT="${PACKAGE_ROOT}/rpms"
RPM_MANIFEST="${PACKAGE_ROOT}/rpms.sha256"
PERCONA_KEY="${PACKAGE_ROOT}/percona-packaging-key.asc"

declare -A EXPECTED_SHA=(
  [redis-5.0.14.tar.gz]=3ea5024766d983249e80d4aa9457c897a9f079957d0fb1f35682df233f997f32
  [redis-7.2.14.tar.gz]=21326da3f66c0aead4c8204c0ac52ff905337a77cadd169f75ac22835ea30025
  [percona-orchestrator-3.2.6-22.el8.x86_64.rpm]=0067ddf9845f31a2f150bbc5714e131676e7c05a87802c8aa3dbc3a0835d0ac2
  [percona-orchestrator-cli-3.2.6-22.el8.x86_64.rpm]=9814b2f688d3841baa8b99acf52a09eb8046d4b71fc4b19a3fff586dacbade40
  [percona-orchestrator-client-3.2.6-22.el8.x86_64.rpm]=d7b4875ec035c3885c88351cd264fcc3f64f1b84780e0682c534d5771831e88a
)

die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
require_file() { [[ -f "$1" ]] || die "required file not found: $1"; }

[[ "$(hostname -s)" == "${EXPECTED_HOSTNAME}" ]] || die 'hostname mismatch'
ip -o -4 addr show scope global | awk '{print $4}' | cut -d/ -f1 |
  grep -Fxq "${EXPECTED_IPV4}" || die 'expected IPv4 is not configured'
[[ "$(tr -d '\r' </etc/openEuler-release)" == "${EXPECTED_OS}" ]] || die 'OS mismatch'
[[ "$(uname -m)" == x86_64 ]] || die 'architecture mismatch'
[[ -n "${EVIDENCE_DIR}" ]] || die 'EVIDENCE_DIR is required'
install -d -m 0700 "${EVIDENCE_DIR}"
command -v gpg >/dev/null || die 'gpg is required to verify the Percona key fingerprint'

for archive in redis-5.0.14.tar.gz redis-7.2.14.tar.gz; do
  require_file "${PACKAGE_ROOT}/${archive}"
  actual=$(sha256sum "${PACKAGE_ROOT}/${archive}" | awk '{print $1}')
  [[ "${actual}" == "${EXPECTED_SHA[$archive]}" ]] || die "SHA256 mismatch: ${archive}"
done

require_file "${RPM_MANIFEST}"
[[ -d "${RPM_ROOT}" ]] || die "RPM closure directory not found: ${RPM_ROOT}"
(
  cd "${PACKAGE_ROOT}"
  sha256sum -c "$(basename "${RPM_MANIFEST}")"
) >"${EVIDENCE_DIR}/rpm-sha256-check.log" 2>&1 || die 'RPM closure SHA256 verification failed'

manifest_paths=$(mktemp)
actual_paths=$(mktemp)
rpmdb_temp=$(mktemp -d)
trap 'rm -f "${manifest_paths}" "${actual_paths}"; rm -rf "${rpmdb_temp}"' EXIT
awk 'NF == 2 && $1 ~ /^[0-9a-f]{64}$/ && $2 ~ /^rpms\/[^/]+[.]rpm$/ {print $2}' \
  "${RPM_MANIFEST}" | sort >"${manifest_paths}"
(cd "${PACKAGE_ROOT}" && find rpms -maxdepth 1 -type f -name '*.rpm' -print | sort) >"${actual_paths}"
[[ -s "${actual_paths}" ]] || die 'RPM closure is empty'
cmp -s "${manifest_paths}" "${actual_paths}" || die 'RPM files do not exactly match rpms.sha256'

for rpm_name in \
  percona-orchestrator-3.2.6-22.el8.x86_64.rpm \
  percona-orchestrator-cli-3.2.6-22.el8.x86_64.rpm \
  percona-orchestrator-client-3.2.6-22.el8.x86_64.rpm; do
  rpm_file="${RPM_ROOT}/${rpm_name}"
  require_file "${rpm_file}"
  actual=$(sha256sum "${rpm_file}" | awk '{print $1}')
  [[ "${actual}" == "${EXPECTED_SHA[$rpm_name]}" ]] || die "SHA256 mismatch: ${rpm_name}"
  [[ "$(rpm -qp --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}' "${rpm_file}")" == "${rpm_name%.rpm}" ]] ||
    die "NEVRA mismatch: ${rpm_name}"
done

find "${RPM_ROOT}" -maxdepth 1 -type f -name '*.rpm' \
  ! -name 'percona-orchestrator*.rpm' -print0 | sort -z |
  xargs -0 -r rpm --define '_pkgverify_level signature' -K \
  >"${EVIDENCE_DIR}/openeuler-rpm-signatures.txt" 2>&1 ||
  die 'one or more openEuler RPM signatures failed'
if grep -Eiq 'BAD|NOT OK|NOKEY|NOTTRUSTED' "${EVIDENCE_DIR}/openeuler-rpm-signatures.txt"; then
  die 'one or more openEuler RPM signatures are not trusted'
fi

require_file "${PERCONA_KEY}"
percona_fingerprint=$(gpg --batch --show-keys --with-colons "${PERCONA_KEY}" 2>/dev/null |
  awk -F: '$1 == "fpr" {print $10; exit}')
expected_fingerprint=${EXPECTED_PERCONA_FINGERPRINT// /}
[[ "${percona_fingerprint}" == "${expected_fingerprint}" ]] ||
  die 'Percona packaging key fingerprint mismatch'
printf '%s\n' "${EXPECTED_PERCONA_FINGERPRINT}" >"${EVIDENCE_DIR}/percona-packaging-key.txt"
rpm --dbpath "${rpmdb_temp}" --initdb
rpm --dbpath "${rpmdb_temp}" --import "${PERCONA_KEY}"
for rpm_name in \
  percona-orchestrator-3.2.6-22.el8.x86_64.rpm \
  percona-orchestrator-cli-3.2.6-22.el8.x86_64.rpm \
  percona-orchestrator-client-3.2.6-22.el8.x86_64.rpm; do
  rpm --dbpath "${rpmdb_temp}" --define '_pkgverify_level signature' \
    -K "${RPM_ROOT}/${rpm_name}" >>"${EVIDENCE_DIR}/percona-rpm-signatures.txt" 2>&1 ||
    die "Percona RPM signature failed: ${rpm_name}"
done
if grep -Eiq 'BAD|NOT OK|NOKEY|NOTTRUSTED' "${EVIDENCE_DIR}/percona-rpm-signatures.txt"; then
  die 'one or more Percona RPM signatures are not trusted'
fi

mapfile -d '' rpms < <(find "${RPM_ROOT}" -maxdepth 1 -type f -name '*.rpm' -print0 | sort -z)
set +e
dnf --disablerepo='*' --setopt=strict=True --setopt=install_weak_deps=False \
  --assumeno install "${rpms[@]}" >"${EVIDENCE_DIR}/dnf-cache-only-assumeno.log" 2>&1
dnf_rc=$?
set -e
[[ "${dnf_rc}" -eq 1 ]] || die "unexpected DNF --assumeno exit code: ${dnf_rc}"
grep -Fq 'Transaction Summary' "${EVIDENCE_DIR}/dnf-cache-only-assumeno.log" ||
  die 'DNF did not reach Transaction Summary'
grep -Eq '^[[:space:]]*Install[[:space:]]+[0-9]+[[:space:]]+Packages' \
  "${EVIDENCE_DIR}/dnf-cache-only-assumeno.log" || die 'DNF has no install-only summary'
if grep -Eiq '(^|[[:space:]])(Upgrading|Downgrading|Removing|Reinstalling|Obsoleting)(:|[[:space:]])|^[[:space:]]*(Upgrade|Downgrade|Remove|Reinstall|Obsolete)[[:space:]]+[0-9]+|nothing provides|conflicting requests|transaction test error|protected packages' \
  "${EVIDENCE_DIR}/dnf-cache-only-assumeno.log"; then
  die 'DNF closure contains a non-install action or unresolved dependency'
fi

{
  printf 'asset_gate=PASS\n'
  printf 'install_execution=NOT_PERFORMED\n'
  printf 'rpm_count=%s\n' "${#rpms[@]}"
  printf 'rpm_manifest_sha256=%s\n' "$(sha256sum "${RPM_MANIFEST}" | awk '{print $1}')"
  printf 'verified_at=%s\n' "$(date --iso-8601=seconds)"
} >"${EVIDENCE_DIR}/asset-gate-result.env"
printf 'REDIS01_ASSET_GATE_OK\n'
