"""The RPC transport itself over HTTP: CSRF, method guards, error envelopes.""" import json from django.test import LiveServerTestCase from tests.live_http import LiveRPCMixin class CSRFTests(LiveRPCMixin, LiveServerTestCase): def test_session_endpoint_sets_csrf_cookie(self): from urllib.request import Request, urlopen url = f"{self.live_server_url}/api/mizan/session/" resp = urlopen(Request(url)) cookies = resp.headers.get_all("Set-Cookie") or [] csrf_cookies = [c for c in cookies if "csrftoken=" in c] self.assertGreater(len(csrf_cookies), 0, "No csrftoken cookie set by /session/") def test_call_without_csrf_is_rejected(self): reply = self.call("system_info", with_csrf=False) self.assertEqual(reply.status, 403) def test_call_with_csrf_succeeds(self): self.session_init() self.assertIn("os_name", self.result("system_info")) class ValidationTests(LiveRPCMixin, LiveServerTestCase): def setUp(self): self.session_init() def test_missing_required_field(self): reply = self.call("create_note", {}) self.assertEqual(reply.status, 422) self.assertEqual(reply.body["code"], "VALIDATION_ERROR") self.assertIn("title", reply.body["details"]["fields"]) def test_wrong_type(self): reply = self.call("delete_note", {"id": "not-an-int"}) self.assertEqual(reply.status, 422) self.assertEqual(reply.body["code"], "VALIDATION_ERROR") def test_missing_multiple_fields(self): reply = self.call("write_file", {}) self.assertEqual(reply.status, 422) self.assertEqual(reply.body["code"], "VALIDATION_ERROR") self.assertEqual( set(reply.body["details"]["fields"]), {"path", "content"} ) class ErrorCodeTests(LiveRPCMixin, LiveServerTestCase): def setUp(self): self.session_init() def test_not_found_function(self): reply = self.call("this_does_not_exist") self.assertEqual(reply.status, 404) self.assertEqual(reply.body["code"], "NOT_FOUND") def test_forbidden_write_outside_home(self): reply = self.call("write_file", {"path": "/etc/nope.txt", "content": "x"}) self.assertEqual(reply.status, 403) self.assertEqual(reply.body["code"], "FORBIDDEN") def test_get_method_rejected(self): reply = self.get("/api/mizan/call/") self.assertEqual(reply.status, 405) self.assertEqual(reply.body["code"], "BAD_REQUEST") def test_invalid_json_body(self): reply = self.post("/api/mizan/call/", "not valid json{{{") self.assertEqual(reply.status, 400) self.assertEqual(reply.body["code"], "BAD_REQUEST") def test_missing_fn_field(self): reply = self.post("/api/mizan/call/", json.dumps({"not_fn": "hello"})) self.assertEqual(reply.status, 400) self.assertEqual(reply.body["code"], "BAD_REQUEST") def test_empty_body(self): reply = self.post("/api/mizan/call/", b"") self.assertEqual(reply.status, 400) self.assertEqual(reply.body["code"], "BAD_REQUEST")