Repository: pypi/warehouse

Issue:
2FA giveaway lists critical + 2FA required projects, should only list critical
<!--
    NOTE: This issue should be for problems with PyPI itself, including:
    * pypi.org
    * test.pypi.org
    * files.pythonhosted.org

    This issue should NOT be for a project installed from PyPI. If you are
    having an issue with a specific package, you should reach out to the
    maintainers of that project directly instead.

    Furthermore, this issue should NOT be for any non-PyPI properties (like
    python.org, docs.python.org, etc.)

    If your problem is related to search (a new or updated project doesn't
    appear in the PyPI search results), please wait for a couple of hours
    and check again before reporting it. The search index may take some
    time to be updated.
-->

**Describe the bug**
<!-- A clear and concise description the bug -->

The 2FA key giveaway eligibility says:

"Congrats, you may be eligible to receive a promo code! The following projects you maintain are considered critical projects:"

But not all of these 15 are critical:

<img width="903" alt="image" src="https://user-images.githubusercontent.com/1324225/186908565-479f41ab-6b23-4506-8469-f164fd49b96e.png">

**Expected behavior**
<!-- A clear and concise description of what you expected to happen -->

Only list the critical projects. 

At https://pypi.org/manage/projects/ only these 4 are listed as critical: prettytable, humanize, ujson, Pillow.

**To Reproduce**
<!-- Steps to reproduce the bug, or a link to PyPI where the bug is visible -->

1. Visit https://pypi.org/security-key-giveaway/
2. Click "Log in to determine if you are eligible" and log in


**My Platform**
<!--
    Any details about your specific platform:
    * If the problem is in the browser, what browser, version, and OS?
    * If the problem is with a command-line tool, what version of that tool?
    * If the problem is with connecting to PyPI, include some details about
      your network, including SSL/TLS implementation in use, internet service
      provider, and if there are any firewalls or proxies in use.
-->

n/a

**Additional context**
<!-- Add any other context, links, etc. about the feature here. -->

I have 18 projects at https://pypi.org/manage/projects/

* 4 are critical
* 11 I've also set as 2FA required
* looks like these 4+11 are being listed as critical on the promo page, but it should just be the 4



Discussion:
Thanks, looks like this line is incorrect: https://github.com/pypi/warehouse/blob/f2d6fc455a135b3b3ba72539d5c9f4c4f0d48223/warehouse/views.py#L487

It's taking into account all projects that require 2FA, not just the critical ones. We'll probably want to additionally filter this comprehension on `project.pypi_mandates_2fa`: https://github.com/pypi/warehouse/blob/604b675e9c554ce7da6d4af8f4019a79282ed864/warehouse/packaging/models.py#L157

Resolving patch:
diff --git a/warehouse/views.py b/warehouse/views.py
--- a/warehouse/views.py
+++ b/warehouse/views.py
@@ -485,6 +485,7 @@ def eligible_projects(self):
             return set(
                 project.name
                 for project in user_projects(self.request)["projects_requiring_2fa"]
+                if project.pypi_mandates_2fa
             )
         else:
             return set()


Test patch:
diff --git a/tests/unit/test_views.py b/tests/unit/test_views.py
--- a/tests/unit/test_views.py
+++ b/tests/unit/test_views.py
@@ -594,11 +594,16 @@ def test_eligible_projects_no_user(self, db_request):
 
     def test_eligible_projects_owners_require_2fa(self, db_request):
         db_request.user = UserFactory.create()
+
         ProjectFactory.create()
-        project = ProjectFactory.create(owners_require_2fa=True)
-        RoleFactory.create(user=db_request.user, project=project)
+        ProjectFactory.create(owners_require_2fa=True)
+        p1 = ProjectFactory.create(pypi_mandates_2fa=True)
+        p2 = ProjectFactory.create(owners_require_2fa=True, pypi_mandates_2fa=True)
 
-        assert SecurityKeyGiveaway(db_request).eligible_projects == {project.name}
+        RoleFactory.create(user=db_request.user, project=p1)
+        RoleFactory.create(user=db_request.user, project=p2)
+
+        assert SecurityKeyGiveaway(db_request).eligible_projects == {p1.name, p2.name}
 
     def test_eligible_projects_pypi_mandates_2fa(self, db_request):
         db_request.user = UserFactory.create()