set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
print_status() {
echo -e "${BLUE}[PRE-COMMIT]${NC} $1"
}
print_success() {
echo -e "${GREEN}✅ $1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_error() {
echo -e "${RED}❌ $1${NC}"
}
command_exists() {
command -v "$1" >/dev/null 2>&1
}
install_missing_tools() {
local missing_tools=()
if ! command_exists cargo; then
print_error "Rust/Cargo not installed. Please install Rust first."
exit 1
fi
if ! command_exists cargo-fmt; then
print_status "Installing rustfmt..."
rustup component add rustfmt
fi
if ! command_exists cargo-clippy; then
print_status "Installing clippy..."
rustup component add clippy
fi
if ! command_exists cargo-audit; then
print_status "Installing cargo-audit..."
cargo install cargo-audit
fi
if ! command_exists cargo-deny; then
print_status "Installing cargo-deny..."
cargo install cargo-deny
fi
if [[ -f "Cargo.toml" ]] && grep -q "capstone" Cargo.toml; then
if [[ "$OSTYPE" == "darwin"* ]]; then
if ! brew list libcapstone &>/dev/null; then
print_warning "libcapstone not found. Install with: brew install capstone"
fi
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
if ! dpkg -l | grep -q libcapstone-dev; then
print_warning "libcapstone-dev not found. Install with: sudo apt-get install libcapstone-dev pkg-config"
fi
fi
fi
}
run_precommit_checks() {
print_status "Running pre-commit checks..."
install_missing_tools
print_status "Checking for TODO/FIXME/XXX comments..."
if git diff --cached --name-only | grep "\.rs$" | xargs grep -Hn "TODO\|FIXME\|XXX\|HACK" 2>/dev/null; then
print_error "Found TODO/FIXME/XXX comments in staged files. Please resolve or document them."
exit 1
fi
print_success "No problematic comments found"
print_status "Checking Rust formatting..."
if ! cargo fmt --all -- --check; then
print_error "Code formatting issues found. Run 'cargo fmt' to fix."
exit 1
fi
print_success "Formatting check passed"
print_status "Running Clippy lints..."
if ! cargo clippy --all-targets --all-features -- -D warnings; then
print_error "Clippy lints failed. Fix warnings and try again."
exit 1
fi
print_success "Clippy checks passed"
print_status "Running tests..."
if ! cargo test --all-features; then
print_error "Tests failed. Fix failing tests before committing."
exit 1
fi
print_success "All tests passed"
print_status "Running security audit..."
if ! cargo audit; then
print_warning "Security vulnerabilities found. Review and address if possible."
else
print_success "No security vulnerabilities found"
fi
print_status "Running cargo deny checks..."
TEMP_DENY=""
if [[ ! -f "deny.toml" ]]; then
TEMP_DENY="deny.toml"
cat > deny.toml << 'EOF'
[advisories]
version = 2
db-path = "~/.cargo/advisory-db"
db-urls = ["https://github.com/rustsec/advisory-db"]
unmaintained = "all"
yanked = "deny"
ignore = []
[licenses]
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"Unicode-3.0",
"Unicode-DFS-2016",
"CC0-1.0",
]
[bans]
multiple-versions = "warn"
deny = []
skip = []
[sources]
unknown-registry = "warn"
unknown-git = "warn"
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
allow-git = []
EOF
fi
if ! cargo deny check; then
if [[ -n "$TEMP_DENY" ]]; then
rm -f "$TEMP_DENY"
fi
print_error "Cargo deny checks failed. Review dependency issues."
exit 1
fi
if [[ -n "$TEMP_DENY" ]]; then
rm -f "$TEMP_DENY"
fi
print_success "Cargo deny checks passed"
print_status "Running build check..."
if ! cargo build --all-features; then
print_error "Build failed. Fix compilation errors."
exit 1
fi
print_success "Build completed successfully"
print_status "Checking documentation..."
if ! cargo doc --all-features --no-deps; then
print_warning "Documentation build failed. Consider fixing doc comments."
else
print_success "Documentation builds successfully"
fi
print_status "Checking for large files..."
large_files=$(git diff --cached --name-only | xargs ls -la 2>/dev/null | awk '$5 > 10485760 {print $9}' || true)
if [[ -n "$large_files" ]]; then
print_error "Large files detected (>10MB):"
echo "$large_files"
print_error "Consider using Git LFS for large files."
exit 1
fi
print_success "No large files detected"
print_status "Scanning for potential secrets..."
if git diff --cached | grep -E "(password|secret|token|key|api[_-]?key).*=.*['\"][^'\"]{16,}['\"]" >/dev/null 2>&1; then
print_error "Potential secrets detected in staged changes!"
print_error "Please review and ensure no real secrets are being committed."
exit 1
fi
print_success "No obvious secrets detected"
print_success "All pre-commit checks passed! 🎉"
}
run_precommit_checks