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

PATH="/usr/sbin:/usr/bin:/sbin:/bin"
LOG_DIR="/var/log/security/lynis"
LOCK_FILE="/var/lock/security_lynis_audit.lock"
RETENTION_DAYS="365"
TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
RUN_LOG="${LOG_DIR}/lynis-audit-${TIMESTAMP}.log"
ARCHIVE_REPORT="${LOG_DIR}/lynis-report-${TIMESTAMP}.dat"
LATEST_REPORT="/var/log/lynis-report.dat"
TOP_ITEMS="10"

if [[ "${EUID}" -ne 0 ]]; then
  echo "ERROR: This script must run as root." >&2
  exit 2
fi

for cmd in lynis flock tee find date cp grep wc awk head; do
  if ! command -v "${cmd}" >/dev/null 2>&1; then
    echo "ERROR: Required command not found: ${cmd}" >&2
    exit 2
  fi
done

mkdir -p "${LOG_DIR}" "$(dirname "${LOCK_FILE}")"
touch "${RUN_LOG}"

reportScannerStatus() {
  local scannerName

  echo "Malware scanner presence check:"
  for scannerName in rkhunter chkrootkit clamscan; do
    if command -v "${scannerName}" >/dev/null 2>&1; then
      echo "  - ${scannerName}: installed"
    else
      echo "  - ${scannerName}: not installed"
    fi
  done
}

exec 9>"${LOCK_FILE}"
if ! flock -n 9; then
  echo "INFO: Lynis audit already running; exiting."
  exit 0
fi

{
  echo "==== Lynis monthly audit started: $(date -Is) ===="
  echo "Run log: ${RUN_LOG}"
  reportScannerStatus

  # Prune old artifacts to control disk usage.
  find "${LOG_DIR}" -maxdepth 1 -type f -name 'lynis-audit-*.log' -mtime +"${RETENTION_DAYS}" -delete || true
  find "${LOG_DIR}" -maxdepth 1 -type f -name 'lynis-report-*.dat' -mtime +"${RETENTION_DAYS}" -delete || true

  lynis audit system --quick --no-colors
} 2>&1 | tee -a "${RUN_LOG}"

LYNIS_RC="${PIPESTATUS[0]}"

if [[ -f "${LATEST_REPORT}" ]]; then
  cp "${LATEST_REPORT}" "${ARCHIVE_REPORT}"
  echo "Archived report: ${ARCHIVE_REPORT}" | tee -a "${RUN_LOG}"

  HARDENING_INDEX="$(awk -F'=' '/^hardening_index=/{v=$2} END{print v}' "${LATEST_REPORT}" || true)"
  WARNING_COUNT="$(grep -E '^warning\[\]=' "${LATEST_REPORT}" | wc -l | awk '{print $1}')"
  SUGGESTION_COUNT="$(grep -E '^suggestion\[\]=' "${LATEST_REPORT}" | wc -l | awk '{print $1}')"

  echo "Summary: hardening_index=${HARDENING_INDEX:-unknown} warnings=${WARNING_COUNT} suggestions=${SUGGESTION_COUNT}" | tee -a "${RUN_LOG}"

  if [[ "${WARNING_COUNT}" -gt 0 ]]; then
    echo "Top warnings (up to ${TOP_ITEMS}):" | tee -a "${RUN_LOG}"
    awk '/^warning\[\]=/{sub(/^warning\[\]=/, ""); print "  - " $0}' "${LATEST_REPORT}" | head -n "${TOP_ITEMS}" | tee -a "${RUN_LOG}"
  else
    echo "Top warnings: none" | tee -a "${RUN_LOG}"
  fi

  if [[ "${SUGGESTION_COUNT}" -gt 0 ]]; then
    echo "Top suggestions (up to ${TOP_ITEMS}):" | tee -a "${RUN_LOG}"
    awk '/^suggestion\[\]=/{sub(/^suggestion\[\]=/, ""); print "  - " $0}' "${LATEST_REPORT}" | head -n "${TOP_ITEMS}" | tee -a "${RUN_LOG}"
  else
    echo "Top suggestions: none" | tee -a "${RUN_LOG}"
  fi
else
  echo "WARNING: Lynis report file not found at ${LATEST_REPORT}." | tee -a "${RUN_LOG}"
fi

echo "==== Lynis monthly audit finished: $(date -Is) (exit ${LYNIS_RC}) ====" | tee -a "${RUN_LOG}"

exit "${LYNIS_RC}"
