validate_pushed_files_name_and_size.py
120 lines
| 4.4 KiB
| text/x-python
|
PythonLexer
r3475 | # Example to validate pushed files names and size using some sort of rules | |||
@has_kwargs({ | ||||
'server_url': 'url of instance that triggered this hook', | ||||
'config': 'path to .ini config used', | ||||
'scm': 'type of version control "git", "hg", "svn"', | ||||
'username': 'username of actor who triggered this event', | ||||
'ip': 'ip address of actor who triggered this hook', | ||||
'action': '', | ||||
'repository': 'repository name', | ||||
'repo_store_path': 'full path to where repositories are stored', | ||||
'commit_ids': 'pre transaction metadata for commit ids', | ||||
'hook_type': '', | ||||
'user_agent': 'Client user agent, e.g git or mercurial CLI version', | ||||
}) | ||||
def _pre_push_hook(*args, **kwargs): | ||||
""" | ||||
Post push hook | ||||
To stop version control from storing the transaction and send a message to user | ||||
use non-zero HookResponse with a message, e.g return HookResponse(1, 'Not allowed') | ||||
This message will be shown back to client during PUSH operation | ||||
Commit ids might look like that:: | ||||
[{u'hg_env|git_env': ..., | ||||
u'multiple_heads': [], | ||||
u'name': u'default', | ||||
r3746 | u'new_rev': u'd0b2ae0692e722e01d5677f27a104631cf798b69', | |||
u'old_rev': u'd0b1ae0692e722e01d5677f27a104631cf798b69', | ||||
r3475 | u'ref': u'', | |||
u'total_commits': 2, | ||||
u'type': u'branch'}] | ||||
""" | ||||
import fnmatch | ||||
from .helpers import extra_fields, extract_pre_files | ||||
from .utils import str2bool, aslist | ||||
from rhodecode.lib.helpers import format_byte_size_binary | ||||
# returns list of dicts with key-val fetched from extra fields | ||||
repo_extra_fields = extra_fields.run(**kwargs) | ||||
# optionally use 'extra fields' to control the logic per repo | ||||
# e.g store a list of patterns to be forbidden e.g `*.exe, *.dump` | ||||
r4305 | forbid_files = extra_fields.get_field(repo_extra_fields, key='forbid_files_glob', | |||
convert_type=False, default=[]) | ||||
r3475 | forbid_files = aslist(forbid_files) | |||
r3746 | # forbid_files = ['*'] # example pattern | |||
r3475 | # optionally get bytes limit for a single file, e.g 1024 for 1KB | |||
r4305 | forbid_size_over = extra_fields.get_field(repo_extra_fields, key='forbid_size_over', | |||
convert_type=False, default=0) | ||||
r3475 | forbid_size_over = int(forbid_size_over or 0) | |||
r3746 | # forbid_size_over = 1024 # example 1024 | |||
r3475 | def validate_file_name_and_size(file_data, forbidden_files=None, size_limit=None): | |||
""" | ||||
r3746 | This function validates comited files against some sort of rules. | |||
r3475 | It should return a valid boolean, and a reason for failure | |||
file_data =[ | ||||
'raw_diff', 'old_revision', 'stats', 'original_filename', 'is_limited_diff', | ||||
'chunks', 'new_revision', 'operation', 'exceeds_limit', 'filename' | ||||
] | ||||
file_data['ops'] = { | ||||
# is file binary | ||||
'binary': False, | ||||
# lines | ||||
'added': 32, | ||||
'deleted': 0 | ||||
'ops': {3: 'modified file'}, | ||||
'new_mode': '100644', | ||||
'old_mode': None | ||||
} | ||||
""" | ||||
file_name = file_data['filename'] | ||||
operation = file_data['operation'] # can be A(dded), M(odified), D(eleted) | ||||
# check files names | ||||
if forbidden_files: | ||||
reason = 'File {} is forbidden to be pushed'.format(file_name) | ||||
for forbidden_pattern in forbid_files: | ||||
# here we can also filter for operation, e.g if check for only ADDED files | ||||
# if operation == 'A': | ||||
if fnmatch.fnmatch(file_name, forbidden_pattern): | ||||
return False, reason | ||||
# validate A(dded) files and size | ||||
if size_limit and operation == 'A': | ||||
r3746 | if 'file_size' in file_data: | |||
size = file_data['file_size'] | ||||
else: | ||||
size = len(file_data['raw_diff']) | ||||
r3475 | ||||
reason = 'File {} size of {} bytes exceeds limit {}'.format( | ||||
file_name, format_byte_size_binary(size), | ||||
format_byte_size_binary(size_limit)) | ||||
if size > size_limit: | ||||
return False, reason | ||||
return True, '' | ||||
if forbid_files or forbid_size_over: | ||||
# returns list of dicts with key-val fetched from extra fields | ||||
file_list = extract_pre_files.run(**kwargs) | ||||
for file_data in file_list: | ||||
file_valid, reason = validate_file_name_and_size( | ||||
file_data, forbid_files, forbid_size_over) | ||||
if not file_valid: | ||||
return HookResponse(1, reason) | ||||
return HookResponse(0, '') | ||||