github.com/blystad/deis@v0.11.0/controller/api/tests/test_hooks.py (about) 1 """ 2 Unit tests for the Deis api app. 3 4 Run the tests with "./manage.py test api" 5 """ 6 7 from __future__ import unicode_literals 8 9 import json 10 import mock 11 import requests 12 13 from django.test import TransactionTestCase 14 from django.test.utils import override_settings 15 16 from django.conf import settings 17 18 19 def mock_import_repository_task(*args, **kwargs): 20 resp = requests.Response() 21 resp.status_code = 200 22 resp._content_consumed = True 23 return resp 24 25 26 @override_settings(CELERY_ALWAYS_EAGER=True) 27 class HookTest(TransactionTestCase): 28 29 """Tests API hooks used to trigger actions from external components""" 30 31 fixtures = ['tests.json'] 32 33 def setUp(self): 34 self.assertTrue( 35 self.client.login(username='autotest', password='password')) 36 body = {'id': 'autotest', 'domain': 'autotest.local', 'type': 'mock', 37 'hosts': 'host1,host2', 'auth': 'base64string', 'options': {}} 38 response = self.client.post('/api/clusters', json.dumps(body), 39 content_type='application/json') 40 self.assertEqual(response.status_code, 201) 41 42 def test_push_hook(self): 43 """Test creating a Push via the API""" 44 url = '/api/apps' 45 body = {'cluster': 'autotest'} 46 response = self.client.post(url, json.dumps(body), content_type='application/json') 47 self.assertEqual(response.status_code, 201) 48 app_id = response.data['id'] 49 # prepare a push body 50 body = { 51 'sha': 'df1e628f2244b73f9cdf944f880a2b3470a122f4', 52 'fingerprint': '88:25:ed:67:56:91:3d:c6:1b:7f:42:c6:9b:41:24:80', 53 'receive_user': 'autotest', 54 'receive_repo': '{app_id}'.format(**locals()), 55 'ssh_connection': '10.0.1.10 50337 172.17.0.143 22', 56 'ssh_original_command': "git-receive-pack '{app_id}.git'".format(**locals()), 57 } 58 # post a request without the auth header 59 url = "/api/hooks/push".format(**locals()) 60 response = self.client.post(url, json.dumps(body), content_type='application/json') 61 self.assertEqual(response.status_code, 403) 62 # now try with the builder key in the special auth header 63 response = self.client.post(url, json.dumps(body), content_type='application/json', 64 HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY) 65 self.assertEqual(response.status_code, 201) 66 for k in ('owner', 'app', 'sha', 'fingerprint', 'receive_repo', 'receive_user', 67 'ssh_connection', 'ssh_original_command'): 68 self.assertIn(k, response.data) 69 70 def test_push_abuse(self): 71 """Test a user pushing to an unauthorized application""" 72 # create a legit app as "autotest" 73 url = '/api/apps' 74 body = {'cluster': 'autotest'} 75 response = self.client.post(url, json.dumps(body), content_type='application/json') 76 self.assertEqual(response.status_code, 201) 77 app_id = response.data['id'] 78 # register an evil user 79 username, password = 'eviluser', 'password' 80 first_name, last_name = 'Evil', 'User' 81 email = 'evil@deis.io' 82 submit = { 83 'username': username, 84 'password': password, 85 'first_name': first_name, 86 'last_name': last_name, 87 'email': email, 88 } 89 url = '/api/auth/register' 90 response = self.client.post(url, json.dumps(submit), content_type='application/json') 91 self.assertEqual(response.status_code, 201) 92 # prepare a push body that simulates a git push 93 body = { 94 'sha': 'df1e628f2244b73f9cdf944f880a2b3470a122f4', 95 'fingerprint': '88:25:ed:67:56:91:3d:c6:1b:7f:42:c6:9b:41:24:99', 96 'receive_user': 'eviluser', 97 'receive_repo': '{app_id}'.format(**locals()), 98 'ssh_connection': '10.0.1.10 50337 172.17.0.143 22', 99 'ssh_original_command': "git-receive-pack '{app_id}.git'".format(**locals()), 100 } 101 # try to push as "eviluser" 102 url = "/api/hooks/push".format(**locals()) 103 response = self.client.post(url, json.dumps(body), content_type='application/json', 104 HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY) 105 self.assertEqual(response.status_code, 403) 106 107 @mock.patch('requests.post', mock_import_repository_task) 108 def test_build_hook(self): 109 """Test creating a Build via an API Hook""" 110 url = '/api/apps' 111 body = {'cluster': 'autotest'} 112 response = self.client.post(url, json.dumps(body), content_type='application/json') 113 self.assertEqual(response.status_code, 201) 114 app_id = response.data['id'] 115 build = {'username': 'autotest', 'app': app_id} 116 url = '/api/hooks/builds'.format(**locals()) 117 body = {'receive_user': 'autotest', 118 'receive_repo': app_id, 119 'image': '{app_id}:v2'.format(**locals())} 120 # post the build without a session 121 self.assertIsNone(self.client.logout()) 122 response = self.client.post(url, json.dumps(body), content_type='application/json') 123 self.assertEqual(response.status_code, 403) 124 # post the build with the builder auth key 125 response = self.client.post(url, json.dumps(body), content_type='application/json', 126 HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY) 127 self.assertEqual(response.status_code, 200) 128 self.assertIn('release', response.data) 129 self.assertIn('version', response.data['release']) 130 self.assertIn('domains', response.data) 131 132 def test_build_hook_procfile(self): 133 """Test creating a Procfile build via an API Hook""" 134 url = '/api/apps' 135 body = {'cluster': 'autotest'} 136 response = self.client.post(url, json.dumps(body), content_type='application/json') 137 self.assertEqual(response.status_code, 201) 138 app_id = response.data['id'] 139 build = {'username': 'autotest', 'app': app_id} 140 url = '/api/hooks/builds'.format(**locals()) 141 PROCFILE = {'web': 'node server.js', 'worker': 'node worker.js'} 142 SHA = 'ecdff91c57a0b9ab82e89634df87e293d259a3aa' 143 body = {'receive_user': 'autotest', 144 'receive_repo': app_id, 145 'image': '{app_id}:v2'.format(**locals()), 146 'sha': SHA, 147 'procfile': PROCFILE} 148 # post the build without a session 149 self.assertIsNone(self.client.logout()) 150 response = self.client.post(url, json.dumps(body), content_type='application/json') 151 self.assertEqual(response.status_code, 403) 152 # post the build with the builder auth key 153 response = self.client.post(url, json.dumps(body), content_type='application/json', 154 HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY) 155 self.assertEqual(response.status_code, 200) 156 self.assertIn('release', response.data) 157 self.assertIn('version', response.data['release']) 158 self.assertIn('domains', response.data) 159 # make sure build fields were populated 160 self.assertTrue( 161 self.client.login(username='autotest', password='password')) 162 url = '/api/apps/{app_id}/builds'.format(**locals()) 163 response = self.client.get(url) 164 self.assertEqual(response.status_code, 200) 165 self.assertIn('results', response.data) 166 build = response.data['results'][0] 167 self.assertEqual(build['sha'], SHA) 168 self.assertEqual(build['procfile'], json.dumps(PROCFILE)) 169 # test listing/retrieving container info 170 url = "/api/apps/{app_id}/containers/web".format(**locals()) 171 response = self.client.get(url) 172 self.assertEqual(response.status_code, 200) 173 self.assertEqual(len(response.data['results']), 1) 174 container = response.data['results'][0] 175 self.assertEqual(container['type'], 'web') 176 self.assertEqual(container['num'], 1) 177 178 def test_build_hook_dockerfile(self): 179 """Test creating a Dockerfile build via an API Hook""" 180 url = '/api/apps' 181 body = {'cluster': 'autotest'} 182 response = self.client.post(url, json.dumps(body), content_type='application/json') 183 self.assertEqual(response.status_code, 201) 184 app_id = response.data['id'] 185 build = {'username': 'autotest', 'app': app_id} 186 url = '/api/hooks/builds'.format(**locals()) 187 SHA = 'ecdff91c57a0b9ab82e89634df87e293d259a3aa' 188 DOCKERFILE = """ 189 FROM busybox 190 CMD /bin/true 191 """ 192 body = {'receive_user': 'autotest', 193 'receive_repo': app_id, 194 'image': '{app_id}:v2'.format(**locals()), 195 'sha': SHA, 196 'dockerfile': DOCKERFILE} 197 # post the build without a session 198 self.assertIsNone(self.client.logout()) 199 response = self.client.post(url, json.dumps(body), content_type='application/json') 200 self.assertEqual(response.status_code, 403) 201 # post the build with the builder auth key 202 response = self.client.post(url, json.dumps(body), content_type='application/json', 203 HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY) 204 self.assertEqual(response.status_code, 200) 205 self.assertIn('release', response.data) 206 self.assertIn('version', response.data['release']) 207 self.assertIn('domains', response.data) 208 # make sure build fields were populated 209 self.assertTrue( 210 self.client.login(username='autotest', password='password')) 211 url = '/api/apps/{app_id}/builds'.format(**locals()) 212 response = self.client.get(url) 213 self.assertEqual(response.status_code, 200) 214 self.assertIn('results', response.data) 215 build = response.data['results'][0] 216 self.assertEqual(build['sha'], SHA) 217 self.assertEqual(build['dockerfile'], DOCKERFILE) 218 # test default container 219 url = "/api/apps/{app_id}/containers/cmd".format(**locals()) 220 response = self.client.get(url) 221 self.assertEqual(response.status_code, 200) 222 self.assertEqual(len(response.data['results']), 1) 223 container = response.data['results'][0] 224 self.assertEqual(container['type'], 'cmd') 225 self.assertEqual(container['num'], 1) 226 227 def test_config_hook(self): 228 """Test reading Config via an API Hook""" 229 url = '/api/apps' 230 body = {'cluster': 'autotest'} 231 response = self.client.post(url, json.dumps(body), content_type='application/json') 232 self.assertEqual(response.status_code, 201) 233 app_id = response.data['id'] 234 url = '/api/apps/{app_id}/config'.format(**locals()) 235 response = self.client.get(url) 236 self.assertEqual(response.status_code, 200) 237 self.assertIn('values', response.data) 238 values = response.data['values'] 239 # prepare the config hook 240 config = {'username': 'autotest', 'app': app_id} 241 url = '/api/hooks/config'.format(**locals()) 242 body = {'receive_user': 'autotest', 243 'receive_repo': app_id} 244 # post without a session 245 self.assertIsNone(self.client.logout()) 246 response = self.client.post(url, json.dumps(body), content_type='application/json') 247 self.assertEqual(response.status_code, 403) 248 # post with the builder auth key 249 response = self.client.post(url, json.dumps(body), content_type='application/json', 250 HTTP_X_DEIS_BUILDER_AUTH=settings.BUILDER_KEY) 251 self.assertEqual(response.status_code, 200) 252 self.assertIn('values', response.data) 253 self.assertEqual(values, response.data['values'])