From dbe8bcd197c13d8c7c5e3ba32faeac20a91a6ca5 Mon Sep 17 00:00:00 2001 From: Alexander Piskun Date: Sun, 12 Apr 2026 14:06:28 +0000 Subject: [PATCH] fix: use GITHUB_TOKEN in get_latest_release to avoid rate limits (#425) --- comfy_cli/command/install.py | 10 ++++- tests/comfy_cli/command/github/test_pr.py | 52 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/comfy_cli/command/install.py b/comfy_cli/command/install.py index 45eb0691..b5e3357e 100755 --- a/comfy_cli/command/install.py +++ b/comfy_cli/command/install.py @@ -476,8 +476,16 @@ def get_latest_release(repo_owner: str, repo_name: str) -> GithubRelease | None: """ url = f"https://api.github.com/repos/{repo_owner}/{repo_name}/releases/latest" + headers = {} + if github_token := os.getenv("GITHUB_TOKEN"): + headers["Authorization"] = f"Bearer {github_token}" + try: - response = requests.get(url, timeout=5) + response = requests.get(url, headers=headers, timeout=5) + + if response.status_code in (403, 429): + handle_github_rate_limit(response) + response.raise_for_status() data = response.json() diff --git a/tests/comfy_cli/command/github/test_pr.py b/tests/comfy_cli/command/github/test_pr.py index 5922e47e..61c237c1 100644 --- a/tests/comfy_cli/command/github/test_pr.py +++ b/tests/comfy_cli/command/github/test_pr.py @@ -11,6 +11,7 @@ PRInfo, fetch_pr_info, find_pr_by_branch, + get_latest_release, handle_github_rate_limit, handle_pr_checkout, parse_pr_reference, @@ -445,6 +446,57 @@ def test_checkout_pr_remote_already_exists(self, mock_getcwd, mock_chdir, mock_s assert mock_subprocess.call_count == 3 +class TestGetLatestRelease: + """Test get_latest_release GitHub API calls""" + + @patch("requests.get") + def test_sends_auth_header_when_token_set(self, mock_get): + """Ensure GITHUB_TOKEN is sent as Bearer auth to avoid rate limits (issue #425)""" + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "tag_name": "v0.18.2", + "zipball_url": "https://github.com/comfyanonymous/ComfyUI/archive/v0.18.2.zip", + } + mock_get.return_value = mock_response + + with patch.dict("os.environ", {"GITHUB_TOKEN": "ghp_test123"}): + result = get_latest_release("comfyanonymous", "ComfyUI") + + headers = mock_get.call_args.kwargs.get("headers", {}) + assert headers["Authorization"] == "Bearer ghp_test123" + assert result is not None + assert result["tag"] == "v0.18.2" + + @patch("requests.get") + def test_no_auth_header_without_token(self, mock_get): + """Without GITHUB_TOKEN the request has no Authorization header""" + mock_response = Mock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "tag_name": "v0.18.2", + "zipball_url": "https://github.com/comfyanonymous/ComfyUI/archive/v0.18.2.zip", + } + mock_get.return_value = mock_response + + with patch.dict("os.environ", {}, clear=True): + get_latest_release("comfyanonymous", "ComfyUI") + + headers = mock_get.call_args.kwargs.get("headers", {}) + assert "Authorization" not in headers + + @patch("requests.get") + def test_rate_limit_raises_error(self, mock_get): + """A 403 with exhausted rate limit raises GitHubRateLimitError""" + mock_response = Mock() + mock_response.status_code = 403 + mock_response.headers = {"x-ratelimit-remaining": "0", "x-ratelimit-reset": "1700000000"} + mock_get.return_value = mock_response + + with pytest.raises(GitHubRateLimitError): + get_latest_release("comfyanonymous", "ComfyUI") + + class TestHandleGithubRateLimit: def test_primary_rate_limit_message_format(self): """Verify the error message does not contain stray characters."""