184 lines
6.2 KiB
Bash
184 lines
6.2 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Colors
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
|
|
echo -e "${GREEN}Running pre-push checks...${NC}"
|
|
|
|
# Paths
|
|
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
CONTENT_DIR="$REPO_ROOT/core/content"
|
|
MKDOCS_CFG_PATH="$CONTENT_DIR/mkdocs.yml"
|
|
SITE_DIR="$REPO_ROOT/site"
|
|
LOG_DIR="$REPO_ROOT/test/log"
|
|
|
|
# Clean logs
|
|
rm -rf "$LOG_DIR"; mkdir -p "$LOG_DIR"
|
|
|
|
SERVER_PID=""
|
|
cleanup() {
|
|
if [[ -n "${SERVER_PID:-}" ]] && ps -p "$SERVER_PID" >/dev/null 2>&1; then
|
|
kill "$SERVER_PID" >/dev/null 2>&1 || true
|
|
for _ in {1..30}; do ps -p "$SERVER_PID" >/dev/null 2>&1 || break; sleep 0.1; done
|
|
fi
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
# --- Optional lightweight checks (keep or remove) ---
|
|
if command -v trivy &>/dev/null; then
|
|
echo -e "${GREEN}Running Trivy scan...${NC}"
|
|
trivy fs . --exit-code 1 --severity CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN --no-progress \
|
|
>"$LOG_DIR/trivy.log" 2>&1 || { echo -e "${RED}Trivy failed. See $LOG_DIR/trivy.log${NC}"; exit 1; }
|
|
else
|
|
echo -e "${YELLOW}Trivy not installed. Skipping vulnerability scan.${NC}"
|
|
fi
|
|
|
|
if command -v trufflehog &>/dev/null && command -v jq &>/dev/null; then
|
|
echo -e "${GREEN}Running TruffleHog (verified only)...${NC}"
|
|
TMPF="$(mktemp)"
|
|
trufflehog filesystem . --json >"$TMPF" 2>"$LOG_DIR/trufflehog.log" || true
|
|
VERIFIED="$(jq 'select(.verified==true)' "$TMPF" | wc -l | tr -d ' ')"
|
|
if [[ "$VERIFIED" -gt 0 ]]; then
|
|
cp "$TMPF" "$LOG_DIR/trufflehog-findings.json"
|
|
echo -e "${RED}Verified secrets found. See $LOG_DIR/trufflehog-findings.json${NC}"
|
|
rm -f "$TMPF"; exit 1
|
|
fi
|
|
rm -f "$TMPF"
|
|
else
|
|
echo -e "${YELLOW}TruffleHog or jq not installed. Skipping secrets scan.${NC}"
|
|
fi
|
|
|
|
if command -v markdownlint &>/dev/null; then
|
|
echo -e "${GREEN}Running markdownlint...${NC}"
|
|
MD_FILES="$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.md$' || true)"
|
|
if [[ -n "$MD_FILES" ]]; then
|
|
# shellcheck disable=SC2086
|
|
echo $MD_FILES | xargs markdownlint >"$LOG_DIR/markdownlint.log" 2>&1 || {
|
|
echo -e "${RED}markdownlint failed. See $LOG_DIR/markdownlint.log${NC}"; exit 1; }
|
|
fi
|
|
else
|
|
echo -e "${YELLOW}markdownlint not installed. Skipping markdown check.${NC}"
|
|
fi
|
|
|
|
if command -v vale &>/dev/null && [[ -f "$REPO_ROOT/.vale.ini" ]]; then
|
|
echo -e "${GREEN}Running Vale...${NC}"
|
|
VALE_FILES="$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.md$' || true)"
|
|
if [[ -n "$VALE_FILES" ]]; then
|
|
# shellcheck disable=SC2086
|
|
echo $VALE_FILES | xargs vale >"$LOG_DIR/vale.log" 2>&1 || {
|
|
echo -e "${RED}Vale issues. See $LOG_DIR/vale.log${NC}"; exit 1; }
|
|
fi
|
|
else
|
|
echo -e "${YELLOW}Vale not installed or .vale.ini missing. Skipping Vale.${NC}"
|
|
fi
|
|
|
|
# --- MkDocs build (strict) ---
|
|
if ! command -v mkdocs >/dev/null 2>&1; then
|
|
echo -e "${RED}MkDocs not installed; cannot build docs.${NC}"; exit 1
|
|
fi
|
|
echo -e "${GREEN}Building documentation (strict)…${NC}"
|
|
mkdocs build -f "$MKDOCS_CFG_PATH" -d "$SITE_DIR" --strict >"$LOG_DIR/mkdocs-build.log" 2>&1 || {
|
|
echo -e "${RED}MkDocs build failed. See $LOG_DIR/mkdocs-build.log${NC}"; exit 1; }
|
|
|
|
# --- Serve built site ---
|
|
# if ! command -v python3 >/dev/null 2>&1; then
|
|
# echo -e "${RED}python3 not found; cannot serve static site.${NC}"; exit 1
|
|
# fi
|
|
|
|
# PORT="$(python3 - <<'PY'
|
|
# import socket
|
|
# s=socket.socket(); s.bind(('127.0.0.1',0))
|
|
# print(s.getsockname()[1]); s.close()
|
|
# PY
|
|
# )"
|
|
|
|
# STATIC_LOG="$LOG_DIR/static-serve.log"
|
|
# echo -e "${GREEN}Serving built site at http://127.0.0.1:$PORT …${NC}"
|
|
# python3 -m http.server "$PORT" --bind 127.0.0.1 --directory "$SITE_DIR" >"$STATIC_LOG" 2>&1 &
|
|
# SERVER_PID="$!"
|
|
|
|
# Wait for server
|
|
# echo -e "${GREEN}Waiting for local server to be reachable…${NC}"
|
|
# START_TIME="$(date +%s)"; TIMEOUT=60
|
|
# while : ; do
|
|
# if ! ps -p "$SERVER_PID" >/dev/null 2>&1; then
|
|
# echo -e "${RED}Static server died during startup. See $STATIC_LOG${NC}"; exit 1
|
|
# fi
|
|
# if curl --fail --silent -I "http://127.0.0.1:$PORT/" >/dev/null 2>>"$STATIC_LOG"; then break; fi
|
|
# if (( $(date +%s) - START_TIME >= TIMEOUT )); then
|
|
# echo -e "${RED}Static server did not come up in ${TIMEOUT}s.${NC}"
|
|
# tail -n 50 "$STATIC_LOG" || true; exit 1
|
|
# fi
|
|
# sleep 0.5
|
|
# done
|
|
|
|
# --- Build URL list (all *.html pages) ---
|
|
# URLS_FILE="$LOG_DIR/urls.txt"
|
|
# BASE_URL="http://127.0.0.1:$PORT/"
|
|
|
|
# export SITE_DIR BASE_URL
|
|
# python3 - <<'PY' > "$URLS_FILE"
|
|
# import os
|
|
# site = os.environ['SITE_DIR']; base = os.environ['BASE_URL']
|
|
# urls = []
|
|
# for root, _, files in os.walk(site):
|
|
# for name in files:
|
|
# if name.endswith('.html'):
|
|
# rel = os.path.relpath(os.path.join(root, name), site).replace(os.sep, '/')
|
|
# urls.append(base + rel)
|
|
# for u in sorted(urls): print(u)
|
|
# PY
|
|
|
|
# TOTAL="$(wc -l < "$URLS_FILE" | tr -d ' ')"
|
|
# echo -e "${GREEN}Lychee will scan ${TOTAL} pages…${NC}"
|
|
|
|
# # --- Lychee (single run, unbuffered, higher FD limit) ---
|
|
# if ! command -v lychee >/dev/null 2>&1; then
|
|
# echo -e "${YELLOW}Lychee not installed. Skipping link check.${NC}"
|
|
# cleanup; exit 0
|
|
# fi
|
|
|
|
# # Raise macOS open-file limit (best-effort) to avoid mid-run aborts
|
|
# ulimit -n 4096 || true
|
|
|
|
# CSV_OUT="$LOG_DIR/lychee.csv"
|
|
# RUN_LOG="$LOG_DIR/lychee-run.log"
|
|
|
|
# echo -e "${GREEN}Starting Lychee…${NC}"
|
|
# set +e
|
|
# # Use script(1) to allocate a PTY so output is line-buffered; tee to file.
|
|
# # Capture Lychee's real exit code via PIPESTATUS.
|
|
# script -q /dev/null lychee \
|
|
# --base-url "http://127.0.0.1:$PORT/" \
|
|
# --format detailed \
|
|
# --output "$CSV_OUT" \
|
|
# --verbose \
|
|
# --no-progress \
|
|
# --max-concurrency 16 \
|
|
# --timeout 30 \
|
|
# --max-retries 2 \
|
|
# --retry-wait-time 2 \
|
|
# --accept '100..=103,200..=399' \
|
|
# --exclude 'https?://(www\.)?github\.com/spread-ai' \
|
|
# --exclude 'https?://[^/]*app\.spread\.ai' \
|
|
# --exclude 'https?://[^/]*stage\.spread\.ai' \
|
|
# --exclude '\?q=' \
|
|
# --exclude '#__.*_annotation_.*' \
|
|
# - < "$URLS_FILE" 2>&1 | tee "$RUN_LOG"
|
|
# LYCHEE_RC=${PIPESTATUS[1]}
|
|
# set -e
|
|
|
|
# Stop server
|
|
# cleanup
|
|
|
|
# # Summarize and exit appropriately
|
|
# if [[ "$LYCHEE_RC" -ne 0 ]]; then
|
|
# echo -e "${RED}Lychee reported problems (exit $LYCHEE_RC). See:${NC}"
|
|
# echo " - $RUN_LOG"
|
|
# echo " - $CSV_OUT"
|
|
# echo " - $STATIC_LOG"
|
|
# exit 1
|
|
# else
|
|
# echo -e "${GREEN}Lychee completed successfully. See $CSV_OUT${NC}"
|
|
# fi
|