Ignore files in gitignore for scanning.

This commit is contained in:
g_it 2026-02-10 22:40:34 +01:00
commit e1db9bde49
Signed by untrusted user who does not match committer: g_it
GPG key ID: A2B0A7C06A054627

View file

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Pre-push hook for comprehensive repository checks # Advanced Pre-Push Security and Quality Check Script
# Fail fast on any error # Fail fast on any error
set -euo pipefail set -euo pipefail
@ -12,12 +12,9 @@ readonly NC='\033[0m'
# Paths # Paths
readonly REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)" readonly REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
readonly CONTENT_DIR="${REPO_ROOT}/content" readonly LOG_DIR="${REPO_ROOT}/.checks/logs"
readonly ZENSICAL_CFG_PATH="${REPO_ROOT}/zensical.toml"
readonly SITE_DIR="${REPO_ROOT}/deploy"
readonly LOG_DIR="${REPO_ROOT}/logs"
# Logging and error handling # Logging functions
log_error() { log_error() {
echo -e "${RED}[ERROR] $*${NC}" >&2 echo -e "${RED}[ERROR] $*${NC}" >&2
} }
@ -30,54 +27,74 @@ log_warning() {
echo -e "${YELLOW}[WARNING] $*${NC}" echo -e "${YELLOW}[WARNING] $*${NC}"
} }
# Cleanup function # Utility function to get scannable files respecting .gitignore
cleanup() { get_scannable_files() {
if [[ -n "${SERVER_PID:-}" ]] && ps -p "$SERVER_PID" >/dev/null 2>&1; then # Find files that are tracked by git or not ignored
kill "$SERVER_PID" >/dev/null 2>&1 || true git ls-files --cached --modified --others --exclude-standard
for _ in {1..30}; do
ps -p "$SERVER_PID" >/dev/null 2>&1 || break
sleep 0.1
done
fi
} }
trap cleanup EXIT INT TERM
# Initialize log directory # Gitignore-aware exclusion generator
get_gitignore_excludes() {
local excludes=()
# Use git ls-files to find ignored files
while IFS= read -r file; do
# Convert file paths to directories for skipping
dir=$(dirname "$file")
excludes+=("--skip-dirs=$dir" "--skip-files=$file")
done < <(git ls-files -o -i --exclude-standard)
printf '%s\n' "${excludes[@]}"
}
# Prepare log directory
prepare_log_directory() { prepare_log_directory() {
rm -rf "$LOG_DIR" rm -rf "$LOG_DIR"
mkdir -p "$LOG_DIR" mkdir -p "$LOG_DIR"
} }
# Vulnerability Scanning # Vulnerability Scanning with Trivy
run_trivy_scan() { run_trivy_scan() {
if ! command -v trivy &>/dev/null; then if ! command -v trivy &>/dev/null; then
log_warning "Trivy not installed. Skipping vulnerability scan." log_warning "Trivy not installed. Skipping vulnerability scan."
return 0 return 0
fi }
log_info "Running Trivy scan..." local files
trivy fs . \ mapfile -t files < <(get_scannable_files)
if [[ ${#files[@]} -eq 0 ]]; then
log_warning "No files to scan with Trivy"
return 0
}
log_info "Running Trivy vulnerability scan..."
# shellcheck disable=SC2046
trivy fs "${files[@]}" \
$(get_gitignore_excludes) \
--exit-code 1 \ --exit-code 1 \
--severity CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN \ --severity CRITICAL,HIGH,MEDIUM,LOW,UNKNOWN \
--no-progress \ --no-progress \
>"$LOG_DIR/trivy.log" 2>&1 || { >"$LOG_DIR/trivy.log" 2>&1 || {
log_error "Trivy failed. See $LOG_DIR/trivy.log" log_error "Trivy scan failed. See $LOG_DIR/trivy.log"
return 1 return 1
} }
} }
# Secrets Detection # Secrets Detection with Trufflehog
run_trufflehog_scan() { run_trufflehog_scan() {
if ! (command -v trufflehog &>/dev/null && command -v jq &>/dev/null); then if ! (command -v trufflehog &>/dev/null && command -v jq &>/dev/null); then
log_warning "TruffleHog or jq not installed. Skipping secrets scan." log_warning "TruffleHog or jq not installed. Skipping secrets scan."
return 0 return 0
fi }
log_info "Running TruffleHog (verified only)..." log_info "Running TruffleHog secrets scan..."
local tmpf local tmpf
tmpf="$(mktemp)" tmpf="$(mktemp)"
trufflehog filesystem . --json >"$tmpf" 2>"$LOG_DIR/trufflehog.log" || true # Use git ls-files to respect .gitignore
git ls-files | xargs trufflehog filesystem \
--json >"$tmpf" 2>"$LOG_DIR/trufflehog.log" || true
local verified local verified
verified="$(jq 'select(.verified==true)' "$tmpf" | wc -l | tr -d ' ')" verified="$(jq 'select(.verified==true)' "$tmpf" | wc -l | tr -d ' ')"
@ -92,32 +109,48 @@ run_trufflehog_scan() {
rm -f "$tmpf" rm -f "$tmpf"
} }
# Additional security and lint checks # Git Secrets Check
run_additional_checks() { run_git_secrets_scan() {
# Git Secrets if ! command -v git-secrets &>/dev/null; then
if command -v git-secrets &>/dev/null; then log_warning "git-secrets not installed. Skipping git-secrets scan."
log_info "Running git-secrets scan..." return 0
git-secrets --scan >"$LOG_DIR/git-secrets.log" 2>&1 || { }
log_error "git-secrets detected potential secrets. See $LOG_DIR/git-secrets.log"
log_info "Running git-secrets scan..."
git-secrets --scan >"$LOG_DIR/git-secrets.log" 2>&1 || {
log_error "git-secrets detected potential secrets. See $LOG_DIR/git-secrets.log"
return 1
}
}
# Python Security Scan with Bandit
run_python_security_scan() {
if ! command -v bandit &>/dev/null; then
log_warning "Bandit not installed. Skipping Python security scan."
return 0
}
local py_files
mapfile -t py_files < <(git ls-files '*.py')
if [[ ${#py_files[@]} -eq 0 ]]; then
log_warning "No Python files to scan"
return 0
}
log_info "Running Bandit Python security scan..."
# shellcheck disable=SC2046
bandit -r "${py_files[@]}" \
-n 5 -lll \
-f json -o "$LOG_DIR/bandit.json" 2>"$LOG_DIR/bandit.log" || {
log_error "Bandit issues found. See $LOG_DIR/bandit.log"
return 1 return 1
} }
fi }
# Python Security (Bandit) # Dependency Vulnerability Check
if command -v bandit &>/dev/null; then run_dependency_checks() {
log_info "Running Bandit Python security scan..." # npm audit
local py_files
py_files="$(find . -type f -name "*.py")"
if [[ -n "$py_files" ]]; then
# shellcheck disable=SC2086
bandit -r $py_files -n 5 -lll -f json -o "$LOG_DIR/bandit.json" 2>"$LOG_DIR/bandit.log" || {
log_error "Bandit issues found. See $LOG_DIR/bandit.log"
return 1
}
fi
fi
# Dependabot-like checks
if command -v npm &>/dev/null && [[ -f package.json ]]; then if command -v npm &>/dev/null && [[ -f package.json ]]; then
log_info "Running npm audit..." log_info "Running npm audit..."
npm audit --audit-level=high >"$LOG_DIR/npm-audit.log" 2>&1 || { npm audit --audit-level=high >"$LOG_DIR/npm-audit.log" 2>&1 || {
@ -126,23 +159,64 @@ run_additional_checks() {
} }
fi fi
# Stylelint # pip-audit for Python dependencies
if command -v stylelint &>/dev/null; then if command -v pip-audit &>/dev/null && [[ -f requirements.txt ]]; then
log_info "Running Stylelint..." log_info "Running pip-audit..."
stylelint "**/*.{css,scss}" --formatter json >"$LOG_DIR/stylelint.json" 2>"$LOG_DIR/stylelint.log" || { pip-audit -r requirements.txt >"$LOG_DIR/pip-audit.log" 2>&1 || {
log_error "Stylelint issues found. See $LOG_DIR/stylelint.log" log_error "pip-audit found issues. See $LOG_DIR/pip-audit.log"
return 1 return 1
} }
fi fi
} }
# Main execution # Stylelint for CSS/SCSS
run_stylelint_check() {
if ! command -v stylelint &>/dev/null; then
log_warning "Stylelint not installed. Skipping stylesheet lint."
return 0
}
local style_files
mapfile -t style_files < <(git ls-files '*.{css,scss,sass}')
if [[ ${#style_files[@]} -eq 0 ]]; then
log_warning "No stylesheet files to lint"
return 0
}
log_info "Running Stylelint..."
# shellcheck disable=SC2046
stylelint "${style_files[@]}" \
--formatter json >"$LOG_DIR/stylelint.json" 2>"$LOG_DIR/stylelint.log" || {
log_error "Stylelint issues found. See $LOG_DIR/stylelint.log"
return 1
}
}
# Main execution function
main() { main() {
prepare_log_directory prepare_log_directory
run_trivy_scan local checks=(
run_trufflehog_scan run_trivy_scan
run_additional_checks run_trufflehog_scan
run_git_secrets_scan
run_python_security_scan
run_dependency_checks
run_stylelint_check
)
local failed=0
for check in "${checks[@]}"; do
if ! "$check"; then
failed=1
fi
done
if [[ $failed -eq 1 ]]; then
log_error "Some pre-push checks failed. Aborting push."
exit 1
fi
log_info "All pre-push checks passed successfully!" log_info "All pre-push checks passed successfully!"
} }