diff --git a/.envrc b/.envrc index 3bf474406a..b505d083a3 100644 --- a/.envrc +++ b/.envrc @@ -19,15 +19,23 @@ fi echo -e "${BLUE}🔧 Verifying Ofelia development environment...${NC}" # Check Go version requirement +REQUIRED_VERSION="1.26" + if ! command -v go &> /dev/null; then - echo -e "${RED}❌ Go not found. Please install Go 1.25+${NC}" + echo -e "${RED}❌ Go not found. Please install Go ${REQUIRED_VERSION}+${NC}" exit 1 fi GO_VERSION=$(go version | grep -o 'go[0-9]\+\.[0-9]\+' | sed 's/go//') -REQUIRED_VERSION="1.25" -if echo "$GO_VERSION $REQUIRED_VERSION" | awk '{exit ($1 < $2)}'; then +# Compare major.minor as integers, not floats — naive numeric comparison +# would incorrectly treat 1.9 as greater than 1.26. +go_major=${GO_VERSION%%.*} +go_minor=${GO_VERSION#*.} +req_major=${REQUIRED_VERSION%%.*} +req_minor=${REQUIRED_VERSION#*.} + +if (( go_major > req_major )) || { (( go_major == req_major )) && (( go_minor >= req_minor )); }; then echo -e "${GREEN}✅ Go $GO_VERSION detected${NC}" else echo -e "${YELLOW}⚠️ Go $GO_VERSION found, but Go $REQUIRED_VERSION+ is recommended for this project${NC}" @@ -49,54 +57,47 @@ check_tool() { echo -e "${BLUE}🛠️ Checking required tools...${NC}" check_tool "golangci-lint" "go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest" -check_tool "gosec" "sudo snap install gosec (or download from https://github.com/securecodewarrior/gosec/releases)" +check_tool "gosec" "go install github.com/securego/gosec/v2/cmd/gosec@latest" check_tool "docker" "https://docs.docker.com/get-docker/" # CRITICAL: Git hooks verification and enforcement echo "" echo -e "${BLUE}🪝 Verifying Git hooks setup...${NC}" -HOOK_FILE=".git/hooks/pre-commit" -HUSKY_HOOK=".husky/pre-commit" -HOOKS_CONFIGURED=false - -if [[ -f "$HOOK_FILE" ]] && grep -q "lefthook" "$HOOK_FILE" 2>/dev/null; then - echo -e "${GREEN}✅ Native Git hooks properly configured (lefthook)${NC}" - HOOKS_CONFIGURED=true -elif [[ -f "$HUSKY_HOOK" ]] && [[ -f "package.json" ]]; then - echo -e "${GREEN}✅ Husky hooks properly configured${NC}" - HOOKS_CONFIGURED=true +# Resolve via git rev-parse so this works in worktrees (.git is a file, not a dir). +# Tolerate failure (no git installed, direnv loaded outside a repo) so set -e +# doesn't abort the entire .envrc — just skip the hooks check. +HOOKS_DIR="" +if command -v git >/dev/null 2>&1; then + HOOKS_DIR="$(git rev-parse --git-path hooks 2>/dev/null || true)" fi +HOOK_FILE="${HOOKS_DIR:+$HOOKS_DIR/pre-commit}" -if [[ "$HOOKS_CONFIGURED" == "false" ]]; then +if [[ -n "$HOOK_FILE" ]] && [[ -f "$HOOK_FILE" ]] && grep -q "lefthook" "$HOOK_FILE" 2>/dev/null; then + echo -e "${GREEN}✅ Git hooks configured (lefthook)${NC}" +elif [[ -z "$HOOK_FILE" ]]; then + echo -e "${YELLOW}⚠️ Skipping hooks check (not in a git repository)${NC}" +else echo -e "${RED}❌ CRITICAL: Git hooks not configured!${NC}" echo -e "${YELLOW} Without pre-commit hooks, your commits WILL FAIL the CI pipeline${NC}" echo "" - echo -e "${YELLOW}🔧 Choose hook installation method:${NC}" - echo -e " ${BLUE}Native (recommended):${NC} ./scripts/install-hooks.sh" - echo -e " ${BLUE}Husky (Node.js teams):${NC} ./scripts/install-husky.sh" - echo "" - - # Auto-install option + if [[ -t 0 ]]; then # Only if running interactively - read -p "🤔 Auto-install native Git hooks now? [Y/n] " -n 1 -r + read -p "🤔 Auto-install lefthook hooks now? [Y/n] " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then - echo -e "${BLUE}🔧 Installing native Git hooks...${NC}" + echo -e "${BLUE}🔧 Installing lefthook hooks...${NC}" if ./scripts/install-hooks.sh >/dev/null 2>&1; then echo -e "${GREEN}✅ Hooks installed successfully!${NC}" else - echo -e "${RED}❌ Hook installation failed - please run manually${NC}" + echo -e "${RED}❌ Hook installation failed — run: make setup${NC}" fi fi + else + echo -e "${YELLOW} Run: make setup${NC}" fi fi -# Set Go-specific environment variables -export CGO_ENABLED=0 -export GOOS=linux -export GOARCH=amd64 - # Add project tools to PATH if command -v go >/dev/null 2>&1; then export PATH="$(go env GOPATH)/bin:$PATH" @@ -130,7 +131,7 @@ echo "" echo -e "${YELLOW}🚀 Quick Commands:${NC}" echo " make help # Show all available commands" echo " make build # Build binary" -echo " make test # Run tests (current: 60.1% coverage)" +echo " make test # Run tests (see: make test-coverage)" echo " make lint-full # Complete linting suite (45+ rules)" echo " make dev-check # Run all development checks" echo " make dev-setup # Set up development environment" diff --git a/Makefile b/Makefile index d83c8079cb..f823f2d519 100644 --- a/Makefile +++ b/Makefile @@ -96,9 +96,8 @@ security-check: echo "✅ Security check passed"; \ else \ echo "❌ gosec not found. Install with:"; \ - echo " - Snap: sudo snap install gosec"; \ - echo " - Binary: https://github.com/securecodewarrior/gosec/releases"; \ - echo " - Or run: make dev-setup"; \ + echo " go install github.com/securego/gosec/v2/cmd/gosec@latest"; \ + echo " Or run: make dev-setup"; \ exit 1; \ fi @@ -214,14 +213,9 @@ dev-setup: @if command -v gosec >/dev/null 2>&1; then \ echo "✅ gosec already available"; \ else \ - echo "📥 Installing gosec via snap..."; \ - if command -v snap >/dev/null 2>&1; then \ - sudo snap install gosec; \ - else \ - echo "⚠️ gosec not found and snap unavailable. Install manually:"; \ - echo " - Snap: sudo snap install gosec"; \ - echo " - Binary: https://github.com/securecodewarrior/gosec/releases"; \ - fi; \ + echo "📥 Installing gosec..."; \ + go install github.com/securego/gosec/v2/cmd/gosec@latest; \ + echo "✅ gosec installed"; \ fi @go install github.com/daixiang0/gci@latest @echo "✅ gci installed" @@ -297,7 +291,7 @@ help: @echo " ci - Run CI checks locally" @echo " tidy - Tidy Go modules" @echo "" - @echo "📊 Current Test Coverage: 60.1%" + @echo "📊 Test Coverage: run 'make test-coverage' for current numbers" @echo "🎯 Quality: 45+ linting rules, security scanning, pre-commit hooks" build: diff --git a/lefthook.yml b/lefthook.yml index 017aa11037..1729258725 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -170,8 +170,12 @@ post-checkout: echo "" fi - # Check if hooks are installed (in case this is first checkout) - if [ ! -f .git/hooks/pre-commit ] || ! grep -q "lefthook" .git/hooks/pre-commit 2>/dev/null; then + # Check if hooks are installed (in case this is first checkout). + # Use git rev-parse so this works in worktrees, where .git is a file + # pointing at the worktree's gitdir rather than a directory. + hooks_dir=$(git rev-parse --git-path hooks 2>/dev/null || true) + hook_file="${hooks_dir:+$hooks_dir/pre-commit}" + if [ -z "$hook_file" ] || [ ! -f "$hook_file" ] || ! grep -q "lefthook" "$hook_file" 2>/dev/null; then echo "" echo "⚠️ Git hooks not installed! Run:" echo " make setup"