This is the comprehensive reference for all pre-commit hooks in the screening-terraform-modules-aws repository. For quick setup, see Run Git hooks on commit.
- Quick Setup
- What Are Pre-Commit Hooks?
- Hook Categories
- Quick Fix Reference
- Common Issues & Troubleshooting
- Running Hooks Manually
- When to Skip Hooks (Emergency Only)
- References
# Install hooks (run once after cloning)
pre-commit install --install-hooks
pre-commit install --hook-type commit-msg
# Run all hooks on the entire repository
pre-commit run --all-files
# On next commit, hooks run automatically
git commit -m "feat(module): description"Pre-commit hooks are automated quality checks that run before every commit. They ensure code meets the repository's standards for formatting, security, and testing.
Benefits:
- Catch errors locally before pushing to GitHub
- Enforce consistent code style and security
- Prevent secrets from being committed
- Save CI/CD time by fixing issues early
This repository has 26 hooks covering Terraform, shell scripts, file formatting, security scanning, and commit message validation.
These hooks operate on .tf and .tfvars files to ensure Terraform modules are well-formatted, validated, and documented.
What it does: Enforces consistent Terraform formatting (indentation, spacing, alignment).
When it fails:
✗ Failed
Terraform formatting checks failed
Fix:
# Auto-fix
terraform fmt -recursive infrastructure/modules/
# or
pre-commit run terraform_fmt --all-files
# Then re-stage and commit
git add .
git commit -m "..."Manual run:
pre-commit run terraform_fmt --files infrastructure/modules/vpc/main.tfWhat it does: Checks that Terraform syntax is valid and modules are properly configured.
In this repository's pre-commit configuration, terraform_providers_lock runs before terraform_validate so lock file platform coverage is reconciled first.
Local pre-commit runs allow Terraform to refresh .terraform.lock.hcl when provider constraints change. In CI, terraform_validate runs with terraform init -lockfile=readonly so checks stay deterministic and do not mutate lock files.
When it fails:
Error: Invalid resource type
on infrastructure/modules/s3-bucket/main.tf line 5, in resource "aws_s3_bucket_typo":
5: resource "aws_s3_bucket_typo" "bucket" {
An invalid resource type "aws_s3_bucket_typo" has been used.
Fix:
-
Review the error message
-
Correct the HCL syntax (typos, missing brackets, invalid references, etc.)
-
Verify locally:
terraform -chdir="infrastructure/modules/s3-bucket" validate
Common causes:
- Resource type typos:
aws_s3_bucket_typoinstead ofaws_s3_bucket - Missing required variables
- Invalid provider configuration or missing provider blocks
- Circular dependencies in locals/outputs
What it does: Runs tflint to detect code issues, bad practices, and security concerns using rules defined in scripts/config/.tflint.hcl.
When it fails:
Error: aws_s3_bucket does not have a "tags" argument (aws_resource_missing_tags)
Fix:
-
Review the tflint rule and message
-
Update your code to comply
-
If it's a legitimate exception, add a tflint disable comment:
resource "aws_s3_bucket" "test" { # tflint-ignore=aws_resource_missing_tags bucket = "my-test-bucket" }
Common issues:
- Missing resource tags
- Unused variables or outputs
- Literal values that should be variables
- Non-standard naming conventions
- Potential security issues (e.g., public access not blocked)
What it does: Auto-generates the module README.md from variables, outputs, and code comments.
When it fails:
✗ Failed
Documentation is out of sync
Fix:
# Auto-regenerate documentation
pre-commit run terraform_docs --all-files
# Verify the changes
git diff infrastructure/modules/*/README.md
# Re-stage and commit
git add .
git commit -m "..."Important: Never manually edit the section between these markers:
<!-- BEGIN_TF_DOCS -->
<!-- END_TF_DOCS -->Always regenerate instead using the hook or:
cd infrastructure/modules/s3-bucket/
terraform-docs markdown . > README.mdWhat it does: Ensures .terraform.lock.hcl includes provider versions for all target platforms:
linux_amd64,linux_arm64(CI/CD)darwin_amd64,darwin_arm64(macOS)windows_amd64(Windows)
When it fails:
✗ Failed
Lock file is not cross-platform
Missing platform: darwin_amd64
Fix:
Option 1: Use the upgrade helper (recommended)
./scripts/terraform/upgrade-module.sh infrastructure/modules/s3-bucketOption 2: Manual regeneration
terraform -chdir="infrastructure/modules/s3-bucket" providers lock \
-platform=linux_amd64 \
-platform=linux_arm64 \
-platform=darwin_amd64 \
-platform=darwin_arm64 \
-platform=windows_amd64Why this matters: Ensures all developers (macOS, Linux, Windows) and CI/CD systems get consistent provider versions.
These hooks catch common Git mistakes and enforce best practices.
What it does: Prevents committing files larger than 5 MB (prevents repository bloat).
Fix: Remove the file and add to .gitignore, or use Git LFS for binary files.
What it does: Detects unresolved merge conflict markers (<<<<<<<, =======, >>>>>>>).
Fix: Resolve the merge conflict and remove the markers, then commit.
What it does: Prevents committing directly to main (enforces PR workflow).
When it fails:
You are attempting to commit to the branch: main
Fix: Create a feature branch:
git checkout -b feature/BCSS-12345-descriptionWhat they do: Auto-fix missing newlines at end of files and remove trailing spaces.
Result: Files are auto-fixed; re-stage and commit:
git add .
git commit -m "..."What it does: Validates YAML syntax in .yml and .yaml files.
When it fails:
Parse error at line 5, column 3: inconsistent indentation
Fix: Check indentation; YAML uses 2 or 4 spaces consistently, not tabs.
What it does: Validates Bash/shell scripts for errors and bad practices.
When it fails:
SC2119: Use foo "$@" if function's $1 should be reached.
Fix:
-
Review the warning code
-
Update the script to comply
-
If it's a false positive, add a disable comment:
# shellcheck disable=SC2119 my_function() { echo $1 }
Common issues:
- Unquoted variables:
$var→"$var" - Unused variables
- Unreachable code
- Literal values that should be parameters
Manual run:
shellcheck scripts/terraform/upgrade-module.shReference: shellcheck Wiki
What it does: Validates general file formatting (EditorConfig compliance, etc.).
Fix: Review error message; fixes usually auto-apply. Re-stage if needed.
What it does: Validates Markdown syntax and style (via Markdown linter).
Common issues:
- Incorrect heading levels
- Missing blank lines around code blocks
- Inconsistent list formatting
Fix:
pre-commit run check-markdown-format --all-filesWhat it does: Checks documentation against British English style rules using Vale.
When it fails:
README.md:10:5: [Vale.Terms] Use 'repo-wide' instead of 'repo-wide mode'
README.md:15:12: [Vale.Spelling] Did you mean 'Boolean'?
Common issues:
- American vs. British spelling: "color" → "colour"
- Terminology: true/false wording
- Missing articles or unclear phrasing
Fix:
# Update the text to match the suggestion, or
# Relax/customize rules in .vale.ini if needed
code README.mdManual run:
vale README.mdWhat it does: Detects embedded AWS access keys, secret keys, and session tokens.
When it fails:
AWS credentials detected
Fix:
- Remove the credential immediately
- Use GitHub Secrets for CI/CD.
- Use AWS iam assume role or OIDC federation.
- Use
~/.aws/credentialsfor local development (never commit).
Prevention: Never paste real credentials anywhere.
What it does: Detects private key files (.pem, .key, id_rsa, etc.).
Fix: Remove the file and add to .gitignore.
What it does: Scans entire git history for embedded secrets (API keys, credentials, etc.).
When it fails:
Leaks found: 1
File: .env.example
Secret: aws_secret_access_key = "AKIA..."
Fix:
If it's a real secret (CRITICAL):
# Use git filter-branch to remove from history
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch PATH_TO_FILE' \
--prune-empty --tag-name-filter cat -- --all
# Force push to remove from remote
git push origin +mainIf it's a false positive (e.g., example credentials):
# Add to .gitleaksignore
echo "commit-sha:path/to/file:rule-type:line-number" >> .gitleaksignore
# Re-run to verify
pre-commit run scan-secrets --all-filesManual run:
gitleaks detect --verboseWhat it does: Validates that commit messages follow Conventional Commits format.
Format:
<type>(<scope>): <description>
optional body explaining the change
optional footer (e.g., Closes #123)
Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
Examples:
✅ Good:
feat(s3-bucket): add encryption-at-rest configuration
Introduces optional KMS key support while defaulting to SSE-S3.
Existing modules fall back to service-managed encryption.
Closes #45
✅ Also good:
fix(vpc): correct CIDR block validation logic
❌ Bad:
Updated stuff
fix s3 bucket
add new feature
When it fails:
Commit message does not conform to Conventional Commits.
Expected format: <type>(<scope>): <description>
Fix:
git commit --amend
# Edit the message to follow the formatReference: Conventional Commits
| Problem | Command |
|---|---|
| Terraform formatting | terraform fmt -recursive infrastructure/modules/ |
| Module docs out of sync | pre-commit run terraform_docs --all-files |
| Provider locks missing platforms | ./scripts/terraform/upgrade-module.sh infrastructure/modules/<name> |
| Shell script errors | Fix the issue; re-run pre-commit run shellcheck |
| Trailing whitespace | pre-commit run --all-files (auto-fixed) |
| Commit message format | git commit --amend and reword the message |
| English/spelling | Update the text or adjust .vale.ini |
| Merge conflict markers | Resolve the conflict and remove markers |
# Verify installation
pre-commit install --install-hooks
pre-commit install --hook-type commit-msg
# Check hooks are installed
cat .git/hooks/pre-commit
cat .git/hooks/commit-msgRun in isolation:
pre-commit run <hook-id> --all-filesThen check the .pre-commit-config.yaml for that hook's configuration.
# Delete locks
rm infrastructure/modules/*/.terraform.lock.hcl
# Regenerate
pre-commit run terraform_providers_lock --all-filesEnsure same shellcheck version:
shellcheck --versionCompare with CI logs and update locally if needed.
Check AWS credentials and region:
echo $AWS_DEFAULT_REGION
aws sts get-caller-identityIf AWS_DEFAULT_REGION is missing, add it:
export AWS_DEFAULT_REGION=eu-west-2
pre-commit run terraform_validate --all-filesEdit .vale.ini to relax rules or add custom exceptions for your terminology:
code .vale.inipre-commit run --all-filespre-commit run terraform_fmt --all-files
pre-commit run shellcheck --files scripts/terraform/upgrade-module.shpre-commit run
# Hooks run automatically on next commitgit commit --no-verify -m "..."- A hook has a genuine bug (report it immediately)
- Emergency production fix
- You'll fix the issues immediately in a follow-up commit
NEVER use --no-verify to bypass:
detect-aws-credentials— detects leaked credentialsdetect-private-key— detects leaked private keysscan-secrets— scans git history for secrets
If you use --no-verify, report the issue immediately.
- pre-commit framework
- antonbabenko/pre-commit-terraform
- shellcheck
- terraform-docs
- Vale — English Prose Linter
- Gitleaks — Secret Scanning
- Conventional Commits
For detailed AI agent guidance, see .github/skills/pre-commit-hooks.skill.md.