Ignore files in gitignore for scanning.
This commit is contained in:
parent
3fb24e8037
commit
e1db9bde49
1 changed files with 132 additions and 58 deletions
190
.checks/pre-push
190
.checks/pre-push
|
|
@ -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!"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue