Files
git-hooks/pre-commit/check-secrets-encrypted-with-ansible-vault.py

90 lines
2.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Pre-commit hook to prevent committing secret files that are not encrypted with Ansible Vault.
This hook checks if any staged files contain 'secret' or 'secrets' word in their filename.
If such files are found and they don't start with '$ANSIBLE_VAULT', the commit is blocked.
"""
import sys
import subprocess
import os
ANSIBLE_VAULT_MARKER = "$ANSIBLE_VAULT"
def get_staged_files():
"""Get list of staged files for commit, excluding deleted files."""
try:
result = subprocess.run(
["git", "diff", "--cached", "--name-only", "--diff-filter=AM"],
capture_output=True,
text=True,
check=True,
)
return result.stdout.strip().split("\n") if result.stdout.strip() else []
except subprocess.CalledProcessError as e:
print(f"Error getting staged files: {e}")
return []
def has_secret_in_name(filename):
"""Check if filename contains 'secret' or 'secrets'."""
basename = os.path.basename(filename).lower()
words = basename.split(".")
return "secret" in words or "secrets" in words
def is_ansible_vault_file(filepath):
"""Check if file starts with special vault marker."""
try:
if not os.path.exists(filepath):
return False
with open(filepath, "r", encoding="utf-8") as f:
first_line = f.readline().strip()
return first_line.startswith(ANSIBLE_VAULT_MARKER)
except (IOError, UnicodeDecodeError):
# If we can't read the file or it's binary, assume it's not a vault file
return False
def main():
"""Main function to check staged files."""
staged_files = get_staged_files()
if not staged_files:
return 0
violations = []
for filepath in staged_files:
if has_secret_in_name(filepath):
if not is_ansible_vault_file(filepath):
violations.append(filepath)
if violations:
print("❌ COMMIT BLOCKED: Secret files must be encrypted with Ansible Vault!")
print("\nThe following files contain 'secret' or 'secrets' word in their name")
print("but are not encrypted with Ansible Vault:")
print()
for violation in violations:
print(f"{violation}")
print()
print("To fix this issue:")
print("1. Encrypt the file(s) with: ansible-vault encrypt <filename>")
print("2. Or rename the file(s) to not contain 'secret' or 'secrets'")
print("3. Or add the file(s) to .gitignore if they shouldn't be committed")
print()
return 1
return 0
if __name__ == "__main__":
sys.exit(main())