From 9b3e282d20149be01cc4819c0781a49e38e3af09 Mon Sep 17 00:00:00 2001 From: Charles N Wyble Date: Fri, 20 Feb 2026 12:11:28 -0500 Subject: [PATCH] feat: add shared git hooks with setup script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Git hooks were only in .git/hooks/ which isn't tracked by git. Created a shared githooks/ directory so all contributors get the pre-commit hook that enforces SDLC requirements. Changes: - githooks/pre-commit: Pre-commit hook enforcing SDLC (lint, tests, docs) - scripts/setup-githooks.sh: Script to configure git core.hooksPath - README.md: Added first-time setup instructions - AGENTS.md: Updated startup steps and project structure Users/agents run ./scripts/setup-githooks.sh after cloning to enable hooks. Reference: docs/SDLC.md 💘 Generated with Crush Assisted-by: GLM-5 via Crush --- AGENTS.md | 5 + README.md | 6 ++ githooks/pre-commit | 186 ++++++++++++++++++++++++++++++++++++++ scripts/setup-githooks.sh | 43 +++++++++ 4 files changed, 240 insertions(+) create mode 100755 githooks/pre-commit create mode 100755 scripts/setup-githooks.sh diff --git a/AGENTS.md b/AGENTS.md index 12c393f..4007c3e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -119,6 +119,8 @@ A pre-commit hook automatically enforces SDLC requirements: └── security-model.md src/ # Source scripts +scripts/ # Utility scripts (setup-githooks.sh) +githooks/ # Shared git hooks (pre-commit) config/ # Configuration files ├── includes.installer/ # Installer configs (preseed.cfg) ├── hooks/live/ # Live system hooks @@ -135,6 +137,9 @@ output/ # Build artifacts ### 1. Start Up ```bash +# Configure git hooks (if not already done) +./scripts/setup-githooks.sh + # Check current state ls -lh output/ git log --oneline -10 diff --git a/README.md b/README.md index 789df57..9a8425e 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,12 @@ tail -f /tmp/knel-iso-build.log ls -lh output/ ``` +### First-Time Setup (After Cloning) +```bash +# Configure git hooks (required for SDLC enforcement) +./scripts/setup-githooks.sh +``` + ### SDLC Workflow (MANDATORY) ```bash # After ANY changes: diff --git a/githooks/pre-commit b/githooks/pre-commit new file mode 100755 index 0000000..c819b12 --- /dev/null +++ b/githooks/pre-commit @@ -0,0 +1,186 @@ +#!/usr/bin/env bash +# +# KNEL-Football Secure OS - Pre-Commit Hook +# Enforces SDLC.md requirements automatically +# +# This hook runs BEFORE every commit and ensures: +# 1. All tests pass +# 2. Zero lint warnings +# 3. Tests exist for modified code +# 4. Documentation is updated for changes +# +# Reference: docs/SDLC.md +# Copyright © 2026 Known Element Enterprises LLC +# License: GNU Affero General Public License v3.0 only + +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}" +echo -e "${YELLOW}║ SDLC ENFORCEMENT - Pre-Commit Check ║${NC}" +echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}" +echo "" + +# Track if any check fails +FAILED=0 + +# Get list of staged files +STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM) +STAGED_SHELL_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(sh|bash)$' || true) + +# Skip checks if only documentation changes +ONLY_DOCS=1 +for file in $STAGED_FILES; do + if [[ ! "$file" =~ ^docs/ && ! "$file" =~ \.md$ && ! "$file" =~ ^LICENSE ]]; then + ONLY_DOCS=0 + break + fi +done + +if [[ "$ONLY_DOCS" == "1" ]]; then + echo -e "${YELLOW}Only documentation changes detected - skipping code checks${NC}" + exit 0 +fi + +# ============================================================================= +# CHECK 1: Lint (ShellCheck) - Zero warnings required +# ============================================================================= +echo -e "${YELLOW}[1/4] Running lint checks (shellcheck)...${NC}" + +if [[ -n "$STAGED_SHELL_FILES" ]]; then + LINT_OUTPUT=$(./run.sh lint 2>&1) || { + echo -e "${RED}✗ LINT FAILED${NC}" + echo "$LINT_OUTPUT" + echo "" + echo -e "${RED}SDLC VIOLATION: Zero lint warnings required${NC}" + echo -e "${RED}Reference: docs/SDLC.md - Code Quality Standards${NC}" + FAILED=1 + } + + if [[ $FAILED -eq 0 ]]; then + echo -e "${GREEN}✓ Lint passed${NC}" + fi +else + echo -e "${GREEN}✓ No shell files to lint${NC}" +fi + +# ============================================================================= +# CHECK 2: Unit Tests - All must pass +# ============================================================================= +echo -e "${YELLOW}[2/4] Running unit tests...${NC}" + +TEST_OUTPUT=$(./run.sh test:unit 2>&1) || { + echo -e "${RED}✗ UNIT TESTS FAILED${NC}" + echo "$TEST_OUTPUT" + echo "" + echo -e "${RED}SDLC VIOLATION: All tests must pass before commit${NC}" + echo -e "${RED}Reference: docs/SDLC.md - TDD Workflow${NC}" + FAILED=1 +} + +if [[ $FAILED -eq 0 ]]; then + echo -e "${GREEN}✓ Unit tests passed${NC}" +fi + +# ============================================================================= +# CHECK 3: Test Coverage - Tests must exist for modified code +# ============================================================================= +echo -e "${YELLOW}[3/4] Checking test coverage for modified files...${NC}" + +MISSING_TESTS="" + +for file in $STAGED_FILES; do + # Check if this is a source file that needs tests + if [[ "$file" =~ ^src/.*\.sh$ ]]; then + basename=$(basename "$file" .sh) + test_file="tests/unit/${basename}_test.bats" + + if [[ ! -f "$test_file" ]]; then + MISSING_TESTS="$MISSING_TESTS\n - $file -> expected: $test_file" + fi + fi + + # Check if this is a config hook that needs tests + if [[ "$file" =~ ^config/hooks/.*\.sh$ ]]; then + hookname=$(basename "$file" .sh) + # Hooks are tested via integration tests + if [[ ! -f "tests/integration/config_test.bats" ]]; then + MISSING_TESTS="$MISSING_TESTS\n - $file -> integration tests missing" + fi + fi +done + +if [[ -n "$MISSING_TESTS" ]]; then + echo -e "${RED}✗ MISSING TEST COVERAGE${NC}" + echo -e "The following files lack corresponding tests:" + echo -e "$MISSING_TESTS" + echo "" + echo -e "${RED}SDLC VIOLATION: TDD requires tests for all code${NC}" + echo -e "${RED}Reference: docs/SDLC.md - Test-Driven Development${NC}" + FAILED=1 +else + echo -e "${GREEN}✓ All modified files have tests${NC}" +fi + +# ============================================================================= +# CHECK 4: Documentation Sync - PRD updated for new features +# ============================================================================= +echo -e "${YELLOW}[4/4] Checking documentation synchronization...${NC}" + +# Check for new function definitions in staged shell files +NEW_FUNCTIONS="" +for file in $STAGED_SHELL_FILES; do + # Extract function names from staged changes + FUNCTIONS=$(git diff --cached "$file" | grep -E '^\+.*\(\)\s*\{' | sed 's/^\+//;s/().*//;s/\s//g' || true) + if [[ -n "$FUNCTIONS" ]]; then + NEW_FUNCTIONS="$NEW_FUNCTIONS\n $file: $(echo "$FUNCTIONS" | tr '\n' ' ')" + fi +done + +# If new functions added, check if PRD, docs, or JOURNAL were updated +if [[ -n "$NEW_FUNCTIONS" ]]; then + DOCS_UPDATED=$(echo "$STAGED_FILES" | grep -E '^(docs/|PRD\.md|JOURNAL\.md)' || true) + + if [[ -z "$DOCS_UPDATED" ]]; then + echo -e "${YELLOW}⚠ New functions detected without documentation updates:${NC}" + echo -e "$NEW_FUNCTIONS" + echo -e "${YELLOW}Note: Consider updating PRD.md, docs/, or JOURNAL.md${NC}" + # This is a warning, not a hard failure + else + echo -e "${GREEN}✓ Documentation appears to be updated${NC}" + fi +else + echo -e "${GREEN}✓ No new functions to document${NC}" +fi + +# ============================================================================= +# Final Result +# ============================================================================= +echo "" +echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}" + +if [[ $FAILED -eq 1 ]]; then + echo -e "${YELLOW}║ COMMIT BLOCKED ║${NC}" + echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}" + echo "" + echo -e "${RED}SDLC requirements not met. Please fix the above issues.${NC}" + echo "" + echo -e "${YELLOW}Quick fix commands:${NC}" + echo " ./run.sh lint # Fix lint warnings" + echo " ./run.sh test:unit # Run unit tests" + echo " ./run.sh test # Run all tests" + echo "" + echo -e "${YELLOW}Reference: docs/SDLC.md${NC}" + exit 1 +else + echo -e "${YELLOW}║ ALL CHECKS PASSED ║${NC}" + echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}" + echo "" + echo -e "${GREEN}✓ SDLC requirements verified${NC}" + echo -e "${GREEN}✓ Commit allowed${NC}" + exit 0 +fi diff --git a/scripts/setup-githooks.sh b/scripts/setup-githooks.sh new file mode 100755 index 0000000..e31a1fc --- /dev/null +++ b/scripts/setup-githooks.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# +# KNEL-Football Secure OS - Git Hooks Setup +# Configures git to use the shared hooks from the githooks/ directory +# +# Run this once after cloning the repository: +# ./scripts/setup-githooks.sh +# +# Copyright (c) 2026 Known Element Enterprises LLC +# License: GNU Affero General Public License v3.0 only + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +HOOKS_DIR="$REPO_ROOT/githooks" + +echo "Setting up git hooks..." +echo "Repository: $REPO_ROOT" +echo "Hooks directory: $HOOKS_DIR" + +# Verify hooks directory exists +if [[ ! -d "$HOOKS_DIR" ]]; then + echo "ERROR: githooks/ directory not found" + exit 1 +fi + +# Make all hooks executable +chmod +x "$HOOKS_DIR"/* + +# Configure git to use the shared hooks directory +git -C "$REPO_ROOT" config core.hooksPath githooks/ + +# Verify configuration +CONFIGURED_PATH=$(git -C "$REPO_ROOT" config --get core.hooksPath) +echo "" +echo "Git hooks configured successfully!" +echo " core.hooksPath = $CONFIGURED_PATH" +echo "" +echo "Available hooks:" +ls -1 "$HOOKS_DIR" +echo "" +echo "Hooks are now active for this repository."