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