#!/usr/bin/env bash
# ============================================================================
# qcrows-verify — Verify integrity and compliance of a QCrows image archive
# ============================================================================
set -euo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

log()   { echo -e "${GREEN}[qcrows-verify]${NC} $*"; }
warn()  { echo -e "${YELLOW}[qcrows-verify]${NC} WARN: $*"; }
fail()  { echo -e "${RED}[qcrows-verify]${NC} FAIL: $*"; }

FILE="${1:-}"
[[ -z "$FILE" ]] && { echo "Usage: qcrows-verify <file.qcrows>"; exit 1; }
[[ ! -f "$FILE" ]] && { echo "File not found: $FILE" >&2; exit 1; }

TMPDIR="$(mktemp -d /tmp/qcrows-verify-XXXXXX)"
trap 'rm -rf "$TMPDIR"' EXIT

# Extract archive
case "$FILE" in
  *.gz) tar xzf "$FILE" -C "$TMPDIR" 2>/dev/null || tar xf "$FILE" -C "$TMPDIR" 2>/dev/null ;;
  *)    tar xf "$FILE" -C "$TMPDIR" 2>/dev/null ;;
esac

# Descend into subdirectory if the archive wraps everything in one
# (i.e., only one child dir and no regular files at the top level)
top_level_files=$(find "$TMPDIR" -maxdepth 1 -type f | wc -l)
top_level_dirs=$(find "$TMPDIR" -maxdepth 1 -type d ! -path "$TMPDIR" | wc -l)
if [[ $top_level_dirs -eq 1 && $top_level_files -eq 0 ]]; then
  TMPDIR="$(find "$TMPDIR" -maxdepth 1 -type d ! -path "$TMPDIR" | head -1)"
fi

PASS=0
FAIL=0
WARN_COUNT=0

# ─── 1. Required files ─────────────────────────────────────────────────────
for req in metadata.toml menu.toml hashes.sha256; do
  if [[ -f "${TMPDIR}/${req}" ]]; then
    log "PASS: ${req} present"
    ((PASS++)) || true
  else
    fail "FAIL: ${req} missing (required)"
    ((FAIL++)) || true
  fi
done

# ─── 2. Rootfs ─────────────────────────────────────────────────────────────
rootfs_found=false
for ext in .tar.gz .tar.xz .tar.zst .tgz; do
  if ls "${TMPDIR}"/rootfs*${ext} 2>/dev/null | head -1 | grep -q .; then
    rootfs_found=true
    break
  fi
done
if [[ "$rootfs_found" == "false" ]] && ls "${TMPDIR}"/rootfs* 2>/dev/null | head -1 | grep -q .; then
  rootfs_found=true
fi

if [[ "$rootfs_found" == "true" ]]; then
  log "PASS: rootfs found"
  ((PASS++)) || true
else
  fail "FAIL: rootfs missing (required)"
  ((FAIL++)) || true
fi

# ─── 3. Kernel binary (required in v0.2+) ──────────────────────────────────
kernel_file=""
for name in kernel/vmlinuz kernel/vmlinux; do
  if [[ -f "${TMPDIR}/${name}" ]]; then
    kernel_file="${TMPDIR}/${name}"
    log "PASS: kernel binary found (${name})"
    ((PASS++)) || true
    break
  fi
done

if [[ -z "$kernel_file" ]]; then
  fail "FAIL: kernel missing (required in QCrows v0.2+)"
  ((FAIL++)) || true
else
  # Kernel format validation
  if file "$kernel_file" 2>/dev/null | grep -qE '(ELF|Linux.*boot)'; then
    log "PASS: kernel binary format valid"
    ((PASS++)) || true
  else
    fail "FAIL: kernel binary format invalid (expected ELF or bzImage)"
    ((FAIL++)) || true
  fi

  # Kernel size warning
  kernel_size=$(stat --format='%s' "$kernel_file" 2>/dev/null || echo 0)
  kernel_size_mb=$(( kernel_size / (1024 * 1024) ))
  if [[ $kernel_size_mb -gt 100 ]]; then
    warn "WARN: kernel exceeds 100MiB (${kernel_size_mb}MiB)"
    ((WARN_COUNT++)) || true
  fi
fi

# ─── 4. Kernel config (required) ───────────────────────────────────────────
if [[ -f "${TMPDIR}/kernel/config" ]]; then
  log "PASS: kernel/config found"
  ((PASS++)) || true

  # Required Kata config options — array-driven validation
  missing_options=0
  for opt in CONFIG_VSOCKETS CONFIG_VIRTIO CONFIG_VIRTIO_PCI CONFIG_DEVTMPFS CONFIG_DEVTMPFS_MOUNT; do
    if ! grep -q "${opt}=y" "${TMPDIR}/kernel/config" 2>/dev/null; then
      warn "WARN: required Kata option ${opt}=y not found in kernel config"
      ((missing_options++)) || true
    fi
  done

  if [[ $missing_options -eq 0 ]]; then
    log "PASS: all required Kata kernel options present"
    ((PASS++)) || true
  else
    warn "WARN: ${missing_options} required Kata options missing from kernel config"
    ((WARN_COUNT++)) || true
  fi
else
  fail "FAIL: kernel/config missing (required in QCrows v0.2+)"
  ((FAIL++)) || true
fi

# ─── 5. Boot params (optional — warn about dangerous params) ───────────────
if [[ -f "${TMPDIR}/boot-params.conf" ]]; then
  log "PASS: boot-params.conf present"
  ((PASS++)) || true
  if grep -qE 'module.sig_enforce=0|nokaslr|nopti|nosmap|nosmep' "${TMPDIR}/boot-params.conf" 2>/dev/null; then
    warn "WARN: potentially dangerous kernel parameters in boot-params.conf"
    ((WARN_COUNT++)) || true
  fi
fi

# ─── 6. Initrd ─────────────────────────────────────────────────────────────
initrd_found=false
for name in initrd.img initrd.cpio.gz initrd.cpio.lz4 initrd.cpio.xz initrd.cramfs; do
  if [[ -f "${TMPDIR}/${name}" ]]; then
    initrd_found=true
    break
  fi
done
if [[ "$initrd_found" == "true" ]]; then
  log "PASS: initrd present"
  ((PASS++)) || true
else
  warn "WARN: no initrd found (one of initrd/cramfs is recommended)"
  ((WARN_COUNT++)) || true
fi

# ─── 7. Hash verification ──────────────────────────────────────────────────
if [[ -f "${TMPDIR}/hashes.sha256" ]]; then
  cd "$TMPDIR"
  if sha256sum --quiet -c hashes.sha256 2>/dev/null; then
    log "PASS: all SHA-256 checksums match"
    ((PASS++)) || true
  else
    fail "FAIL: SHA-256 checksum mismatch"
    ((FAIL++)) || true
  fi
  cd - >/dev/null
fi

# ─── 8. metadata.toml format check ─────────────────────────────────────────
if [[ -f "${TMPDIR}/metadata.toml" ]]; then
  if grep -q "format_version" "${TMPDIR}/metadata.toml"; then
    meta_ver=$(grep "format_version" "${TMPDIR}/metadata.toml" | head -1 | grep -oP '"[\d.]+"' | tr -d '"')
    log "PASS: metadata format_version = ${meta_ver}"
    ((PASS++)) || true
  else
    fail "FAIL: metadata.toml missing format_version"
    ((FAIL++)) || true
  fi

  if grep -q "hypervisors" "${TMPDIR}/metadata.toml"; then
    log "PASS: hypervisor compatibility declared"
    ((PASS++)) || true
  else
    warn "WARN: no hypervisor compatibility in metadata"
    ((WARN_COUNT++)) || true
  fi
fi

# ─── Summary ────────────────────────────────────────────────────────────────
echo ""
echo -e "${CYAN}──────────────────────────────────────────────────────${NC}"
echo -e "  Passed: ${GREEN}${PASS}${NC}   Failed: ${RED}${FAIL}${NC}   Warnings: ${YELLOW}${WARN_COUNT}${NC}"
echo -e "${CYAN}──────────────────────────────────────────────────────${NC}"

[[ $FAIL -gt 0 ]] && exit 1
exit 0
