initial import for Open Source 🎉
This commit is contained in:
parent
1898c361f3
commit
9c0dd3b722
2048 changed files with 218743 additions and 0 deletions
29
util/config/validators/test/test_validate_access.py
Normal file
29
util/config/validators/test/test_validate_access.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
import pytest
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_access import AccessSettingsValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config, expected_exception', [
|
||||
({}, None),
|
||||
({'FEATURE_DIRECT_LOGIN': False}, ConfigValidationException),
|
||||
({'FEATURE_DIRECT_LOGIN': False, 'SOMETHING_LOGIN_CONFIG': {}}, None),
|
||||
({'FEATURE_DIRECT_LOGIN': False, 'FEATURE_GITHUB_LOGIN': True}, None),
|
||||
({'FEATURE_DIRECT_LOGIN': False, 'FEATURE_GOOGLE_LOGIN': True}, None),
|
||||
({'FEATURE_USER_CREATION': True, 'FEATURE_INVITE_ONLY_USER_CREATION': False}, None),
|
||||
({'FEATURE_USER_CREATION': True, 'FEATURE_INVITE_ONLY_USER_CREATION': True}, None),
|
||||
({'FEATURE_INVITE_ONLY_USER_CREATION': True}, None),
|
||||
({'FEATURE_USER_CREATION': False, 'FEATURE_INVITE_ONLY_USER_CREATION': True},
|
||||
ConfigValidationException),
|
||||
({'FEATURE_USER_CREATION': False, 'FEATURE_INVITE_ONLY_USER_CREATION': False}, None),
|
||||
])
|
||||
def test_validate_invalid_oidc_login_config(unvalidated_config, expected_exception, app):
|
||||
validator = AccessSettingsValidator()
|
||||
|
||||
if expected_exception is not None:
|
||||
with pytest.raises(expected_exception):
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
else:
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
|
@ -0,0 +1,52 @@
|
|||
import pytest
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_actionlog_archiving import ActionLogArchivingValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({}),
|
||||
({'ACTION_LOG_ARCHIVE_PATH': 'foo'}),
|
||||
({'ACTION_LOG_ARCHIVE_LOCATION': ''}),
|
||||
])
|
||||
def test_skip_validate_actionlog(unvalidated_config, app):
|
||||
validator = ActionLogArchivingValidator()
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('config, expected_error', [
|
||||
({'FEATURE_ACTION_LOG_ROTATION': True}, 'Missing action log archive path'),
|
||||
({'FEATURE_ACTION_LOG_ROTATION': True,
|
||||
'ACTION_LOG_ARCHIVE_PATH': ''}, 'Missing action log archive path'),
|
||||
({'FEATURE_ACTION_LOG_ROTATION': True,
|
||||
'ACTION_LOG_ARCHIVE_PATH': 'foo'}, 'Missing action log archive storage location'),
|
||||
({'FEATURE_ACTION_LOG_ROTATION': True,
|
||||
'ACTION_LOG_ARCHIVE_PATH': 'foo',
|
||||
'ACTION_LOG_ARCHIVE_LOCATION': ''}, 'Missing action log archive storage location'),
|
||||
({'FEATURE_ACTION_LOG_ROTATION': True,
|
||||
'ACTION_LOG_ARCHIVE_PATH': 'foo',
|
||||
'ACTION_LOG_ARCHIVE_LOCATION': 'invalid'},
|
||||
'Action log archive storage location `invalid` not found in storage config'),
|
||||
])
|
||||
def test_invalid_config(config, expected_error, app):
|
||||
validator = ActionLogArchivingValidator()
|
||||
|
||||
with pytest.raises(ConfigValidationException) as ipe:
|
||||
validator.validate(ValidatorContext(config))
|
||||
|
||||
assert str(ipe.value) == expected_error
|
||||
|
||||
def test_valid_config(app):
|
||||
config = ValidatorContext({
|
||||
'FEATURE_ACTION_LOG_ROTATION': True,
|
||||
'ACTION_LOG_ARCHIVE_PATH': 'somepath',
|
||||
'ACTION_LOG_ARCHIVE_LOCATION': 'somelocation',
|
||||
'DISTRIBUTED_STORAGE_CONFIG': {
|
||||
'somelocation': {},
|
||||
},
|
||||
})
|
||||
|
||||
validator = ActionLogArchivingValidator()
|
||||
validator.validate(config)
|
30
util/config/validators/test/test_validate_apptokenauth.py
Normal file
30
util/config/validators/test/test_validate_apptokenauth.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
import pytest
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_apptokenauth import AppTokenAuthValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({'AUTHENTICATION_TYPE': 'AppToken'}),
|
||||
({'AUTHENTICATION_TYPE': 'AppToken', 'FEATURE_APP_SPECIFIC_TOKENS': False}),
|
||||
({'AUTHENTICATION_TYPE': 'AppToken', 'FEATURE_APP_SPECIFIC_TOKENS': True,
|
||||
'FEATURE_DIRECT_LOGIN': True}),
|
||||
])
|
||||
def test_validate_invalid_auth_config(unvalidated_config, app):
|
||||
validator = AppTokenAuthValidator()
|
||||
|
||||
with pytest.raises(ConfigValidationException):
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
|
||||
def test_validate_auth(app):
|
||||
config = ValidatorContext({
|
||||
'AUTHENTICATION_TYPE': 'AppToken',
|
||||
'FEATURE_APP_SPECIFIC_TOKENS': True,
|
||||
'FEATURE_DIRECT_LOGIN': False,
|
||||
})
|
||||
|
||||
validator = AppTokenAuthValidator()
|
||||
validator.validate(config)
|
|
@ -0,0 +1,48 @@
|
|||
import pytest
|
||||
|
||||
from httmock import urlmatch, HTTMock
|
||||
|
||||
from util.config import URLSchemeAndHostname
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_bitbucket_trigger import BitbucketTriggerValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
(ValidatorContext({})),
|
||||
(ValidatorContext({'BITBUCKET_TRIGGER_CONFIG': {}})),
|
||||
(ValidatorContext({'BITBUCKET_TRIGGER_CONFIG': {'CONSUMER_KEY': 'foo'}})),
|
||||
(ValidatorContext({'BITBUCKET_TRIGGER_CONFIG': {'CONSUMER_SECRET': 'foo'}})),
|
||||
])
|
||||
def test_validate_invalid_bitbucket_trigger_config(unvalidated_config, app):
|
||||
validator = BitbucketTriggerValidator()
|
||||
|
||||
with pytest.raises(ConfigValidationException):
|
||||
validator.validate(unvalidated_config)
|
||||
|
||||
def test_validate_bitbucket_trigger(app):
|
||||
url_hit = [False]
|
||||
|
||||
@urlmatch(netloc=r'bitbucket.org')
|
||||
def handler(url, request):
|
||||
url_hit[0] = True
|
||||
return {
|
||||
'status_code': 200,
|
||||
'content': 'oauth_token=foo&oauth_token_secret=bar',
|
||||
}
|
||||
|
||||
with HTTMock(handler):
|
||||
validator = BitbucketTriggerValidator()
|
||||
|
||||
url_scheme_and_hostname = URLSchemeAndHostname('http', 'localhost:5000')
|
||||
unvalidated_config = ValidatorContext({
|
||||
'BITBUCKET_TRIGGER_CONFIG': {
|
||||
'CONSUMER_KEY': 'foo',
|
||||
'CONSUMER_SECRET': 'bar',
|
||||
},
|
||||
}, url_scheme_and_hostname=url_scheme_and_hostname)
|
||||
|
||||
validator.validate(unvalidated_config)
|
||||
|
||||
assert url_hit[0]
|
23
util/config/validators/test/test_validate_database.py
Normal file
23
util/config/validators/test/test_validate_database.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
import pytest
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_database import DatabaseValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config,user,user_password,expected', [
|
||||
(ValidatorContext(None), None, None, TypeError),
|
||||
(ValidatorContext({}), None, None, KeyError),
|
||||
(ValidatorContext({'DB_URI': 'sqlite:///:memory:'}), None, None, None),
|
||||
(ValidatorContext({'DB_URI': 'invalid:///:memory:'}), None, None, KeyError),
|
||||
(ValidatorContext({'DB_NOTURI': 'sqlite:///:memory:'}), None, None, KeyError),
|
||||
])
|
||||
def test_validate_database(unvalidated_config, user, user_password, expected, app):
|
||||
validator = DatabaseValidator()
|
||||
|
||||
if expected is not None:
|
||||
with pytest.raises(expected):
|
||||
validator.validate(unvalidated_config)
|
||||
else:
|
||||
validator.validate(unvalidated_config)
|
69
util/config/validators/test/test_validate_github.py
Normal file
69
util/config/validators/test/test_validate_github.py
Normal file
|
@ -0,0 +1,69 @@
|
|||
import pytest
|
||||
|
||||
from httmock import urlmatch, HTTMock
|
||||
|
||||
from config import build_requests_session
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_github import GitHubLoginValidator, GitHubTriggerValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.fixture(params=[GitHubLoginValidator, GitHubTriggerValidator])
|
||||
def github_validator(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.mark.parametrize('github_config', [
|
||||
({}),
|
||||
({'GITHUB_ENDPOINT': 'foo'}),
|
||||
({'GITHUB_ENDPOINT': 'http://github.com'}),
|
||||
({'GITHUB_ENDPOINT': 'http://github.com', 'CLIENT_ID': 'foo'}),
|
||||
({'GITHUB_ENDPOINT': 'http://github.com', 'CLIENT_SECRET': 'foo'}),
|
||||
({
|
||||
'GITHUB_ENDPOINT': 'http://github.com',
|
||||
'CLIENT_ID': 'foo',
|
||||
'CLIENT_SECRET': 'foo',
|
||||
'ORG_RESTRICT': True
|
||||
}),
|
||||
({
|
||||
'GITHUB_ENDPOINT': 'http://github.com',
|
||||
'CLIENT_ID': 'foo',
|
||||
'CLIENT_SECRET': 'foo',
|
||||
'ORG_RESTRICT': True,
|
||||
'ALLOWED_ORGANIZATIONS': [],
|
||||
}),
|
||||
])
|
||||
def test_validate_invalid_github_config(github_config, github_validator, app):
|
||||
with pytest.raises(ConfigValidationException):
|
||||
unvalidated_config = {}
|
||||
unvalidated_config[github_validator.config_key] = github_config
|
||||
github_validator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
def test_validate_github(github_validator, app):
|
||||
url_hit = [False, False]
|
||||
|
||||
@urlmatch(netloc=r'somehost')
|
||||
def handler(url, request):
|
||||
url_hit[0] = True
|
||||
return {'status_code': 200, 'content': '', 'headers': {'X-GitHub-Request-Id': 'foo'}}
|
||||
|
||||
@urlmatch(netloc=r'somehost', path=r'/api/v3/applications/foo/tokens/foo')
|
||||
def app_handler(url, request):
|
||||
url_hit[1] = True
|
||||
return {'status_code': 404, 'content': '', 'headers': {'X-GitHub-Request-Id': 'foo'}}
|
||||
|
||||
with HTTMock(app_handler, handler):
|
||||
unvalidated_config = ValidatorContext({
|
||||
github_validator.config_key: {
|
||||
'GITHUB_ENDPOINT': 'http://somehost',
|
||||
'CLIENT_ID': 'foo',
|
||||
'CLIENT_SECRET': 'bar',
|
||||
},
|
||||
})
|
||||
|
||||
unvalidated_config.http_client = build_requests_session()
|
||||
github_validator.validate(unvalidated_config)
|
||||
|
||||
assert url_hit[0]
|
||||
assert url_hit[1]
|
49
util/config/validators/test/test_validate_gitlab_trigger.py
Normal file
49
util/config/validators/test/test_validate_gitlab_trigger.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
import json
|
||||
import pytest
|
||||
|
||||
from httmock import urlmatch, HTTMock
|
||||
|
||||
from config import build_requests_session
|
||||
from util.config import URLSchemeAndHostname
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_gitlab_trigger import GitLabTriggerValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({}),
|
||||
({'GITLAB_TRIGGER_CONFIG': {'GITLAB_ENDPOINT': 'foo'}}),
|
||||
({'GITLAB_TRIGGER_CONFIG': {'GITLAB_ENDPOINT': 'http://someendpoint', 'CLIENT_ID': 'foo'}}),
|
||||
({'GITLAB_TRIGGER_CONFIG': {'GITLAB_ENDPOINT': 'http://someendpoint', 'CLIENT_SECRET': 'foo'}}),
|
||||
])
|
||||
def test_validate_invalid_gitlab_trigger_config(unvalidated_config, app):
|
||||
validator = GitLabTriggerValidator()
|
||||
|
||||
with pytest.raises(ConfigValidationException):
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
def test_validate_gitlab_enterprise_trigger(app):
|
||||
url_hit = [False]
|
||||
|
||||
@urlmatch(netloc=r'somegitlab', path='/oauth/token')
|
||||
def handler(_, __):
|
||||
url_hit[0] = True
|
||||
return {'status_code': 400, 'content': json.dumps({'error': 'invalid code'})}
|
||||
|
||||
with HTTMock(handler):
|
||||
validator = GitLabTriggerValidator()
|
||||
|
||||
url_scheme_and_hostname = URLSchemeAndHostname('http', 'localhost:5000')
|
||||
|
||||
unvalidated_config = ValidatorContext({
|
||||
'GITLAB_TRIGGER_CONFIG': {
|
||||
'GITLAB_ENDPOINT': 'http://somegitlab',
|
||||
'CLIENT_ID': 'foo',
|
||||
'CLIENT_SECRET': 'bar',
|
||||
},
|
||||
}, http_client=build_requests_session(), url_scheme_and_hostname=url_scheme_and_hostname)
|
||||
|
||||
validator.validate(unvalidated_config)
|
||||
|
||||
assert url_hit[0]
|
45
util/config/validators/test/test_validate_google_login.py
Normal file
45
util/config/validators/test/test_validate_google_login.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
import pytest
|
||||
|
||||
from httmock import urlmatch, HTTMock
|
||||
|
||||
from config import build_requests_session
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_google_login import GoogleLoginValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({}),
|
||||
({'GOOGLE_LOGIN_CONFIG': {}}),
|
||||
({'GOOGLE_LOGIN_CONFIG': {'CLIENT_ID': 'foo'}}),
|
||||
({'GOOGLE_LOGIN_CONFIG': {'CLIENT_SECRET': 'foo'}}),
|
||||
])
|
||||
def test_validate_invalid_google_login_config(unvalidated_config, app):
|
||||
validator = GoogleLoginValidator()
|
||||
|
||||
with pytest.raises(ConfigValidationException):
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
def test_validate_google_login(app):
|
||||
url_hit = [False]
|
||||
@urlmatch(netloc=r'www.googleapis.com', path='/oauth2/v3/token')
|
||||
def handler(_, __):
|
||||
url_hit[0] = True
|
||||
return {'status_code': 200, 'content': ''}
|
||||
|
||||
validator = GoogleLoginValidator()
|
||||
|
||||
with HTTMock(handler):
|
||||
unvalidated_config = ValidatorContext({
|
||||
'GOOGLE_LOGIN_CONFIG': {
|
||||
'CLIENT_ID': 'foo',
|
||||
'CLIENT_SECRET': 'bar',
|
||||
},
|
||||
})
|
||||
|
||||
unvalidated_config.http_client = build_requests_session()
|
||||
|
||||
validator.validate(unvalidated_config)
|
||||
|
||||
assert url_hit[0]
|
65
util/config/validators/test/test_validate_jwt.py
Normal file
65
util/config/validators/test/test_validate_jwt.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
import pytest
|
||||
|
||||
from config import build_requests_session
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_jwt import JWTAuthValidator
|
||||
from util.morecollections import AttrDict
|
||||
|
||||
from test.test_external_jwt_authn import fake_jwt
|
||||
|
||||
from test.fixtures import *
|
||||
from app import config_provider
|
||||
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({}),
|
||||
({'AUTHENTICATION_TYPE': 'Database'}),
|
||||
])
|
||||
def test_validate_noop(unvalidated_config, app):
|
||||
config = ValidatorContext(unvalidated_config)
|
||||
config.config_provider = config_provider
|
||||
JWTAuthValidator.validate(config)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({'AUTHENTICATION_TYPE': 'JWT'}),
|
||||
({'AUTHENTICATION_TYPE': 'JWT', 'JWT_AUTH_ISSUER': 'foo'}),
|
||||
({'AUTHENTICATION_TYPE': 'JWT', 'JWT_VERIFY_ENDPOINT': 'foo'}),
|
||||
])
|
||||
def test_invalid_config(unvalidated_config, app):
|
||||
with pytest.raises(ConfigValidationException):
|
||||
config = ValidatorContext(unvalidated_config)
|
||||
config.config_provider = config_provider
|
||||
JWTAuthValidator.validate(config)
|
||||
|
||||
|
||||
# TODO: fix these when re-adding jwt auth mechanism to jwt validators
|
||||
@pytest.mark.skip(reason='No way of currently testing this')
|
||||
@pytest.mark.parametrize('username, password, expected_exception', [
|
||||
('invaliduser', 'invalidpass', ConfigValidationException),
|
||||
('cool.user', 'invalidpass', ConfigValidationException),
|
||||
('invaliduser', 'somepass', ConfigValidationException),
|
||||
('cool.user', 'password', None),
|
||||
])
|
||||
def test_validated_jwt(username, password, expected_exception, app):
|
||||
with fake_jwt() as jwt_auth:
|
||||
config = {}
|
||||
config['AUTHENTICATION_TYPE'] = 'JWT'
|
||||
config['JWT_AUTH_ISSUER'] = jwt_auth.issuer
|
||||
config['JWT_VERIFY_ENDPOINT'] = jwt_auth.verify_url
|
||||
config['JWT_QUERY_ENDPOINT'] = jwt_auth.query_url
|
||||
config['JWT_GETUSER_ENDPOINT'] = jwt_auth.getuser_url
|
||||
|
||||
unvalidated_config = ValidatorContext(config)
|
||||
unvalidated_config.user = AttrDict(dict(username=username))
|
||||
unvalidated_config.user_password = password
|
||||
unvalidated_config.config_provider = config_provider
|
||||
|
||||
unvalidated_config.http_client = build_requests_session()
|
||||
|
||||
if expected_exception is not None:
|
||||
with pytest.raises(ConfigValidationException):
|
||||
JWTAuthValidator.validate(unvalidated_config, public_key_path=jwt_auth.public_key_path)
|
||||
else:
|
||||
JWTAuthValidator.validate(unvalidated_config, public_key_path=jwt_auth.public_key_path)
|
54
util/config/validators/test/test_validate_keystone.py
Normal file
54
util/config/validators/test/test_validate_keystone.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
import pytest
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_keystone import KeystoneValidator
|
||||
|
||||
from test.test_keystone_auth import fake_keystone
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({}),
|
||||
({'AUTHENTICATION_TYPE': 'Database'}),
|
||||
])
|
||||
def test_validate_noop(unvalidated_config, app):
|
||||
KeystoneValidator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({'AUTHENTICATION_TYPE': 'Keystone'}),
|
||||
({'AUTHENTICATION_TYPE': 'Keystone', 'KEYSTONE_AUTH_URL': 'foo'}),
|
||||
({'AUTHENTICATION_TYPE': 'Keystone', 'KEYSTONE_AUTH_URL': 'foo',
|
||||
'KEYSTONE_ADMIN_USERNAME': 'bar'}),
|
||||
({'AUTHENTICATION_TYPE': 'Keystone', 'KEYSTONE_AUTH_URL': 'foo',
|
||||
'KEYSTONE_ADMIN_USERNAME': 'bar', 'KEYSTONE_ADMIN_PASSWORD': 'baz'}),
|
||||
])
|
||||
def test_invalid_config(unvalidated_config, app):
|
||||
with pytest.raises(ConfigValidationException):
|
||||
KeystoneValidator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('admin_tenant_id, expected_exception', [
|
||||
('somegroupid', None),
|
||||
('groupwithnousers', ConfigValidationException),
|
||||
('somegroupid', None),
|
||||
('groupwithnousers', ConfigValidationException),
|
||||
])
|
||||
def test_validated_keystone(admin_tenant_id, expected_exception, app):
|
||||
with fake_keystone(2) as keystone_auth:
|
||||
auth_url = keystone_auth.auth_url
|
||||
|
||||
config = {}
|
||||
config['AUTHENTICATION_TYPE'] = 'Keystone'
|
||||
config['KEYSTONE_AUTH_URL'] = auth_url
|
||||
config['KEYSTONE_ADMIN_USERNAME'] = 'adminuser'
|
||||
config['KEYSTONE_ADMIN_PASSWORD'] = 'adminpass'
|
||||
config['KEYSTONE_ADMIN_TENANT'] = admin_tenant_id
|
||||
|
||||
unvalidated_config = ValidatorContext(config)
|
||||
|
||||
if expected_exception is not None:
|
||||
with pytest.raises(ConfigValidationException):
|
||||
KeystoneValidator.validate(unvalidated_config)
|
||||
else:
|
||||
KeystoneValidator.validate(unvalidated_config)
|
72
util/config/validators/test/test_validate_ldap.py
Normal file
72
util/config/validators/test/test_validate_ldap.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
import pytest
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_ldap import LDAPValidator
|
||||
from util.morecollections import AttrDict
|
||||
|
||||
from test.test_ldap import mock_ldap
|
||||
|
||||
from test.fixtures import *
|
||||
from app import config_provider
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({}),
|
||||
({'AUTHENTICATION_TYPE': 'Database'}),
|
||||
])
|
||||
def test_validate_noop(unvalidated_config, app):
|
||||
config = ValidatorContext(unvalidated_config, config_provider=config_provider)
|
||||
LDAPValidator.validate(config)
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({'AUTHENTICATION_TYPE': 'LDAP'}),
|
||||
({'AUTHENTICATION_TYPE': 'LDAP', 'LDAP_ADMIN_DN': 'foo'}),
|
||||
])
|
||||
def test_invalid_config(unvalidated_config, app):
|
||||
with pytest.raises(ConfigValidationException):
|
||||
config = ValidatorContext(unvalidated_config, config_provider=config_provider)
|
||||
LDAPValidator.validate(config)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('uri', [
|
||||
'foo',
|
||||
'http://foo',
|
||||
'ldap:foo',
|
||||
])
|
||||
def test_invalid_uri(uri, app):
|
||||
config = {}
|
||||
config['AUTHENTICATION_TYPE'] = 'LDAP'
|
||||
config['LDAP_BASE_DN'] = ['dc=quay', 'dc=io']
|
||||
config['LDAP_ADMIN_DN'] = 'uid=testy,ou=employees,dc=quay,dc=io'
|
||||
config['LDAP_ADMIN_PASSWD'] = 'password'
|
||||
config['LDAP_USER_RDN'] = ['ou=employees']
|
||||
config['LDAP_URI'] = uri
|
||||
|
||||
with pytest.raises(ConfigValidationException):
|
||||
config = ValidatorContext(config, config_provider=config_provider)
|
||||
LDAPValidator.validate(config)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('admin_dn, admin_passwd, user_rdn, expected_exception', [
|
||||
('uid=testy,ou=employees,dc=quay,dc=io', 'password', ['ou=employees'], None),
|
||||
('uid=invalidadmindn', 'password', ['ou=employees'], ConfigValidationException),
|
||||
('uid=testy,ou=employees,dc=quay,dc=io', 'invalid_password', ['ou=employees'], ConfigValidationException),
|
||||
('uid=testy,ou=employees,dc=quay,dc=io', 'password', ['ou=invalidgroup'], ConfigValidationException),
|
||||
])
|
||||
def test_validated_ldap(admin_dn, admin_passwd, user_rdn, expected_exception, app):
|
||||
config = {}
|
||||
config['AUTHENTICATION_TYPE'] = 'LDAP'
|
||||
config['LDAP_BASE_DN'] = ['dc=quay', 'dc=io']
|
||||
config['LDAP_ADMIN_DN'] = admin_dn
|
||||
config['LDAP_ADMIN_PASSWD'] = admin_passwd
|
||||
config['LDAP_USER_RDN'] = user_rdn
|
||||
|
||||
unvalidated_config = ValidatorContext(config, config_provider=config_provider)
|
||||
|
||||
if expected_exception is not None:
|
||||
with pytest.raises(ConfigValidationException):
|
||||
with mock_ldap():
|
||||
LDAPValidator.validate(unvalidated_config)
|
||||
else:
|
||||
with mock_ldap():
|
||||
LDAPValidator.validate(unvalidated_config)
|
50
util/config/validators/test/test_validate_oidc.py
Normal file
50
util/config/validators/test/test_validate_oidc.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
import json
|
||||
import pytest
|
||||
|
||||
from httmock import urlmatch, HTTMock
|
||||
|
||||
from config import build_requests_session
|
||||
from oauth.oidc import OIDC_WELLKNOWN
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_oidc import OIDCLoginValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({'SOMETHING_LOGIN_CONFIG': {}}),
|
||||
({'SOMETHING_LOGIN_CONFIG': {'OIDC_SERVER': 'foo'}}),
|
||||
({'SOMETHING_LOGIN_CONFIG': {'OIDC_SERVER': 'foo', 'CLIENT_ID': 'foobar'}}),
|
||||
({'SOMETHING_LOGIN_CONFIG': {'OIDC_SERVER': 'foo', 'CLIENT_SECRET': 'foobar'}}),
|
||||
])
|
||||
def test_validate_invalid_oidc_login_config(unvalidated_config, app):
|
||||
validator = OIDCLoginValidator()
|
||||
|
||||
with pytest.raises(ConfigValidationException):
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
def test_validate_oidc_login(app):
|
||||
url_hit = [False]
|
||||
@urlmatch(netloc=r'someserver', path=r'/\.well-known/openid-configuration')
|
||||
def handler(_, __):
|
||||
url_hit[0] = True
|
||||
data = {
|
||||
'token_endpoint': 'foobar',
|
||||
}
|
||||
return {'status_code': 200, 'content': json.dumps(data)}
|
||||
|
||||
with HTTMock(handler):
|
||||
validator = OIDCLoginValidator()
|
||||
unvalidated_config = ValidatorContext({
|
||||
'SOMETHING_LOGIN_CONFIG': {
|
||||
'CLIENT_ID': 'foo',
|
||||
'CLIENT_SECRET': 'bar',
|
||||
'OIDC_SERVER': 'http://someserver',
|
||||
'DEBUGGING': True, # Allows for HTTP.
|
||||
},
|
||||
})
|
||||
unvalidated_config.http_client = build_requests_session()
|
||||
|
||||
validator.validate(unvalidated_config)
|
||||
|
||||
assert url_hit[0]
|
34
util/config/validators/test/test_validate_redis.py
Normal file
34
util/config/validators/test/test_validate_redis.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
import pytest
|
||||
import redis
|
||||
|
||||
from mock import patch
|
||||
|
||||
from mockredis import mock_strict_redis_client
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_redis import RedisValidator
|
||||
|
||||
from test.fixtures import *
|
||||
from util.morecollections import AttrDict
|
||||
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config,user,user_password,use_mock,expected', [
|
||||
({}, None, None, False, ConfigValidationException),
|
||||
({'BUILDLOGS_REDIS': {}}, None, None, False, ConfigValidationException),
|
||||
({'BUILDLOGS_REDIS': {'host': 'somehost'}}, None, None, False, redis.ConnectionError),
|
||||
({'BUILDLOGS_REDIS': {'host': 'localhost'}}, None, None, True, None),
|
||||
])
|
||||
def test_validate_redis(unvalidated_config, user, user_password, use_mock, expected, app):
|
||||
with patch('redis.StrictRedis' if use_mock else 'redis.None', mock_strict_redis_client):
|
||||
validator = RedisValidator()
|
||||
unvalidated_config = ValidatorContext(unvalidated_config)
|
||||
|
||||
unvalidated_config.user = AttrDict(dict(username=user))
|
||||
unvalidated_config.user_password = user_password
|
||||
|
||||
if expected is not None:
|
||||
with pytest.raises(expected):
|
||||
validator.validate(unvalidated_config)
|
||||
else:
|
||||
validator.validate(unvalidated_config)
|
48
util/config/validators/test/test_validate_secscan.py
Normal file
48
util/config/validators/test/test_validate_secscan.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
import pytest
|
||||
|
||||
from config import build_requests_session
|
||||
from util.config import URLSchemeAndHostname
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators.validate_secscan import SecurityScannerValidator
|
||||
from util.secscan.fake import fake_security_scanner
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({'DISTRIBUTED_STORAGE_PREFERENCE': []}),
|
||||
])
|
||||
def test_validate_noop(unvalidated_config, app):
|
||||
|
||||
unvalidated_config = ValidatorContext(unvalidated_config, feature_sec_scanner=False, is_testing=True,
|
||||
http_client=build_requests_session(),
|
||||
url_scheme_and_hostname=URLSchemeAndHostname('http', 'localhost:5000'))
|
||||
|
||||
SecurityScannerValidator.validate(unvalidated_config)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config, expected_error', [
|
||||
({
|
||||
'TESTING': True,
|
||||
'DISTRIBUTED_STORAGE_PREFERENCE': [],
|
||||
'FEATURE_SECURITY_SCANNER': True,
|
||||
'SECURITY_SCANNER_ENDPOINT': 'http://invalidhost',
|
||||
}, Exception),
|
||||
|
||||
({
|
||||
'TESTING': True,
|
||||
'DISTRIBUTED_STORAGE_PREFERENCE': [],
|
||||
'FEATURE_SECURITY_SCANNER': True,
|
||||
'SECURITY_SCANNER_ENDPOINT': 'http://fakesecurityscanner',
|
||||
}, None),
|
||||
])
|
||||
def test_validate(unvalidated_config, expected_error, app):
|
||||
unvalidated_config = ValidatorContext(unvalidated_config, feature_sec_scanner=True, is_testing=True,
|
||||
http_client=build_requests_session(),
|
||||
url_scheme_and_hostname=URLSchemeAndHostname('http', 'localhost:5000'))
|
||||
|
||||
with fake_security_scanner(hostname='fakesecurityscanner'):
|
||||
if expected_error is not None:
|
||||
with pytest.raises(expected_error):
|
||||
SecurityScannerValidator.validate(unvalidated_config)
|
||||
else:
|
||||
SecurityScannerValidator.validate(unvalidated_config)
|
20
util/config/validators/test/test_validate_signer.py
Normal file
20
util/config/validators/test/test_validate_signer.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
import pytest
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_signer import SignerValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config,expected', [
|
||||
({}, None),
|
||||
({'SIGNING_ENGINE': 'foobar'}, ConfigValidationException),
|
||||
({'SIGNING_ENGINE': 'gpg2'}, Exception),
|
||||
])
|
||||
def test_validate_signer(unvalidated_config, expected, app):
|
||||
validator = SignerValidator()
|
||||
if expected is not None:
|
||||
with pytest.raises(expected):
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
else:
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
75
util/config/validators/test/test_validate_ssl.py
Normal file
75
util/config/validators/test/test_validate_ssl.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
import pytest
|
||||
|
||||
from mock import patch
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_ssl import SSLValidator, SSL_FILENAMES
|
||||
from util.security.test.test_ssl_util import generate_test_cert
|
||||
|
||||
from test.fixtures import *
|
||||
from app import config_provider
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({}),
|
||||
({'PREFERRED_URL_SCHEME': 'http'}),
|
||||
({'PREFERRED_URL_SCHEME': 'https', 'EXTERNAL_TLS_TERMINATION': True}),
|
||||
])
|
||||
def test_skip_validate_ssl(unvalidated_config, app):
|
||||
validator = SSLValidator()
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('cert, server_hostname, expected_error, error_message', [
|
||||
('invalidcert', 'someserver', ConfigValidationException, 'Could not load SSL certificate: no start line'),
|
||||
(generate_test_cert(hostname='someserver'), 'someserver', None, None),
|
||||
(generate_test_cert(hostname='invalidserver'), 'someserver', ConfigValidationException,
|
||||
'Supported names "invalidserver" in SSL cert do not match server hostname "someserver"'),
|
||||
(generate_test_cert(hostname='someserver'), 'someserver:1234', None, None),
|
||||
(generate_test_cert(hostname='invalidserver'), 'someserver:1234', ConfigValidationException,
|
||||
'Supported names "invalidserver" in SSL cert do not match server hostname "someserver"'),
|
||||
(generate_test_cert(hostname='someserver:1234'), 'someserver:1234', ConfigValidationException,
|
||||
'Supported names "someserver:1234" in SSL cert do not match server hostname "someserver"'),
|
||||
(generate_test_cert(hostname='someserver:more'), 'someserver:more', None, None),
|
||||
(generate_test_cert(hostname='someserver:more'), 'someserver:more:1234', None, None),
|
||||
])
|
||||
def test_validate_ssl(cert, server_hostname, expected_error, error_message, app):
|
||||
with NamedTemporaryFile(delete=False) as cert_file:
|
||||
cert_file.write(cert[0])
|
||||
cert_file.seek(0)
|
||||
|
||||
with NamedTemporaryFile(delete=False) as key_file:
|
||||
key_file.write(cert[1])
|
||||
key_file.seek(0)
|
||||
|
||||
def return_true(filename):
|
||||
return True
|
||||
|
||||
def get_volume_file(filename):
|
||||
if filename == SSL_FILENAMES[0]:
|
||||
return open(cert_file.name)
|
||||
|
||||
if filename == SSL_FILENAMES[1]:
|
||||
return open(key_file.name)
|
||||
|
||||
return None
|
||||
|
||||
config = {
|
||||
'PREFERRED_URL_SCHEME': 'https',
|
||||
'SERVER_HOSTNAME': server_hostname,
|
||||
}
|
||||
|
||||
with patch('app.config_provider.volume_file_exists', return_true):
|
||||
with patch('app.config_provider.get_volume_file', get_volume_file):
|
||||
validator = SSLValidator()
|
||||
config = ValidatorContext(config)
|
||||
config.config_provider = config_provider
|
||||
|
||||
if expected_error is not None:
|
||||
with pytest.raises(expected_error) as ipe:
|
||||
validator.validate(config)
|
||||
|
||||
assert str(ipe.value) == error_message
|
||||
else:
|
||||
validator.validate(config)
|
40
util/config/validators/test/test_validate_storage.py
Normal file
40
util/config/validators/test/test_validate_storage.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
import pytest
|
||||
|
||||
from moto import mock_s3_deprecated as mock_s3
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_storage import StorageValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config, expected', [
|
||||
({}, ConfigValidationException),
|
||||
({'DISTRIBUTED_STORAGE_CONFIG': {}}, ConfigValidationException),
|
||||
({'DISTRIBUTED_STORAGE_CONFIG': {'local': None}}, ConfigValidationException),
|
||||
({'DISTRIBUTED_STORAGE_CONFIG': {'local': ['FakeStorage', {}]}}, None),
|
||||
])
|
||||
def test_validate_storage(unvalidated_config, expected, app):
|
||||
validator = StorageValidator()
|
||||
if expected is not None:
|
||||
with pytest.raises(expected):
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
else:
|
||||
validator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
def test_validate_s3_storage(app):
|
||||
validator = StorageValidator()
|
||||
with mock_s3():
|
||||
with pytest.raises(ConfigValidationException) as ipe:
|
||||
validator.validate(ValidatorContext({
|
||||
'DISTRIBUTED_STORAGE_CONFIG': {
|
||||
'default': ('S3Storage', {
|
||||
's3_access_key': 'invalid',
|
||||
's3_secret_key': 'invalid',
|
||||
's3_bucket': 'somebucket',
|
||||
'storage_path': ''
|
||||
}),
|
||||
}
|
||||
}))
|
||||
|
||||
assert str(ipe.value) == 'Invalid storage configuration: default: S3ResponseError: 404 Not Found'
|
32
util/config/validators/test/test_validate_timemachine.py
Normal file
32
util/config/validators/test/test_validate_timemachine.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
import pytest
|
||||
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_timemachine import TimeMachineValidator
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config', [
|
||||
({}),
|
||||
])
|
||||
def test_validate_noop(unvalidated_config):
|
||||
TimeMachineValidator.validate(ValidatorContext(unvalidated_config))
|
||||
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('default_exp,options,expected_exception', [
|
||||
('2d', ['1w', '2d'], None),
|
||||
|
||||
('2d', ['1w'], 'Default expiration must be in expiration options set'),
|
||||
('2d', ['2d', '1M'], 'Invalid tag expiration option: 1M'),
|
||||
])
|
||||
def test_validate(default_exp, options, expected_exception, app):
|
||||
config = {}
|
||||
config['DEFAULT_TAG_EXPIRATION'] = default_exp
|
||||
config['TAG_EXPIRATION_OPTIONS'] = options
|
||||
|
||||
if expected_exception is not None:
|
||||
with pytest.raises(ConfigValidationException) as cve:
|
||||
TimeMachineValidator.validate(ValidatorContext(config))
|
||||
assert str(cve.value) == str(expected_exception)
|
||||
else:
|
||||
TimeMachineValidator.validate(ValidatorContext(config))
|
39
util/config/validators/test/test_validate_torrent.py
Normal file
39
util/config/validators/test/test_validate_torrent.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
import pytest
|
||||
|
||||
from config import build_requests_session
|
||||
from httmock import urlmatch, HTTMock
|
||||
|
||||
from app import instance_keys
|
||||
from util.config.validator import ValidatorContext
|
||||
from util.config.validators import ConfigValidationException
|
||||
from util.config.validators.validate_torrent import BittorrentValidator
|
||||
|
||||
from test.fixtures import *
|
||||
|
||||
@pytest.mark.parametrize('unvalidated_config,expected', [
|
||||
({}, ConfigValidationException),
|
||||
({'BITTORRENT_ANNOUNCE_URL': 'http://faketorrent/announce'}, None),
|
||||
])
|
||||
def test_validate_torrent(unvalidated_config, expected, app):
|
||||
announcer_hit = [False]
|
||||
|
||||
@urlmatch(netloc=r'faketorrent', path='/announce')
|
||||
def handler(url, request):
|
||||
announcer_hit[0] = True
|
||||
return {'status_code': 200, 'content': ''}
|
||||
|
||||
with HTTMock(handler):
|
||||
validator = BittorrentValidator()
|
||||
if expected is not None:
|
||||
with pytest.raises(expected):
|
||||
config = ValidatorContext(unvalidated_config, instance_keys=instance_keys)
|
||||
config.http_client = build_requests_session()
|
||||
|
||||
validator.validate(config)
|
||||
assert not announcer_hit[0]
|
||||
else:
|
||||
config = ValidatorContext(unvalidated_config, instance_keys=instance_keys)
|
||||
config.http_client = build_requests_session()
|
||||
|
||||
validator.validate(config)
|
||||
assert announcer_hit[0]
|
Reference in a new issue