# lefthook.yml # Migrated from pre-commit # # INSTALL: lefthook install # MANUAL PIPELINES: # lefthook run security-full # lefthook run codeql (sequential: go → js → findings → parity) # lefthook run testing # lefthook run lint-full # # TOOL REQUIREMENTS (no longer managed by pre-commit, must be installed): # shellcheck, actionlint, markdownlint, semgrep, gitleaks, hadolint (docker) # All existing scripts are reused as-is — no changes to scripts/ needed. # ============================================================ # PRE-COMMIT (blocking, runs on every commit) # ============================================================ pre-commit: parallel: true commands: # --- File hygiene (replaces pre-commit/pre-commit-hooks) --- end-of-file-fixer: glob: "*.{go,ts,tsx,js,jsx,yaml,yml,sh,md}" exclude: "frontend/(coverage|dist|node_modules|\\.vite)/|.*\\.tsbuildinfo$" run: | modified=0 for file in {all_files}; do [ -f "$file" ] && [ -s "$file" ] && \ [ -n "$(tail -c1 "$file")" ] && echo >> "$file" && modified=1 done if [ "$modified" -eq 1 ]; then git add {all_files} echo "end-of-file-fixer: files modified and re-staged — review changes and commit again." exit 1 fi trailing-whitespace: glob: "*.{go,ts,tsx,js,jsx,yaml,yml,sh,md}" exclude: "frontend/(coverage|dist|node_modules|\\.vite)/|.*\\.tsbuildinfo$" run: | modified=0 for file in {all_files}; do if grep -qP '\s+$' "$file" 2>/dev/null; then sed -i 's/[[:space:]]*$//' "$file" && modified=1 fi done if [ "$modified" -eq 1 ]; then git add {all_files} echo "trailing-whitespace: trailing spaces removed and re-staged — review changes and commit again." exit 1 fi check-yaml: glob: "*.{yaml,yml}" run: python3 -c "import sys,yaml; [yaml.safe_load(open(f)) for f in sys.argv[1:]]" {all_files} # --- Blocking security/commit guards (always run) --- check-lfs-large-files: run: bash scripts/pre-commit-hooks/check-lfs-for-large-files.sh block-codeql-db: run: bash scripts/pre-commit-hooks/block-codeql-db-commits.sh block-data-backups: run: bash scripts/pre-commit-hooks/block-data-backups-commit.sh # --- Shell / Actions / Docker --- shellcheck: glob: "*.sh" exclude: "frontend/(coverage|dist|node_modules|\\.vite)/|test-results|codeql-agent-results" run: shellcheck --severity=error {all_files} actionlint: glob: ".github/workflows/*.{yaml,yml}" run: actionlint {all_files} dockerfile-check: glob: "Dockerfile*" run: tools/dockerfile_check.sh {all_files} # --- Go --- go-vet: glob: "*.go" run: cd backend && go vet ./... golangci-lint-fast: glob: "*.go" run: scripts/pre-commit-hooks/golangci-lint-fast.sh check-version-match: glob: ".version" run: bash scripts/check-version-match-tag.sh # --- Frontend --- # NOTE: ESLint upgraded to v10.x. Overrides in frontend/package.json for # react-hooks, jsx-a11y, promise plugins (peer deps not yet updated). # Remove overrides when plugins declare ESLint v10 support natively. frontend-type-check: glob: "frontend/**/*.{ts,tsx}" run: cd frontend && npx tsc --noEmit frontend-lint: glob: "frontend/**/*.{ts,tsx,js,jsx}" run: cd frontend && npm run lint semgrep: glob: "{**/*.{go,ts,tsx,js,jsx,sh,yml,yaml,json},Dockerfile*}" exclude: 'frontend/(coverage|dist|node_modules|\.vite)/' run: scripts/pre-commit-hooks/semgrep-scan.sh # ============================================================ # MANUAL: security-full # Run with: lefthook run security-full # ============================================================ security-full: parallel: true commands: security-scan: glob: "*.go" run: scripts/security-scan.sh gorm-scan: glob: "*.go" run: scripts/pre-commit-hooks/gorm-security-check.sh gitleaks: run: scripts/pre-commit-hooks/gitleaks-tuned-scan.sh # ============================================================ # MANUAL: codeql # Run with: lefthook run codeql # MUST remain sequential — findings check depends on scan output # ============================================================ codeql: parallel: false commands: 1-go-scan: glob: "*.go" run: scripts/pre-commit-hooks/codeql-go-scan.sh 2-js-scan: glob: "frontend/**/*.{ts,tsx,js,jsx}" run: scripts/pre-commit-hooks/codeql-js-scan.sh 3-check-findings: run: scripts/pre-commit-hooks/codeql-check-findings.sh 4-parity-check: run: scripts/ci/check-codeql-parity.sh # ============================================================ # MANUAL: testing # Run with: lefthook run testing # ============================================================ testing: parallel: true commands: go-test-coverage: glob: "*.go" run: scripts/go-test-coverage.sh go-test-race: glob: "*.go" run: cd backend && go test -race ./... frontend-test-coverage: glob: "frontend/**/*.{ts,tsx,js,jsx}" run: scripts/frontend-test-coverage.sh # ============================================================ # MANUAL: lint-full # Run with: lefthook run lint-full # ============================================================ lint-full: parallel: false commands: golangci-lint-full: glob: "*.go" run: scripts/pre-commit-hooks/golangci-lint-full.sh hadolint: glob: "Dockerfile*" run: docker run --rm -i hadolint/hadolint < Dockerfile markdownlint: run: | markdownlint --fix .; md_exit=$? if ! git diff --quiet; then git add -A echo "markdownlint: auto-fixed files and re-staged — review changes and commit again." exit 1 fi exit $md_exit exclude: "node_modules|\\.venv|test-results|codeql-db|codeql-agent-results"