Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# pragma: no cover - the standard coverage exclusion pattern
# To be used for code that's impossible to reach and/or not worth the effort.

# cover 100 - custom coverage exclusion pattern
# Used for one-time jump to 100% coverage to enable checking whether test were added for new code.
# Not meant for further use - existing exclusions are considered TODOs.

# Adding code to excluded blocks should be considered carefully and avoided if possible.

[report]
exclude_lines =
pragma: no cover
cover 100
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/runtime
bootstrap.json
.cache
/.coverage*
/.coverage
coverage.xml
/htmlcov
node_modules/
Expand Down
2 changes: 1 addition & 1 deletion api/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def check_superuser(self, *args, **kwargs):
return handler_method(self, *args, **kwargs)
return check_superuser

def require_drone(handler_method):
def require_drone(handler_method): # cover 100
"""
A decorator to ensure the request is made as a drone.

Expand Down
6 changes: 3 additions & 3 deletions api/auth/authproviders.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def factory(auth_type):
else:
raise NotImplementedError('Auth type {} is not supported'.format(auth_type))

def validate_code(self, code, **kwargs):
def validate_code(self, code, **kwargs): # cover 100
raise NotImplementedError

def ensure_user_exists(self, uid):
Expand Down Expand Up @@ -71,7 +71,7 @@ def set_refresh_token_if_exists(self, uid, refresh_token):
if not token:
# user does not have refresh token, alert the client
raise APIRefreshTokenException('invalid_refresh_token')
else:
else: # cover 100
# user does have a previously saved refresh token, move on
return

Expand Down Expand Up @@ -331,7 +331,7 @@ def validate_user_api_key(key):
user = config.db.users.find_one_and_update({'api_key.key': key}, {'$set': {'api_key.last_used': timestamp}}, ['_id'])
if user:
return user['_id']
else:
else: # cover 100
raise APIAuthProviderException('Invalid API key')


Expand Down
24 changes: 12 additions & 12 deletions api/auth/containerauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def f(method, _id=None, payload=None, unset_payload=None, recursive=False, r_pay
if target_parent_container:
has_access = _get_access(handler.uid, target_parent_container) >= INTEGER_PERMISSIONS[required_perm]
else:
has_access = _get_access(handler.uid, container) >= INTEGER_PERMISSIONS[required_perm]
has_access = _get_access(handler.uid, container) >= INTEGER_PERMISSIONS[required_perm] # cover 100
elif method == 'PUT' and target_parent_container is not None:
has_access = (
_get_access(handler.uid, container) >= INTEGER_PERMISSIONS['admin'] and
Expand All @@ -44,14 +44,14 @@ def f(method, _id=None, payload=None, unset_payload=None, recursive=False, r_pay
required_perm = 'rw'
has_access = _get_access(handler.uid, container) >= INTEGER_PERMISSIONS[required_perm]
else:
has_access = False
has_access = False # cover 100

if has_access:
return exec_op(method, _id=_id, payload=payload, unset_payload=unset_payload, recursive=recursive, r_payload=r_payload, replace_metadata=replace_metadata, projection=projection)
else:
error_msg = 'user not authorized to perform a {} operation on the container.'.format(method)
if additional_error_msg:
error_msg += ' '+additional_error_msg
error_msg += ' '+additional_error_msg # cover 100
handler.abort(403, error_msg)
return f
return g
Expand All @@ -67,20 +67,20 @@ def f(method, _id=None, payload = None):
if method == 'GET' and container.get('public', False):
has_access = True
elif method == 'GET':
has_access = _get_access(handler.uid, container) >= INTEGER_PERMISSIONS['ro']
has_access = _get_access(handler.uid, container) >= INTEGER_PERMISSIONS['ro'] # cover 100
elif method == 'DELETE':
has_access = _get_access(handler.uid, container) >= INTEGER_PERMISSIONS['admin']
elif method == 'POST':
has_access = True
has_access = True # cover 100
elif method == 'PUT':
has_access = _get_access(handler.uid, container) >= INTEGER_PERMISSIONS['rw']
else:
has_access = False
has_access = False # cover 100

if has_access:
return exec_op(method, _id=_id, payload=payload)
else:
handler.abort(403, 'user not authorized to perform a {} operation on the container'.format(method))
handler.abort(403, 'user not authorized to perform a {} operation on the container'.format(method)) # cover 100
return f
return g

Expand All @@ -92,16 +92,16 @@ def f(method, _id=None, payload=None):
if method == 'GET' and parent_container.get('public', False):
has_access = True
elif method == 'GET':
has_access = access >= INTEGER_PERMISSIONS['ro']
has_access = access >= INTEGER_PERMISSIONS['ro'] # cover 100
elif method in ['POST', 'PUT', 'DELETE']:
has_access = access >= INTEGER_PERMISSIONS['rw']
else:
has_access = False
has_access = False # cover 100

if has_access:
return exec_op(method, _id=_id, payload=payload)
else:
handler.abort(403, 'user not authorized to perform a {} operation on parent container'.format(method))
handler.abort(403, 'user not authorized to perform a {} operation on parent container'.format(method)) # cover 100
return f
return g

Expand All @@ -115,7 +115,7 @@ def f(method, _id=None, payload = None):
if method == 'GET' and container.get('public', False):
return exec_op(method, _id, payload)
else:
handler.abort(403, 'not authorized to perform a {} operation on this container'.format(method))
handler.abort(403, 'not authorized to perform a {} operation on this container'.format(method)) # cover 100
return f
return g

Expand All @@ -126,7 +126,7 @@ def f(method, query=None, user=None, public=False, projection=None):
handler.abort(403, 'User ' + handler.uid + ' may not see the Projects of User ' + user['_id'])
query['permissions'] = {'$elemMatch': {'_id': handler.uid}}
if handler.is_true('public'):
query['$or'] = [{'public': True}, {'permissions': query.pop('permissions')}]
query['$or'] = [{'public': True}, {'permissions': query.pop('permissions')}] # cover 100
return exec_op(method, query=query, user=user, public=public, projection=projection)
return f
return g
Expand Down
14 changes: 7 additions & 7 deletions api/auth/groupauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ def f(method, _id=None, query=None, payload=None, projection=None):
if handler.superuser_request:
pass
elif handler.public_request:
handler.abort(400, 'public request is not valid')
handler.abort(400, 'public request is not valid') # cover 100
elif handler.user_is_admin:
pass
elif method in ['DELETE', 'POST']:
elif method in ['DELETE', 'POST']: # cover 100
handler.abort(403, 'not allowed to perform operation')
elif _get_access(handler.uid, group) >= INTEGER_PERMISSIONS['admin']:
elif _get_access(handler.uid, group) >= INTEGER_PERMISSIONS['admin']: # cover 100
pass
elif method == 'GET' and _get_access(handler.uid, group) >= INTEGER_PERMISSIONS['ro']:
elif method == 'GET' and _get_access(handler.uid, group) >= INTEGER_PERMISSIONS['ro']: # cover 100
pass
else:
else: # cover 100
handler.abort(403, 'not allowed to perform operation')
return exec_op(method, _id=_id, query=query, payload=payload, projection=projection)
return f
Expand All @@ -30,7 +30,7 @@ def g(exec_op):
def f(method, query=None, projection=None):
if uid is not None:
if uid != handler.uid and not handler.superuser_request and not handler.user_is_admin:
handler.abort(403, 'User ' + handler.uid + ' may not see the Groups of User ' + uid)
handler.abort(403, 'User ' + handler.uid + ' may not see the Groups of User ' + uid) # cover 100
query = query or {}
query['permissions._id'] = uid
projection = projection or {}
Expand All @@ -40,7 +40,7 @@ def f(method, query=None, projection=None):
query = query or {}
projection = projection or {}
if handler.is_true('admin'):
query['permissions'] = {'$elemMatch': {'_id': handler.uid, 'access': 'admin'}}
query['permissions'] = {'$elemMatch': {'_id': handler.uid, 'access': 'admin'}} # cover 100
else:
query['permissions._id'] = handler.uid
log.debug(query)
Expand Down
24 changes: 12 additions & 12 deletions api/auth/listauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ def f(method, _id, query_params=None, payload=None, exclude_params=None):
elif method in ['POST', 'PUT', 'DELETE']:
min_access = INTEGER_PERMISSIONS['rw']
else:
min_access = sys.maxint
min_access = sys.maxint # cover 100

if access >= min_access:
return exec_op(method, _id, query_params, payload, exclude_params)
else:
handler.abort(403, 'user not authorized to perform a {} operation on the list'.format(method))
handler.abort(403, 'user not authorized to perform a {} operation on the list'.format(method)) # cover 100
return f
return g

Expand All @@ -44,7 +44,7 @@ def group_permissions_sublist(handler, container):
def g(exec_op):
def f(method, _id, query_params = None, payload = None, exclude_params=None):
if method in ['GET', 'DELETE'] and query_params.get('_id') == handler.uid:
return exec_op(method, _id, query_params, payload, exclude_params)
return exec_op(method, _id, query_params, payload, exclude_params) # cover 100
elif access >= INTEGER_PERMISSIONS['admin']:
return exec_op(method, _id, query_params, payload, exclude_params)
else:
Expand All @@ -60,11 +60,11 @@ def group_tags_sublist(handler, container):
def g(exec_op):
def f(method, _id, query_params = None, payload = None, exclude_params=None):
if method == 'GET' and access >= INTEGER_PERMISSIONS['ro']:
return exec_op(method, _id, query_params, payload, exclude_params)
return exec_op(method, _id, query_params, payload, exclude_params) # cover 100
elif access >= INTEGER_PERMISSIONS['rw']:
return exec_op(method, _id, query_params, payload, exclude_params)
else:
handler.abort(403, 'user not authorized to perform a {} operation on the list'.format(method))
handler.abort(403, 'user not authorized to perform a {} operation on the list'.format(method)) # cover 100
return f
return g

Expand All @@ -77,11 +77,11 @@ def g(exec_op):
def f(method, _id, query_params = None, payload = None, exclude_params=None):
log.debug(query_params)
if method in ['GET', 'DELETE'] and query_params.get('_id') == handler.uid:
return exec_op(method, _id, query_params, payload, exclude_params)
return exec_op(method, _id, query_params, payload, exclude_params) # cover 100
elif access >= INTEGER_PERMISSIONS['admin']:
return exec_op(method, _id, query_params, payload, exclude_params)
else:
handler.abort(403, 'user not authorized to perform a {} operation on the list'.format(method))
handler.abort(403, 'user not authorized to perform a {} operation on the list'.format(method)) # cover 100
return f
return g

Expand All @@ -94,19 +94,19 @@ def g(exec_op):
def f(method, _id, query_params = None, payload = None, exclude_params=None):
if access >= INTEGER_PERMISSIONS['admin']:
pass
elif method == 'POST' and access >= INTEGER_PERMISSIONS['rw'] and payload['user'] == handler.uid:
elif method == 'POST' and access >= INTEGER_PERMISSIONS['rw'] and payload['user'] == handler.uid: # cover 100
pass
elif method == 'GET' and (access >= INTEGER_PERMISSIONS['ro'] or container.get('public')):
elif method == 'GET' and (access >= INTEGER_PERMISSIONS['ro'] or container.get('public')): # cover 100
pass
elif method in ['GET', 'DELETE', 'PUT'] and container['notes'][0]['user'] == handler.uid:
elif method in ['GET', 'DELETE', 'PUT'] and container['notes'][0]['user'] == handler.uid: # cover 100
pass
else:
else: # cover 100
handler.abort(403, 'user not authorized to perform a {} operation on the list'.format(method))
return exec_op(method, _id, query_params, payload, exclude_params)
return f
return g

def public_request(handler, container):
def public_request(handler, container): # cover 100
"""
For public requests we allow only GET operations on containers marked as public.
"""
Expand Down
14 changes: 7 additions & 7 deletions api/auth/userauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@ def default(handler, user=None):
def g(exec_op):
def f(method, _id=None, query=None, payload=None, projection=None):
if handler.public_request:
handler.abort(403, 'public request is not authorized')
handler.abort(403, 'public request is not authorized') # cover 100
elif handler.superuser_request and not (method == 'DELETE' and _id == handler.uid):
pass
elif handler.user_is_admin and (method == 'DELETE' and not _id == handler.uid):
pass
elif method == 'PUT' and handler.uid == _id:
if 'root' in payload and payload['root'] != user['root']:
if 'root' in payload and payload['root'] != user['root']: # cover 100
handler.abort(400, 'user cannot alter own admin privilege')
elif 'disabled' in payload and payload['disabled'] != user.get('disabled'):
elif 'disabled' in payload and payload['disabled'] != user.get('disabled'): # cover 100
handler.abort(400, 'user cannot alter own disabled status')
else:
else: # cover 100
pass
elif method == 'PUT' and handler.user_is_admin:
pass
elif method == 'POST' and not handler.superuser_request and not handler.user_is_admin:
handler.abort(403, 'only admins are allowed to create users')
handler.abort(403, 'only admins are allowed to create users') # cover 100
elif method == 'POST' and (handler.superuser_request or handler.user_is_admin):
pass
elif method == 'GET':
pass
else:
handler.abort(403, 'not allowed to perform operation')
handler.abort(403, 'not allowed to perform operation') # cover 100
return exec_op(method, _id=_id, query=query, payload=payload, projection=projection)
return f
return g
Expand All @@ -32,7 +32,7 @@ def list_permission_checker(handler):
def g(exec_op):
def f(method, query=None, projection=None):
if handler.public_request:
handler.abort(403, 'public request is not authorized')
handler.abort(403, 'public request is not authorized') # cover 100
return exec_op(method, query=query, projection=projection)
return f
return g
8 changes: 4 additions & 4 deletions api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def apply_env_variables(config):
elif value.lower() == 'none':
value = None
config[outer_key][inner_key] = value
except Exception: # pylint: disable=broad-except
except Exception: # cover 100 # pylint: disable=broad-except
# ignore uniterable keys like `created` and `modified`
pass
return config
Expand Down Expand Up @@ -257,7 +257,7 @@ def get_config():
log.info('Persisting configuration')

db_config = db.singletons.find_one({'_id': 'config'})
if db_config is not None:
if db_config is not None: # cover 100
startup_config = copy.deepcopy(__config)
startup_config = util.deep_update(startup_config, db_config)
# Precedence order for config is env vars -> db values -> default
Expand All @@ -269,7 +269,7 @@ def get_config():
db.singletons.replace_one({'_id': 'config'}, __config, upsert=True)
__config_persisted = True
__last_update = now
elif now - __last_update > datetime.timedelta(seconds=120):
elif now - __last_update > datetime.timedelta(seconds=120): # cover 100
log.debug('Refreshing configuration from database')
__config = db.singletons.find_one({'_id': 'config'})
__last_update = now
Expand Down Expand Up @@ -303,7 +303,7 @@ def mongo_pipeline(table, pipeline):
output = db.command('aggregate', table, pipeline=pipeline)
result = output.get('result')

if output.get('ok') != 1.0 or result is None:
if output.get('ok') != 1.0 or result is None: # cover 100
raise Exception()

return result
Expand Down
2 changes: 1 addition & 1 deletion api/dao/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class APIPermissionException(Exception):
pass

class APIValidationException(Exception):
def __init__(self, errors):
def __init__(self, errors): # cover 100

super(APIValidationException, self).__init__('Validation Error.')
self.errors = errors
Expand Down
Loading