fix: remove dead helper, add state logging, add integration-style oauth tests
- Remove unused `_gitea_cfg_url` module-level helper from http.py - Add logger.warning on invalid/expired state in oauth_gitea_callback - Add test_callback_invalid_state_rejects and test_full_oauth_flow_chain to tests/test_oauth.py (21 tests total, all passing) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -259,3 +259,66 @@ async def test_fetch_user_raises_on_error_status():
|
||||
)):
|
||||
with pytest.raises(oauth.OAuthError):
|
||||
await oauth.fetch_user(CFG_ON, "tok123")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Integration-style tests: callback logic chain
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_callback_invalid_state_rejects():
|
||||
"""Verify validate_state returns False for unknown state tokens."""
|
||||
fake_state = "this-is-not-a-real-state"
|
||||
assert oauth.validate_state(fake_state) is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_full_oauth_flow_chain():
|
||||
"""Integration-style test: state → exchange → fetch → provision chain."""
|
||||
redirect_uri = "https://hbd.example.com/login/oauth/gitea/callback"
|
||||
|
||||
# Step 1: create a state token
|
||||
state = oauth.make_state()
|
||||
assert oauth.validate_state(state) is True # consumed; replay would return False
|
||||
|
||||
# Step 2: exchange code → token (mocked)
|
||||
mock_token_response = AsyncMock()
|
||||
mock_token_response.status = 200
|
||||
mock_token_response.json = AsyncMock(return_value={"access_token": "flow_token"})
|
||||
|
||||
mock_user_response = AsyncMock()
|
||||
mock_user_response.status = 200
|
||||
mock_user_response.json = AsyncMock(return_value={
|
||||
"login": "flowuser",
|
||||
"full_name": "Flow User",
|
||||
"avatar_url": "https://git.example.com/avatars/flow.png",
|
||||
})
|
||||
|
||||
mock_session = MagicMock()
|
||||
mock_session.post = MagicMock(return_value=AsyncMock(
|
||||
__aenter__=AsyncMock(return_value=mock_token_response),
|
||||
__aexit__=AsyncMock(return_value=False),
|
||||
))
|
||||
mock_session.get = MagicMock(return_value=AsyncMock(
|
||||
__aenter__=AsyncMock(return_value=mock_user_response),
|
||||
__aexit__=AsyncMock(return_value=False),
|
||||
))
|
||||
|
||||
with patch("hbd.server.oauth.aiohttp.ClientSession", return_value=AsyncMock(
|
||||
__aenter__=AsyncMock(return_value=mock_session),
|
||||
__aexit__=AsyncMock(return_value=False),
|
||||
)):
|
||||
token = await oauth.exchange_code(CFG_ON, "authcode", redirect_uri)
|
||||
profile = await oauth.fetch_user(CFG_ON, token)
|
||||
|
||||
assert token == "flow_token"
|
||||
assert profile["login"] == "flowuser"
|
||||
|
||||
# Step 3: provision user
|
||||
_reset_users()
|
||||
user = users_mod.provision_oauth_user(
|
||||
profile["login"], profile["full_name"], profile["avatar_url"]
|
||||
)
|
||||
assert user.username == "flowuser"
|
||||
assert user.check_password("anything") is False
|
||||
|
||||
Reference in New Issue
Block a user