77from unittest .mock import AsyncMock , MagicMock
88
99import pytest
10+ from pydantic import SecretStr
1011
1112from foreman .config import RepoConfig
1213from foreman .memory import MemoryStore
@@ -75,7 +76,7 @@ def test_returns_events_for_open_issues(self, memory: MemoryStore, mocker) -> No
7576 mock_repo .get_issues .return_value = [make_issue (1 ), make_issue (2 )]
7677 mock_repo .get_collaborators .return_value = []
7778
78- poller = GitHubPoller (token = "test-token" , memory = memory )
79+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
7980 events = poller .poll_repo (RepoConfig (owner = "owner" , name = "repo" ))
8081
8182 assert len (events ) == 2
@@ -88,7 +89,7 @@ def test_event_has_required_fields(self, memory: MemoryStore, mocker) -> None:
8889 mock_repo .get_issues .return_value = [make_issue (7 )]
8990 mock_repo .get_collaborators .return_value = []
9091
91- poller = GitHubPoller (token = "test-token" , memory = memory )
92+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
9293 events = poller .poll_repo (RepoConfig (owner = "owner" , name = "repo" ))
9394
9495 assert len (events ) == 1
@@ -108,7 +109,7 @@ def test_skips_issues_by_collaborators(self, memory: MemoryStore, mocker) -> Non
108109 ]
109110 mock_repo .get_collaborators .return_value = [make_collaborator ("maintainer" )]
110111
111- poller = GitHubPoller (token = "test-token" , memory = memory )
112+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
112113 events = poller .poll_repo (RepoConfig (owner = "owner" , name = "repo" ))
113114
114115 assert len (events ) == 1
@@ -125,7 +126,7 @@ def test_passes_since_to_get_issues_when_last_polled_set(self, memory: MemorySto
125126 last_polled = datetime (2024 , 6 , 1 , tzinfo = timezone .utc )
126127 memory .set_last_polled ("owner/repo" , last_polled )
127128
128- poller = GitHubPoller (token = "test-token" , memory = memory )
129+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
129130 poller .poll_repo (RepoConfig (owner = "owner" , name = "repo" ))
130131
131132 call_kwargs = mock_repo .get_issues .call_args
@@ -139,7 +140,7 @@ def test_get_issues_called_without_since_on_first_poll(self, memory: MemoryStore
139140 mock_repo .get_issues .return_value = []
140141 mock_repo .get_collaborators .return_value = []
141142
142- poller = GitHubPoller (token = "test-token" , memory = memory )
143+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
143144 poller .poll_repo (RepoConfig (owner = "owner" , name = "repo" ))
144145
145146 call_kwargs = mock_repo .get_issues .call_args
@@ -155,7 +156,7 @@ def test_updates_last_polled_after_successful_poll(self, memory: MemoryStore, mo
155156
156157 assert memory .get_last_polled ("owner/repo" ) is None
157158
158- poller = GitHubPoller (token = "test-token" , memory = memory )
159+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
159160 poller .poll_repo (RepoConfig (owner = "owner" , name = "repo" ))
160161
161162 assert memory .get_last_polled ("owner/repo" ) is not None
@@ -168,11 +169,11 @@ def test_last_polled_survives_new_instance(self, memory: MemoryStore, mocker) ->
168169 mock_repo .get_issues .return_value = []
169170 mock_repo .get_collaborators .return_value = []
170171
171- poller1 = GitHubPoller (token = "test-token" , memory = memory )
172+ poller1 = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
172173 poller1 .poll_repo (RepoConfig (owner = "owner" , name = "repo" ))
173174 ts1 = memory .get_last_polled ("owner/repo" )
174175
175- poller2 = GitHubPoller (token = "test-token" , memory = memory )
176+ poller2 = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
176177 poller2 .poll_repo (RepoConfig (owner = "owner" , name = "repo" ))
177178 ts2 = memory .get_last_polled ("owner/repo" )
178179
@@ -188,7 +189,7 @@ def test_payload_contains_issue_metadata(self, memory: MemoryStore, mocker) -> N
188189 mock_repo .get_issues .return_value = [make_issue (3 , author_login = "alice" , title = "A bug" )]
189190 mock_repo .get_collaborators .return_value = []
190191
191- poller = GitHubPoller (token = "test-token" , memory = memory )
192+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
192193 events = poller .poll_repo (RepoConfig (owner = "owner" , name = "repo" ))
193194
194195 payload = events [0 ]["payload" ]
@@ -211,7 +212,7 @@ async def test_poll_all_calls_poll_repo_for_each_repo(self, memory: MemoryStore,
211212 mocker .patch ("foreman.poller.Github" )
212213 mock_poll = mocker .patch .object (GitHubPoller , "poll_repo" , return_value = [])
213214
214- poller = GitHubPoller (token = "test-token" , memory = memory )
215+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
215216 repos = [
216217 RepoConfig (owner = "org" , name = "repo1" ),
217218 RepoConfig (owner = "org" , name = "repo2" ),
@@ -235,7 +236,7 @@ def side_effect(repo_cfg: RepoConfig):
235236
236237 mocker .patch .object (GitHubPoller , "poll_repo" , side_effect = side_effect )
237238
238- poller = GitHubPoller (token = "test-token" , memory = memory )
239+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
239240 repos = [RepoConfig (owner = "org" , name = "repo1" ), RepoConfig (owner = "org" , name = "repo2" )]
240241 collected : list [dict ] = []
241242
@@ -250,7 +251,7 @@ async def callback(repo_cfg: RepoConfig, event: dict) -> None:
250251 async def test_poll_all_with_empty_repo_list (self , memory : MemoryStore , mocker ) -> None :
251252 """poll_all completes without error when given an empty repo list."""
252253 mocker .patch ("foreman.poller.Github" )
253- poller = GitHubPoller (token = "test-token" , memory = memory )
254+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
254255 await poller .poll_all ([], AsyncMock ()) # must not raise
255256
256257
@@ -281,7 +282,7 @@ def fail_then_succeed(repo_cfg: RepoConfig):
281282
282283 mocker .patch .object (GitHubPoller , "poll_repo" , side_effect = fail_then_succeed )
283284
284- poller = GitHubPoller (token = "test-token" , memory = memory )
285+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
285286 await poller .poll_all ([RepoConfig (owner = "owner" , name = "repo" )], AsyncMock ())
286287
287288 assert call_count == 2 , "should retry once after 429"
@@ -306,7 +307,7 @@ def fail_then_succeed(repo_cfg: RepoConfig):
306307
307308 mocker .patch .object (GitHubPoller , "poll_repo" , side_effect = fail_then_succeed )
308309
309- poller = GitHubPoller (token = "test-token" , memory = memory )
310+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
310311 await poller .poll_all ([RepoConfig (owner = "owner" , name = "repo" )], AsyncMock ())
311312
312313 assert call_count == 2
@@ -325,7 +326,7 @@ async def test_poll_all_skips_repo_after_repeated_failures(self, memory: MemoryS
325326 side_effect = GithubException (429 , {"message" : "rate limited" }, {}),
326327 )
327328
328- poller = GitHubPoller (token = "test-token" , memory = memory )
329+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
329330 # Must not raise
330331 await poller .poll_all ([RepoConfig (owner = "owner" , name = "repo" )], AsyncMock ())
331332
@@ -345,7 +346,7 @@ async def test_non_rate_limit_github_exception_logs_error_and_skips_repo(
345346 side_effect = GithubException (500 , {"message" : "server error" }, {}),
346347 )
347348
348- poller = GitHubPoller (token = "test-token" , memory = memory )
349+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
349350 # Must not raise — error is logged and repo is skipped this cycle
350351 await poller .poll_all ([RepoConfig (owner = "owner" , name = "repo" )], AsyncMock ())
351352
@@ -365,7 +366,7 @@ async def test_bad_credentials_logs_critical_and_skips_repo(self, memory: Memory
365366 side_effect = GithubException (401 , {"message" : "Bad credentials" }, {}),
366367 )
367368
368- poller = GitHubPoller (token = "test-token" , memory = memory )
369+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
369370 # Must not raise — critical is logged and repo is skipped
370371 await poller .poll_all ([RepoConfig (owner = "owner" , name = "repo" )], AsyncMock ())
371372
@@ -383,14 +384,14 @@ class TestSemaphore:
383384 def test_default_max_concurrent_is_five (self , memory : MemoryStore , mocker ) -> None :
384385 """GitHubPoller defaults to max_concurrent=5."""
385386 mocker .patch ("foreman.poller.Github" )
386- poller = GitHubPoller (token = "test-token" , memory = memory )
387- assert poller ._max_concurrent == 5 # noqa: SLF001
387+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory )
388+ assert poller ._max_concurrent == 5
388389
389390 def test_custom_max_concurrent_is_stored (self , memory : MemoryStore , mocker ) -> None :
390391 """max_concurrent passed to __init__ is stored on the instance."""
391392 mocker .patch ("foreman.poller.Github" )
392- poller = GitHubPoller (token = "test-token" , memory = memory , max_concurrent = 2 )
393- assert poller ._max_concurrent == 2 # noqa: SLF001
393+ poller = GitHubPoller (token = SecretStr ( "test-token" ) , memory = memory , max_concurrent = 2 )
394+ assert poller ._max_concurrent == 2
394395
395396
396397# ---------------------------------------------------------------------------
0 commit comments