From b9f41bbda885c6fd900711b867102511835ed8fa Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Fri, 1 Aug 2025 13:24:10 +0300 Subject: [PATCH] Init commit --- README.md | 35 ++++++++ ...ck-secrets-encrypted-with-ansible-vault.py | 88 +++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 README.md create mode 100755 pre-commit/check-secrets-encrypted-with-ansible-vault.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..992196a --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# Git Hooks + +Коллекция моих собственных git hooks, написанных преимущественно на Python. + +## Описание + +Этот репозиторий содержит набор пользовательских git hooks для автоматизации проверок и обеспечения качества кода в процессе разработки. + +## Структура + +### pre-commit/ + +- **check-secrets-encrypted-with-ansible-vault.py** - Проверяет, что файлы с секретами (содержащие 'secret' или 'secrets' в имени) зашифрованы с помощью Ansible Vault перед коммитом + +## Использование + +### Ручная установка + +1. Скопируйте нужный hook в директорию `.git/hooks/` вашего проекта +2. Переименуйте файл, убрав расширение (например, `pre-commit`) +3. Сделайте файл исполняемым: `chmod +x .git/hooks/pre-commit` + +### Использование с lefthook + +Hooks также можно использовать вместе с инструментом [lefthook](https://github.com/evilmartians/lefthook) для более удобного управления git hooks в проекте. + +## Требования + +- Python 3.x +- Git +- Для некоторых hooks могут потребоваться дополнительные зависимости (указаны в комментариях к файлам) + +## Лицензия + +Личная коллекция для собственного использования. diff --git a/pre-commit/check-secrets-encrypted-with-ansible-vault.py b/pre-commit/check-secrets-encrypted-with-ansible-vault.py new file mode 100755 index 0000000..6cde0fc --- /dev/null +++ b/pre-commit/check-secrets-encrypted-with-ansible-vault.py @@ -0,0 +1,88 @@ +#!/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' 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() + return 'secret' in basename or 'secrets' in basename + + +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' 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 ") + 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())