diff --git a/src/psrt_ghsa_bot/app.py b/src/psrt_ghsa_bot/app.py index 7c7f248..d860e71 100644 --- a/src/psrt_ghsa_bot/app.py +++ b/src/psrt_ghsa_bot/app.py @@ -161,6 +161,20 @@ def apply_to_repo( print(f" 🧹 Closed {ghsa_id}") continue + # Advisories that are in the 'draft' state without a private + # fork active will have a fork requested. + if state == "draft" and security_advisory.get("private_fork") is None: + print(" 🔨 No private fork, creating a private fork") + try: + github.rest.security_advisories.create_fork( + owner=owner, + repo=repo, + ghsa_id=ghsa_id, + ) + except RequestFailed as e: + print(f" ⚠️ Error creating private fork: {e.response.json()}") + raise e + # Maintain a dictionary of updates to make and then submit them all at once. patch_data = {} diff --git a/tests/test_app.py b/tests/test_app.py index bb1d124..4c444fe 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -43,6 +43,7 @@ def _create_advisory_dict(state, cve_id, collaborating_teams, summary=""): "cve_id": cve_id, "collaborating_teams": [{"slug": team} for team in collaborating_teams], "collaborating_users": [{"login": "octocat", "id": 1, "type": "User"}], + "private_fork": {"name": "repo-ghsa-xxxx-xxxx-xxxx", "owner": {"login": "owner"}}, } @@ -156,8 +157,6 @@ def test_does_not_reserve_cve_id_for_triage_security_advisories(state) -> None: def test_update_collaborating_users() -> None: - security_advisory = _create_advisory_dict("draft", None, ["psrt"]) - github = mock.Mock() cve_api = mock.Mock() @@ -178,6 +177,26 @@ def test_update_collaborating_users() -> None: ) +def test_create_private_fork() -> None: + github = mock.Mock() + cve_api = mock.Mock() + + with ( + mock.patch("psrt_ghsa_bot.app.get_repository_advisories") as get_repo_advs, + ): + security_advisory = _create_advisory_dict("draft", "CVE-2026-0001", ["psrt"]) + security_advisory.pop("private_fork", None) + get_repo_advs.return_value = [security_advisory] + + app.apply_to_repo(github, "owner", "repo", cve_api) + + github.rest.security_advisories.create_fork.assert_called_once_with( + owner="owner", + repo="repo", + ghsa_id="GHSA-xxxx-xxxx-xxxx", + ) + + @pytest.mark.parametrize( "summary", [