@@ -663,3 +663,79 @@ def fake_get(url, headers=None, timeout=None):
663663 )
664664 assert not any (url == "https://opencode.ai/zen/go/v1/models" for url , _ , _ in calls )
665665 assert not any ("opencode" in url .lower () and "models" in url .lower () for url , _ , _ in calls )
666+
667+
668+ class TestGitHubTokenCheck :
669+ """Tests for GitHub token / gh auth detection in doctor."""
670+
671+ def test_no_token_and_not_gh_authenticated_shows_warn (self , monkeypatch , tmp_path ):
672+ home = tmp_path / ".hermes"
673+ home .mkdir (parents = True , exist_ok = True )
674+ monkeypatch .setenv ("HERMES_HOME" , str (home ))
675+ monkeypatch .setenv ("PATH" , "/nonexistent" ) # gh not found
676+
677+ from hermes_cli .doctor import run_doctor , _DHH
678+ import io , contextlib
679+
680+ buf = io .StringIO ()
681+ with contextlib .redirect_stdout (buf ):
682+ run_doctor (Namespace (fix = False ))
683+ out = buf .getvalue ()
684+
685+ assert "No GITHUB_TOKEN" in out
686+ assert "60 req/hr" in out
687+
688+ def test_token_env_present_shows_ok (self , monkeypatch , tmp_path ):
689+ home = tmp_path / ".hermes"
690+ home .mkdir (parents = True , exist_ok = True )
691+ monkeypatch .setenv ("HERMES_HOME" , str (home ))
692+ monkeypatch .setenv ("GITHUB_TOKEN" , "ghp_test123" )
693+ monkeypatch .setenv ("PATH" , "/nonexistent" ) # gh not found
694+
695+ from hermes_cli .doctor import run_doctor
696+ import io , contextlib
697+
698+ buf = io .StringIO ()
699+ with contextlib .redirect_stdout (buf ):
700+ run_doctor (Namespace (fix = False ))
701+ out = buf .getvalue ()
702+
703+ assert "GitHub token configured" in out
704+
705+ def test_gh_authenticated_without_env_token_shows_ok (self , monkeypatch , tmp_path ):
706+ home = tmp_path / ".hermes"
707+ home .mkdir (parents = True , exist_ok = True )
708+ monkeypatch .setenv ("HERMES_HOME" , str (home ))
709+ # No GITHUB_TOKEN or GH_TOKEN
710+ monkeypatch .delenv ("GITHUB_TOKEN" , raising = False )
711+ monkeypatch .delenv ("GH_TOKEN" , raising = False )
712+
713+ # Mock gh to return success
714+ import shutil
715+ real_which = shutil .which
716+ def mock_which (cmd ):
717+ return "/usr/local/bin/gh" if cmd == "gh" else real_which (cmd )
718+ monkeypatch .setattr (shutil , "which" , mock_which )
719+
720+ call_log = []
721+ def mock_run (cmd , ** kwargs ):
722+ call_log .append (cmd )
723+ if cmd [:2 ] == ["gh" , "auth" ]:
724+ result = types .SimpleNamespace (returncode = 0 , stdout = "" , stderr = "" )
725+ else :
726+ result = types .SimpleNamespace (returncode = 1 , stdout = "" , stderr = "" )
727+ return result
728+
729+ import subprocess
730+ monkeypatch .setattr (subprocess , "run" , mock_run )
731+
732+ from hermes_cli .doctor import run_doctor
733+ import io , contextlib
734+
735+ buf = io .StringIO ()
736+ with contextlib .redirect_stdout (buf ):
737+ run_doctor (Namespace (fix = False ))
738+ out = buf .getvalue ()
739+
740+ assert "gh auth" in str (call_log ) or any (c [0 ] == "gh" for c in call_log ), f"gh not called: { call_log } "
741+ assert "GitHub authenticated via gh CLI" in out or "token configured" in out
0 commit comments