From ee6f9cf4c027b92b1efca90e3d36567a2e8e79fd Mon Sep 17 00:00:00 2001 From: mhucka <1450019+mhucka@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:29:44 +0000 Subject: [PATCH 1/6] Move GitHub access token from query parameter to Authorization header. GitHub deprecated passing the access token in the URL. This change moves it to the Authorization header, which is more secure and compliant with GitHub's current API standards. --- dev_tools/prepared_env.py | 10 +++----- dev_tools/prepared_env_security_test.py | 33 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 dev_tools/prepared_env_security_test.py diff --git a/dev_tools/prepared_env.py b/dev_tools/prepared_env.py index 842ed675a..aba480716 100644 --- a/dev_tools/prepared_env.py +++ b/dev_tools/prepared_env.py @@ -97,14 +97,12 @@ def report_status_to_github( if target_url is not None: payload['target_url'] = target_url - url = "https://api.github.com/repos/{}/{}/statuses/{}?access_token={}".format( - self.repository.organization, - self.repository.name, - self.actual_commit_id, - self.repository.access_token, + url = "https://api.github.com/repos/{}/{}/statuses/{}".format( + self.repository.organization, self.repository.name, self.actual_commit_id ) + headers = {'Authorization': 'token {}'.format(self.repository.access_token)} - response = requests.post(url, json=payload) + response = requests.post(url, json=payload, headers=headers) if response.status_code != 201: raise IOError( diff --git a/dev_tools/prepared_env_security_test.py b/dev_tools/prepared_env_security_test.py new file mode 100644 index 000000000..960ccfedf --- /dev/null +++ b/dev_tools/prepared_env_security_test.py @@ -0,0 +1,33 @@ + +import unittest +from unittest.mock import patch, MagicMock +from dev_tools.prepared_env import PreparedEnv +from dev_tools.github_repository import GithubRepository + +class TestPreparedEnvSecurity(unittest.TestCase): + @patch('requests.post') + def test_report_status_to_github_token_in_header(self, mock_post): + # Setup + mock_response = MagicMock() + mock_response.status_code = 201 + mock_post.return_value = mock_response + + repo = GithubRepository('my-org', 'my-repo', 'my-token') + env = PreparedEnv(repo, 'my-commit', 'compare-commit', None, None) + + # Execute + env.report_status_to_github('success', 'desc', 'ctx') + + # Verify + args, kwargs = mock_post.call_args + url = args[0] + headers = kwargs.get('headers', {}) + + # Security check: Token should NOT be in the URL + self.assertNotIn('access_token=my-token', url, "Token should not be passed in the URL") + + # Security check: Token should be in the Authorization header + self.assertEqual(headers.get('Authorization'), 'token my-token', "Token should be passed in the Authorization header") + +if __name__ == '__main__': + unittest.main() From 8ab3a43477ca53a6cf0695391b9dd0e24f9a62fe Mon Sep 17 00:00:00 2001 From: mhucka Date: Fri, 10 Apr 2026 22:02:05 +0000 Subject: [PATCH 2/6] Format --- dev_tools/prepared_env_security_test.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dev_tools/prepared_env_security_test.py b/dev_tools/prepared_env_security_test.py index 960ccfedf..9ba02654b 100644 --- a/dev_tools/prepared_env_security_test.py +++ b/dev_tools/prepared_env_security_test.py @@ -1,9 +1,9 @@ - import unittest from unittest.mock import patch, MagicMock from dev_tools.prepared_env import PreparedEnv from dev_tools.github_repository import GithubRepository + class TestPreparedEnvSecurity(unittest.TestCase): @patch('requests.post') def test_report_status_to_github_token_in_header(self, mock_post): @@ -27,7 +27,12 @@ def test_report_status_to_github_token_in_header(self, mock_post): self.assertNotIn('access_token=my-token', url, "Token should not be passed in the URL") # Security check: Token should be in the Authorization header - self.assertEqual(headers.get('Authorization'), 'token my-token', "Token should be passed in the Authorization header") + self.assertEqual( + headers.get('Authorization'), + 'token my-token', + "Token should be passed in the Authorization header", + ) + if __name__ == '__main__': unittest.main() From 5f27e244376b57af6bd18bd5611d7624a25135dc Mon Sep 17 00:00:00 2001 From: Michael Hucka Date: Wed, 22 Apr 2026 22:35:00 -0700 Subject: [PATCH 3/6] Handle case of actual_commit_id == None Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- dev_tools/prepared_env.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev_tools/prepared_env.py b/dev_tools/prepared_env.py index aba480716..94c5c9ab9 100644 --- a/dev_tools/prepared_env.py +++ b/dev_tools/prepared_env.py @@ -97,6 +97,8 @@ def report_status_to_github( if target_url is not None: payload['target_url'] = target_url + if self.actual_commit_id is None: + return url = "https://api.github.com/repos/{}/{}/statuses/{}".format( self.repository.organization, self.repository.name, self.actual_commit_id ) From 4f04743874cdf0988ffaac54b324ba2f4421f25a Mon Sep 17 00:00:00 2001 From: Michael Hucka Date: Wed, 22 Apr 2026 22:35:35 -0700 Subject: [PATCH 4/6] Provide a timeout Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- dev_tools/prepared_env.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev_tools/prepared_env.py b/dev_tools/prepared_env.py index 94c5c9ab9..71c7fccd5 100644 --- a/dev_tools/prepared_env.py +++ b/dev_tools/prepared_env.py @@ -104,7 +104,7 @@ def report_status_to_github( ) headers = {'Authorization': 'token {}'.format(self.repository.access_token)} - response = requests.post(url, json=payload, headers=headers) + response = requests.post(url, json=payload, headers=headers, timeout=30) if response.status_code != 201: raise IOError( From 7f02a9e2ee7c66b9c8e4ae693d7a2682bff89cb3 Mon Sep 17 00:00:00 2001 From: Michael Hucka Date: Wed, 22 Apr 2026 22:46:32 -0700 Subject: [PATCH 5/6] Update dev_tools/prepared_env.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- dev_tools/prepared_env.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev_tools/prepared_env.py b/dev_tools/prepared_env.py index 71c7fccd5..b7b42c2b4 100644 --- a/dev_tools/prepared_env.py +++ b/dev_tools/prepared_env.py @@ -102,7 +102,7 @@ def report_status_to_github( url = "https://api.github.com/repos/{}/{}/statuses/{}".format( self.repository.organization, self.repository.name, self.actual_commit_id ) - headers = {'Authorization': 'token {}'.format(self.repository.access_token)} + headers = {'Authorization': 'Bearer {}'.format(self.repository.access_token)} response = requests.post(url, json=payload, headers=headers, timeout=30) From 397ee63efe25b59f7b98ad2f75cf91496c8507b1 Mon Sep 17 00:00:00 2001 From: Michael Hucka Date: Wed, 22 Apr 2026 22:46:54 -0700 Subject: [PATCH 6/6] Update dev_tools/prepared_env_security_test.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- dev_tools/prepared_env_security_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev_tools/prepared_env_security_test.py b/dev_tools/prepared_env_security_test.py index 9ba02654b..e657fe583 100644 --- a/dev_tools/prepared_env_security_test.py +++ b/dev_tools/prepared_env_security_test.py @@ -29,7 +29,7 @@ def test_report_status_to_github_token_in_header(self, mock_post): # Security check: Token should be in the Authorization header self.assertEqual( headers.get('Authorization'), - 'token my-token', + 'Bearer my-token', "Token should be passed in the Authorization header", )