fix(skills-hub): cover remaining SSRF fetch paths after #10029

This commit is contained in:
heathley 2026-05-09 23:18:49 +03:00 committed by Teknium
parent af9df46525
commit 0c5c4d1b8d
3 changed files with 135 additions and 25 deletions

View file

@ -560,6 +560,11 @@ class TestFindSkillInRepoTree:
class TestWellKnownSkillSource:
@pytest.fixture(autouse=True)
def _allow_public_skill_fetches(self, monkeypatch):
monkeypatch.setattr("tools.skills_hub.is_safe_url", lambda _url: True)
monkeypatch.setattr("tools.skills_hub.check_website_access", lambda _url: None)
def _source(self):
return WellKnownSkillSource()
@ -675,6 +680,11 @@ class TestWellKnownSkillSource:
class TestUrlSource:
@pytest.fixture(autouse=True)
def _allow_public_skill_fetches(self, monkeypatch):
monkeypatch.setattr("tools.skills_hub.is_safe_url", lambda _url: True)
monkeypatch.setattr("tools.skills_hub.check_website_access", lambda _url: None)
def _source(self):
return UrlSource()
@ -753,6 +763,13 @@ class TestUrlSource:
mock_get.side_effect = httpx.HTTPError("boom")
assert self._source().inspect("https://example.com/SKILL.md") is None
@patch("tools.skills_hub.httpx.get")
@patch("tools.skills_hub.check_website_access", return_value=None)
@patch("tools.skills_hub.is_safe_url", return_value=False)
def test_inspect_blocks_private_url(self, _mock_safe, _mock_policy, mock_get):
assert self._source().inspect("http://127.0.0.1/SKILL.md") is None
mock_get.assert_not_called()
@patch("tools.skills_hub.httpx.get")
def test_inspect_flags_awaiting_name_when_unresolvable(self, mock_get):
# No frontmatter name + a URL path that can't produce a valid slug
@ -855,6 +872,24 @@ class TestUrlSource:
mock_get.return_value = MagicMock(status_code=404)
assert self._source().fetch("https://example.com/SKILL.md") is None
@patch("tools.skills_hub.httpx.get")
@patch("tools.skills_hub.check_website_access", return_value=None)
@patch("tools.skills_hub.is_safe_url", side_effect=[True, False])
def test_fetch_blocks_redirect_to_private_url(self, _mock_safe, _mock_policy, mock_get):
redirect = MagicMock(status_code=302)
redirect.headers = {"location": "http://127.0.0.1/private/SKILL.md"}
mock_get.return_value = redirect
assert self._source().fetch("https://example.com/SKILL.md") is None
assert mock_get.call_count == 1
@patch("tools.skills_hub.httpx.get")
@patch("tools.skills_hub.check_website_access", return_value=None)
@patch("tools.skills_hub.is_safe_url", return_value=False)
def test_fetch_blocks_private_url(self, _mock_safe, _mock_policy, mock_get):
assert self._source().fetch("http://127.0.0.1/SKILL.md") is None
mock_get.assert_not_called()
@patch("tools.skills_hub.httpx.get")
def test_fetch_skips_non_matching_identifier(self, mock_get):
assert self._source().fetch("owner/repo/skill") is None