From 16baea21f0ac0ed3c490d35828a732412fcb03ca Mon Sep 17 00:00:00 2001 From: g_it Date: Tue, 10 Feb 2026 23:03:08 +0100 Subject: [PATCH] . --- .checks/pre-push | 208 +++++++++++++++++++---------------------------- 1 file changed, 85 insertions(+), 123 deletions(-) diff --git a/.checks/pre-push b/.checks/pre-push index 16a6693..8c1ed17 100755 --- a/.checks/pre-push +++ b/.checks/pre-push @@ -2,139 +2,101 @@ set -euo pipefail # Colors -readonly RED='\033[0;31m' -readonly GREEN='\033[0;32m' -readonly YELLOW='\033[1;33m' -readonly NC='\033[0m' +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' -readonly REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" -readonly LOG_DIR="${REPO_ROOT}/.checks/logs" +echo -e "${GREEN}Running pre-push checks...${NC}" -log() { echo -e "${GREEN}[INFO] $*${NC}"; } -warn() { echo -e "${YELLOW}[WARN] $*${NC}"; } -err() { echo -e "${RED}[ERROR] $*${NC}" >&2; } +# Paths +REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" +CONTENT_DIR="$REPO_ROOT/content" +ZENSICAL_CFG_PATH="$REPO_ROOT/zensical.toml" +SITE_DIR="$REPO_ROOT/deploy" +LOG_DIR="$REPO_ROOT/logs" -prepare_logs() { - rm -rf "$LOG_DIR" - mkdir -p "$LOG_DIR" -} +# Clean logs +rm -rf "$LOG_DIR"; mkdir -p "$LOG_DIR" -# Files that git considers "scannable" (tracked + untracked not ignored) -scannable_files() { - git ls-files --cached --modified --others --exclude-standard -} - -# Files listed as ignored by git (used to build tool-specific skip args) -ignored_files() { - git ls-files -o -i --exclude-standard -} - -# Build Trivy skip args from git-ignored paths -trivy_skip_args() { - local path dir - while IFS= read -r path; do - [[ -z "$path" ]] && continue - dir="$(dirname "$path")" - printf -- '--skip-files=%q ' "$path" - printf -- '--skip-dirs=%q ' "$dir" - done < <(ignored_files) -} - -run_tool() { - local name="$1"; shift - if ! command -v "$name" &>/dev/null; then - warn "$name not installed; skipping." - return 0 - fi - "$@" -} - -run_trivy() { - run_tool trivy bash -c ' - files=("$@") - if [[ ${#files[@]} -eq 0 ]]; then - echo "no files"; exit 0 - fi - # Expand skip args passed via environment variable SKIP_ARGS - eval trivy fs "${files[@]}" $SKIP_ARGS --exit-code 1 --severity CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN --no-progress - ' _ $(scannable_files) -} - -run_trufflehog() { - run_tool trufflehog bash -c ' - files=("$@") - tmpf="$(mktemp)" - printf "%s\n" "${files[@]}" | xargs trufflehog filesystem --json >"$tmpf" 2>"'"$LOG_DIR"'/trufflehog.log" || true - if command -v jq &>/dev/null; then - if jq -e '"'"'any(inputs; .verified==true)'"'"' "$tmpf" >/dev/null 2>&1; then - cp "$tmpf" "'"$LOG_DIR"'/trufflehog-findings.json" - echo "verified"; exit 2 - fi - fi - rm -f "$tmpf" - ' _ $(git ls-files) - local rc=$?; [[ $rc -eq 2 ]] && { err "TruffleHog found verified secrets. See $LOG_DIR/trufflehog-findings.json"; return 1; } - return 0 -} - -run_git_secrets() { - run_tool git-secrets git-secrets --scan >"$LOG_DIR/git-secrets.log" 2>&1 || { - err "git-secrets detected potential secrets. See $LOG_DIR/git-secrets.log"; return 1; } -} - -run_bandit() { - run_tool bandit bash -c ' - py=("$@") - [[ ${#py[@]} -eq 0 ]] && exit 0 - bandit -r "${py[@]}" -n 5 -lll -f json -o "'"$LOG_DIR"'/bandit.json" 2>"'"$LOG_DIR"'/bandit.log" - ' _ $(git ls-files '*.py') -} - -run_npm_audit() { - if [[ -f package.json ]]; then - run_tool npm npm audit --audit-level=high >"$LOG_DIR/npm-audit.log" 2>&1 || { - err "npm audit found issues. See $LOG_DIR/npm-audit.log"; return 1; } +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 -run_pip_audit() { - if [[ -f requirements.txt ]] || [[ -f pyproject.toml ]]; then - run_tool pip-audit pip-audit -r requirements.txt >"$LOG_DIR/pip-audit.log" 2>&1 || { - err "pip-audit found issues. See $LOG_DIR/pip-audit.log"; return 1; } +# Trivy check for vulnerabilities in dependencies +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 + +# Trufflehog check for passwords and secrets +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 -run_stylelint() { - run_tool stylelint bash -c ' - files=("$@") - [[ ${#files[@]} -eq 0 ]] && exit 0 - stylelint "${files[@]}" --formatter json > "'"$LOG_DIR"'/stylelint.json" 2>"'"$LOG_DIR"'/stylelint.log" - ' _ $(git ls-files '*.{css,scss,sass,less}') -} - -main() { - prepare_logs - - # Precompute skip args for trivy (safe quoting) - export SKIP_ARGS - SKIP_ARGS="$(trivy_skip_args || true)" - - local failed=0 - - run_trivy || failed=1 - run_trufflehog || failed=1 - run_git_secrets || failed=1 - run_bandit || failed=1 - run_npm_audit || failed=1 - run_pip_audit || failed=1 - run_stylelint || failed=1 - - if [[ $failed -ne 0 ]]; then - err "Pre-push checks failed. Check logs in $LOG_DIR" +# Dependabot-like dependency vulnerability check +if command -v npm &>/dev/null && [[ -f package.json ]]; then + echo -e "${GREEN}Running npm audit...${NC}" + npm audit --audit-level=high >"$LOG_DIR/npm-audit.log" 2>&1 || { + echo -e "${RED}npm audit found vulnerabilities. See $LOG_DIR/npm-audit.log${NC}" exit 1 + } +elif command -v pip &>/dev/null && [[ -f requirements.txt ]]; then + echo -e "${GREEN}Running pip dependency check...${NC}" + pip list --outdated >"$LOG_DIR/pip-outdated.log" 2>&1 || true + if grep -q "upgradable" "$LOG_DIR/pip-outdated.log"; then + echo -e "${YELLOW}Outdated Python dependencies found. See $LOG_DIR/pip-outdated.log${NC}" fi +else + echo -e "${YELLOW}No dependency management files found. Skipping dependency checks.${NC}" +fi - log "All pre-push checks passed." -} +# Lint all the markdown files using markdownlint-cli2 +if command -v markdownlint-cli2 &>/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-cli2 >"$LOG_DIR/markdownlint.log" 2>&1 || { + echo -e "${RED}markdownlint-cli2 failed. See $LOG_DIR/markdownlint.log${NC}"; exit 1; } + fi +else + echo -e "${YELLOW}markdownlint-cli2 not installed. Skipping markdown check.${NC}" +fi -main "$@" +# Lint language using Vale +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 + +# Build the site using Zensical to check for build errors +if ! command -v zensical >/dev/null 2>&1; then + echo -e "${RED}Zensical not installed; cannot build docs.${NC}"; exit 1 +fi +echo -e "${GREEN}Building documentation (strict)…${NC}" +zensical build -f "$ZENSICAL_CFG_PATH" -d "$SITE_DIR" --strict >"$LOG_DIR/zensical-build.log" 2>&1 || { + echo -e "${RED}Zensical build failed. See $LOG_DIR/zensical-build.log${NC}"; exit 1; }