90 lines
2.6 KiB
Python
Executable File
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."""
|
|
try:
|
|
result = subprocess.run(
|
|
["git", "diff", "--cached", "--name-only"],
|
|
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())
|