From 43f903f797f075a477a3b95405e99d261939330f Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Wed, 6 May 2026 13:34:49 -0500 Subject: [PATCH 1/3] Automatically create private forks for draft reports --- src/psrt_ghsa_bot/app.py | 14 ++++++++++++++ tests/test_app.py | 23 +++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/psrt_ghsa_bot/app.py b/src/psrt_ghsa_bot/app.py index 7c7f248..672d0e2 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(f" + 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", [ From e1536681f97e66cac4b23420de5cd5ade329caab Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Wed, 6 May 2026 13:38:45 -0500 Subject: [PATCH 2/3] -f --- src/psrt_ghsa_bot/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psrt_ghsa_bot/app.py b/src/psrt_ghsa_bot/app.py index 672d0e2..e447480 100644 --- a/src/psrt_ghsa_bot/app.py +++ b/src/psrt_ghsa_bot/app.py @@ -164,7 +164,7 @@ def apply_to_repo( # 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(f" + No private fork, creating a private fork") + print(" + No private fork, creating a private fork") try: github.rest.security_advisories.create_fork( owner=owner, From b58be9a84be85de124fce5a431d874b69db422b2 Mon Sep 17 00:00:00 2001 From: Seth Larson Date: Wed, 6 May 2026 18:40:34 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/psrt_ghsa_bot/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psrt_ghsa_bot/app.py b/src/psrt_ghsa_bot/app.py index e447480..d860e71 100644 --- a/src/psrt_ghsa_bot/app.py +++ b/src/psrt_ghsa_bot/app.py @@ -164,7 +164,7 @@ def apply_to_repo( # 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") + print(" 🔨 No private fork, creating a private fork") try: github.rest.security_advisories.create_fork( owner=owner,