From c0384eae1164c4b87e6782cc2368afca3718f5ce Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 05:02:27 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=92=20Add=20timeout=20to=20all=20reque?= =?UTF-8?q?sts=20library=20calls=20in=20create=5Fworklog.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit addresses a security vulnerability where `requests` calls were missing a `timeout` argument. This could lead to the script hanging indefinitely if the remote server fails to respond, potentially causing resource exhaustion and a Denial of Service (DoS) condition. Changes: - Added `timeout=10` to all `requests.get` and `requests.post` calls in `create_worklog.py`. - Updated `test_create_worklog.py` to assert that the `timeout` parameter is correctly passed. - Fixed an issue in `test_create_worklog.py` where `requests.exceptions.HTTPError` was not correctly mocked. Co-authored-by: yj9404 <47413412+yj9404@users.noreply.github.com> --- create_worklog.py | 8 ++++---- test_create_worklog.py | 43 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/create_worklog.py b/create_worklog.py index a4c4695..17978dd 100644 --- a/create_worklog.py +++ b/create_worklog.py @@ -14,7 +14,7 @@ def get_folder_id_by_name(name, parent_id): # parentId 하위 폴더 조회 url = f"{BASE_URL}/folders/{parent_id}?include-direct-children=true" headers = {"Accept": "application/json"} - r = requests.get(url, auth=AUTH, headers=headers) + r = requests.get(url, auth=AUTH, headers=headers, timeout=10) r.raise_for_status() data = r.json() @@ -38,7 +38,7 @@ def find_or_create_folder(name, parent_id): url = f"{BASE_URL}/folders" payload = {"spaceId": SPACE_ID, "title": name, "parentId": parent_id} - r = requests.post(url, auth=AUTH, json=payload) + r = requests.post(url, auth=AUTH, json=payload, timeout=10) if r.status_code in (200, 201): data = r.json() print(f"[CREATE] Folder created: {name} (id={data['id']})") @@ -62,7 +62,7 @@ def create_page(title, parent_id, body): "subtype": "live" } - r = requests.post(url, auth=AUTH, json=data) + r = requests.post(url, auth=AUTH, json=data, timeout=10) if r.status_code == 400: # 이미 존재 print(f"[SKIP] Page already exists: {title}") return None @@ -74,7 +74,7 @@ def create_page(title, parent_id, body): def get_template_body(): url = f"{BASE_URL_V1}/template/{TEMPLATE_ID}" # v1 API headers = {"Accept": "application/json"} - r = requests.get(url, auth=AUTH, headers=headers) + r = requests.get(url, auth=AUTH, headers=headers, timeout=10) r.raise_for_status() data = r.json() return data["body"]["storage"]["value"] diff --git a/test_create_worklog.py b/test_create_worklog.py index a03db6f..0d50a3b 100644 --- a/test_create_worklog.py +++ b/test_create_worklog.py @@ -13,6 +13,19 @@ os.environ["ATLASSIAN_API_TOKEN"] = "test_token" # requests가 import되기 전에 환경 변수가 설정되었는지 확인하기 위해 여기서 import합니다. +from unittest.mock import MagicMock +import sys + +class MockRequestsException(Exception): + pass + +class MockHTTPError(MockRequestsException): + pass + +mock_requests = MagicMock() +mock_requests.exceptions.HTTPError = MockHTTPError +sys.modules['requests'] = mock_requests + import create_worklog import requests @@ -38,7 +51,8 @@ def test_get_folder_id_by_name_found(self, mock_get): mock_get.assert_called_once_with( "https://test.atlassian.net/wiki/rest/api/folders/parent_id?include-direct-children=true", auth=("test@example.com", "test_token"), - headers={"Accept": "application/json"} + headers={"Accept": "application/json"}, + timeout=10 ) @patch('create_worklog.requests.get') @@ -76,7 +90,12 @@ def test_find_or_create_folder_create_success(self, mock_post, mock_get_folder): folder_id = create_worklog.find_or_create_folder("new_folder", "parent") self.assertEqual(folder_id, "new_folder_id") mock_get_folder.assert_called_once_with("new_folder", "parent") - mock_post.assert_called_once() + mock_post.assert_called_once_with( + "https://test.atlassian.net/wiki/rest/api/folders", + auth=("test@example.com", "test_token"), + json={"spaceId": "12345", "title": "new_folder", "parentId": "parent"}, + timeout=10 + ) @patch('create_worklog.get_folder_id_by_name', return_value=None) @patch('create_worklog.requests.post') @@ -99,6 +118,23 @@ def test_create_page_success(self, mock_post): page_id = create_worklog.create_page("test_page", "parent", "body") self.assertEqual(page_id, "new_page_id") + mock_post.assert_called_once_with( + "https://test.atlassian.net/wiki/rest/api/pages", + auth=("test@example.com", "test_token"), + json={ + "spaceId": "12345", + "title": "test_page", + "parentId": "parent", + "status": "current", + "position": 0, + "body": { + "representation": "storage", + "value": "body" + }, + "subtype": "live" + }, + timeout=10 + ) @patch('create_worklog.requests.post') def test_create_page_already_exists(self, mock_post): @@ -121,7 +157,8 @@ def test_get_template_body(self, mock_get): mock_get.assert_called_once_with( "https://test.atlassian.net/wiki/rest/api/v1/template/67890", auth=("test@example.com", "test_token"), - headers={"Accept": "application/json"} + headers={"Accept": "application/json"}, + timeout=10 ) @patch('create_worklog.create_page')