From a046d0a0c7420307205f34f779f89eae21238061 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Wed, 1 Jul 2026 20:42:50 +0200 Subject: [PATCH] Limit installations the bot runs on --- .env.example | 1 + .github/workflows/cron.yml | 1 + README.md | 4 +++- src/psrt_ghsa_bot/app.py | 9 ++++++++- tests/test_app.py | 24 ++++++++++++++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 7bbe4b0..6387b73 100644 --- a/.env.example +++ b/.env.example @@ -5,4 +5,5 @@ CVE_USERNAME="user@example.org" CVE_API_KEY="123456" CVE_ENV="testproddev" CVE_ENABLED_REPOS="python/cpython" +REQUIRED_ORG="python" SENTRY_DSN="{PROTOCOL}://{PUBLIC_KEY}:{SECRET_KEY}@{HOST}{PATH}/{PROJECT_ID}" diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 6ac8a22..426ba01 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -45,4 +45,5 @@ jobs: CVE_API_KEY: ${{ secrets.CVE_API_KEY }} CVE_ENV: ${{ vars.CVE_ENV }} CVE_ENABLED_REPOS: ${{ vars.CVE_ENABLED_REPOS }} + REQUIRED_ORG: ${{ vars.REQUIRED_ORG }} SENTRY_DSN: ${{ github.event_name == 'schedule' && secrets.SENTRY_DSN || '' }} diff --git a/README.md b/README.md index 603967e..5ab74a9 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,9 @@ and, for every advisory it closes ones marked as completed, promotes accepted on from triage to draft, reserves CVE IDs, creates private forks, and adds the PSRT team as collaborators. -It processes every repository the GitHub App is installed on. +It only processes installations owned by the account named in the `REQUIRED_ORG` +environment variable; installations under any other user are skipped. +For that account it processes every repository the GitHub App is installed on. The process is identical across repositories except that CVE IDs are only reserved for repositories listed in the `CVE_ENABLED_REPOS` environment variable. diff --git a/src/psrt_ghsa_bot/app.py b/src/psrt_ghsa_bot/app.py index 46c9754..b0746da 100644 --- a/src/psrt_ghsa_bot/app.py +++ b/src/psrt_ghsa_bot/app.py @@ -223,6 +223,8 @@ def run() -> None: name.strip() for name in (os.environ.get("CVE_ENABLED_REPOS") or "python/cpython").split(",") if name.strip() ) + required_org = os.environ["REQUIRED_ORG"] + print("Fetching installations...") # Apply to all repositories for each installation. installations = github.rest.paginate( @@ -230,8 +232,13 @@ def run() -> None: ) installation_count = 0 for installation_data in installations: + account_login = installation_data.account.login + if account_login.lower() != required_org.lower(): + print(f"\n⏭️ Skipping installation for {account_login!r} (not {required_org!r})") + continue + installation_count += 1 - print(f"\nProcessing installation {installation_count}: {installation_data.account.login}") + print(f"\nProcessing installation {installation_count}: {account_login}") installation_github = github.with_auth( github.auth.as_installation(installation_data.id), diff --git a/tests/test_app.py b/tests/test_app.py index 25551c8..8b4ab4e 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -259,3 +259,27 @@ def test_reserve_one_cve_id(cve_reserve_response, cve_id, year) -> None: assert app.reserve_one_cve(cve_api) == cve_id cve_api.reserve.assert_called_with(count=1, year=year, random=True) + + +def test_only_processes_installations_for_required_org(monkeypatch) -> None: + monkeypatch.setenv("GH_CLIENT_ID", "123") + monkeypatch.setenv("GH_CLIENT_PRIVATE_KEY", "a2V5") + monkeypatch.setenv("CVE_USERNAME", "stan@python.org") + monkeypatch.setenv("CVE_API_KEY", "key") + monkeypatch.setenv("REQUIRED_ORG", "python") + + github = mock.Mock() + github.rest.paginate.return_value = [ + mock.Mock(id=1, account=mock.Mock(login="evil-org")), + mock.Mock(id=2, account=mock.Mock(login="python")), + ] + github.with_auth.return_value.rest.paginate.return_value = [] + + with ( + mock.patch("psrt_ghsa_bot.app.GitHub", return_value=github), + mock.patch("psrt_ghsa_bot.app.CveApi"), + mock.patch("psrt_ghsa_bot.app.apply_to_repo"), + ): + app.run() + + github.auth.as_installation.assert_called_once_with(2)