mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2025-08-14 17:31:28 +08:00
150 lines
4.5 KiB
Python
150 lines
4.5 KiB
Python
from __future__ import print_function
|
|
from __future__ import unicode_literals
|
|
|
|
import argparse
|
|
import os
|
|
from typing import Dict
|
|
from typing import List
|
|
from typing import Optional
|
|
from typing import Sequence
|
|
from typing import Set
|
|
|
|
from six.moves import configparser
|
|
|
|
|
|
def get_aws_credential_files_from_env(): # type: () -> Set[str]
|
|
"""Extract credential file paths from environment variables."""
|
|
files = set()
|
|
for env_var in (
|
|
'AWS_CONFIG_FILE', 'AWS_CREDENTIAL_FILE', 'AWS_SHARED_CREDENTIALS_FILE',
|
|
'BOTO_CONFIG',
|
|
):
|
|
if env_var in os.environ:
|
|
files.add(os.environ[env_var])
|
|
return files
|
|
|
|
|
|
def get_aws_secrets_from_env(): # type: () -> Set[str]
|
|
"""Extract AWS secrets from environment variables."""
|
|
keys = set()
|
|
for env_var in (
|
|
'AWS_SECRET_ACCESS_KEY', 'AWS_SECURITY_TOKEN', 'AWS_SESSION_TOKEN',
|
|
):
|
|
if env_var in os.environ:
|
|
keys.add(os.environ[env_var])
|
|
return keys
|
|
|
|
|
|
def get_aws_secrets_from_file(credentials_file): # type: (str) -> Set[str]
|
|
"""Extract AWS secrets from configuration files.
|
|
|
|
Read an ini-style configuration file and return a set with all found AWS
|
|
secret access keys.
|
|
"""
|
|
aws_credentials_file_path = os.path.expanduser(credentials_file)
|
|
if not os.path.exists(aws_credentials_file_path):
|
|
return set()
|
|
|
|
parser = configparser.ConfigParser()
|
|
try:
|
|
parser.read(aws_credentials_file_path)
|
|
except configparser.MissingSectionHeaderError:
|
|
return set()
|
|
|
|
keys = set()
|
|
for section in parser.sections():
|
|
for var in (
|
|
'aws_secret_access_key', 'aws_security_token',
|
|
'aws_session_token',
|
|
):
|
|
try:
|
|
key = parser.get(section, var).strip()
|
|
if key:
|
|
keys.add(key)
|
|
except configparser.NoOptionError:
|
|
pass
|
|
return keys
|
|
|
|
|
|
def check_file_for_aws_keys(filenames, keys):
|
|
# type: (Sequence[str], Set[str]) -> List[Dict[str, str]]
|
|
"""Check if files contain AWS secrets.
|
|
|
|
Return a list of all files containing AWS secrets and keys found, with all
|
|
but the first four characters obfuscated to ease debugging.
|
|
"""
|
|
bad_files = []
|
|
|
|
for filename in filenames:
|
|
with open(filename, 'r') as content:
|
|
text_body = content.read()
|
|
for key in keys:
|
|
# naively match the entire file, low chance of incorrect
|
|
# collision
|
|
if key in text_body:
|
|
bad_files.append({
|
|
'filename': filename, 'key': key[:4] + '*' * 28,
|
|
})
|
|
return bad_files
|
|
|
|
|
|
def main(argv=None): # type: (Optional[Sequence[str]]) -> int
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('filenames', nargs='+', help='Filenames to run')
|
|
parser.add_argument(
|
|
'--credentials-file',
|
|
dest='credentials_file',
|
|
action='append',
|
|
default=[
|
|
'~/.aws/config', '~/.aws/credentials', '/etc/boto.cfg', '~/.boto',
|
|
],
|
|
help=(
|
|
'Location of additional AWS credential file from which to get '
|
|
'secret keys. Can be passed multiple times.'
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
'--allow-missing-credentials',
|
|
dest='allow_missing_credentials',
|
|
action='store_true',
|
|
help='Allow hook to pass when no credentials are detected.',
|
|
)
|
|
args = parser.parse_args(argv)
|
|
|
|
credential_files = set(args.credentials_file)
|
|
|
|
# Add the credentials files configured via environment variables to the set
|
|
# of files to to gather AWS secrets from.
|
|
credential_files |= get_aws_credential_files_from_env()
|
|
|
|
keys = set() # type: Set[str]
|
|
for credential_file in credential_files:
|
|
keys |= get_aws_secrets_from_file(credential_file)
|
|
|
|
# Secrets might be part of environment variables, so add such secrets to
|
|
# the set of keys.
|
|
keys |= get_aws_secrets_from_env()
|
|
|
|
if not keys and args.allow_missing_credentials:
|
|
return 0
|
|
|
|
if not keys:
|
|
print(
|
|
'No AWS keys were found in the configured credential files and '
|
|
'environment variables.\nPlease ensure you have the correct '
|
|
'setting for --credentials-file',
|
|
)
|
|
return 2
|
|
|
|
bad_filenames = check_file_for_aws_keys(args.filenames, keys)
|
|
if bad_filenames:
|
|
for bad_file in bad_filenames:
|
|
print('AWS secret found in {filename}: {key}'.format(**bad_file))
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
exit(main())
|