#!/usr/bin/env bash set -euo pipefail HOMELAB_STATE_DIR="${HOMELAB_STATE_DIR:-${XDG_DATA_HOME:-${HOME}/.local/share}/homelab}" SECURITY_REPORT_DIR="${SECURITY_REPORT_DIR:-${HOMELAB_STATE_DIR}/security-reports}" SECURITY_LOG_SINCE="${SECURITY_LOG_SINCE:-24h}" GITEA_CONTAINER="${GITEA_CONTAINER:-${LAB_GITEA_CONTAINER_NAME:-homelab-gitea}}" KUBECONFIG="${KUBECONFIG:-${HOME}/.kube/config}" timestamp() { date -u +%Y%m%dT%H%M%SZ } ensure_report_dir() { mkdir -p "${SECURITY_REPORT_DIR}" } print_matches() { local title="$1" local log_file="$2" local pattern="$3" local limit="${4:-20}" printf '\n== %s ==\n' "${title}" if [[ ! -s "${log_file}" ]]; then printf 'no log input\n' return 0 fi if grep -Eai "${pattern}" "${log_file}" >/dev/null; then grep -Eai "${pattern}" "${log_file}" | tail -n "${limit}" else printf 'none\n' fi } collect_gitea_logs() { local output_file="$1" if ! command -v docker >/dev/null 2>&1; then return 0 fi if ! docker ps --format '{{.Names}}' | grep -Fxq "${GITEA_CONTAINER}"; then return 0 fi docker logs --since "${SECURITY_LOG_SINCE}" "${GITEA_CONTAINER}" >"${output_file}" 2>&1 || true } collect_traefik_logs() { local output_file="$1" if ! command -v kubectl >/dev/null 2>&1; then return 0 fi if [[ ! -f "${KUBECONFIG}" ]]; then return 0 fi kubectl --kubeconfig "${KUBECONFIG}" -n traefik logs \ -l app.kubernetes.io/name=traefik \ --since="${SECURITY_LOG_SINCE}" \ --tail="${SECURITY_LOG_TAIL:-5000}" >"${output_file}" 2>&1 || true } main() { local stamp local gitea_log local traefik_log local report_file local suspicious_paths local suspicious_agents stamp="$(timestamp)" ensure_report_dir gitea_log="${SECURITY_REPORT_DIR}/security-gitea-logs-${stamp}.txt" traefik_log="${SECURITY_REPORT_DIR}/security-traefik-logs-${stamp}.txt" report_file="${SECURITY_REPORT_DIR}/security-logs-${stamp}.txt" suspicious_paths='/(wp-admin|wp-login|xmlrpc\.php|\.env|\.git|vendor/phpunit|cgi-bin|boaform|solr|actuator|server-status)|\.\./|%2e%2e|/etc/passwd|/proc/self/environ' suspicious_agents='nikto|sqlmap|nuclei|masscan|zgrab|gobuster|dirbuster|dirsearch|wpscan|acunetix|nessus|openvas|curl/[0-9]|python-requests|Go-http-client' collect_gitea_logs "${gitea_log}" collect_traefik_logs "${traefik_log}" { echo "Homelab security log summary" echo "Generated: ${stamp}" echo "Window: ${SECURITY_LOG_SINCE}" echo print_matches "Gitea auth or permission failures" "${gitea_log}" 'authentication failed|invalid credentials|denied|forbidden|unauthorized|failed login|401|403' print_matches "Gitea suspicious repo/path activity" "${gitea_log}" "${suspicious_paths}" print_matches "Traefik suspicious paths" "${traefik_log}" "${suspicious_paths}" print_matches "Traefik suspicious user agents" "${traefik_log}" "${suspicious_agents}" print_matches "Traefik client/server errors" "${traefik_log}" ' 4[0-9][0-9] | 5[0-9][0-9] |level=error|level=warn' echo echo "Raw Gitea log sample: ${gitea_log}" echo "Raw Traefik log sample: ${traefik_log}" } | tee "${report_file}" echo "Security log report: ${report_file}" } main "$@"