diff --git a/.env.example b/.env.example index 7bbe4b0..7280519 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" +GH_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..0222ef4 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 }} + GH_REQUIRED_ORG: ${{ vars.GH_REQUIRED_ORG }} SENTRY_DSN: ${{ github.event_name == 'schedule' && secrets.SENTRY_DSN || '' }} diff --git a/README.md b/README.md index 603967e..49c73ff 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 `GH_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..971a5d6 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["GH_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..e130477 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("GH_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)