From 5b875ad09a3e31754f13b31c8f958054ae0f800b Mon Sep 17 00:00:00 2001 From: dapineyro <45285897+dapineyro@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:16:42 +0100 Subject: [PATCH] Patch: Updates API request to send API key via HTTP only. Deprecates API key via parameters. (#170) * update requests * update requests * update pytests --- CHANGELOG.md | 6 +++ cloudos/_version.py | 2 +- cloudos/clos.py | 37 +++++++++++++------ cloudos/jobs/job.py | 7 +++- tests/test_clos/test_detect_workflow.py | 7 ++-- tests/test_clos/test_get_job_list.py | 14 ++++--- tests/test_clos/test_get_project_list.py | 14 ++++--- tests/test_clos/test_get_workflow_list.py | 14 ++++--- tests/test_clos/test_is_module.py | 7 ++-- .../test_errors/test_bad_request_exception.py | 7 ++-- tests/test_jobs/test_project_id.py | 7 ++-- tests/test_jobs/test_send_job.py | 10 ++--- tests/test_jobs/test_workflow_id.py | 7 ++-- 13 files changed, 86 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a81a38e0..eddac8b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ## lifebit-ai/cloudos-cli: changelog +## v2.11.2 (2024-11-6) + +### Fix + +- Updates API requests to only use API key via HTTP header. Done in preparation for the upcoming deprecation of API key via parameters in CloudOS API. + ## v2.11.1 (2024-10-22) ### Fix diff --git a/cloudos/_version.py b/cloudos/_version.py index d3583e9b..ded7bd35 100644 --- a/cloudos/_version.py +++ b/cloudos/_version.py @@ -1 +1 @@ -__version__ = '2.11.1' +__version__ = '2.11.2' diff --git a/cloudos/clos.py b/cloudos/clos.py index f23298e3..ae2aa4ba 100644 --- a/cloudos/clos.py +++ b/cloudos/clos.py @@ -235,10 +235,13 @@ def get_job_list(self, workspace_id, last_n_jobs=30, page=1, verify=True): r : list A list of dicts, each corresponding to a jobs from the user and the workspace. """ - data = {"apikey": self.apikey} + headers = { + "Content-type": "application/json", + "apikey": self.apikey + } r = retry_requests_get("{}/api/v1/jobs?teamId={}&page={}".format(self.cloudos_url, workspace_id, page), - params=data, verify=verify) + headers=headers, verify=verify) if r.status_code >= 400: raise BadRequestException(r) content = json.loads(r.content) @@ -329,8 +332,7 @@ def get_curated_workflow_list(self, workspace_id, get_all=True, page=1, verify=T r : list A list of dicts, each corresponding to a workflow. """ - data = {"apikey": self.apikey, - "search": "", + data = {"search": "", "page": page, "filters": [ [ @@ -355,9 +357,13 @@ def get_curated_workflow_list(self, workspace_id, get_all=True, page=1, verify=T ] ] } + headers = { + "Content-type": "application/json", + "apikey": self.apikey + } r = retry_requests_post("{}/api/v1/workflows/getByType?teamId={}".format(self.cloudos_url, workspace_id), - json=data, verify=verify) + json=data, headers=headers, verify=verify) if r.status_code >= 400: raise BadRequestException(r) content = json.loads(r.content) @@ -391,10 +397,13 @@ def get_workflow_list(self, workspace_id, verify=True): r : list A list of dicts, each corresponding to a workflow. """ - data = {"apikey": self.apikey} + headers = { + "Content-type": "application/json", + "apikey": self.apikey + } r = retry_requests_get("{}/api/v1/workflows?teamId={}".format(self.cloudos_url, workspace_id), - params=data, verify=verify) + headers=headers, verify=verify) if r.status_code >= 400: raise BadRequestException(r) return json.loads(r.content) @@ -520,9 +529,12 @@ def get_project_list(self, workspace_id, verify=True): r : requests.models.Response The server response """ - data = {"apikey": self.apikey} + headers = { + "Content-type": "application/json", + "apikey": self.apikey + } r = retry_requests_get("{}/api/v1/projects?teamId={}".format(self.cloudos_url, workspace_id), - params=data, verify=verify) + headers=headers, verify=verify) if r.status_code >= 400: raise BadRequestException(r) return r @@ -615,7 +627,6 @@ def workflow_import(self, workspace_id, workflow_url, workflow_name, repository_name = workflow_url.split('/')[-1] data = { - "apikey": self.apikey, "workflowType": "nextflow", "repository": { "platform": platform, @@ -638,9 +649,13 @@ def workflow_import(self, workspace_id, workflow_url, workflow_name, "docsLink": workflow_docs_link, "team": workspace_id } + headers = { + "Content-type": "application/json", + "apikey": self.apikey + } r = retry_requests_post("{}/api/v1/workflows?teamId={}".format(self.cloudos_url, workspace_id), - json=data, verify=verify) + json=data, headers=headers, verify=verify) if r.status_code == 401: raise ValueError('It seems your API key is not authorised. Please check if ' + 'your workspace has support for importing workflows using cloudos-cli') diff --git a/cloudos/jobs/job.py b/cloudos/jobs/job.py index 22d95049..47974dcc 100644 --- a/cloudos/jobs/job.py +++ b/cloudos/jobs/job.py @@ -143,11 +143,14 @@ def fetch_cloudos_id(self, if resource not in allowed_resources: raise ValueError('Your specified resource is not supported. ' + f'Use one of the following: {allowed_resources}') - data = {"apikey": apikey} + headers = { + "Content-type": "application/json", + "apikey": apikey + } r = retry_requests_get("{}/api/v1/{}?teamId={}".format(cloudos_url, resource, workspace_id), - params=data, verify=verify) + headers=headers, verify=verify) if r.status_code >= 400: raise BadRequestException(r) content = json.loads(r.content) diff --git a/tests/test_clos/test_detect_workflow.py b/tests/test_clos/test_detect_workflow.py index e4e4b931..bda50a7c 100644 --- a/tests/test_clos/test_detect_workflow.py +++ b/tests/test_clos/test_detect_workflow.py @@ -19,12 +19,13 @@ def test_detect_workflow(): API request is mocked and replicated with json files """ json_data = load_json_file(INPUT) - params = {"teamId": WORKSPACE_ID, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}" # mock GET method with the .json responses.add( responses.GET, diff --git a/tests/test_clos/test_get_job_list.py b/tests/test_clos/test_get_job_list.py index 268d339b..eebb59b3 100644 --- a/tests/test_clos/test_get_job_list.py +++ b/tests/test_clos/test_get_job_list.py @@ -21,12 +21,13 @@ def test_get_job_list_correct_response(): API request is mocked and replicated with json files """ create_json = load_json_file(INPUT) - params = {"teamId": WORKSPACE_ID, "page": 1, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID, "page": 1} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&page=1&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}&page=1" # mock GET method with the .json responses.add( responses.GET, @@ -53,12 +54,13 @@ def test_get_job_list_incorrect_response(): error_message = {"statusCode": 400, "code": "BadRequest", "message": "Bad Request.", "time": "2022-11-23_17:31:07"} error_json = json.dumps(error_message) - params = {"teamId": WORKSPACE_ID, "page": 1, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID, "page": 1} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&page=1&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}&page=1" # mock GET method with the .json responses.add( responses.GET, diff --git a/tests/test_clos/test_get_project_list.py b/tests/test_clos/test_get_project_list.py index 3736ab8e..6ba6b916 100644 --- a/tests/test_clos/test_get_project_list.py +++ b/tests/test_clos/test_get_project_list.py @@ -18,12 +18,13 @@ def test_get_project_list_correct_response(): """ Test 'get_project_list' to work as intended """ - params = {"teamId": WORKSPACE_ID, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}" # mock GET method with the .json responses.add( responses.GET, @@ -50,12 +51,13 @@ def test_get_project_list_incorrect_response(): error_message = {"statusCode": 400, "code": "BadRequest", "message": "Bad Request.", "time": "2022-11-23_17:31:07"} error_json = json.dumps(error_message) - params = {"teamId": WORKSPACE_ID, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}" # mock GET method with the .json responses.add( responses.GET, diff --git a/tests/test_clos/test_get_workflow_list.py b/tests/test_clos/test_get_workflow_list.py index 6b6a5e6e..5b7e29d1 100644 --- a/tests/test_clos/test_get_workflow_list.py +++ b/tests/test_clos/test_get_workflow_list.py @@ -21,12 +21,13 @@ def test_get_workflow_list_correct_response(): API request is mocked and replicated with json files """ create_json = load_json_file(INPUT) - params = {"teamId": WORKSPACE_ID, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}" # mock GET method with the .json responses.add( responses.GET, @@ -54,12 +55,13 @@ def test_get_workflow_list_incorrect_response(): error_message = {"statusCode": 400, "code": "BadRequest", "message": "Bad Request.", "time": "2022-11-23_17:31:07"} error_json = json.dumps(error_message) - params = {"teamId": WORKSPACE_ID, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}" # mock GET method with the .json responses.add( responses.GET, diff --git a/tests/test_clos/test_is_module.py b/tests/test_clos/test_is_module.py index 2e13bd54..6a2148db 100644 --- a/tests/test_clos/test_is_module.py +++ b/tests/test_clos/test_is_module.py @@ -19,12 +19,13 @@ def test_is_module(): API request is mocked and replicated with json files """ json_data = load_json_file(INPUT) - params = {"teamId": WORKSPACE_ID, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}" # mock GET method with the .json responses.add( responses.GET, diff --git a/tests/test_errors/test_bad_request_exception.py b/tests/test_errors/test_bad_request_exception.py index 8a799e63..7fd32b96 100644 --- a/tests/test_errors/test_bad_request_exception.py +++ b/tests/test_errors/test_bad_request_exception.py @@ -22,12 +22,13 @@ def test_bad_request_exception(): API request is mocked and replicated with json files """ create_json = load_json_file(INPUT) - params = {"teamId": WORKSPACE_ID, "page": 1, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID, "page": 1} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&page=1&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}&page=1" # mock GET method with the .json responses.add( responses.GET, diff --git a/tests/test_jobs/test_project_id.py b/tests/test_jobs/test_project_id.py index 87e259cf..a3358c79 100644 --- a/tests/test_jobs/test_project_id.py +++ b/tests/test_jobs/test_project_id.py @@ -23,12 +23,13 @@ def test_project_id(): """ create_json_project = load_json_file(INPUT_PROJECT) create_json_workflow = load_json_file(INPUT_WORKFLOW) - params = {"teamId": WORKSPACE_ID, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}" # mock GET method with the .json responses.add( responses.GET, diff --git a/tests/test_jobs/test_send_job.py b/tests/test_jobs/test_send_job.py index 651e75ca..b2df5152 100644 --- a/tests/test_jobs/test_send_job.py +++ b/tests/test_jobs/test_send_job.py @@ -32,13 +32,11 @@ def test_send_job(): create_json_workflow = load_json_file(INPUT_WORKFLOW) create_json = load_json_file(INPUT) params_job = {"teamId": WORKSPACE_ID} - params_pro_wf = {"teamId": WORKSPACE_ID, "apikey": APIKEY} header = { "Content-type": "application/json", "apikey": APIKEY } search_str = f"teamId={WORKSPACE_ID}" - search_str_pro_wf = f"teamId={WORKSPACE_ID}&apikey={APIKEY}" # mock GET method with the .json responses.add( responses.POST, @@ -49,17 +47,17 @@ def test_send_job(): status=200) responses.add( responses.GET, - url=f"{CLOUDOS_URL}/api/v1/projects?{search_str_pro_wf}", + url=f"{CLOUDOS_URL}/api/v1/projects?{search_str}", body=create_json_project, headers=header, - match=[matchers.query_param_matcher(params_pro_wf)], + match=[matchers.query_param_matcher(params_job)], status=200) responses.add( responses.GET, - url=f"{CLOUDOS_URL}/api/v1/workflows?{search_str_pro_wf}", + url=f"{CLOUDOS_URL}/api/v1/workflows?{search_str}", body=create_json_workflow, headers=header, - match=[matchers.query_param_matcher(params_pro_wf)], + match=[matchers.query_param_matcher(params_job)], status=200) # start cloudOS service job = Job(apikey=APIKEY, diff --git a/tests/test_jobs/test_workflow_id.py b/tests/test_jobs/test_workflow_id.py index b98a9de1..6be57832 100644 --- a/tests/test_jobs/test_workflow_id.py +++ b/tests/test_jobs/test_workflow_id.py @@ -23,12 +23,13 @@ def test_workflow_id(): """ create_json_project = load_json_file(INPUT_PROJECT) create_json_workflow = load_json_file(INPUT_WORKFLOW) - params = {"teamId": WORKSPACE_ID, "apikey": APIKEY} + params = {"teamId": WORKSPACE_ID} header = { "Accept": "application/json, text/plain, */*", - "Content-Type": "application/json;charset=UTF-8" + "Content-Type": "application/json;charset=UTF-8", + "apikey": APIKEY } - search_str = f"teamId={WORKSPACE_ID}&apikey={APIKEY}" + search_str = f"teamId={WORKSPACE_ID}" # mock GET method with the .json responses.add( responses.GET,